Skip to content

fix(webkit): [ENG-47001] close the token-check guardrail gap and canonicalize v4 syntax - #849

Merged
isaque-bock-azion merged 21 commits into
mainfrom
feat/ENG-47001-canonical-tailwind-v4-syntax
Aug 10, 2026
Merged

fix(webkit): [ENG-47001] close the token-check guardrail gap and canonicalize v4 syntax#849
isaque-bock-azion merged 21 commits into
mainfrom
feat/ENG-47001-canonical-tailwind-v4-syntax

Conversation

@isaque-bock-azion

@isaque-bock-azion isaque-bock-azion commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

ENG-47001 — canonicalize Tailwind v4 class syntax + close the token-check guardrail gap

Decision A (adopt the canonical syntax) — recorded in .claude/rules/styling.md and mirrored into the shipped cli-templates styling rule.

The load-bearing fix — guardrails (ships regardless of the codemod)

Six token-checks keyed on a literal [, so the canonical v4 paren spelling walked straight through the typography / motion / animation gates:

check evaded by
typography-raw-length text-(length:--text-…)
leading-raw leading-(--…)
tracking-raw tracking-(--…)
font-family-raw font-(family-name:--…)
animate-arbitrary animate-(--…)
motion-hardcoded duration-(--…)

Each now matches both spellings. Regression tests (packages/webkit/test/eslint-plugin/token-checks.test.mjs) pin every paren form named in the acceptance criteria and assert the widened guards stay silent on a plain canonical token (bg-(--primary)).

The sweep

Three families the real v4 compiler proves emit byte-identical CSS were rewritten across packages/webkit/src, apps/storybook, .specs, packages/webkit/docs, .claude/**, cli-templates, packages/theme:

family conversion count
A whole-value var prop-[var(--x)]prop-(--x) 2470
B typed value prop-[type:var(--x)]prop-(type:--x) 29
E numeric arbitrary z-[N]z-N 51

Two families are left bracketed — the paren form emits no CSS for them (silent style loss, no build/lint error):

  • C custom-property declarations — [--table-row-bg:var(--bg-surface)]
  • D expression values / var-with-fallback — w-[calc(var(--a)*2)], bg-[var(--x,var(--y))], gradients, box-shadows

The rewrite was done with a one-time codemod (not retained in the tree): it only converted a bracket whose content is exactly var(--token) (family A) or type:var(--token) with a letter-leading type (family B), so C and D could not match by construction — verified at apply-time (no C/D var-bracket changed) and permanently backstopped by the CI visual baselines, since any C/D breakage would change the rendered CSS.

Also

  • Standards/docs/scaffolder teach the paren form (DESIGN.md, COMPONENT_REQUIREMENTS.md, component-scaffold, the rule set, .specs).
  • apps/icons-gallery (Tailwind v3) untouched.

Notes for the reviewer / follow-ups

  • CI gates the rest. This branch was prepared without node_modules, so webkit:lint, type-check, storybook:build, the Vitest browser suite and visual baselines were not run locally — they run here. A/B/E compile byte-identically, so any baseline diff means the sweep broke something (the net for a C/D-style silent loss). The node guardrail suite is green: 10/10.
  • Root tailwindcss ^3.4.19 audit: no root Tailwind config and no root/sub-package consumer under pnpm's strict isolation (icons-gallery declares its own v3) → stale. Not removed here because regenerating pnpm-lock.yaml needs pnpm; recommend a follow-up that removes tailwindcss / @tailwindcss/typography / autoprefixer from the root and reinstalls.
  • packages/theme/dist/v4/globals.css is a generated artifact (do not edit banner); its one stale bracket-form comment regenerates on the next theme:build:tokens — the source (build-tokens.mjs) is already canonical.

How to test

  1. Guardrails — the six widened token-checks catch the paren spelling:
    node --test packages/webkit/test/eslint-plugin/token-checks.test.mjs
    Expect 12/12 green.
  2. No bracket token left behind — should return nothing (the only hits allowed are the intentional counter-examples in the two styling rule docs):
    grep -rnE '\[(([a-z-]+):)?var\(--[A-Za-z0-9-]+\)\]|\bz-\[[0-9]+\]' packages/webkit/src apps/storybook .specs
  3. Nothing changed visuallypnpm storybook:dev and spot-check a few components (Button, Switch, Sidebar, Breadcrumb): rendering must be identical to main, since the paren and bracket spellings compile to byte-identical CSS. CI's visual baselines assert this for every story.
  4. Spec gate intact — checksums were re-sealed, so editing any component via the AI pipeline must not be blocked with "checksum mismatch".

Comment thread scripts/codemods/canonicalize-tw-v4.mjs Fixed
@CLAassistant

CLAassistant commented Aug 4, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

isaque-bock-azion and others added 7 commits August 5, 2026 11:14
…-check guardrails

typography-raw-length, leading-raw, tracking-raw, font-family-raw,
animate-arbitrary and motion-hardcoded keyed on a literal '[', so the
canonical v4 paren syntax (duration-(--x), animate-(--x), text-(length:--x),
font-(family-name:--x), leading-(--x), tracking-(--x)) walked straight through
the typography / motion / animation gates. Each now matches both spellings.
Regression tests pin both forms and assert the widened guards stay silent on a
plain canonical token (bg-(--primary)).
…tax repo-wide

Decision A: standardize on Tailwind v4's paren shorthand for design-token values
(bg-(--primary), text-(length:--text-body-md), z-1), so IntelliSense stops
flagging every styled line with suggestCanonicalClasses. The two spellings
compile to byte-identical CSS.

A codemod (scripts/codemods/canonicalize-tw-v4.mjs) rewrites the three safe
families across packages/webkit/src, apps/storybook, .specs, packages/webkit/docs,
.claude/**, cli-templates and packages/theme:
  A  prop-[var(--x)]      -> prop-(--x)        (2470)
  B  prop-[type:var(--x)] -> prop-(type:--x)   (29)
  E  z-[<int>]            -> z-<int>           (51)

It provably leaves two families bracketed, because the paren form emits no CSS
for them (silent style loss, no build or lint error):
  C  custom-property declarations  [--x:var(--y)]
  D  expression values / var-with-fallback  w-[calc(var(--a)*2)], bg-[var(--x,var(--y))]

canonicalize-tw-v4.test.mjs pins the A/B/E conversions and the C/D skips.
The decision is recorded in .claude/rules/styling.md and mirrored into the shipped
cli-templates styling rule; DESIGN.md and the scaffolder examples teach the paren
form. apps/icons-gallery (Tailwind v3) is untouched.
The canonicalization sweep is applied and committed, so the one-shot codemod
(scripts/codemods/canonicalize-tw-v4.mjs) and its skip-proof test are no longer
needed — the permanent protection is the token-check guardrail tests plus the
CI visual baselines (which prove the A/B/E conversions are byte-identical).
Also removes the explanatory comments from the guardrail tests.
…weep

The canonicalization changed class-string lengths, so prettier re-wraps a few
:class attributes and the token-check test. Formatting only — no behavior change.
@isaque-bock-azion
isaque-bock-azion force-pushed the feat/ENG-47001-canonical-tailwind-v4-syntax branch from e3624ee to 1e4c351 Compare August 5, 2026 14:15
@isaque-bock-azion isaque-bock-azion added WIP Work in Progress and removed WIP Work in Progress labels Aug 5, 2026
Conflicts resolved by keeping main's semantics with the branch's canonical
Tailwind v4 paren token syntax; flow-anchor's PORT_CLASS (new from main)
canonicalized to match flow-node's.
@isaque-bock-azion
isaque-bock-azion force-pushed the feat/ENG-47001-canonical-tailwind-v4-syntax branch from 2274681 to 2f16087 Compare August 5, 2026 17:31
Two spots merged in from main still used the bracket syntax for
fallback-less var() tokens; convert them to the parenthesis shorthand
the sweep standardizes on.
Conflicts from the calendar field-contract refactor resolved by keeping
main's semantics with the branch's canonical Tailwind v4 paren token
syntax; fallback-carrying forms stay in bracket notation.
@isaque-bock-azion
isaque-bock-azion force-pushed the feat/ENG-47001-canonical-tailwind-v4-syntax branch from 487a29b to 1ad0b35 Compare August 5, 2026 17:46
isaque-bock-azion and others added 5 commits August 5, 2026 14:50
… merges

Merges f24330a/17f4244b kept the branch-side tab-view-item/list and
panel shells, silently dropping main's Figma pill fix (#857) and the
Panel max-h-full scroll bound (#835) while taking main's updated visual
baselines — so the TabView snapshots failed CI. Restore main's
semantics in the branch's canonical token syntax, and canonicalize the
standalone story + spec line that came in bracketed.
Brings the Menu compound (#853); menu-item resolved keeping main's
semantics in canonical token syntax, the retired menu-item spec deleted,
the compound's new files canonicalized and the catalog regenerated.
@isaque-bock-azion
isaque-bock-azion marked this pull request as draft August 6, 2026 14:32
herbert-julio-azion and others added 4 commits August 7, 2026 10:44
… sweep

The sweep canonicalized token syntax inside spec bodies without
recomputing the checksum: frontmatter, which would make the
enforce-spec-exists write-gate block every affected component after
merge. Recomputed mechanically with the engine's own bodyChecksum()
(.claude/hooks/_lib/spec.mjs), as suggested in review.

28 of the 63 resealed specs were already mismatched on origin/main
(pre-existing, unrelated to this branch); the reseal heals those too.
.specs/_template.md keeps its placeholder.
@isaque-bock-azion
isaque-bock-azion force-pushed the feat/ENG-47001-canonical-tailwind-v4-syntax branch from e96a261 to 73993c7 Compare August 10, 2026 12:57
@aziontech aziontech deleted a comment from herbert-julio-azion Aug 10, 2026
@isaque-bock-azion
isaque-bock-azion marked this pull request as ready for review August 10, 2026 13:07
@isaque-bock-azion
isaque-bock-azion merged commit ffd7102 into main Aug 10, 2026
23 checks passed
@isaque-bock-azion
isaque-bock-azion deleted the feat/ENG-47001-canonical-tailwind-v4-syntax branch August 10, 2026 14:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

5 participants