Skip to content

Measure figure tokens in the browser and retire #19's two site.css text tests - #28

Open
adewale wants to merge 2 commits into
mainfrom
claude/rendered-figure-token-checks
Open

adewale wants to merge 2 commits into
mainfrom
claude/rendered-figure-token-checks

Conversation

@adewale

@adewale adewale commented Oct 12, 2026 •

Copy link
Copy Markdown
Owner

#19 added two tests that read public/site.css as text, the kind #20 replaced with rendered-style checks. This PR moves what they meant into the browser check and deletes them.

What changed

  • New scripts/figure_theme_contract.mjs, called by scripts/check_browser_layout.mjs in light and dark. On the rendered values page it measures:

    • every token in the grammar's FIGURE_TOKENS_LIGHT / FIGURE_TOKENS_DARK (imported from src/marginalia_grammar.py through uv) resolves to a colour on the figures, and equals the documented colour. Colours are compared as the browser computes them, not as they are spelled;
    • every stroke and fill painted through a var(--fig-*) token paints that token's colour;
    • every such stroke and fill changes colour between light and dark;
    • no figure SVG has a painted background (no chip), and the ink keeps 4.5:1 contrast on the page.

    Measure rendered styles in the browser, smoke-test deploys, warn before waivers expire #20's three figure checks (ink contrast, chip, ink recolour) moved into the module unchanged in meaning. The recolour check now covers all 13 painted strokes and fills, not only the first ink stroke.

  • Deleted tests/test_app.py::DarkModeAndAccessibilityTests::test_dark_mode_recolours_marginalia_figures_through_tokens and tests/test_marginalia_geometry.py::FigureThemeTokenContract::test_site_css_defines_every_token_in_both_schemes. Neither held a non-text assertion. FigureThemeTokenContract keeps test_every_painted_colour_is_a_token_reference.

  • The rubric and the visual-explainer spec cited "Contract 15" as a site.css check; they now point at the rendered check. The README's list of what the browser test measures gains figure colours.

Where each assertion moved

Old assertion What it was for Rendered check now
A1: each of --fig-ink, --fig-ink-soft, --fig-accent, --fig-soft appears after @media (prefers-color-scheme: dark) dark mode redefines every figure token new: each dark token equals the grammar's dark colour; every painted stroke/fill changes between themes. relied on: dark ink contrast ≥ 4.5
A2: --figure-paper appears nowhere the pre-#19 light paper chip stays gone relied on (from #20): every figure SVG's computed background is transparent, both themes
A3: no .cell-banner figure svg rule in the dark block same chip, by its old selector same chip check
B: name: value; text for every grammar token, in the light part and in the dark part each token defined in both schemes, with the grammar's values (social cards and gestalt pages embed the same values) new: each token resolves to a colour in each scheme and equals the documented colour; painted strokes/fills use their token's colour

The values page never paints --fig-accent. So the module reads every token the grammar documents, not only the painted ones, and plant 3 below shows that this is what catches it.

Planted-bug proofs

Each bug was planted in public/site.css and in the served, byte-identical copy public/site.32ce5906d3c1.css (what a rebuild would serve). curl against the local Worker confirmed the plant was being served. Both old tests (still present at commit f897746) and the rendered check were then run, the files were restored with git checkout, and git diff --quiet and the served CSS confirmed the restore after every plant.

