word-addin: replace comment-enforced design parity with mechanisms
From the PR description
Summary
Two invariants in the Word add-in were enforced only by comments, and both had quietly stopped being true:
word-addin/src/shared/styles/tokens.csshand-duplicates 121 design tokens from the web'sglobals.css, guarded by "Keep values in sync with globals.css." Nothing verified it, and four light-mode surface tokens drifted when the web palette moved (--app-background,--app-surface-hover,--app-surface-active,--app-floating) - the pane has been rendering slightly different surfaces than the web app it mirrors.word-addin/src/shared/ui/tab-pill-button.tsxwas forked from the web's pill with "Only thecnimport path differs." Also no longer true: the web version moved to the sharedLiquidGlassUIconstants and gained afocus-visiblering; the fork kept a stale hardcoded shadow and had no visible keyboard-focus state at all, against AGENTS.md's own accessibility baseline.
This PR turns both comments into mechanisms:
scripts/check-token-drift.mjs: parses both CSS files and requires every token the add-in declares (:root,.dark,@theme inline) to matchglobals.cssexactly (web-only additions allowed - the add-in is a subset). Fails naming each drifted token, add-in vs web value; also fails if it parses zero tokens, so a file refactor can't silently no-op the check. Wired asnpm run check:tokensinsidenpm run typecheck, whichnpm run buildand the existing word-addin CI workflow already run - drift now fails every build and PR with zero new CI wiring. The four drifted values are fixed to the web's palette (web is the source of truth; it moved first, deliberately).- TabPillButton converges on the web implementation: same
focus-visiblering cluster, sameLIQUID_GLASS_SUBTLE_CLASS/LIQUID_GLASS_HOVER_CLASSconstants, imported via a new@mike/liquid-glass-uialias (the established webpack+tsconfig pattern forfrontend/src/shared/uimodules). No new duplication - the pane already importsLiquidGlassUI.cssand listsLiquidGlassUI.tsas a Tailwind@source; the fork just predated them.
Reproduce on main
# The guard is a comment, and it failed - four tokens differ from globals.css:
grep -n "Keep values in sync" word-addin/src/shared/styles/tokens.css
git checkout olp-pr/tokens-mechanism -- word-addin/scripts/check-token-drift.mjs
node word-addin/scripts/check-token-drift.mjs # exits 1, names the 4 drifted tokens
# The pill has no focus indicator:
grep -c "focus-visible" word-addin/src/shared/ui/tab-pill-button.tsx # 0
Verify on this branch
npm run check:tokens --prefix word-addin # 121 add-in tokens match globals.css
npm run typecheck --prefix word-addin # tsc app + e2e + token check, all green
grep -c "focus-visible" word-addin/src/shared/ui/tab-pill-button.tsx # 1 (ring cluster present)
Keyboard check: build/serve the pane, Tab to the Add Documents modal's tab bar - each pill now shows the blue focus ring the web shows.
Demo
Live recording: the new checker run against main's tokens.css (4 drifted tokens named) -> this branch (121 match) -> the typecheck wiring -> the pill's focus-visible count, main vs branch:

Testing performed
npm run typecheck --prefix word-addin- green (tsc app, tsc e2e, token check).npm run build:e2e --prefix word-addin- production webpack build succeeds with the new alias; verified the built bundle contains theliquid-glass-*classes, thefocus-visible:ring-*utilities, and the corrected token values (--app-background: #f9fafblight /#0b0f14dark).- Negative test: running the checker against
main's tokens.css exits 1 and names exactly the four drifted tokens (recorded in the demo below).
Tradeoffs & design decisions
- Check, not code-generation. Generating tokens.css from globals.css would remove the duplication entirely, but the add-in file is a deliberate adaptation (own header, font-variable notes,
@custom-variantline), and a generator would need to own that structure. A fail-loud equality check gets the same guarantee with a fraction of the machinery; generation remains the natural upgrade if the token set starts churning. - Subset semantics. Web-only tokens don't fail the check - the add-in intentionally declares only what the pane uses. The cost: a web token rename shows up as "not defined in web" only because the add-in still carries the old name, which is the desired failure anyway.
- The pill stays a duplicated file. Moving it into
frontend/src/shared/ui/per AGENTS.md's cross-target rule is the full fix, but the web copy imports from@/app/components/uicontext and the move touches web consumers - out of scope for a mechanisms PR. The comment now states the real contract (shared constants, byte-identical class strings) instead of a false one. - Other hardcoded liquid-glass shadows remain in the pane (
InitialView,ModalForm,ChatInput) - same fork pattern, not regressed by this PR, and each needs its own visual verification to converge; deliberately not batched in here. - Class-string parity for the pill is still comment-enforced (the token check does not read .tsx files). Extending the checker to diff the two pill files' class strings would be the next mechanism if this drifts again.
🤖 Generated with Claude Code
Our analysis
Enforce Word add-in design parity — read the full analysis →
Think the analysis missed something the PR description covers?
Capture this PR into my fork
Download a Markdown prompt that tells Claude how to port every
commit in this PR into your working tree. Run it via
claude -p < capture-pull-396.md from
inside the repo you want the changes in.