Skip to content

feat(gate): catch the tokens that resolve to nothing - #7

Merged
anilcancakir merged 1 commit into
mainfrom
feat/token-resolution-guard
Aug 27, 2026
Merged

feat(gate): catch the tokens that resolve to nothing#7
anilcancakir merged 1 commit into
mainfrom
feat/token-resolution-guard

Conversation

@anilcancakir

Copy link
Copy Markdown
Contributor

Wind drops an unrecognised token silently: no warning, no throw, nothing at the call site. So a token that never existed, one that was renamed, and one that works look identical in the source, and the only symptom is a colour that never appears.

That makes this the rare rule worth a test rather than a reviewer: the failure is invisible exactly where a person reads.

Mirrored from the guard in uptizm, where it found four dead tokens, two of them invisible to a full-tree review. It found two more here on its first run, and both are fixed rather than allowlisted.

1. text-destructive painted nothing

The dashboard's heart glyph rendered in the inherited colour. design:sync emits bg-destructive and text-on-destructive (the colour that sits on the solid) but no text- peer.

Worth naming as a shape: the role exists in DESIGN.md, the prefix does not exist in the generated map, and the near-miss reads perfectly.

2. config/view.dart reached for the raw palette

bg-white, text-gray-600, bg-red-500. Those resolve, so the first check cannot see them, which is why the second one exists: a hardcoded colour cannot answer to a theme change, and regenerating wind_theme.g.dart from a different DESIGN.md restyled the whole app while every dialog kept the old palette. Those strings are as much a design surface as a widget's className.

The dialog tones move as a result, deliberately: bg-white dark:bg-gray-800 becomes bg-surface-container, the card tone, because a dialog sits above the page rather than on it. The dark: peers disappear from that file because each alias already carries its own.

Two supporting changes

  • buildWindTheme() moves the assembly out of main(), so a test can ask the same theme the app runs on. A second copy would drift and certify the wrong map.
  • supplementAliases gives hand-authored tokens a home beside the generated file rather than inside it, since design:sync overwrites that file wholesale and would drop them silently.

Verification

bin/check green. Both halves mutation-tested: restoring one palette colour reddens the Token-Only check, dropping the supplement reddens the dead-token one.

Not visually verified. Driving this app locally fails on a CORS preflight between the web build and its API, an environment problem this change did not cause and does not fix, so the moved dialog tones have been reasoned about rather than looked at.

Wind drops an unrecognised token SILENTLY: no warning, no throw, nothing at
the call site. So a token that never existed, one that was renamed, and one
that works look identical in the source, and the only symptom is a colour
that never appears. That is the rare rule worth a test rather than a
reviewer, because the failure is invisible exactly where a person reads.

This guard mirrors one that first paid for itself in a product built on
this boilerplate, where it found four dead tokens, two of them invisible to
a full-tree review. It found two more here on its first run, and both are
fixed in this commit rather than allowlisted:

`text-destructive` resolved to nothing, so the dashboard's heart glyph
rendered in the inherited colour. `design:sync` emits `bg-destructive` and
`text-on-destructive` (the colour that sits ON the solid) but no `text-`
peer, which is a shape worth naming: the role exists in DESIGN.md, the
prefix does not exist in the generated map, and the near-miss reads
perfectly.

`config/view.dart` reached straight for `bg-white`, `text-gray-600` and
`bg-red-500`. Those resolve, so the first check cannot see them, which is
why the second one exists: a hardcoded colour cannot answer to a theme
change, and regenerating `wind_theme.g.dart` from a different DESIGN.md
restyled the whole app while every dialog kept the old palette. Those
strings are as much a design surface as a widget's className.

THE DIALOG TONES MOVE as a result, and deliberately: `bg-white
dark:bg-gray-800` becomes `bg-surface-container`, the card tone, because a
dialog sits above the page rather than on it. The `dark:` peers disappear
from that file because each alias already carries its own.

Two supporting changes. `buildWindTheme()` moves the assembly out of
`main()` so a test can ask the same theme the app runs on; a second copy
would drift and certify the wrong map. And `supplementAliases` gives
hand-authored tokens a home beside the generated file rather than inside
it, since `design:sync` overwrites that file wholesale and would drop them
silently.

Both halves mutation-tested: restoring one palette colour reddens the
Token-Only check, dropping the supplement reddens the dead-token one.
`bin/check` green.

NOT VISUALLY VERIFIED. Driving this app locally fails on a CORS preflight
between the web build and its API, which is an environment problem this
change did not cause and does not fix, so the moved dialog tones have been
reasoned about rather than looked at.
@anilcancakir
anilcancakir merged commit 75c1b7b into main Aug 27, 2026
5 checks passed
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