# Planted bug Old A Old B Rendered check
1 dark block loses --fig-ink pass (missed) fail fail: dark ink contrast 1.26:1; dark --fig-ink is rgb(82, 16, 0), grammar documents rgb(243, 231, 220); 9 of 13 strokes/fills kept their light colour
2 dark block loses --fig-soft fail fail fail: dark --fig-soft is the light value; 1 of 13 fills kept its light colour
3 dark block loses --fig-accent (not painted on this page) fail fail fail: dark --fig-accent is rgb(255, 72, 1), grammar documents rgb(255, 107, 46)
4 light :root loses --fig-ink pass (dark-only test) fail fail: light --fig-ink does not resolve; 9 strokes/fills off-token (strokes paint none, fills rgb(0, 0, 0)); ink contrast undefined
5 light --fig-ink-soft drifts to rgba(82, 16, 0, 0.55) pass (dark-only test) fail fail: light --fig-ink-soft is rgba(82, 16, 0, 0.55), not the documented rgba(82, 16, 0, 0.7)
6 the pre-#19 chip returns verbatim (--figure-paper plus the dark .cell-banner figure svg, .journey-section-figure svg { … background: var(--figure-paper) }) fail pass fail: dark figures sit on a painted chip rgb(245, 241, 235)
7 chip under another selector: dark .cell-banner svg { background: #F5F1EB; } pass (missed) pass fail: dark figures sit on a painted chip
8 control, not a bug: light --fig-ink: #521000 respelled rgb(82 16 0) pass fail (false alarm) pass

Plant 1 is a real gap: old test A's assertIn("--fig-ink", dark_block) also matches --fig-ink-soft, so it could never catch a missing dark ink. The clean page passes the rendered check: all four tokens match the grammar in both themes, ink contrast is 13.03:1 light and 15.18:1 dark, and no chip appears.

How the proofs ran. make browser-layout-test did not become ready in this container. The values page never gets window.pythonByExampleEditor / .cm-content, because CodeMirror loads from esm.sh, which this container's Chromium cannot reach; the same thing happened on 2026-10-10 and 2026-10-11. So the proofs used a throwaway probe, not committed. It loads /examples/values through the local Worker (pywrangler dev --port 9696) and waits up to 60 s for server-rendered content only. It then imports scripts/figure_theme_contract.mjs and runs the same measurement and figureThemeFailures() that check_browser_layout.mjs runs, in light and then emulated dark, at the same 390×1800 viewport. The full browser check is left to GitHub CI's Chrome.

Local verification (CI=true)

Run with the local Worker up on port 9696, at head 85c2da1:

  • npm audit --audit-level=high: pass (0 vulnerabilities)
  • git diff --exit-code -- pylock.toml: pass
  • make -k verify: every target passes except browser-layout-test. That includes 231 unit tests, verify-examples (109), all quality checks, search-ranking-test, ruff and check-generated. browser-layout-test fails at the known readiness step (CDN editor never loads here). It got that far only after the new top-level documentedFigureTokens() call had already run uv successfully.
  • scripts/format_examples.py --check: pass
  • make verify-python-version VERSION=3.13: pass (109 verified)
  • git diff --check: pass
  • Figure probe on this head: pass

GitHub CI's Chrome runs the full browser-layout-test, new checks included.

🤖 Generated with Claude Code

https://claude.ai/code/session_012eisRQmQvg4TphwztxhQGJ


Generated by Claude Code

The browser check covered #19's figure design for --fig-ink only: its
contrast, the SVG having no painted chip, and the ink changing between
themes. Two unit tests still guarded the rest by reading site.css as text.

scripts/figure_theme_contract.mjs now measures, in light and in dark, on
the rendered page:
- every token in the grammar's FIGURE_TOKENS_LIGHT/DARK resolves to a
  colour on the figures and equals the colour the grammar documents
  (compared as computed colours, not as spelled);
- every stroke and fill painted through a token paints that token's colour;
- every such stroke and fill changes colour between light and dark;
- no figure SVG has a painted background, and the ink keeps 4.5:1.

The existing ink, chip and recolour checks move into the module, so the
browser check and a stand-alone probe can share one implementation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012eisRQmQvg4TphwztxhQGJ
The browser check now measures what both tests meant on the rendered page
(scripts/figure_theme_contract.mjs). Planting each bug they targeted in
site.css and its served copy fails the rendered check; two of those plants
passed one of the text tests:

- test_dark_mode_recolours_marginalia_figures_through_tokens asserted
  "--fig-ink" appears after the dark media query. "--fig-ink-soft" also
  matches, so deleting the dark --fig-ink passed it, while the page drew
  1.26:1 ink on the dark background.
- A chip under another selector (.cell-banner svg { background: ... })
  passed both tests; the rendered chip check fails it.
- test_site_css_defines_every_token_in_both_schemes failed when a token
  was respelled as the same colour (#521000 to rgb(82 16 0)); the
  rendered check compares computed colours and passes.

Neither test held a non-text assertion. FigureThemeTokenContract keeps
test_every_painted_colour_is_a_token_reference, and the docs that cited
Contract 15 as a site.css check now point at the rendered check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012eisRQmQvg4TphwztxhQGJ
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants