Follow-up to #3176 — the container-scoped tokenization refactor merged without new tests covering its newly-introduced semantics. theme_manager_test continues to pass but only exercises the legacy flat-token getter API; the v2 surface area is largely uncovered.
Test gaps to close
JSON loader / writer
Scope tree
Compound font tokens
Editor surface (smoke)
Why this matters
The refactor merged with several non-obvious bugs caught mid-stream by the operator running the app (cssFragment-empty-for-ThemeFont, size combo not marking dirty, root-scope clear deleting tokens tree-wide, destructor SEGV during scope change). Smoke tests across the new APIs would catch the next regression before it lands in someone's workflow.
The 23 commits in #3176 establish the new surface — this issue is the test-debt invoice.
73, Jeremy KK7GWY & Claude (AI dev partner)
Follow-up to #3176 — the container-scoped tokenization refactor merged without new tests covering its newly-introduced semantics.
theme_manager_testcontinues to pass but only exercises the legacy flat-token getter API; the v2 surface area is largely uncovered.Test gaps to close
JSON loader / writer
tokensblock migrates cleanly intoscopes.root.tokens.primitives+{alias}references: load default-dark, assertcolor("color.accent")returns the resolved#00b4d8(not the literal"{color.blue.500}"). This would have caught thecssFragment-returns-empty-for-ThemeFont bug we fixed mid-PR.flattenTokenscorrectly routes objects withtype→ThemeGradient, objects withfamily→ThemeFont, plain nested → recurse. Discriminator order matters.Scope tree
setColor(path, token, c)at a nested scope: override atapplet/txdoesn't change root's value.applet, read fromapplet/txresolves to applet's value (no own override at tx).removeOverride()at a nested scope drops the override; reading from that scope falls back to parent.removeOverride()at root is a no-op (defensive guard from3b833fd1).scopeOrCreate("a/b/c")creates the full chain with parent pointers wired correctly.Compound font tokens
setFontToken(path, "font.family.ui", {family, size, color})round-trip: read back viafontTokenAtmatches.value(token)on a ThemeFont returns the.familyfield — preserves the ~35 legacy callers.cssFragment("font.size.freq")virtual lookup returns the compound's embedded size.{family, size, color}shape (not as a nested scope).Editor surface (smoke)
Why this matters
The refactor merged with several non-obvious bugs caught mid-stream by the operator running the app (cssFragment-empty-for-ThemeFont, size combo not marking dirty, root-scope clear deleting tokens tree-wide, destructor SEGV during scope change). Smoke tests across the new APIs would catch the next regression before it lands in someone's workflow.
The 23 commits in #3176 establish the new surface — this issue is the test-debt invoice.
73, Jeremy KK7GWY & Claude (AI dev partner)