Skip to content

style: consume the canonical cool design tokens from openadapt-web - #168

Merged
abrichr merged 1 commit into
mainfrom
codex/palette-docs
Aug 28, 2026
Merged

style: consume the canonical cool design tokens from openadapt-web#168
abrichr merged 1 commit into
mainfrom
codex/palette-docs

Conversation

@abrichr

@abrichr abrichr commented Aug 28, 2026

Copy link
Copy Markdown
Member

What was wrong

docs.openadapt.ai was serving the retired warm palette. It was not stale. The
Sync Documentation workflow ran and succeeded, and the CSS on the live site
matched the CSS on main byte for byte. Read from the live page:

--oa-ground   #f2f1ec      --surface          (undefined)
--oa-panel    #fdfcf9      --ink              (undefined)
--oa-ink      #23281f      --accent-verified  (undefined)
body background  rgb(242, 241, 236)

The source was simply four weeks behind: openadapt-web owns the tokens,
openadapt-cloud adopted them in its #325, openadapt-desktop in its #139, and
tokens.json already listed openadapt-ops docs (vendor + hash-check) among
its consumers. This makes that line true.

What carried the old palette

Three of the four carriers were invisible to a search for token names, and two
were invisible to a search of stylesheets.

where what how it hid
docs/stylesheets/brand.css a private copy of the whole palette as hex literals no canonical token name appears in it
docs/assets/logo.svg fill="#23281F" a stylesheet search does not reach an SVG
7 of 10 shipped images grounds measuring #f2f1ec, #fdfcf9, #fdfcf8 no text search of any kind reaches a PNG
tests/test_brand_styles.py the retired values pinned as expected constants the test agreed with the bug

What changed

styles/tokens.css and styles/tokens.json are vendored byte-identical from
openadapt-web into docs/stylesheets/vendor/openadapt-web/, hashing to the
same digests Cloud and Desktop recorded:

tokens.css   3697a7c8f7c9f671397a7f678d00354114e0b94c7d13265d3a970ce973b7e7fa
tokens.json  bf52a448c70d1e7333867661d4dd3f25b5ec920705de3739b5e63d5778f0d4f7

brand.css now defines no colour of its own. It maps the canonical tokens onto
Material's variables and derives every tint with color-mix(). Its dark scheme
uses the canonical --inset-* family, so the docs in dark mode and a dark
inset on openadapt.ai are the same two greys. Every link, heading, and footer
state clears WCAG AA, measured from the vendored tokens rather than from a copy
of their values.

All seven warm images are re-vendored from openadapt-web, which owns the
published visual record and re-shot them on the cool palette. Each copy is
byte-identical to its upstream file and hashes to the digest that repository's
provenance manifest records.

image ground before ground after
ui/desktop-qualification-cockpit.png #f2f1ec 76.1% #f5f7fa 75.8%
ui/business-decision-qualification-capture.png #f2f1ec 13.3% #ffffff 21.4%
ui/business-decision-runtime-request.png #fdfcf9 21.1% #ffffff 33.9%
ui/mobile-decision-request.jpg #fdfcf8 12.5% #ffffff 24.7%
ui/mobile-decision-pending.jpg #fdfcf8 18.2% #ffffff 26.3%
ui/mobile-decision-result.jpg #fdfcf8 13.2% #ffffff 21.9%
screenshots/dashboard-overview.png #fdfcf9 32.5% #ffffff 46.5%
screenshots/for-each-program-graph.png #ffffff 78.3% unchanged
showcase/demo.gif #0d0b1e 94.7% unchanged
favicon.ico #ffffff 68.0% unchanged

Measured, not eyeballed. #fdfcf9 and #fdfcf8 differ by one digit and read
as the same off-white; only measurement separates them.

The guard

tests/test_design_tokens.py runs offline in pytest tests/:

  • each vendored copy still hashes to what provenance.json pins
  • brand.css redefines no canonical colour token, and carries no literal
    colour at all
  • no retired value appears in any shipped stylesheet, template, script, or SVG
  • every image under docs/assets is recorded in
    docs/assets/visual-palette.json, still hashes to its record, and has a cool
    ground

