# Task 19 — Re-point the verification contract **Agent**: `verification-engineer` · **Model**: Codex **Depends on**: 15, 16 · **Parallel with**: 18 **Worktree**: `.agents/scripts/worktree.sh start 19 verify-repoint` ## Goal All 42 assertions pin the same user-visible facts against the new architecture. Coverage does not fall. You are the only role permitted to remove an assertion, and every removal needs a written reason. ## The three kinds | Kind | Example | What to do | | --------------------- | --------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | | Content presence | `data-phase="plan"` | re-point at `dist/full-guide/index.html`; the token should survive rendering. If it does not, a component dropped content — **stop and report** | | Implementation detail | `const phases`, `renderTree`, `from './catalog.js'` | obsolete as written, but each pins a **feature**. Replace with an output-level assertion of that feature. Never drop | | Asset version | `app.js?v=20260904-vote-widget` | Astro hashes assets — assert the built HTML references a hashed asset | ## Steps 1. `pnpm run build`, then re-point `read()` calls at `dist/`. 2. Work through all 42 in order. For each: does the fact it pins still exist? Yes → re-point. No → content was lost; escalate. 3. Add rendered-text snapshot assertions for all ten routes so this class of regression is caught structurally, not by string luck. 4. Confirm `check-tokens.mjs` and the extended `audit-ui.mjs` are in `pnpm run verify`. ## Done when - [ ] `grep -c 'throw new Error' scripts/verify.mjs` ≥ the `origin/main` baseline - [ ] Every removal has a one-line reason in this file - [ ] Snapshot assertions cover all ten routes - [ ] `pnpm run gate` green, and it **fails** when you deliberately delete a paragraph from a component (prove the net works, then revert) ## Do not Do not weaken an assertion to make it pass. If it cannot pass, something is 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 `
` 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 `
` 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.