Step 5 ships /practice/ and the six practice-area pages (construction,
technology, energy, insurance, shareholder, cross-border) from one route, and
adds the mechanical §4 gate Pouya ruled for.
check:claims — §4 Forbidden becomes a build error
scripts/check-claims.mjs greps dist/**/*.html for 10 patterns, each carrying
the incident that put it there. It strips <style> and non-JSON-LD <script>
first (a bare sweep for "leading" returned 26 hits, 25 of them
var(--leading-body)), self-tests every pattern against fixtures before
sweeping, and refuses a missing, empty or stale dist/. Wired into /build
Phase 5 and both deploy paths.
Q54 — six conduct undertakings publish, and §4 gains a third class
Conduct undertakings sit apart from credentials and offerings: the gate is
that Pouya said it in terms. The strings live in CONDUCT_UNDERTAKINGS so a
softening is one visible diff. (e) and (f) replace the third-person sentences
already on /arbitration/ rather than joining them.
Q49, Q50 recorded as rulings. §7 records the SES us-east-1 stray identity's
deletion. R11 holds typescript at its current major, with the peer-range
reason recorded.
Three facts corrected, two of them already shipped
- The LAT gloss said mediation "before filing and continuing after filing";
the Tribunal names mediation for "Before you apply" only and its second
sentence is about negotiation. An ellipsis in docs/01 had deleted it.
- "Connection allocation" is not an Ontario term.
- "The 2026 privacy statute" does not exist — Bill C-27 died without royal
assent. Struck from docs/03 rather than corrected in place.
ADR Chambers struck from /arbitration/ and from docs/01 item 3 (Pouya,
2026-08-30): the source establishes what the firm publishes, not that an
outside neutral can be appointed under its rules.
claims-auditor gains a second lens — for every quoted source, whether the
sentence beneath stays inside what the quotation establishes. Four shipped
defects had that shape and none of them is greppable.
CLAUDE.md gains a convention: never truncate the output of a check you intend
to believe. `npm run check | tail -3` returns warnings, hints and a blank line
and drops the errors line; it was reported as passing four times while
astro check was exiting 1 with 10 type errors.
Gates, exit status read directly, not through a pipe:
npm run check exit=0
npm run lint exit=0
npm run build exit=0
npm run check:claims exit=0
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Md3GndFqWPzK78xAoebsg5
Run at the step 1 → step 2 boundary, which is what R11 asks for rather than
waiting for something to break. `npm view <pkg> version` across all fourteen
pins; two were stale.
- astro ^7.2.7 → ^7.2.9. Patch. 7.2.8 published 2026-08-26, 7.2.9 2026-08-27.
- typescript ^5.9.3 → ^6.0.3. A full major behind, and installable.
TypeScript 7.0.2 is `latest` and is NOT taken — a deliberate hold with a
checkable reason, per R11. Both peer ranges exclude it:
typescript-eslint@8.68.0 peer typescript >=4.8.4 <6.1.0
@astrojs/check@0.9.10 peer typescript ^5.0.0 || ^6.0.0
6.0.3 is the newest stable both accept. Recorded in AGENTS.md §7 so the hold
is visible rather than looking like an oversight.
@lhci/cli is still 0.15.1 — unchanged, and it is not re-added here. R11's
re-add trigger is step 7.
Verified, not asserted: `npx tsc --version` 6.0.3 · `npm run check` 0 errors /
0 warnings / 0 hints · `npm run lint` clean (ESLint + Prettier) · `npm run
build` complete · `npm audit` 0 vulnerabilities.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0148NztQskLKKApP5SzAA78e
Amends D1 to pin the major explicitly (v7.x) rather than inherit it. The
^5.0.0 pin was recalled rather than checked and was two majors stale the day
it was written, which meant shipping a framework carrying high-severity XSS
advisories. CLAUDE.md now requires every version pin to be verified against
the registry, and R11 requires re-checking at each build-order boundary.
npm audit now reports 0 vulnerabilities, down from 16. Every Astro advisory
is cleared; the residual 10 all traced to @lhci/cli, which is removed — it
was the sole source of 7 high-severity findings, 0.15.1 is latest so there
was no clean upgrade, and it cannot run without pages or a lighthouserc.
Re-added at build step 7 with a freshly verified pin.
Content collections migrated to the Content Layer API: src/content.config.ts,
loader: glob(), z from astro/zod.
Two review passes found seven defects in the fix itself, all now closed:
- z.coerce.date() read an unquoted 20260801 as epoch milliseconds and
yielded 1970-01-01 silently; the first replacement then accepted
2026-13-45 as an Invalid Date and rolled 2026-02-30 over to 2026-03-02.
Dates are now anchored, date-only, parsed as UTC and round-tripped.
- The title bound applied the SEO spec's 50-60 to the headline rather than
the rendered <title>, which guaranteed 68-78 on every article and rejected
all five planned launch headlines. Articles are now the documented
exception: the headline is the <title>, no suffix.
- An article could ship an image with no alt text, or whitespace-only alt.
- Two schema comments asserted controls nothing enforced; both are now real
refinements, each tested with a failing and a passing case.
- PRACTICE_SLUGS and PRACTICE_AREAS could drift silently; a compile-time
check now catches both directions.
- eslint.config.js imported globals and @eslint/js undeclared, resolving by
hoisting accident.
- scripts/deploy-local.sh claimed parity with CI while skipping npm run
check and two credential guards — on the only path this site can ship
today.
Accessibility linting is on (36 jsx-a11y rules) before step 1 writes the
layout. An earlier claim in §7 that none was possible was wrong twice, and
is corrected in AGENTS.md entry (t) along with the reasoning.
Opens Q30 and Q31 for two unregistered claims in src/data/site.ts.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012XquaEq4BgWMCwUqLEyNkF
Answers four questions and starts build step 1.
Q22 — the scoped deploy user does not exist: aws iam get-user returns
NoSuchEntity. Recorded in §7 as NOT PROVISIONED and swept so that no file
describes it as existing. §10 records that user/pouya, the broadly-
permissioned personal user that has been authenticating to this account,
must never be used in CI; scripts/deploy-local.sh refuses to run as it.
Q23 — the Gitea instance reports 1.27.2, well above the vars-context floor,
so the first-step guard is belt-and-braces rather than load-bearing. What
remains is not a fact but a dependency: the instance is jointly administered,
so enabling Actions and registering a runner both need a second admin. Hence
npm run deploy (scripts/deploy-local.sh), which performs exactly what the
workflow performs — same guard, same three passes, same headers, same
invalidation. Documented as the current path, not as a workaround.
§10 gains the risk that follows: the deploy secret will live on jointly
administered infrastructure, where an instance admin can reach repo secrets.
That does not change the plan, but it makes the scoped IAM policy the actual
control between a shared Gitea instance and an AWS account holding another
business's client-database backups. Never widen it.
Q27 — response time is two business days, in site.ts with a derived short
form so the confirmation email cannot drift from the page.
Q28 — OBA sections confirmed, stamped "for now"; membership renews yearly,
tracked as R10.
Build step 1: dependencies installed and package-lock.json created, closing
the npm ci blocker. ESLint flat config and Prettier config added; npm run
lint, check and build all pass. Prettier deliberately excludes *.md and
tokens.css — reasons recorded in .prettierignore.
npm audit reports 7 high-severity advisories, all requiring an Astro major
upgrade. Not applied; escalated in AGENTS.md entry (s) as a decision.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012XquaEq4BgWMCwUqLEyNkF