cmux NEXT webviews: fail hand-set popup roles and raw design values in new code outside ui/

Merged
TE
3d ago
+1126-14

Part of the cmux NEXT design-system pass (Leo: "there's just tons of design systems related stuff for spacing gutters icons etc whatever like we don't yet feel "designed" yet"). This is the lint piece: new code outside webviews/src/ui/ can no longer hand-roll a popup widget or write a raw design value, while today's tree passes on a shrinking allowlist.

What changes

1. hand-set-role in scripts/check-ui-review.ts (fails)

  • Flags role="menu" | "menuitem" | "menuitemradio" | "menuitemcheckbox" | "listbox" | "option" | "dialog" | "tablist" | "tab" written in TSX outside src/ui/: a JSX attribute (including a conditional such as role={x ? "option" : undefined}) or a role: "option" property in a props object. querySelector('[role="menu"]') strings, other roles (group, alert, status), src/ui/, tests and gallery files are not flagged.
  • Fingerprint <role>|<tag or props>|<enclosing component>, so moving lines does not churn the allowlist.
  • Today's 55 occurrences (DiffToolbar, BranchBasePicker, the slash/palette/file-search listboxes, New Tab, History, Apps, the inspector tabs, and others) are in ui-review-allowlist.jsonl. The checker's own scan generated them.
  • hand-set-role is the one rule in FAILING_RULES. A new occurrence fails, and so does a stale entry (the code is fixed but the entry is still listed), so the list only shrinks. The copy and row rules still only warn, as before.
  • check:ui-review is already in check:pieces, so this adds no CI job or step.

2. Token literals in scripts/check-design-tokens.ts (fails, same ratchet)

The existing per-file baseline ratchet now also counts, in CSS and in TSX inline style={{}} objects:

kindflaggedallowed
colorraw #hex, rgb/rgba/hsl/hsla/hwb/lab/lch/oklab/oklch/color()var() and its fallback, a colour function or color-mix that takes a token, masks, --x: token definitions
spacingmargin*, inset*, top/right/bottom/left (padding/gap as before)0/4/8/12/16/24/32 + 40/48/56 layout gaps (abs value, so -4px is fine)
radiusborder-radius*0/4/6/8/12/16, >= 999px capsules, tokens (menu 5 comes from --cmux-menu-*)
font-weightanything else, bold, and 700400, 600, normal, var(); 700 for monograms lives in the baseline
durationa literal transition/animation duration other than 0var(--cmux-motion-*)
easingcubic-bezier(), ease, ease-in, ease-out, ease-in-outvar(--cmux-ease-out), linear
  • The token file pages/shared/desktop.css and generated CSS are not scanned for the new kinds. Font sizes stay with the existing type-scale ratchet (scripts/cmux-next/check-type-scale.py), which already counts every literal font size; this PR does not duplicate it.
  • Baseline: the 1,463 existing rows are byte-for-byte unchanged; 1,107 new rows record today's counts (spacing 2,220 occurrences incl. padding/gap, radius 415, font-weight 186, color 57, duration 40, easing 34). These match the static audit's totals (radius 403, font-weight 185, raw colour 87 including about 30 mask stops that are not colours).

How a migration PR shrinks the lists

After moving a surface onto ui/ and tokens, run from webviews/:

bun scripts/check-ui-review.ts --shrink-allowlist && bun scripts/check-design-tokens.ts --update-baseline

--shrink-allowlist drops only stale entries and never adds one; --update-baseline refuses to grow any count. Both checks fail until the fixed entries are removed, so no list ever grows back.

Overlap

  • #33595 (icon-scale check) also edits check-design-tokens.ts (how height is judged for icon boxes) and the baseline. The two changes are in separate functions; whichever lands second rebases and re-runs --update-baseline.
  • The parallel grid migration PRs will remove rows; each one runs the command above.

Tests

test/check-ui-review.test.ts: positive (JSX, conditional, props object, every role), negative (other roles, selector strings, ui/, gallery, tests, .ts), allowlisted passes, new fails, stale entry fails until --shrink-allowlist, shrinking never adds, today's tree passes. test/design-tokens.test.ts: each kind positive and negative, var/fallback/token-composing colour, TSX inline styles, ratchet new/allowlisted/shrink.

Observed / Not run

  • Ran on the fleet (cmux-ci test): both test files, bun scripts/check-ui-review.ts, bun scripts/check-design-tokens.ts, vp check --no-fmt --no-lint. 64 tests pass, both checkers pass on today's tree, no type errors.
  • vp fmt --check clean. No runtime or rendering code changes, so no Performance table and no captures; no new loops, timers or observers.

Changelog

none

Agent session: agent session

🤖 Generated with Claude Code


Autofix with [code]smith
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.


Summary by cubic

Adds two failing design-system lint rules so new code outside webviews/src/ui/ can't hand-roll a popup widget or write a raw design value.

hand-set-role in check-ui-review.ts

  • Flags menu, menuitem*, listbox, option, dialog, tablist, and tab roles set in TSX outside src/ui/ (tests, gallery, and ui/ files exempt).
  • Today's 55 occurrences are allowlisted by file + fingerprint; a new finding or a stale entry fails the check, while the copy and row rules still warn.
  • bun scripts/check-ui-review.ts --shrink-allowlist drops stale entries and never adds.

Token literals in check-design-tokens.ts

  • Flags raw color literals, off-scale spacing/radius/font-weight, and non-token durations/easings in CSS and TSX inline style={{}} objects.
  • The baseline was re-recorded against the current base, so it includes rows from surfaces that landed since (the next-step card, conversation margins, settings radii).
  • bun scripts/check-design-tokens.ts --update-baseline re-records counts and refuses to grow any, so a count can only shrink.