feat: D20 moves the claims pass to cutover; rule Q56 unscoped; close Q55; freeze check:claims

Four rulings from Pouya, 2026-08-30, and their sweep.

D20 — the review protocol. Per build step the review is `adversarial-reviewer`
alone. `claims-auditor` no longer runs per step; it runs ONCE, at cutover, over
the whole finished site, as a blocking item near the top of docs/06's checklist.
`check:claims` is unchanged and still runs on every build and both deploy paths.
The reasoning is recorded in full in AGENTS.md D20, as a calibration and not an
erosion: nothing has shipped, so every claims finding so far has been about a
page no visitor can reach, and one pass over twenty finished pages catches more
than nine passes over drafts because it sees the site as a reader does. The
/med-arb/ ADRIC gloss is the proof — no individual claim was false, the defect
was adjacency, and adjacency does not exist until the pages sit next to each
other. The code reviewer stays per step because what it catches compounds.
What this costs is recorded honestly beside it, not summarised away.

D17 and D19 amended to match. D19's two-round cap governs the per-step code
review only; the single cutover claims pass runs until its findings are
resolved, because there is no second pass behind it.

Q56 — mediation is NOT scoped commercial. Thirteen shipped strings corrected
across five files: page titles, meta descriptions, hero ledes, section ledes,
the `Service` node's name and description, and `ProfessionalService`'s. §4's
mediation row stays unscoped, and the reason now sits beside both rows so the
asymmetry reads as designed: arbitration is scoped commercial because of a
LEGAL GATE (Q39 — family arbitration in Ontario requires prescribed training);
mediation has no such gate. `adversarial-reviewer` then found three surfaces
the sweep had missed, the worst on /practice/ — "These describe the process the
parties are choosing between, in commercial matters" scoped mediation with the
two words never appearing in the same element, so no proximity grep reached it.

Q55 — CLOSED WITHOUT BEING RESOLVED, and the difference is the ruling. The
Q.Arb stamp is split: `[verified]` on the status, `[Pouya's stated basis]` on
the date. The 2026-08-26 record is marked UNRECONCILED, permanently and on
purpose. The date is not published and nothing depends on it.

check:claims — FROZEN. Round 2 found five defects in round 1's own fixes to
that script, two of which made it worse than before the pattern existed. A
pattern is added only after a real breach reaches dist/, never speculatively,
and each addition ships with a probe plus a negative fixture. No refactors, no
coverage improvements. It is a tripwire, not a program.

