emrg: gui — fix undefined theme tokens (--fs-small/--bg-1/--bg-hover/--radius-sm) + add theme-integrity guard - #1051
Conversation
…--radius-sm) + add theme-integrity guard Two-part change hardening renderer theming (rant 2026-08-27T20:33:31 → argszero#1047 light-theme regression class): FIX: tokens.css lacked 4 variables that layout.css/components.css consume as bare var(--x) (no fallback): --fs-small (11px), --radius-sm (8px), --bg-1 and --bg-hover (per-theme values). Bare undefined vars make declarations invalid at computed-value time — task-form background transparent, filetab hover dead, badge font-size/radius wrong. All 4 now defined in every theme block (light default + forced, dark media + forced). GUARD: emrg/gui/test/theme-guard.test.js — 2 static tests: 1. every bare var(--x) in renderer CSS must be defined in tokens.css (catches silent invalid declarations — the bug above) 2. no Catppuccin dark-palette hexes outside tokens.css, comment-stripped (the exact argszero#1047 regression shape: hardcoded theme colors bypassing vars) Negative-state verified: guard fails on pre-fix tokens, passes on fixed. GUI tests 93 -> 95, Agent.md synced.
argszero
left a comment
There was a problem hiding this comment.
❌ Needs fix: guard scan is non-recursive — nested CSS escapes both guards
The core fix is verified and correct: the 4 tokens (--fs-small/--radius-sm/--bg-1/--bg-hover) are genuinely undefined on master and consumed as bare var(--x) in layout.css/components.css → silent invalid declarations. Guard 1 correctly FAILS against pre-fix tokens (verified locally) and both guards pass on the fixed tree (npm test 95: 87 pass + 8 skip; renderer 445/445; typecheck clean; CI test + test-windows green).
However, rendererCssFiles() scans only renderer/css/*.css + renderer/src/*.css (top-level readdirSync). I empirically proved the gap: injecting .x { background: #1e1e2e; } into a new renderer/src/components/Shell.css was not detected by either guard (npm test stayed green), while the same injection into src/shell.css correctly fails guard 2. The React migration is already placing styles under src/components/ — a future scoped CSS file there would silently bypass the guard, recreating exactly the silent-regression class this guard exists to catch.
Suggested fix (Node 20+, CI uses Node 22):
for(constfoffs.readdirSync(srcDir,{recursive: true})){if(typeoff==="string"&&f.endsWith(".css"))files.push(`src/${f}`);}Directory entries from the recursive read also end with ".css"? No — they don't, so the endsWith filter is sufficient. — cycle cyc20260827-232221
argszero
commented
Aug 27, 2026
Maintainer push: resolved the ❌ — Verified locally on the updated head (66e4473):
Thanks for the solid guard — this closes the coverage gap. CI (test + test-windows) re-triggered on the synchronize event. |
argszero
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle cyc20260827-232221 (1/3). The ❌ (non-recursive guard scan) is resolved via maintainer push 66e4473: rendererCssFiles() now scans src/ recursively. Verified on the new head: both theme guards pass (GUI npm test 95: 87 pass + 8 skip); negative state — #1e1e2e in a nested src/components/Nested.css correctly FAILS guard 2 (previously silently missed). CI test + test-windows green (33087932931), MERGEABLE/CLEAN. Core fix (4 undefined tokens → defined in tokens.css, per-theme values in all 4 blocks) verified correct.
argszero
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle cyc20260827-233730 (2/3). Head 66e4473 unchanged since cyc20260827-232221 LGTM (1/3, after maintainer fix of the non-recursive scan), CI test + test-windows green (33087932931), MERGEABLE/CLEAN. Core fix (4 undefined tokens + theme-integrity guard) verified.
argszero
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle cyc20260827-234739 (3/3). Head 66e4473 unchanged since cyc20260827-233730 LGTM (2/3), CI test + test-windows green (33087932931), MERGEABLE/CLEAN. The earlier ❌ (non-recursive scan) was resolved by maintainer push 66e4473 and is followed by clean consecutive ✅s (232221, 233730, 234739) with no ❌ between them. Merging.
Uh oh!
There was an error while loading. Please reload this page.
Summary
Fix 4 undefined theme tokens in the renderer + add a static theme-integrity guard (third host-caught regression → guard, following #1037 boot-chain and #1045 upgrade-prompt).
Background
The v0.2.84 light-theme regression (#1047, rant 2026-08-27T20:33:31) was another host-caught-after-release theming bug: the React shell hardcoded Catppuccin dark hexes instead of using
tokens.csstheme variables. While auditing the theme layer after that fix, a second, deeper problem surfaced:4 theme variables are consumed as bare
var(--x)(no fallback) but never defined intokens.css—--fs-small,--radius-sm,--bg-1,--bg-hover. A barevar(--x)with an undefined name makes the whole declaration invalid at computed-value time, so those properties silently don't apply:.task-formbackground is transparent, filetab hover has no background, badge font-size/radius fall back to inherited/0.Changes
Fix —
emrg/gui/renderer/css/tokens.css:--fs-small: 11px(below--fs-aux: 12px),--radius-sm: 8px(below--radius-input/btn: 12px) — theme-independent, defined once in:root--bg-1/--bg-hover— per-theme values in all 4 color blocks: light#eceef2/#e8eaed, dark#2e3138/#2e3138Guard —
emrg/gui/test/theme-guard.test.js(2 static tests, node:test):var(--x)in renderer CSS must be defined intokens.css— catches silent invalid declarations (the bug fixed here)tokens.css(comment-stripped) — pins the exact emrg: gui — use theme variables in React shell (fix light theme regression) #1047 regression shapeNegative-state verified: both guards fail against the pre-fix tokens (undefined vars removed) and pass against the fixed file.
Verification
npm test— 95 tests (87 pass + 8 skipped), 0 failnpm run typecheckclean + 445 vitest passuv run pytest tests/— 1126 passed + 1 skipped; doc-count guard 4/4Note
GUI test count 93 → 95, Agent.md synced.