Commit 5f7b706
ci(theme): pin the compiled theme seed against the bundled JSON (#4570)
Groundwork for #3184 item 2 ("generate the seed table from the resource
at build time — the
high-leverage one; kills the drift class permanently").
**This PR changes no colours.** It proves the drift class is real, pins
it, and stops it widening,
so the generator lands against a floor and gets a regression test for
free.
## The drift already happened
`ThemeManager::seedBuiltinDefaults()` compiles a copy of the default
theme into the binary so the
UI works with zero theme files on disk. It is kept in sync with
`resources/themes/default-dark.json`
**by hand**, and the source says so twice — including this warning:
> `KEEP IN SYNC: ... If those primitives shift, update both sites or the
seeded look will drift`
> `from the JSON-defined look on bundled themes (silently — both layers
resolve, the JSON wins,`
> `but the visible vs. seeded values diverge for pre-PR user themes).`
Nine tokens on `main` @ `d50377f6` disagree today:
| token | compiled seed | `default-dark.json` |
|---|---|---|
| `color.accent.dim` | `#0090e0` | `#0070c0` |
| `color.slice.a` | `#ff4040` | `#00d4ff` |
| `color.slice.b` | `#ff8c00` | `#ff40ff` |
| `color.slice.c` | `#ffd040` | `#40ff40` |
| `color.slice.d` | `#40c060` | `#ffff00` |
| `color.slice.e` | `#00b4d8` | `#ffa000` |
| `color.slice.f` | `#4080ff` | `#00e0c0` |
| `color.slice.g` | `#c060ff` | `#ff6080` |
| `color.slice.h` | `#ff60a0` | `#b080ff` |
The slice colours explain themselves — the seed's own comment reads
*"Preliminary values — a
dedicated slice-colour audit may tune these in a follow-up."* The JSON
was later tuned; the seed
never was. Both bundled themes agree slice A is cyan/blue; only the
compiled seed still says red.
**Why it stayed hidden:** on a normal run the JSON wins, so a drifted
seed is invisible. It only
surfaces for a user whose theme predates a token — the seed then
supplies the value the JSON would
have overridden — or when no theme file loads at all. Both are exactly
the situations nobody is
watching, which is what makes this worth a gate rather than a one-off
correction.
## What this adds
- **`tools/check_theme_seed.py`** — parses both sides (resolving
`{color.red.500}` aliases against
the primitives palette) and diffs them. The nine existing divergences
are frozen in
`KNOWN_SEED_DRIFT`; `--strict` fails on anything else. The list may only
shrink: a token that
stops drifting is reported as **stale** so it gets removed rather than
quietly padding the
baseline.
- **`.github/workflows/theme-seed-check.yml`** — runs it on PRs touching
`ThemeManager.cpp`,
`resources/themes/**`, or the checker. Modelled directly on
`engine-boundary.yml`: same
concurrency block, same pinned action SHAs, same known-warn / new-fail
shape.
The checker **refuses to report a clean run if it parses zero shared
tokens**, so a future refactor
of `seedBuiltinDefaults()` that breaks the regex fails loudly instead of
silently passing. That
failure mode is the whole risk of a parser-based gate, so it is guarded
explicitly.
## Verification
All three paths exercised, not just the happy one:
| case | result |
|---|---|
| current `main` | 9 known, 0 new → exit 0 |
| inject a new divergence (`color.spectrum.grid` → `#deadbe`) | reported
as **NEW**, separate from the nine → **exit 1** |
| repair a known one (`slice.a` → JSON value) | reported as **stale**,
prompting its removal |
Same results on Windows/Python 3.14 and on Linux/Python 3.12 — the
version CI pins.
## Deliberately not in this PR
**Fixing the nine.** Which side wins is a design call, not a mechanical
one: the JSON is almost
certainly right (it is what every user actually sees, and both bundled
themes agree), but the seed
is what pre-v2 user themes fall back to, so changing it is a visible
change for those users. That
belongs with whoever owns the slice-colour audit the comment refers to —
happy to do it in a
follow-up once someone says which way.
**The generator itself.** Once the seed is generated from the resource,
`KNOWN_SEED_DRIFT` empties
and this checker becomes the test that the generator stays correct.
Refs #3184.
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Jeremy [KK7GWY] <kk7gwy@aethersdr.com>1 parent b82f613 commit 5f7b706
2 files changed
Lines changed: 488 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
0 commit comments