9f2d83c32fc3e23c4cef187915ec2eedc57cc8c3
16
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
210bc25a26 |
feat: build steps 7a-10 — the site is complete and reviewable at 22 pages
Steps 7a through 10 as one authorised run. Nothing deployed (D11).
7a Lighthouse returns as `lighthouse@13.4.1` + `chrome-launcher`, NOT
`@lhci/cli`. AGENTS.md §7's advisory attribution was wrong: the carriers
were @lhci/cli's own `tmp` and @puppeteer/browsers' `extract-zip`, not
Lighthouse, which audits clean. A deliberate deviation from R11's literal
trigger, recorded with what it costs. Local gate; CI has no Chrome.
7b OG card generator (satori + sharp) discharges R15 — 20 typed cards plus
per-article cards; the portrait stays on / and /about/ by Q40. Insights
plumbing: ArticleCard, Prose, the index, the article route, articleGraph,
and /'s section 7. Card copy is constrained structurally because text in a
JPEG cannot be grepped by check:claims: every headline IS its page's <h1>,
enforced by `npm run og:proof`.
7c Five drafted launch articles, draft: true / reviewedByPouya: false. An
independent compliance audit returned 76 findings and 57 unsourced
assertions; all blocking and should-fix applied.
8 /contact/, the intake form, and backend/intake/ (undeployed). Plain HTML
POST to a same-origin /api/intake with a 303 redirect, so the form works
with zero JavaScript. docs/05 records three deliberate deviations.
9 /fees/ on Q59's ruling — overtime runs from the session cap, and the
reservation point ships adjacent to the rate. One-page PDF bio discharges
R16; /bio/ is its source, so the circulated artefact stays inside the
review apparatus.
10 /legal/privacy/ and /legal/terms/, written to the backend as built. Three
of the policy's statements are derived and cannot drift.
Also: /about/'s inverse credentials band (approved at step 6); Q59 closed;
R15 and R16 discharged; and a fix to shipped copy — /practice/energy/ asserted
the absence of a regulation the source extract says must not be asserted.
Review: adversarial-reviewer, two rounds (D20/D19). Round 1 returned 16
findings including two blocking — an invisible ghost button on /fees/ at
1.00:1 that Lighthouse scored 100, and a privacy policy that named one data
processor when there are two. All 16 acted on.
Lighthouse, 22 pages, mobile: performance 99-100, accessibility 100,
best practices 100, SEO 100 on every indexable page, CLS 0.000.
AGENTS.md entry (ah) has the detail, including four of my own verification
commands that were wrong and what each of them nearly caused.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Md3GndFqWPzK78xAoebsg5
|
||
|
|
6cfe69033f |
feat: rule Q58 and close Q57; §4 lists all six areas; docs/03's checklist cites §4 instead of restating it
Build and deploy / build-and-deploy (push) Failing after 4s
Four rulings from Pouya, plus what implementing them turned up. Q58 — RULED, and he attributed the ambiguity to his own document: "3.5 was meant as the TOTAL time committed, of which 2 is preparation — leaving 1.5 hours in the room. Your arithmetic caught it: if prep sat inside, 3.5 and 7 wouldn't be exactly 2x, because preparation doesn't scale with session length." The card now reads: half day up to 3 hours of session, fee includes up to 2 hours of preparation, $2,000; full day up to 6 hours, up to 3 hours of preparation, $4,000. docs/07's own research table corroborates 3 and 6 — Patey and Zuber both publish those hours, and ADR Chambers' roster rate counts preparation separately from "up to three hours of mediation". One provenance note under R14: he recalled "all or part of 3 hours" as their wording; the committed extract carries the hours but not the phrase, so docs/07 cites the hours and attributes the phrase to nobody. Two things fell out of the ruling that the instruction did not name, and both were defects. docs/07 §All parameters confirmed was itself prescribing the flat "including 2 hours of preparation" — the sentence /for-parties/ was built against, so the spec was generating the defect. And the cap had to reach the copy: "including up to 2 hours". FEES.mediation.*.hours is corrected 3.5 -> 3 and 7 -> 6; it had no consumer in src/ while the question was open, which is the only reason no page was ever wrong. /fees/ is unblocked for step 9 on the question Q58 asked. Q57 — CLOSED with no seventh undertaking. "A reader assumes the outcome, and the obvious undertaking adds nothing a reader doesn't already infer." The TODO(pouya) is replaced by the ruling where the question was; src/ now carries zero live TODO(pouya) markers. §4's mediation row lists all six published areas. Q56's ruling had named five, which was four areas plus the word "commercial" — a scope descriptor, not a seventh area. The hedge is struck on his instruction; the clause saying the six are not the authorised subject-matter list is restored, because his ruling supplied a correct value and did not close Q35(c)'s class. Split-stamped. docs/03's compliance checklist now names what to look for on a page and which §4 row decides it, never the bar's own wording. 12 items before, 12 after — a structural fix, not a coverage change. Thirteen review findings across two rounds, all applied, none declined. Three were mine to own. The capped-form rule was written and then applied to one surface: /mediation/ shipped an uncapped form in words no barred-string grep could reach, site.ts quoted a docs/07 sentence Q58 had just deleted, and §9's Q15/Q16/Q17 row prescribed the flat form — which is what a later implementer building /fees/ reads. A derived fee term was asserted as applied fact in the document that is the authority on money: "overtime begins after 3 h and 6 h" is in no ruling. Struck, and opened as Q59. And round 2 caught the arithmetic in round 1's own fix. The full-day route is flat $4,000 until hour 6, so generalising it as 500n+1000 for all n>=3 was valid only from 6 h, and "cheaper by $500 at every length" was wrong across the whole 3-6 h band. The real spread is $2,000 at three hours narrowing to $500 from six on — up to four times larger, and largest exactly where a half-day booking overruns. Written into docs/07 §Recorded dissent and §12's R5 row, which is where the 12-month fee review will read it. Round 1's fix for the missing consequence also published the overtime rate on a page that now states an unambiguous cap, defining the trigger by adjacency with no other quantity for it to attach to; the rate came off the page. R11 at the step 6 -> 7 boundary: 13 of 14 pins current. §7's TypeScript hold named one gate and there are two — typescript-eslint requires <6.1.0, tighter than @astrojs/check, so the recorded removal trigger was unreachable. Both are now named. Verified: check 0 errors, lint 0, build 0 (14 pages), check:claims 0, npm audit 0, minifier tripwire clean, zero JS shipped, all copy present with JavaScript disabled. Lighthouse not run — tool unavailable until step 7. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Md3GndFqWPzK78xAoebsg5 |
||
|
|
2ea4c0f8ac |
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 |
||
|
|
610edc24fd |
feat: Q.Arb is held; strike C.Med-Arb entirely; dissolve the paired disclosure
Build and deploy / build-and-deploy (push) Failing after 4s
Pouya's ruling, 2026-08-29. Treated as D3-class and swept accordingly. §4 Q.Arb becomes a HELD designation. Obtained July 2026 — recorded in the register, deliberately not published. Public copy carries "Q.Arb (ADRIC / ADRIO)" beside Q.Med and nothing more. Every stage form is struck: "commenced", "in progress", "pathway", "not yet". C.Med-Arb as a stated goal is struck. This DEVIATES FROM THE STRATEGY BRIEF, which made it "the explicit long-term professional narrative"; the brief is not in this repository, so the deviation is recorded in four places so nobody reinstates it from a document no reader can open. The designation stays in §11 as a definition — what is struck is its status as a goal of his. The paired-disclosure condition dissolves. It existed only because Q.Arb was in progress; there is no stage left to disclose, and a condition with no subject cannot be half-kept. Pages /about/'s credentialing arc is DELETED, not rewritten — two held designations are not a journey. /arbitration/ loses its stage section and its "Available now, and open about the stage" h1. /med-arb/'s endpoint section is rewritten. Deleting CREDENTIALS.goal/goalName rather than emptying them turned every consumer into a build error, which is how the last two surfaced. hasCredential now maps CREDENTIALS.designations instead of indexing [0]; _DesignationRowParity pins the visible credential row to the same constant. check:claims q-arb-as-a-stage (inverted from the predecessor, which barred Q.Arb reading as HELD) and c-med-arb-struck. Each page is now scanned twice — as published, and with inline tags collapsed — because [^<] cannot cross <strong>, which this site sets in prose. Two open questions for Pouya, neither blocking: Q55 — the acquisition date. §4 says obtained July 2026; the Change Log of 2026-08-26 records "commenced August 2026", both stamped [verified — Pouya]. They cannot both be true. Nothing published turns on it. Q56 — is the mediation offering scoped commercial? §4 leaves it unscoped; four surfaces say "commercial mediation"; /practice/insurance/ offers mediation in insured-versus-insurer SABS matters. Two review rounds, all findings applied or declined with a stated reason. Round 2 found ten lines in docs/03 still instructing the struck form — the 2026-08-29 sweep missed them because `git grep 'Q.Arb'` is line-anchored and the block never names it. Sweep the vocabulary, not only the subject. Gates, exit statuses read directly, never through a pipe: npm run check exit=0 (0 errors, 0 warnings, 0 hints) npm run lint exit=0 npm run build exit=0 (12 pages) npm run check:claims exit=0 (11 patterns, 26 approved strings) npm audit exit=0 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Md3GndFqWPzK78xAoebsg5 |
||
|
|
79b19a7bd0 |
feat: build step 5 — /practice/ and six area pages; check:claims gates §4 in dist
Build and deploy / build-and-deploy (push) Failing after 5s
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
|
||
|
|
fd5f610982 |
feat: D19 bounds the review loop; apply nine rulings; close Q46(a) and Q48–Q53
D19 into §3 and swept to all six destinations Pouya named: both agent briefs
(scope + severity filter), /build Phases 2–4 (non-gating questions, scope, stop
signal, two-round cap), /wrap, and CLAUDE.md (comments record decisions, not
history). Sweep verified by command, not recalled.
Rulings applied:
Q46(a) PUBLISHABLE — three §4 Offerings rows flipped; gate 1 records
[Pouya's stated basis], never [verified]. Step 5 unblocked.
Q48 closed, not site-relevant.
Q49 one §4 row, "Mediator"; read as declining Q49(b), so worksFor stays out.
Q50 DEVIATES — ships as name + slogan, not the concatenation. Flagged.
Q51 OBA sections stay; the regulator/voluntary distinction recorded.
Q52 docs/reference/deploy-credential-verification.md — 18 read-only AWS
calls, re-run rather than transcribed, access key ID redacted.
Q53 memberOf emitted on /about/'s Person node.
Two review rounds. The headline finding was this session's own: the Q53 sweep
was asserted and never run, leaving six in-scope records saying memberOf was
withheld — including §12 R10, which is read aloud every session. Round 2 then
found that round 1's simplification had put memberOf on / as well; the per-page
opt-in is restored, because Pouya's ruling turns on /about/'s visible HTML.
Also fixed: MEMBERSHIP_ORGS had orphaned BOUTIQUE's D16 JSDoc; /'s title now
derives from the constants; §7's deploy row stated and retracted three facts.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0148NztQskLKKApP5SzAA78e
|
||
|
|
77a7b410b2 |
feat: apply six rulings; close Q22/Q44/Q45/Q46(b)/Q47; revert Q47's two graph fields
Pouya's rulings: Q44 (memberships current — ship the group), Q45 (PDF bio deferred to step 9), Q46(a) (three offerings pass all gates), Q46(b) (§11 ratified as the source for definitional expansions, conditional on committing the source), Q47 (set jobTitle and worksFor), the legal-advice formulation ratified without change, and Q22 closed on his own execution evidence. Q46(b): docs/reference/adrio-designations.md commits all five ADRIO expansions with reproducible sha256 (four fetches each; both review agents independently reproduced every digest). It immediately caught the error Pouya raised in the same message — §11 had said "Chartered Mediator-Arbitrator" since the file was created, ADRIO's term is "Chartered Med-Arbitrator", and the wrong form was in dist/about/index.html. Four prior review passes read that string and checked only whether it was sourced, not whether it was right. Q47 REVERTED after both review agents struck it independently. jobTitle shipped for one pass as "Mediator and Commercial Arbitrator" — the string claims-auditor had removed from this same node's description the previous day, since §4 has no row for a completed arbitration. The implementation flagged the wrong defect: it argued about scoping and missed that the whole string was already struck. worksFor was reverted because ProfessionalService.provider is this Person, so provider -> Person -> worksFor asserts a same-entity claim transitively. Now jobTitle: 'Mediator', no worksFor. Q49 asks for the two §4 rows. Q44: memberships render with NO currency warranty (his condition), and R10 is re-armed with an event trigger rather than a date since he declined renewal-date tracking. Q22: §7 goes to PROVISIONED; R17 carries the first rotation date, 2026-11-26. New CLAUDE.md convention, his: never suppress stderr in a verification script — suppression turns "it failed" into "it found nothing". Two review rounds resolved 48 findings; the majority of the second round were defects in the first round's fixes, including a re-widening of §4's renewal period inside the comment that corrects that widening, a cited guard in schema.ts that does not exist, and a struck §9 row describing a reverted state. Three findings were one lift from a public page: docs/03's /for-parties/ directive breached D13 twice, docs/01 told an implementer an unpublishable strip could ship, and docs/07 priced three ungated offerings with no gate note. Also commits docs/reference/adrio-extract/ — the extraction script and its five outputs, since the digests covered raw HTML and said nothing about the text the term counts were run against. The equivalent gap for Q22's IAM verification is NOT closed and is Q52. Verified: astro check 0/0/0, eslint + prettier clean, build 2 pages, 0 .js emitted, minifier guard silent, animation-timeline intact, no currency-warranty phrasing in dist, JSON-LD correct on both pages. NOT run: Lighthouse (tool unavailable until step 7, R11); HTML validator. Opens Q48-Q53. Live reminders: R1, R10, R11, R13, R14, R15, R16, R17. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0148NztQskLKKApP5SzAA78e |
||
|
|
165d259f5c |
feat: build step 2 — the home page; close Q35, Q37, Q39; Q39's answer corrected the register
Pouya's rulings and the page are one commit, not two, because they are not separable: Q37 changed the credential label the page renders, Q39 scoped the arbitration copy, and Q35 gave Med-Arb the row that lets the footer link stand. Splitting them would produce a commit where the register says one thing and the page says another. RULINGS Q39 — ANSWERED, and my assertion was FALSE as a universal. Pouya checked rather than defended. Family arbitration in Ontario is gated: prescribed training, 14h on screening for domestic violence and power imbalances, 30h of Ontario family law for arbitrators outside the bar, 10h ongoing per two years. claims-auditor produced that counter-example from inside the repo on 2026-08-26 and it was right. The source is now IN the repo per R14 — docs/reference/ontario-family-arbitration-training.md, retrieved with its provenance — and §4 states which half it establishes: the family gate directly, the commercial half only by absence. So "commercial arbitration in Ontario requires no licence and no designation" is recorded as Pouya's stated position, unstamped. What disposes of the question is the scope exclusion: he does not do family arbitration, so it is NOT OFFERED and the gate never bears on the practice. The false universal survived in three more live places, found by grep, not recall: §4's NOT-NEGOTIABLE boundary bullet (the boundary paragraph breaching its own boundary), §9's Q33 closure row, and a comment in SiteHeader.astro. Q35 — ANSWERED, all four items, and the answer supplied a gate that was missing. Med-Arb gets an Offerings row and stays in the footer sitemap. The six subject-matter labels pass test 1. §4 gains "Subject-matter areas — the publication gate": competence to accept an appointment, AND a page that frames it as positioning without claiming history. Nothing in the nav or footer is unrowed any more. Q37 — ANSWERED. "Law and engineering" becomes "Legal training and engineering practice". A degree is not a practice; the parallel was doing the implying. Q38/R13 — the committed SVG does not close it; the walk-back went too far. It renders faithfully BECAUSE it is the raster. R13 stays open. R1 — surfaced and acknowledged; the interim licensure framing is now carried by a shipped page rather than a spec, which raises the stakes. BUILD STEP 2 Seven of docs/01's eight home sections, six new components, zero JavaScript. Section 7 (Latest insights) ships at step 7 with the collection it lists — recorded in docs/01 and in the page, not just here. Four credential slots, not three: §4's paired-disclosure condition requires the Q.Arb stage on any page that offers arbitration. No booking link (R6). The masthead tagline is suppressed on / (it duplicated the hero eyebrow). The step-1 proof sheet is deleted, and five live references to it were found by grep. WHAT THE REVIEWS FOUND — 24 findings across the two passes claims-auditor FAILED it on ten, every one implication or scope rather than fabrication, which is where D13 says the risk lives. The four that mattered: "I mediate and arbitrate" asserted a track record §4 does not hold for arbitration; the JSON-LD asserted arbitration twice and stated the stage nowhere (a crawler-only claim is still a claim); "at one published rate with preparation time included" misdescribed money against docs/07's two day rates and capped prep allowance; and "Law and engineering are not blended here" was Q37's struck parallel relocated into prose one day after Pouya struck it. It also found the Canadian Tax Foundation missing from §9 Q8 — a stale second copy of a fact that would have bitten at step 3. adversarial-reviewer found fourteen, three blocking. The first was class="section-head" on <SectionHeading> never matching — the parent-cannot- style-a-child defect for the FOURTH time, written into a diff where I had just added fresh warnings about it to two other components. Measured: 0px margin, 0px gap, headings over the card edges, with astro check and eslint both clean. I had looked at a screenshot of that section and passed over it. Fixed with a page-owned wrapper (48px, measured) and the prop is deleted from six components so it is now a build error. Also: the credential row was never "two up on a phone" and its comment said it was; PROCESS was hardcoded in the page against the reason written in site.ts; 83px of residual overflow at a 200% default font size, now 3px. Seven more I found myself first, including <Picture widths> declaring the untouched 1600px master as the <img src> fallback (254,626 B for a 476px slot, and the build log said "before: 349kB" either way), and a prop named `as` silently turning off type-checking for a whole component. VERIFICATION — run, not asserted. Full figures in AGENTS.md entry (w). npx tsc 6.0.3 · check 0/0/0 · lint clean · build clean · audit 0 1 <script> and it is JSON-LD; non-JSON-LD scripts 0; no JS bundle; identical page with script execution disabled (444 nodes, 6,578 chars) Phase 5 minifier check: no `animation` shorthand beside animation-timeline overflow 0 at 14 widths, AND every mark measured at 1.5654-1.5657 vs 1.5657 one h1, no heading skips, focus order == DOM order across 44 focusables 31 painted contrast pairs at 3 widths, 0 failures 72/72 hit-test points across 8 cards resolve to the card's link print 0 hidden, reduced-motion 0 hidden Lighthouse NOT RUN — tool unavailable until step 7 (R11) HTML validator NOT RUN, and 4 of 12 srcsets carry a duplicate 1x descriptor Opened for Pouya: Q40 (one OG image for nineteen pages), Q41 (does Q37 reach prose; may the comparative be restored; what LAT pre-hearing mediation means), Q42 (the four "also offered" processes have no row), Q43 (the process timings are published commitments with no row). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0148NztQskLKKApP5SzAA78e |
||
|
|
364b09632e |
fix: replace the traced infinity mark with the real artwork; add §4 Offerings
Q32 — the traced mark was a WRONG SHAPE and had shipped. Pouya compared it against the master and rejected it. Two grounds reproduce from the path and are verified here: all four cubic branches meet the origin at exactly 90 degrees, so the loops are tangent rather than crossing and at stroke-width 28 render as two kissing circles (signed crossing number 0; the strokes fuse across 61% of the mark's height at 2rem); and the master's ink bbox is 2668x1704 = 1.5657:1. The path is deleted, not kept as a fallback. Pouya's 1.23:1 figure is reconciled rather than left dangling: it is the bounding box of the path's COORDINATES, not the curve. Control points sit at y +/-160 where the curve reaches +/-120, so the hull is 400x320 and with stroke 428x348 = 1.2299. A trap rather than a slip — x is monotone, so the control points give the right width and a 33% inflated height, and the "does the width look right" check passes. The real artwork is now in the repo: master, tight crop (the render source, so the file's aspect ratio IS the mark's), full lockup, and the SVG. InfinityMark renders AVIF/WebP; a Retina device takes 3,063 B. Favicons regenerated; favicon.svg deleted. Q33/Q36 — Pouya accepts arbitration appointments now. §4 gains an Offerings category: competence for an offering, permission for a credential, with an explicit boundary so it cannot become a route around D13. The masthead tagline is restored, and the footer designation strip now carries "Q.Arb — commenced August 2026" so §4's paired-disclosure condition is actually met on every page rather than only asserted. Two conventions added to CLAUDE.md, both earned this session: anything a spec makes a claim about must be reachable from the repo (R14 — the traced mark survived two review passes because the artwork was not here to compare against); and a command that did not run is not evidence of absence (`timeout` is not installed on macOS, so four Drive reads never executed and were reported as an empty directory). Reviews: claims-auditor FAIL/13 and adversarial-reviewer 2 blocking, all resolved. The severe one was self-inflicted — `flex: none` landed on the <img> while <Picture>'s <picture> wrapper is the flex item, so the logo compressed to 28.5x32 at 1024px with seven nav items. The page-level overflow check passed throughout because the brand block absorbed the deficit by crushing the mark. Harness now asserts rendered aspect ratio. Opened: Q38, Q39. Closed: Q32, Q33, Q36. Narrowed: Q35. Added: R13, R14. AGENTS.md entry (v) carries a RESUME HERE section. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012XquaEq4BgWMCwUqLEyNkF |
||
|
|
8134709548 |
feat: build step 1 — scaffold, layout, header, footer, SEO; zero JavaScript
Build order step 1 (docs/01): scaffold, tokens, base layout, header, footer, SEO component, plus a temporary /type-scale/ proof sheet that step 2 deletes. THE FONTS WERE NEVER ON DISK. global.css declared six @font-face rules pointing at /fonts/*.woff2 and public/fonts/ did not exist, so every face had been silently falling back to Georgia and the system sans. Six cuts committed, 123,804 bytes, SIL OFL 1.1, provenance in docs/reference/fonts-provenance.md. ?v=1 on every URL because the deploy script serves them immutable for a year. ZERO JAVASCRIPT. The reveal was an inline IntersectionObserver in <head>; docs/05 specifies script-src 'self' with no unsafe-inline, so the only script on the site was the one thing the site's own CSP would refuse to execute. Replaced with animation-timeline: view() behind @supports. 0 script tags and 0 .js files in dist. The infinity mark is lifted verbatim from the deployed site's own smlMark loading thumbnail, not redrawn (Q32 asks whether a canonical vector exists). The proof sheet computes its contrast table from tokens.css rather than restating docs/02 — all eleven ratios reproduce the measured table exactly. Register: Canadian Tax Foundation added (§4, R10 widened); Q30 closed — SML Company Ltd is federally incorporated under the CBCA, and the footer publishes neither that nor the place of business; Q31 closed — Plausible, on EU-only data residency (D15 amended). ROLE constants added for "Director of Firm Operations" and "active litigation exposure" so step 3 does not hand-type them. Lighthouse unavailability now stated in six places rather than left as a control that had silently stopped existing (§7, R11). Both review agents ran twice. The second pass found four defects in the first pass's fixes, including the minifier bug written back into its own fix and a colour-alone repair that used the banned gold-on- cream pairing at 2.10:1. Measured in headless Chrome at thirteen widths with a seventh nav item injected: 0 overflow, 0 tap targets under 44x44, 0 focus-order inversions, state indicators at 12.29:1, 755 words of body text with no JavaScript. Opened: Q32-Q37. Closed: Q30, Q31. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012XquaEq4BgWMCwUqLEyNkF |
||
|
|
7514a49803 |
feat: upgrade to Astro 7; harden the content schema; wire a11y linting
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 |
||
|
|
0d8b63380a |
chore: install toolchain, wire lint, add local deploy path
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 |
||
|
|
2b6176e4d7 |
feat: SES production access and monitoring; §7 as single source of operational truth
Q19 is closed — SES production access granted in ca-central-1, confirmed in writing. Nothing now blocks /contact/. The structural change is the important one. Specs in docs/ carried their own copies of resource IDs, regions, DNS records and service state. AGENTS.md §7 is now the single source of truth for operational facts and docs/ cite it rather than restating it, with the rule recorded in CLAUDE.md under Conventions. The reason is the previous commit's DKIM inversion, generalised: the same fact lived in §7 and docs/05, a correction reached one of them, and the stale copy told an operator to delete the records that authenticate outbound mail. A duplicated fact is one that will eventually be wrong in one place, and the copy that goes stale is the one nobody re-reads. Verified by grep over docs/*.md — no operational identifier remains. Also in this change: - §7 records the SES monitoring: SNS topic ses-alerts, alarms SES-BounceRate-High (>= 0.03) and SES-ComplaintRate-High (>= 0.001), and the deliberate choice of email feedback forwarding over an SNS feedback topic at this volume. The ses-alerts email subscription is stamped PENDING CONFIRMATION — the alarms currently notify nobody, now tracked as R9 and on the cutover checklist. - docs/05 records why those alarms are a real control: SES suspends above roughly a 5% bounce rate, and under 100 messages a month five bounces crosses it. - Q29: the deploy guard now covers AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY (emptiness only, never echoed) and INTAKE_ENDPOINT, promoted to job-level env. An empty intake endpoint ships a live form posting to nothing, which is worse than a failed build. Executed under sh -e across four input states; fails closed, leaks nothing. - docs/06: account ID removed from the backup-bucket callout, pointing at §10 instead, as README already does. - astro.config.mjs: prefetch removed entirely. Any setting ships Astro's prefetch script to every page against the zero-JS convention. Recorded as a decision; revisit against real Lighthouse numbers. AGENTS.md entry (r) records the full reasoning. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012XquaEq4BgWMCwUqLEyNkF |
||
|
|
6bf1167624 |
fix: sweep D3 amendment through the specs; correct inverted DKIM table
The re-audit of the deploy-guard change surfaced defects well outside the diff, including one that would have broken production mail. docs/05-backend-spec.md had the two SES DKIM sets exactly inverted, labelling the three records that resolve as "orphans" and the three NXDOMAIN records as "Live. Never delete". Entry (j) corrected this in AGENTS.md §7 and the correction never reached docs/05. Since SES has no custom MAIL FROM, DKIM is the only thing satisfying DMARC, so acting on that table would have silently broken intake mail authentication. Also in this change: - .gitea/workflows/deploy.yml gains a guard as steps[0] that fails the run, naming the variable, if AWS_REGION, S3_BUCKET or CLOUDFRONT_DISTRIBUTION_ID is empty — how a Gitea too old for the vars context manifests. Verified fail-closed under bash -e, sh -e and bash -euo pipefail. - AGENTS.md Current Truth: SPF and DMARC recorded as present (Q20), the matching §10 High risk row retired, three duplicate Q rows removed. - docs/reference/AWS-Hosting-Guide.md tracked and given a do-not-execute banner; it was an executable procedure for the architecture D1/D3 replace. - Copy decks: "a working litigator" and "an active litigation practice" replaced with the register's own wording; LegalService JSON-LD replaced with ProfessionalService; tribunal-secretary offers removed per D14; nine stale question blockers swept. - astro.config.mjs: prefetchAll disabled — it injected JS into every page against the zero-JS convention with no decision recorded. - src/data/site.ts: unregistered response-time commitment nulled (Q27); OBA section names downgraded to [assumed] (Q28). - s3:AbortMultipartUpload reasoning corrected to measure ./dist, not the repo. Opens Q27, Q28, Q29. AGENTS.md entry (q) records the full resolution, including the findings declined and why. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012XquaEq4BgWMCwUqLEyNkF |
||
|
|
e6abdf42e8 |
feat: execution protocol, review agents, DNS and SES findings
Build and deploy / build-and-deploy (push) Failing after 6s
|
||
|
|
19f7226661 |
chore: project scaffold, specs, and working record
Build and deploy / build-and-deploy (push) Failing after 5s
|