c576b9a85f53535f87b785c1d817117c41ba007e
10
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
c576b9a85f |
feat: build step 3 — /about/, minus its memberships; close Q40–Q43
Build and deploy / build-and-deploy (push) Failing after 6s
Applies Pouya's rulings on Q42, Q41(a)(b)(c), Q43 and Q40, then builds `/about/` — six of docs/01's seven items. `/about/` ships WITHOUT a memberships group. R10 is a prohibition on shipping a page that lists memberships before they are re-confirmed; the re-confirmation is a fact only Pouya holds and was not obtained. The first version published all four and disclosed the gap in five places instead; both review agents rejected that. Q44 carries the question. Rulings: - Q42 — ENE, dispute-system design and pre-dispute technical advisory rowed; settlement counsel struck as a partisan role. The strike exposed a hole in the offering test, which now states the prior question it was missing. - Q41(a) — Q37 reaches prose, and prose is held to a higher bar. The sentence is now one constant, ASYMMETRY_LINE, because two hand-typed copies had already diverged inside one session. - Q41(b) — not restored; the implication turned out to be in three places, two of which survived the sweep that closed it. - Q41(c) — verified against the LAT's own Rules and extracted into docs/reference/lat-case-conference.md. Rule 2.4 makes "Pre-Hearing Conference" the Tribunal's own term for a case conference; the Rules contain zero occurrences of `mediat` in 66,593 characters. - Q43 — the timings are service commitments; PROCESS_FRAMING renders adjacent to them, not in a lede above. - Q40 — bundled to step 7 as R15, blocking cutover. Four review passes, 43 findings, nine of them defects in their own predecessors' fixes. The worst was mine: the false universal Q39 struck reached a public page. Also fixed a portrait ladder that upscaled 1.93x at 1024/DPR2 on BOTH pages — the shipped home page included — because its 960 ceiling was derived from the layout range where the image is narrowest. Verified: check/lint/build/audit clean; 0 upscaling across 11 device profiles; 0 overflow and 0 over-wide elements at 13 widths; 0 contrast failures across 127 and 88 painted pairs; 0 print failures against white paper; reveal 0 hidden under reduced-motion and print; zero JavaScript. Lighthouse NOT RUN — tool unavailable until step 7 (R11). HTML validator NOT RUN. Opens Q44 (memberships), Q45 (PDF bio), Q46 (offering-test gating; the glossary standard), Q47 (jobTitle without worksFor). Adds R15. 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
|