The warm-ground rule is mechanical: the dominant colour must have blue >= red.
Every canonical ground satisfies it (#FFFFFF, #F5F7FA, #EDF1F6,
#0B1220) and every retired one fails it (#f2f1ec, #fbfaf6, #fdfcf9,
#fdfcf8, #f4f3ef, #f4f3ed). No allowlist, and no warm palette can satisfy
it. It stops at the dominant colour on purpose: a warm tint below the ground is
usually --accent-halt tinting a halt card, which is a canonical token
behaving correctly.

scripts/vendor_design_tokens.py --check is the online half, in its own CI
job. It fails when a vendored copy drifts from openadapt-web@main — that is,
when the surfaces have come apart again. Nothing is installed for it, so it
cannot break on a lock refresh.

Each of these was verified by reintroducing the regression it exists to catch
and watching the right test fail.

Verified

  • pytest tests/ — 289 passed
  • python scripts/validate_docs.py — passed
  • mkdocs build --strict — passed
  • The built site served locally and read through the browser:
    --surface #F5F7FA, --ink #0B1220, --accent-verified #0B7A5A,
    body background rgb(245, 247, 250), prose link rgb(11, 122, 90). Dark
    scheme: background rgb(11, 18, 32), link rgb(52, 211, 153), body text at
    14.7:1.

Note for reviewers

docs/assets/screenshots/PROVENANCE.txt is also touched by #165. This branch
edits only the dashboard-overview.png entry and one header sentence, to keep
that overlap as small as possible. #165 is not modified here.

docs.openadapt.ai was serving the retired warm palette. The site was not
stale: the deploy workflow ran and succeeded, and the CSS on the live site
matched the CSS on main byte for byte. The source was simply on the old
palette, four weeks after openadapt-web, openadapt-cloud (#325), and
openadapt-desktop (#139) had all moved off it.

Vendor styles/tokens.css and styles/tokens.json from openadapt-web
byte-identical, the same way Cloud and Desktop do, and hash them to the same
digests those two recorded. tokens.json already names "openadapt-ops docs
(vendor + hash-check)" among its consumers; this makes that true.

brand.css now defines no colour of its own. It maps the canonical tokens onto
Material's variables and derives every tint with color-mix(). Its dark scheme
uses the canonical --inset-* family, so the docs in dark mode and a dark inset
on openadapt.ai are the same two greys. Every link, heading, and footer state
clears WCAG AA, measured from the vendored tokens rather than from a copy of
their values.

Three carriers of the old palette had nothing to do with token names:

  - docs/assets/logo.svg set its fill to the warm ink #23281F. A search of
    stylesheets does not reach an SVG.
  - Seven of the ten shipped images were captured on the warm ground. Their
    measured dominant colours were #f2f1ec, #fdfcf9, and #fdfcf8; no text
    search of any kind reaches a PNG.
  - The docs kept a private copy of the palette as hex literals, so a search
    for canonical token names found nothing at all.

All seven images are re-vendored from openadapt-web, which owns the published
visual record and re-shot them on the cool palette. Each copy is byte-identical
to its upstream file and hashes to the digest that repository's provenance
manifest records. Their grounds now measure #ffffff and #f5f7fa.

The guards:

  - tests/test_design_tokens.py runs offline. It pins the digest of each
    vendored copy, fails when brand.css redefines a canonical colour token or
    carries any literal colour, fails on a retired value in any shipped
    stylesheet, template, script, or SVG, and fails when a shipped image is
    unrecorded, changed without re-measurement, or shot on a warm ground.
  - scripts/vendor_design_tokens.py --check runs in CI with network access and
    fails when a vendored copy drifts from openadapt-web@main.

The warm-ground rule is mechanical: the dominant colour of every shipped image
must have blue >= red. Every canonical ground satisfies it and every retired
one fails it, so it needs no allowlist. It stops at the dominant colour on
purpose, because a warm tint below the ground is usually --accent-halt doing
its job.

docs/assets/visual-palette.json records what was measured, because reading a
screenshot with your eyes cannot separate #f2f1ec from #f5f7fa.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@abrichr
abrichr merged commit a722dfb into main Aug 28, 2026
8 checks passed
@abrichr
abrichr deleted the codex/palette-docs branch August 28, 2026 00:39
abrichr added a commit that referenced this pull request Aug 28, 2026
… ledger

#168 landed the palette guard while this branch was open, and this branch adds
four images it has never measured. Three are cool. The fourth is not.

    program-workbench-desktop.png   #f2f1ed 33.1%   blue < red   FAILS
    program-state-live-relation.png #f6f7fb 23.1%   blue >= red
    program-workbench-cloud.png     #0c1220 19.7%   blue >= red
    program-workbench-cli.png       #ffffff 26.5%   blue >= red

`#f2f1ed` is one digit off the retired `#f2f1ec`, and the second colour,
`#fbfaf6` at 10.2%, is an exact retired value. Nobody can see that. The cause
is ordinary: openadapt-desktop added the workbench in its #137 and moved to the
canonical tokens in its #139, and the capture came from a build between them.

Re-shot from `ebc10b0`, the #139 merge, at the same 1440x1000 through the same
`?surface=program-workbench-preview` route. Ground is now `#f5f7fa` at 35.1%,
which is the canonical `--surface`. Nothing was tinted and the guard was not
touched.

Ledger entries added for all four, so the two "recorded set == disk set" tests
cover them. Each names the upstream repository, and the desktop entry names the
commit and says why that commit is the one that matters.

Two other things this pass found.

`dashboard-overview.png` is vendored from openadapt-web
public/product-preview/dashboard-workflows.png, and that file was re-shot in
openadapt-web #405 tonight. The copy here is refreshed so the byte-identity the
ledger claims is true again, and the PROVENANCE entry now names the Cloud
commit it actually came from.

The PROVENANCE header said every product-chrome capture is a byte-identical
copy of an openadapt-web file. These four are not: openadapt-web publishes
those surfaces as live components, not as stills. The header says so now.

Verified: 289 tests pass, `measure_asset_palette.py` reports 14 of 14 matching,
strict mkdocs build clean. Merging main brought no conflict in PROVENANCE.txt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
abrichr added a commit that referenced this pull request Aug 28, 2026
* docs: explain the program evidence visual system

* docs: re-shoot the desktop workbench cool, and record all four in the ledger

#168 landed the palette guard while this branch was open, and this branch adds
four images it has never measured. Three are cool. The fourth is not.

    program-workbench-desktop.png   #f2f1ed 33.1%   blue < red   FAILS
    program-state-live-relation.png #f6f7fb 23.1%   blue >= red
    program-workbench-cloud.png     #0c1220 19.7%   blue >= red
    program-workbench-cli.png       #ffffff 26.5%   blue >= red

`#f2f1ed` is one digit off the retired `#f2f1ec`, and the second colour,
`#fbfaf6` at 10.2%, is an exact retired value. Nobody can see that. The cause
is ordinary: openadapt-desktop added the workbench in its #137 and moved to the
canonical tokens in its #139, and the capture came from a build between them.

Re-shot from `ebc10b0`, the #139 merge, at the same 1440x1000 through the same
`?surface=program-workbench-preview` route. Ground is now `#f5f7fa` at 35.1%,
which is the canonical `--surface`. Nothing was tinted and the guard was not
touched.

Ledger entries added for all four, so the two "recorded set == disk set" tests
cover them. Each names the upstream repository, and the desktop entry names the
commit and says why that commit is the one that matters.

Two other things this pass found.

`dashboard-overview.png` is vendored from openadapt-web
public/product-preview/dashboard-workflows.png, and that file was re-shot in
openadapt-web #405 tonight. The copy here is refreshed so the byte-identity the
ledger claims is true again, and the PROVENANCE entry now names the Cloud
commit it actually came from.

The PROVENANCE header said every product-chrome capture is a byte-identical
copy of an openadapt-web file. These four are not: openadapt-web publishes
those surfaces as live components, not as stills. The header says so now.

Verified: 289 tests pass, `measure_asset_palette.py` reports 14 of 14 matching,
strict mkdocs build clean. Merging main brought no conflict in PROVENANCE.txt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant