utils/.github/workflows
Krzysztof kuhy Rudnicki ccef40e817 unified-design-system: check one palette across all four token sources
`tokens.md` freezes the palette as prose and three packages re-express it
as code -- `web_ui/src/tokens.css`, `design_system`'s `tokens.dart`, and
gatelock's `LockConfig`. Nothing compared them, so "one palette
everywhere" held only for as long as four hand-maintained copies happened
to agree. A hex edited in one stack drifted silently in the other three.

`palette_check.py` parses all four and runs two halves:

  * agreement -- every mapped token carries the same hex in every
    non-exempt stack
  * completeness -- every colour parsed from any source must be mapped or
    exempted with a stated reason

The second half is the load-bearing one. A pure agreement check passes
happily when someone adds a token to one stack and never touches the map,
which is the drift most likely to actually happen; an unmapped token is
therefore a failure, not a skip. Absences are declared per token per stack
with a reason (Tk has no light theme and no borders; the categorical ramp
is web-only) so "this stack doesn't have it" is on the record rather than
a silent pass.

It found one real gap on its first run: `tokens.css` sets `--surface-2` to
`paper-raised` in the light block -- the light theme collapses both
elevation steps onto one surface -- which `tokens.md` documented only in
prose and no map covered. Now an explicitly compared row, so if either
half of that pair moves, it fails.

Proven to fail, not just to pass: drift injected into each of the four
sources in turn, plus an unmapped token, was caught every time with the
offending stack named; re-proven after the 250-line-cap split into
`palette_map.py`. Runs from its own workflow with deliberately no `paths:`
filter -- drift is a disagreement *between* packages, so a path-scoped
trigger would skip exactly the edit that causes it. That was not
hypothetical: `ramp_check.py` was reachable only from the
`web_ui/**`-filtered workflow, so a ramp edit in `tokens.md` or
`design_system` never ran it. It moves here too.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U4Rj3s7K2qzrLNgJqqPhno
2026-08-15 15:27:17 +02:00
..
crdt-sync-precommit.yml Root scaffold: README, LICENSE, per-subdirectory CI for utils monorepo 2026-07-10 13:02:20 +02:00
crdt-sync-tests.yml Root scaffold: README, LICENSE, per-subdirectory CI for utils monorepo 2026-07-10 13:02:20 +02:00
design-system-tests.yml Wire design_system into CI, and drop EmptyState's speculative action slot 2026-08-14 23:08:59 +02:00
gatelock-precommit.yml Let the gatelock workflows trigger on their own files 2026-08-03 18:36:47 +02:00
gatelock-tests.yml Let the gatelock workflows trigger on their own files 2026-08-03 18:36:47 +02:00
palette-drift.yml unified-design-system: check one palette across all four token sources 2026-08-15 15:27:17 +02:00
sync-settings-ui-tests.yml Add sync_settings_ui: shared Firebase-only sync settings screen 2026-08-12 23:10:17 +02:00
web-ui-tests.yml web_ui: add the CI + pre-commit gate, and make pnpm lint actually run 2026-08-15 15:08:18 +02:00