Two conventions into CLAUDE.md: sweep the VOCABULARY, not only the subject
(`git grep 'Q.Arb'` is line-anchored and could not find ten lines entirely
about Q.Arb that never name it); and agent definitions load at session start,
so an edit to .claude/agents/*.md does not reach the session that made it.

Verified: check 0 errors, lint 0, build 0 (12 pages), check:claims 0.
Lighthouse not run — tool unavailable until build step 7.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Md3GndFqWPzK78xAoebsg5
This commit is contained in:
Pouya Lajevardi
2026-08-31 07:33:06 -04:00
co-authored by Claude Opus 5
parent 610edc24fd
commit 2ea4c0f8ac
14 changed files with 520 additions and 125 deletions
+88 -7
View File
@@ -57,8 +57,9 @@ being restated in the prompt.
anything live), read the governing specs, name the decisions the task touches,
and **stop and ask on any conflict**. A blocked build is a correct build.
2. **Implement** — following the conventions below.
3. **Adversarial review** — invoke `adversarial-reviewer` and `claims-auditor` in
parallel on the diff.
3. **Adversarial review** — invoke `adversarial-reviewer` on the diff. **D20:
`claims-auditor` does NOT run per step.** It runs once, at cutover, over the
whole finished site.
4. **Resolve** — fix each finding or decline it with a stated reason. Re-review
material fixes.
5. **Verify** — run the checks. Never report a check as passing that you did not
@@ -67,6 +68,14 @@ being restated in the prompt.
`/review` runs phase 3 alone. `/wrap` runs phase 6 at session end.
**Agent definitions load at session start.** An edit to `.claude/agents/*.md`
does not reach the session you made it in — the brief in force is the one that
was on disk when the session began. After committing a change to one, **restart
before relying on it, and say in the report which version actually ran.** Found
2026-08-30: the gloss lens was added to `claims-auditor` and the agent then
reconstructed it from the `AGENTS.md` Change Log rather than having it in its
brief, which is luck, not process.
**Think deeply before acting.** Extended thinking is on by default for this
project (`.claude/settings.json`), and `/build` and `/review` request it
explicitly. The planning and review phases are where it earns its cost — a defect
@@ -90,11 +99,33 @@ an accusation, and do not argue a reviewer down — either fix it, or record the
reason you declined it so a later reader can see the judgement was made rather
than missed.
**Two reviewers, because they catch different things.** `adversarial-reviewer`
reads the code. `claims-auditor` reads the copy against the §4 register and knows
nothing about whether the code is elegant. A generic reviewer consistently
under-weights the professional-conduct check, which is the highest-stakes failure
mode on this project — so it gets its own pass.
**Two reviewers, because they catch different things — but they no longer run at
the same time.** `adversarial-reviewer` reads the code. `claims-auditor` reads the
copy against the §4 register and knows nothing about whether the code is elegant.
A generic reviewer consistently under-weights the professional-conduct check,
which is the highest-stakes failure mode on this project — so it keeps its own
pass rather than being folded into the code review.
**D20, 2026-08-30 — the claims pass moved to cutover.** Per step it is
`adversarial-reviewer` alone. `claims-auditor` runs **once, over the whole
finished site**, as a blocking item on `docs/06`'s cutover checklist. Pouya's
reasoning, and it is a calibration and not an erosion: nothing has shipped, so
every claims finding so far has been about a page no visitor can reach — the risk
is deferred to cutover anyway, and one pass over twenty finished pages catches
**more** than nine passes over drafts, because it sees the site as a reader does.
The `/med-arb/` ADRIC gloss is the proof: no individual claim was false, the
defect was **adjacency**, and adjacency does not exist until the pages sit next to
each other. The code reviewer stays per step because what it catches **compounds**
— an accessibility or crawlability defect propagates into the next page built on
it, and a claims defect does not; it sits there until someone reads it.
**What it costs is recorded in `AGENTS.md` D20, not summarised away here.** Read
it before proposing any further relaxation: `claims-auditor` has caught defects
that would have been serious on a live page, and D20 accepts that such a defect
may now live in an unpublished draft for weeks. Two things carry that risk in the
meantime — **`npm run check:claims`, which is unchanged and runs on every build
and both deploy paths**, and **Pouya reading the copy as it is built**. Neither is
optional, and neither is a substitute for the cutover pass.
## Commands
@@ -221,6 +252,16 @@ argument and the comparison never ran. Prefer `git grep`, quote or array-expand
anything you pass as flags, and re-check any result whose shape is "uniformly
bad".
**And re-check "uniformly GOOD" too — that is the dangerous half.** *Added
2026-08-30.* The same `set -- $pair` loop recurred while confirming nine restored
files matched a saved copy, and this time it printed **`same` on all nine**:
`shasum` was handed both filenames as one argument, errored, and left both
variables empty, so `"" = ""` passed. **The `DIFFER` version announces itself
because it is alarming; a false pass is the answer you wanted and it ends the
check.** A comparison must **assert that both things it compares exist** before
comparing them, and `git grep` silently misses untracked files — so a clean sweep
across new work means nothing until the files are staged.
**A parent cannot style a child component's root element.** Astro does not pass
a parent's scope attribute down, so `<Button class="header-cta" />` compiles the
parent's rule to `.header-cta[data-astro-cid-<parent>]` while the rendered `<a>`
@@ -339,6 +380,46 @@ sweep; instances survived all three, and one of them was inside
`.claude/agents/claims-auditor.md` — the definition of the agent whose job is to
catch exactly that. Recall is not evidence.
**And sweep the VOCABULARY, not only the subject.** *Added 2026-08-30, from the
Q.Arb amendment.* `git grep 'Q.Arb'` is line-anchored, so it could not find **ten
lines in `docs/03` that were entirely about Q.Arb and never named it** — an
unstruck, imperative block still instructing the struck form, eleven lines below
that change set's own strike notice on the same bullet. The sweep was a real
command and its output was read honestly. It was still the wrong command.
So after sweeping the term, sweep the words its claims are **made of** — here,
the stage vocabulary (`commenced`, `in progress`, `pathway`, `not yet`) with no
mention of the designation. This is R8's sharpest edge, and it is the one that
survives an honest reader: a sweep can pass every test in the rule above and
still miss everything, because the anchor you chose is not the anchor the text
uses. The same session also excluded `docs/reference/` as "sourced extracts" —
half right. The quotations there are evidence; **the commentary around them is
this repository's voice**, and three lines of it still asserted the struck row.
**`check:claims` IS FROZEN. It is a tripwire, not a program.** *Pouya's ruling,
2026-08-30.* Round 2 of the Q.Arb amendment found **five defects in round 1's own
fixes to that script, two of which made it worse than before the pattern
existed** — a dedup key that reported two breaches of the same string as one (the
check truncating its own output), and a collapsed-text view whose window leapt
paragraph boundaries onto approved copy while its comment claimed it could not.
At that point it was generating defects at roughly the rate it caught them.
The rule, and it has no exceptions:
- **A pattern is added only after a real breach has reached `dist/`.** Never
speculatively, never to close a gap you can imagine.
- **Each addition ships with a probe** — an injected page proving it catches the
actual breach — **and a negative fixture** proving it stays silent on the
approved copy nearest to it.
- **No refactors. No coverage improvements. No tidying.** If a pattern is wrong,
change that pattern deliberately, with a Change Log entry. Do not rewrite the
scanner around it.
Under D20 this script is the only per-step claims control, which is an argument
for keeping it **correct**, not for growing it. It catches the §4 breaches that
are greppable and makes no claim about the ones that are not.
**Comments record decisions, not history — D19.** *"X because D13"* stays.
*"This was Y, then flagged, then became X"* belongs in the `AGENTS.md` Change
Log, which is where a reader looks for how something got here. **A comment