docs: tell 19 what the gate missed and which checks caught it
verify-and-publish / gate (push) Successful in 33m45s
verify-and-publish / publish (push) Has been skipped

This commit is contained in:
Marcos Paulo
2026-09-05 23:03:55 +00:00
parent 71c74fb7f1
commit 12bc1dc067
@@ -43,3 +43,68 @@ a written reason.
Do not weaken an assertion to make it pass. If it cannot pass, something is Do not weaken an assertion to make it pass. If it cannot pass, something is
broken — that is the assertion doing its job. broken — that is the assertion doing its job.
## Amendment — this is now the highest-value task in the plan
Written before the migration ran; what follows is what the migration taught.
Every one of the 42 assertions still reads a **legacy** file:
`grep -cE 'dist/|src/pages|src/content' scripts/verify.mjs` returns 0. Nothing
in the gate looks at what the Astro pages render. Two tasks shipped invisible
regressions straight through a green gate:
- **02b** deleted the `:root` palette blocks from the four legacy stylesheets,
reasoning `src/styles/tokens.css` is the single source of truth. It is — for
Astro pages. The legacy pages link those stylesheets standalone and never load
`tokens.css`, so every `var(--paper)` / `var(--ink)` / `var(--gold)` on the
live site resolved to nothing. Eight pages, colourless. Gate green.
- **15d attempt 1** built `/full-guide/` by importing
`full-guide/index.html?raw` and `set:html`-ing the `<main>` out of it. Zero
`data-language-content` attributes, zero `.pt` reads: Portuguese gone from the
largest page on a bilingual site. Gate green. Tagged `rejected/15d-attempt-1`.
The gate is doing its job — it is a legacy-content contract. Your job is to make
it an output contract too. Until you land, "gate green" means nothing about the
new site.
### Three checks to build in, each of which caught a real regression
1. **Bilingual coverage of the built HTML.** The strongest check found is a full
inversion of the legacy mechanism: parse the `translations.pt` object out of
`app.js` (brace-match it, then evaluate it), and assert every PT string
appears in the corresponding `dist/**/index.html`. Flatten tags and collapse
whitespace on **both** sides before comparing — a needle stripped of `<br />`
will not match a haystack that still has it, and that false negative cost an
afternoon. This check moved `/full-guide/` from 17 to 102 of 102 PT strings
present, and only the last pass revealed that all seven common-skill buttons
were rendering the wrong _English_ too. `translations.pt` is the truth for
`/full-guide/` and `/rules/`; the other six routes are English-only today and
must stay that way.
2. **Every `var()` resolves.** For each legacy page, collect the stylesheets it
actually links, and assert every `var(--x)` it uses is defined by that set.
`--score` is the only legitimate miss — `app.js:289` sets it inline. This is
the check that would have caught 02b in seconds.
3. **Built-CSS diff against `main`.** Build, then enumerate every colour and
size declaration in `dist/_astro/*.css` that exists on `main` and not on the
branch. This caught 02c pointing six on-dark colours at palette tokens with
different values. Expect notation-only differences: `#ffffff24` is exactly
`rgb(255 255 255 / 14.1176%)`, and `32px`/`48px` now resolve through
`--step-32`/`--step-48`.
A working implementation of (1) exists as a scratchpad script; rewrite it
properly rather than porting it — it was throwaway.
### On the assertion count
Baseline is 42 and the gate enforces it. Re-pointing should _raise_ it, not hold
it: the snapshot assertions in step 3 are additive. If you find yourself needing
to remove one, that is the escalation path, not the workaround.
### Screenshots
`playwright` is now a devDependency (`c2a046d`) and
`.agents/scripts/visual-regression.mjs` runs. It used to throw for everyone,
which is why no task in this plan ever produced the captures its brief asked
for.