diff --git a/.claude/agents/claims-auditor.md b/.claude/agents/claims-auditor.md index 9409869..5893a7a 100644 --- a/.claude/agents/claims-auditor.md +++ b/.claude/agents/claims-auditor.md @@ -33,9 +33,21 @@ replaced with something verified. **Licensure (D13).** The site asserts the JD and nothing further. Flag: "lawyer", "called to the bar", "licensed", "my law practice", "my litigation practice", -"my clients", "acts for", "represents", "legal advice", or any post-nominal -implying a licence. **Flag implication as hard as assertion** — "my litigation -practice" claims licensure without the word. +"my clients", "acts for", "represents", or any post-nominal implying a licence. +**Flag implication as hard as assertion** — "my litigation practice" claims +licensure without the word. + +**"legal advice" — FLAG IT ONLY WHERE IT ATTACHES A CAPACITY TO POUYA.** This +list carried a bare *"legal advice"* until 2026-08-28, which applied literally +flags the **ratified** sentence *"each party should have their own legal +advice"*. Flag *giving* legal advice, *practising law*, or *holding a licence* +predicated of him — not the phrase wherever it appears. `docs/03`'s +*"When a fact is `[unestablished]`"* section carries the pattern and the three +tests; the shipped sentence is its worked example of a **pass**. + +*This is the fourth stale claim found inside this brief. The same correction +reached `docs/03`'s compliance checklist and did not reach here — the shape this +paragraph's own memberships note records two sections down.* The approved phrasing for the boutique role is **"active litigation exposure"** or **"involvement in litigation and ADR matters"**. The word **"practice"** in diff --git a/AGENTS.md b/AGENTS.md index 1db9862..e58f212 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -180,7 +180,7 @@ since May. | Iranian-Canadian; cross-cultural fluency with diaspora business communities | `[verified 2026-08-25 — strategy brief §I]` | | Operator of SML Company Ltd. alongside the practice | `[verified 2026-08-25 — strategy brief §I]` | | **SML Company Ltd — incorporated FEDERALLY, under the CBCA** | `[verified 2026-08-26 — Pouya, Q30]`. Two facts were being conflated and one of them was wrong: **jurisdiction of incorporation is federal (Canada)**; **place of business is Toronto, Ontario**. `src/data/site.ts` carried `'SML Company Ltd. · Ontario, Canada'`, which reads as a jurisdiction of incorporation and named the wrong one. **No corporation number** — none is held and the line does not need one. **Caution, and it is the point of this row:** "federally incorporated" says nothing about professional licensure, and nothing about where the practice may operate. It must not be read together with the **Licence status — NOT ESTABLISHED** row into an implication that neither row makes. **Not published:** on Pouya's direction the footer reads `© SML Company Ltd` and nothing further — the fact is verified and available, it is simply not on a page | -| Memberships: **ADRIC**, **ADRIO**, **OBA — Construction & Infrastructure, ADR, and Civil Litigation sections**, and the **Canadian Tax Foundation** | `[verified 2026-08-26 — Pouya]`, **for now**. *CTF added 2026-08-26.* Both the OBA sections and the CTF renew yearly; every line here is a fact with a shelf life, tracked as R10. Re-confirm at renewal and before any page listing memberships ships. **CTF is a membership, not a practice area** — it is the one credential none of the six areas touch, and `docs/01-architecture.md` records why there is no seventh page at launch and when to revisit (R3) | +| Memberships: **ADRIC**, **ADRIO**, **OBA — Construction & Infrastructure, ADR, and Civil Litigation sections**, and the **Canadian Tax Foundation** | **`[verified 2026-08-28 — Pouya]` — RE-CONFIRMED, R10 DISCHARGED, AND NOW PUBLISHED ON `/about/`.** Q44 closed: *"All four are current as of today."* **Note on the stamp date, because it is a currency stamp and the date is the whole content:** Pouya's ruling said *"Stamp `[verified 2026-08-26 — Pouya]`"*, which is the date of the **original** confirmation. The stamp here reads **2026-08-28**, the date he actually re-confirmed — a stamp records when the assertion was made, and back-dating a re-confirmation by two days would understate the only thing the stamp is for. Flagged to him; one edit to change if he meant otherwise. **NO CURRENCY WARRANTY MAY BE PUBLISHED.** His words: *"List the memberships; promise nothing about their future state."* The struck sentence (*"Memberships are renewed annually and are listed as current"*) stays struck and nothing replaces it. **Renewal periods: the OBA sections and the CTF renew yearly. This record says NOTHING about ADRIC's or ADRIO's period** — an earlier form asserted "all four renew yearly" and that widened form propagated to four files. **He declined renewal-date tracking**, so R10 no longer fires on a date; it fires on an **event** — re-confirm before any cutover or major republish. `memberOf` is separately withheld from the JSON-LD; see `src/data/schema.ts`. **CTF is a membership, not a practice area** — it is the one credential none of the six areas touch, and `docs/01-architecture.md` records why there is no seventh page at launch and when to revisit (R3) | | ~~OCNI~~ | **Not current. Do not publish** `[verified 2026-08-26 — Pouya]` | | ~~LSO~~ | **Do not publish.** Listing the Law Society among memberships implies licensure, which D13 bars. Excluded deliberately, not by oversight `[verified 2026-08-26]` | | Toronto, Ontario; by appointment | `[verified 2026-08-26]` | @@ -265,9 +265,29 @@ appointments now**, and that — his acceptance — is what the rows below recor > **For an offering, ask about COMPETENCE. For a credential, ask about > PERMISSION.** A credential claim needs a row in the Verified table because it -> asserts a fact about Pouya that is either true or false. An offering needs two -> things, and they are answered by different people: +> asserts a fact about Pouya that is either true or false. An offering needs +> **three** things, and they are answered by different people: > +> 0. **Is this a role in which the practice is PARTISAN between the parties to a +> dispute?** — ***his call, and only his.*** It is a question about **role +> design**: what the practice holds itself out as doing, which is his to +> define. Not the register's, not an implementer's, not a reviewer's. +> **If the answer is yes, the offering is refused before the test starts**, +> and neither question below is reached. Numbered **0** because it runs first +> and disposes of the candidate on its own. +> +> *The owner was left unstated when this gate was numbered on 2026-08-28, +> while gates 1 and 2 both name one and the ENE row supplied one anyway +> ("it is his to answer"). `adversarial-reviewer`: the intro promises +> "answered by different people", and this section's whole failure history is +> gate 1 being closed by the wrong party — twice, both times caught by audit. +> An unowned gate recreates that opening.* +> +> It is the gate that disposed of **settlement counsel** — and the catch was +> **Pouya's**, not this register's. §4's own row records it: *"Pouya removed it +> as his own error in `docs/01`."* An earlier version of this bullet called it +> "this register's highest-value catch"; the register's credit is for keeping +> the worked example, not for making the catch. > 1. **Is the activity gated?** — *a question for THIS REGISTER, not for the > subject.* It needs a source that a reviewer can check, and it is answered > per activity and per jurisdiction, never as a class. Until it is answered, @@ -275,6 +295,15 @@ appointments now**, and that — his acceptance — is what the rows below recor > 2. **Is he competent to do it?** — *his call, and only his.* Not the > register's, not an implementer's, not a reviewer's. > +> ⚠️ **GATE 0 WAS UNNUMBERED PROSE UNTIL 2026-08-28, AND IT LIVED ONLY IN THE +> WORKED EXAMPLE.** The rows in the Offerings table cited "gates 2 and 3" and +> quoted Pouya's ruling about *"all three gates"* while the section titled *The +> offering test* enumerated two — so an implementer at step 5 reading the +> definition would not find a third gate at all, and the partisan check was +> invisible from the place it is defined. Found by `adversarial-reviewer`. +> **The rows' "gate 3" is this gate 0.** Numbering it 0 rather than 3 records +> that it runs before the others rather than after them. +> > **Question 1 is not his to answer**, and an earlier draft of this test said it > was: it ended "That is his call, not the register's, and not an implementer's" > attached to the *whole* preceding question, gating included. That hands a @@ -345,9 +374,9 @@ never be read as one: | **Arbitration — co-arbitration** | `[verified 2026-08-26 — Pouya, Q33/Q36]`. Offered **now**. This closes Q36, which had flagged the claim as asserted in three specs and resting on no §4 row — the row is here | | **Med-Arb** — mediation-arbitration | `[verified 2026-08-27 — Pouya, Q35]`. Offered **now**. Both halves are live: Q.Med is held, and arbitration appointments are accepted (rows above). Ungated by the same reasoning as arbitration. This closes the "Still unanswered" note that used to sit below this table, and it is why `/med-arb/` may stay in the footer sitemap | | ~~**Family arbitration** under the *Family Law Act*~~ | **NOT OFFERED — a scope exclusion, not a gating problem** `[verified 2026-08-27 — Pouya, Q39]`. Pouya has confirmed he does not do family arbitration. It is therefore out of scope by his choice, and the prescribed-training question never arises for this practice. Recorded because the register reasoned from a false universal for one day and must not do so again — see the box above and `docs/reference/ontario-family-arbitration-training.md`. **`Shareholder & Family Business` does not touch this:** it means commercial disputes among family shareholders — shareholder and partnership disputes, co-founder breakdowns, business succession — and its page must say plainly that family law matters are not accepted | -| **Early neutral evaluation (ENE)** | ⚠️ **COMPETENCE ANSWERED; GATING NOT ANSWERED — NOT YET PUBLISHABLE.** Question 2: *"A neutral assessment of merits sits inside a Q.Med's competence"* `[Pouya's stated basis 2026-08-27, Q42]`. Question 1 — **is the activity gated?** — is `[unestablished]`. An earlier version of this row read *"Ungated on the same footing as mediation — no designation is required to give a non-binding evaluation"* under a `[verified — Pouya]` stamp. That is **a proposition of Ontario law inside a stamp §4 says cannot carry one**, and it was the register doing exactly what the box above warns against, one paragraph after warning against it. Struck by `claims-auditor` on two consecutive passes. **ENE is also the offering nearest the gated side of the boundary** — a neutral assessment of the *merits*, delivered to parties — so it is the one that most needs a source rather than an assertion. Q46. Priced hourly in `docs/07-fees.md`, which is a fee-page question, not a publication licence | -| **Dispute-system design** | ⚠️ **COMPETENCE ANSWERED; GATING NOT ANSWERED — NOT YET PUBLISHABLE.** Question 2: *"Consulting, no appointment, no neutrality question"* `[Pouya's stated basis 2026-08-27, Q42]`. **That sentence answers neutrality, not gating**, and an earlier version of this row presented it as though it answered both. Question 1 is `[unestablished]` and is not his to answer. Q46 | -| **Pre-dispute technical advisory** | ⚠️ **COMPETENCE ANSWERED; GATING NOT ANSWERED — NOT YET PUBLISHABLE.** Question 2, in three words: *"It is the moat"* `[Pouya's stated basis 2026-08-27, Q42]`. Question 1 is `[unestablished]`. Q46. **Caution that belongs with the row regardless:** advisory work for one organisation is the one item in this table that can create a conflict against a later appointment in the same matter. That is practice management rather than a publication gate — but no copy may imply it is free of that tension | +| **Early neutral evaluation (ENE)** | ⚠️ **GATES 0 AND 2 ANSWERED; GATE 1 STILL HAS NO SOURCE — NOT YET PUBLISHABLE.** **Q46(a), ruled 2026-08-28:** *"ENE, dispute-system design and pre-dispute technical advisory get explicit rows in §4 Offerings. They pass all three gates including the new partisan question."* **Gate 0 (partisan?) — PASSES, and it is his to answer:** ENE is delivered *to the parties* as a neutral, not for one of them. **Gate 2 (competence) — PASSES:** *"A neutral assessment of merits sits inside a Q.Med's competence"* `[Pouya's stated basis 2026-08-27, Q42]`. **Gate 1 (is the activity gated?) — the ruling asserts it passes and this register cannot record that it does.** §4's own test: *"Question 1 is not his to answer… It needs a source that a reviewer can check, and it is answered per activity and per jurisdiction, never as a class."* No source for ENE exists in `docs/reference/` (R14), and the ruling did not name one. **This is not a disagreement about the answer — it is that the artefact the test requires does not exist**, and the test was written this way *because* gate 1 had twice been closed with the subject's words. Letting a ruling close it defeats the mechanism at exactly the point it was built to hold. **ENE is the offering nearest the NOT-NEGOTIABLE boundary** — a neutral assessment of the *merits*, delivered to parties, sits closest to *"providing legal services"* — so it is the one that least tolerates an unsourced gate. **What would close it:** the Ontario *Law Society Act* definition of "providing legal services" (s. 1), plus LSO By-Law 4, committed to `docs/reference/` verbatim with the application to ENE left to Pouya or to counsel — not drawn by this register or by an implementer. Offered as a next-session task; not done unasked, because it is legal research and §4 bars this file from concluding it. **Consequence today: none on the site.** Blocks `/practice/`'s "also offered" strip at **step 5**, not step 4. Priced hourly in `docs/07-fees.md`, which is a fee-page question, not a publication licence | +| **Dispute-system design** | ⚠️ **GATES 0 AND 2 ANSWERED; GATE 1 STILL HAS NO SOURCE — NOT YET PUBLISHABLE.** Same ruling and same position as the ENE row above; read it for the full reasoning. **Gate 0 — PASSES:** it advises *an organisation* about its future disputes, so there is no party to be partisan between. **Gate 2 — PASSES:** *"Consulting, no appointment, no neutrality question"* `[Pouya's stated basis 2026-08-27, Q42]` — noting that sentence answers **neutrality**, which is gate 0, and an earlier version of this row presented it as answering gating too. **Gate 1 — `[unestablished]`, no source.** Weakest gating concern of the three (advisory consulting to an organisation is furthest from the boundary), and still unsourced. Q46(a). Blocks step 5 | +| **Pre-dispute technical advisory** | ⚠️ **GATES 0 AND 2 ANSWERED; GATE 1 STILL HAS NO SOURCE — NOT YET PUBLISHABLE.** Same ruling and same position as the ENE row above. **Gate 0 — PASSES:** it precedes any dispute, so there is no party to be partisan between. **Gate 2 — PASSES**, in three words: *"It is the moat"* `[Pouya's stated basis 2026-08-27, Q42]`. **Gate 1 — `[unestablished]`, no source.** Q46(a). Blocks step 5. **Caution that belongs with the row regardless, and it is not a gating question:** advisory work for one organisation is the one item in this table that can create a **conflict against a later appointment in the same matter**. That is practice management, not a publication gate — but no copy may imply the offering is free of that tension, and `/practice/`'s strip at step 5 is where the temptation to imply it will arise | | ~~**Settlement counsel**~~ | **NOT OFFERED, AND IT IS STRUCK RATHER THAN UNROWED** `[verified 2026-08-27 — Pouya, Q42]`. Pouya removed it as **his own error in `docs/01`**: *"Settlement counsel acts **FOR a party** in negotiation. That is a partisan role, and putting it on a site that (a) sells neutrality and (b) asserts no licensure under D13 is **wrong twice over**: it undercuts the brand's central claim and it edges into acting for a client."* **Note the ordering — the positioning objection comes first.** It would still be wrong on a site with no licensure question at all, which is why this row does not read as a D13 consequence. Struck from `docs/01` §`/practice/`, from `docs/07-fees.md`'s hourly list, and from the §4 scope enumeration above. Never priced, never listed, never restored | | ~~Tribunal secretary~~ | **Not offered.** D14 removed the rate and bars offering it | @@ -392,12 +421,19 @@ above. candidates at once and one of them fails.** Pouya's instruction was literally *"apply the offering test"*, and the outcome was 3–1. -| Candidate | Q1 — is the activity gated? *(the register's, with a source)* | Q2 — competence? *(his)* | Outcome | -|---|---|---|---| -| Early neutral evaluation | **`[unestablished]`** — no source. Q46 | *"sits inside a Q.Med's competence"* | **Not publishable yet** | -| Dispute-system design | **`[unestablished]`** — no source. Q46 | *"Consulting, no appointment, no neutrality question"* | **Not publishable yet** | -| Pre-dispute technical advisory | **`[unestablished]`** — no source. Q46 | *"It is the moat"* | **Not publishable yet** | -| Settlement counsel | **Never reached** | — | **STRUCK** | +| Candidate | **Gate 0 — partisan between the parties?** *(his)* | Gate 1 — is the activity gated? *(the register's, with a source)* | Gate 2 — competence? *(his)* | Outcome | +|---|---|---|---|---| +| Early neutral evaluation | **No** — delivered to the parties as a neutral | **`[unestablished]`** — no source. **Q46(a)** | *"sits inside a Q.Med's competence"* | **Not publishable yet** | +| Dispute-system design | **No** — advises an organisation; no party to be partisan between | **`[unestablished]`** — no source. **Q46(a)** | *"Consulting, no appointment, no neutrality question"* | **Not publishable yet** | +| Pre-dispute technical advisory | **No** — precedes any dispute | **`[unestablished]`** — no source. **Q46(a)** | *"It is the moat"* | **Not publishable yet** | +| **Settlement counsel** | **YES — acts FOR a party. Disposed of here.** | *never reached* | *never reached* | **STRUCK** | + +*The gate-0 column was added 2026-08-28. Without it the only STRUCK candidate's +disposition sat inside the Q1 cell ("Never reached — failed gate 0"), so the gate +that actually disposed of it was recorded under a different gate's heading — and +a reader running the table column by column ran gates 1 and 2 only. This table is +the operational artefact; `adversarial-reviewer` found it did not run the test it +demonstrates.* **THE Q1 COLUMN WAS FILLED IN WITH HIS ANSWERS AND HAS BEEN EMPTIED.** The first version of this table read *"No. A non-binding neutral assessment is not a @@ -409,6 +445,31 @@ No jurisdiction was named for any of the three. `claims-auditor` caught this substitution on 2026-08-26 in one place and again on 2026-08-28 in this table — **the same defect, in the paragraph added to explain the defect.** +**AND THE COLUMN STAYS EMPTY AFTER Q46(a), WHICH IS THE HARDEST THING IN THIS +FILE TO WRITE.** Pouya ruled on 2026-08-28 that all three *"pass all three gates +including the new partisan question"*. Gates 2 and 3 are his and they are +answered. **Gate 1 is not his** — this section says so twice, in bold, and says +why: it was closed with his words twice already, and both times the closure was +caught by an audit rather than by the register. + +So the ruling is recorded in the three rows above as the ruling, and the rows +stay **not yet publishable**, because what gate 1 requires is not a decision but +an **artefact**: *"a source that a reviewer can check… answered per activity and +per jurisdiction, never as a class."* No such source exists in +`docs/reference/` for any of the three, and the ruling did not name one. + +**This is not the register disagreeing with the architect about Ontario law** — +it has no view, and §4 is explicit that it cannot have one. It is the register +declining to convert a decision into evidence. If a ruling could close gate 1, +gate 1 would protect nothing, and the two audits that caught the earlier +closures would have been catching a rule that did not really exist. + +**What closes it** is named in the ENE row: the *Law Society Act* s. 1 definition +of "providing legal services" and LSO By-Law 4, committed verbatim, with the +application left to Pouya or to counsel. **Nothing on the site turns on this +today** — the three appear in no copy, and it blocks build **step 5**, not +step 4. + **The reason settlement counsel fails is the finding.** It did not fail question 1 and it did not fail question 2. It failed a prior question the test does not ask: **is this a neutral's role at all?** Settlement counsel acts *for* a party. @@ -556,7 +617,7 @@ the audience it targets. Revisit at month 12–18. `[verified 2026-08-25 — dec | Intake backend | API Gateway (HTTP API) → Lambda → DynamoDB, notifications via SES `[verified 2026-08-25 — AWS-Hosting-Guide.md]` | | Repository | **`adr-sml`**, self-hosted **Gitea**. Local clone at `/Users/pouya/Dev/Websites/adr-sml` `[verified 2026-08-26]` | | CI/CD | **Gitea Actions**, `.gitea/workflows/deploy.yml`. Instance **git.larsnolden.com, version 1.27.2** `[verified 2026-08-26 — /api/v1/version]` — well above the ~1.21 floor for the `vars` context. The GitHub OIDC workflow is kept as `docs/reference/github-actions-oidc.yml.example`, outside `.github/workflows/` so Gitea cannot fall back to it. **No OIDC available** — Gitea is not an AWS OIDC provider | -| **Deploy credential — NOT PROVISIONED** | `aws iam get-user --user-name adr-sml-deploy` returns **NoSuchEntity** `[verified 2026-08-26 — Q22]`. The scoped IAM user does not exist, no access key has been issued, and the Gitea secrets are unset. **No file may describe this credential as existing.** Creation commands are with Pouya; this is a to-do, not an open question | +| **Deploy credential — PROVISIONED** | IAM user **`adr-sml-deploy`**, created **2026-08-26T15:45:18Z**, `arn:aws:iam::327082975128:user/adr-sml-deploy` `[verified 2026-08-28 — Pouya, Q22]`. **No managed policies, no group memberships.** One inline policy, `adr-sml-deploy-minimal`: `s3:ListBucket` on the bucket, `s3:PutObject` + `s3:DeleteObject` on `bucket/*`, `cloudfront:CreateInvalidation` on the distribution §7 records. **One active access key, `LastUsed` null** — issued, never used, because deploys still run locally. **Verified by execution, not by reading** — `iam simulate-principal-policy`, **nine** results: `allowed` for the four intended actions (`s3:PutObject`, `s3:DeleteObject`, `s3:ListBucket`, `cloudfront:CreateInvalidation`); `implicitDeny` for **five** — `s3:ListBucket` and `s3:GetObject` on the client-database backup bucket, `s3:DeleteBucket` on its own bucket, `s3:PutObject` on `meshkinilaw.ca`, and `iam:CreateUser` on `*`. *This row said "eight calls" while enumerating nine, and the Change Log counted the backup bucket as one item to reach eight — the two records disagreed on how many checks ran. `adversarial-reviewer` caught the arithmetic; **4 + 5 = 9** and the enumeration is the authority.* **And the one gap reading the policy could not close was closed by execution too:** `aws s3api get-bucket-policy` on the backup bucket returns **`NoSuchBucketPolicy`**, so no resource-based grant exists, IAM is the only path in, and this user has none. ⚠️ **THE TOOL OUTPUT IS NOT IN THE REPOSITORY — R14 IS NOT SATISFIED FOR THIS ROW.** A **High** §10 risk was downgraded and §10's control declared "tested against the thing it protects" on evidence no reviewer can reach; `aws-inventory.txt` (2026-08-26) predates the user and does not mention it. **Q52** asks Pouya to commit the `simulate-principal-policy` JSON and the inline policy document to `docs/reference/`, with the command that produced them and the key ID redacted. Contrast `docs/reference/adrio-designations.md`, whose evidence both review agents independently reproduced. **Rotation: §12 R17 carries the date and the procedure** — this row deliberately does not restate it (R17: *"§7 carries the inventory; this row carries the date"*). ⚠️ **GITEA ACTIONS SECRETS: `UNSET`** `[verified 2026-08-26 — Q22]` — no access key has been placed in a repository secret on `git.larsnolden.com`, so the key exists in IAM and **nowhere on the jointly-administered instance**. *This clause said "Gitea secrets: see the row below", and the row below is about runner registration and says nothing about secrets — so the previous row's "the Gitea secrets are unset" was deleted and recorded nowhere, in the file `CLAUDE.md` designates as the single source for credential state. `LastUsed` null is a different fact: a key can sit on shared infrastructure unused. Found by `adversarial-reviewer`.* | | **How deploys actually happen today** | **Locally, via `npm run deploy`** (`scripts/deploy-local.sh`) — same guard, same three sync passes, same cache headers, same invalidation as the workflow. Gitea Actions needs `[actions] ENABLED` in `app.ini` and a registered `act_runner`, both of which need the instance's second administrator (Q23). At this scale the pipeline changes only **how a deploy is triggered**, not what it does `[verified 2026-08-26]` | | **Interim auth — do not repeat in CI** | Pouya has been authenticating as **`user/pouya`**, the broadly-permissioned personal user the Q10 inventory captured. Acceptable for interactive work at a keyboard; **never** as a CI credential — see §10 `[verified 2026-08-26]` | | Analytics | **Plausible** — cookieless, no personal data, no consent banner, **all data held in the EU** `[verified 2026-08-26 — D15 as amended, Q31]`. `src/data/site.ts` sets `ANALYTICS.provider`. Not yet installed: no script is on any page, and `/legal/privacy/` (step 10) is where the processor gets named | @@ -591,7 +652,7 @@ Nothing below can be invented. Each needs an answer from Pouya. | ~~Q25~~ | **ANSWERED 2026-08-26. Struck.** The §4 row permitting the boutique to be named is removed; D16 governs alone | — | | ~~Q26~~ | **ANSWERED 2026-08-26.** §4 now carries an explicit **Licence status — NOT ESTABLISHED** row, and its opening no longer asserts that LSO rules apply. The register's rationale stands on the fabricated-credentials history alone | — | | ~~Q24~~ | **ANSWERED 2026-08-26.** `AWS-Hosting-Guide.md` copied into `docs/reference/` — it is the only record of how the hand-built infrastructure was created. Scanned for credentials before copying: no access keys, no secrets, no account ID | — | -| ~~Q22~~ | **ANSWERED 2026-08-26 — it does not exist.** `aws iam get-user --user-name adr-sml-deploy` returns `NoSuchEntity`. Recorded in §7 as **NOT PROVISIONED**; creation commands are with Pouya, so it is now a **to-do**, not a question. Consequence while it is outstanding: deploys run locally (`npm run deploy`), and the quarterly rotation obligation in D3 still has no subject | — | +| ~~Q22~~ | **CLOSED ON EXECUTION 2026-08-28 — it exists, and it was verified by running the checks rather than by reading the policy.** IAM user `adr-sml-deploy` created 2026-08-26T15:45:18Z; one inline least-privilege policy; one active access key, never used. Full inventory and the eight `simulate-principal-policy` results are in §7. **Two things make this a closure rather than a status update.** (1) The scoped policy was the control §10 identified as *"the actual control standing between a shared Gitea instance and an AWS account holding another business's client-database backups"* — it now exists **and has been proven negative** against that bucket, not just positive against its own. (2) `get-bucket-policy` on the backup bucket returns `NoSuchBucketPolicy`, closing the gap that policy-reading alone could not: a resource-based grant would have been invisible from the IAM side. **The quarterly rotation obligation in D3 now has a subject and a date** — 2026-11-26, in §12 R17. Deploys still run locally; the key exists but is unused. **The tool output is not committed — R14 unsatisfied, tracked as Q52.** | — | | Q5 | Booking tool — **parked 2026-08-26 at Pouya's request.** Build `/contact/` with the form only and a clean slot for the embed. Now tracked as standing reminder R6 | `/contact/` — non-blocking | | ~~Q6~~ | **ANSWERED 2026-08-26.** Supplied and committed: `src/assets/pouya-lajevardi.jpg` (1600×1600 master) and `src/assets/og-portrait.jpg` (1200×630 link-preview crop) | — | | ~~Q7~~ | **ANSWERED 2026-08-26.** Pouya reverted to generic. The boutique is **never named**; refer to it as *a Toronto litigation and ADR boutique* throughout | — | @@ -625,10 +686,17 @@ Nothing below can be invented. Each needs an answer from Pouya. | ~~Q41~~ | **ANSWERED 2026-08-27 — all three, and two of the three interim wordings were wrong in a way the interim had not identified.** **(a) Q37's reasoning DOES extend to prose, and prose is held to a HIGHER bar, not a looser one.** Pouya: *"The implication test applies everywhere, not just to labels. Prose has more room, so it is easier to satisfy: **state the asymmetry explicitly** rather than relying on a parallel construction to carry it."* Deleting the parallel — which is all the interim did — was half the fix; a reader can still supply the missing symmetry from silence. Both pages now name both halves, from **one constant** — `ASYMMETRY_LINE` in `src/data/site.ts`, which is where a claim-bearing sentence belongs (`ROLE`'s reasoning: *"these are the two where the wording IS the compliance"*). It was typed into `/` and then into `/about/`, and **the two copies had diverged inside the same session** — a comma on one, full stops on the other — which is why it is a constant and why this row cites it rather than quoting a variant. Calling the legal half **training** is what makes the licence implication impossible rather than merely absent. `docs/01` §`/` item 3 and `docs/03` §Home both carry a warning not to lift their own phrase *"law and engineering"* into copy. **(b) NOT restored, and the editorial reason outranks the compliance one.** Pouya: *"That is an unverifiable empirical claim about other practitioners… **It is also weaker copy: assert his capability, not the field's incapability.**"* His replacement is used verbatim — *"disputes that turn on the contract, the code, and the engineering documents"* — and it replaces the comparative in `docs/03`'s **core positioning statement**, so the approved-copy defence that had protected it is gone. The interim (*"the documents rather than the pleadings"*) is also gone: it said nothing about other neutrals but still worked by contrast. **(c) Verified, and the interim was ambiguous in the one word that mattered.** `docs/reference/lat-case-conference.md` `[verified 2026-08-28]`: LAT **Rule 2.4** makes *"Pre-Hearing Conference"* the Tribunal's own term for a **case conference**; **Rule 14.3** puts a **Member** in the chair and then disqualifies them from the hearing panel; **Rule 14.6** makes attendance mandatory; and the Rules contain **zero** occurrences of `mediat` or `arbitrat` in 66,593 characters. A privately retained neutral cannot be appointed to it. The affirmative basis is on the Tribunal's own AABS page: *"you may want to consider negotiation or mediation services… including before filing at the LAT-AABS, and continuing… after a claim has been filed."* The interim read *"private mediation of matters **before** the LAT"* — where `before` reads as *pending at* as readily as *prior to*. Published: *"private mediation alongside a LAT application, before filing or after."* No roster claim, because there is no row for one | — | | ~~Q42~~ | **ANSWERED 2026-08-27 — 3 offered, 1 STRUCK, and the one that failed is the finding.** Pouya applied the offering test himself: **early neutral evaluation** (*"A neutral assessment of merits sits inside a Q.Med's competence"*), **dispute-system design** (*"Consulting, no appointment, no neutrality question"*) and **pre-dispute technical advisory** (*"It is the moat"*) each gained a §4 Offerings row and may now ship on `/practice/`. **Settlement counsel is struck**, as his own error in `docs/01`: *"Settlement counsel acts **FOR a party** in negotiation. That is a partisan role, and putting it on a site that (a) sells neutrality and (b) asserts no licensure under D13 is **wrong twice over**: it undercuts the brand's central claim and it edges into acting for a client."* **The positioning objection comes first** — it would be wrong on a site with no licensure question at all, so it is not a D13 consequence. **What it exposed about the test:** settlement counsel fails neither question 1 nor question 2. Run mechanically the test would have PASSED it. It fails a prior question the test does not ask — *is this a neutral's role at all?* — so §4 now records that the offering test **presumes** a neutral role, with the Q42 worked example kept as the 3–1 table. Swept by command: `docs/01` §`/practice/`, `docs/07-fees.md` (three services at the hourly rate, not four), `FEES.hourly`'s comment, and `/`'s areas-more comment. `AGENTS.md` lines 293 and 3298 are the §4 scope enumeration (fixed) and Change Log entry (d) (history, not edited) | — | | ~~Q43~~ | **ANSWERED 2026-08-27 — and the ruling reversed the reasoning that had blocked it.** The interim shipped the five timings as bare numbers because `docs/03` §Process required them *"real"* rather than illustrative, which was read as **barring** the word "typical". Pouya: the timings are **service commitments, the same class as Q27's response time** — *"not facts about Pouya, so they need framing, not a Verified row. Present them as the TYPICAL shape of an engagement, explicitly not a guarantee: mediation timing depends on party and counsel availability, which he does not control. **Published as typical, they are honest and useful; published as commitments, the first matter that slips makes the page false.**"* So no §4 row, and **the numbers are unchanged** — softening them was never the fix. What ships is `PROCESS_FRAMING` in `src/data/site.ts`: *"This is the typical shape of an engagement, not a commitment. Timing depends on party and counsel availability, which I do not control."* **Not optional, and placed adjacent to the numbers rather than in a section lede above them** — a reader who scans the strip and skips the lede has read a commitment. `docs/03` §Process amended to record the override; `docs/01` §`/process/` requires the same rendering at step 6 | — | -| **Q44** | **R10 discharge — are all four memberships current TODAY, and in which month does each renew?** §4 verifies **ADRIC**, **ADRIO**, the three **OBA** sections (Construction & Infrastructure, ADR, Civil Litigation) and the **Canadian Tax Foundation** `[verified 2026-08-26 — Pouya]`, *for now*. **Only Claude Code can raise this; only Pouya can close it** — a two-day-old stamp is not a renewal receipt. **What §4 actually says about renewal, because an earlier version of this row said more:** the **OBA sections and the CTF** renew yearly. §4 records **nothing** about ADRIC's or ADRIO's renewal period, and this row asserted *"All renew yearly"* — a widened fact that had already propagated to `schema.ts`, `docs/06` and `/about/`'s own comment. Fixed in all four. **`/about/` DOES NOT PUBLISH THE MEMBERSHIPS.** An earlier version of this row said it did, and so did §12 R10, `docs/06` and `schema.ts` — four documents recording a page state that had been reversed and not swept, on the one credential class that has already lapsed once (OCNI). R10 is written as a **prohibition**, not a disclosure duty, so the group is withheld and `CREDENTIAL_GROUPS` carries a `TODO(pouya)` with this question. Designations, Education and Certifications ship. **Blocks the memberships block, not step 3.** Four yes/no answers and four renewal months closes it — and the months are what stop this recurring, because they turn R10 from a reminder into a date. Raised by Claude Code 2026-08-28; scope corrected the same day by `claims-auditor` | The Memberships group on `/about/`; `memberOf` in the Person JSON-LD; cutover | -| **Q45** | **The one-page PDF bio — generated, authored, or dropped?** `docs/01` §`/about/` item 7 lists it (brief §VIII: an asset for circulation with appointment proposals) and **it does not exist**; `/about/` therefore ships without a link to it, because a link to a missing file on the page an appointing body reads is worse than the absence. **Why it is a question and not a task:** it is a **credential document**, so every line traces to §4 exactly as a web page does — and it is circulated **detached from the site**, where no reviewer ever sees it again and no build can re-check it. That is the one artefact class this project's whole review apparatus cannot reach. Two decisions are his: (a) generated at build (a dependency and an `npm audit` surface, against R11) or authored once as a designed artefact; (b) whether it carries anything the site does not — a matter list, a fee summary, referees — each of which is a §4 question of its own. Raised by Claude Code, 2026-08-28 | Nothing on the site. It is a circulation asset, wanted before the first appointment proposal | -| **Q46** | **Two questions the offering test cannot close by itself, and one about the glossary.** **(a) Is early neutral evaluation gated in Ontario, and are dispute-system design and pre-dispute technical advisory?** Pouya answered question 2 (competence) for all three on 2026-08-27 and those answers stand. **Question 1 is the register's and it is `[unestablished]`** — §4: *"It needs a source that a reviewer can check, and it is answered per activity and per jurisdiction, never as a class."* No source exists in `docs/reference/` for any of the three (R14). It matters most for **ENE**, which is the offering nearest §4's NOT-NEGOTIABLE boundary: a neutral assessment of the **merits**, delivered to parties, sits closest to *"providing legal services"*, where the binding question is permission and the answer is not established. **Consequence today: none on the site** — the three appear only in comments — but the rows authorise `/practice/`'s "also offered" strip at step 5 and `docs/07-fees.md` prices them, so it blocks step 5, not step 3. Twice-flagged: `claims-auditor` found the register answering its own question 1 with the subject's words on 2026-08-26 and again on 2026-08-28, the second time inside the paragraph added to explain the first. **(b) May §11 Glossary be published as the source for DEFINITIONAL expansions** — what `Q.Med`, `Q.Arb`, `C.Med-Arb`, `POA`, `SABS`, `ADRIC` and `ADRIO` stand for? This is not a claim about Pouya; "he holds it" is the claim and that has a row. `/about/` currently publishes all four classes on this basis, and the alternative is to strip *"Provincial Offences Act"*, *"the ADR Institute of Canada and the ADR Institute of Ontario"* and `recognizedBy` from the JSON-LD as well — which serves no reader and reduces no risk. Sourcing them externally was tried and failed: `adric.ca/designations/` redirects to `/designations-cee/` and serves **zero** occurrences of `Q.Med`, `Qualified Mediator` or `Chartered Mediator` in 114,985 bytes. **This is the one place this session went against a review finding**, on a later finding that the standard was being applied inconsistently. Raised by Claude Code 2026-08-28 | (a) `/practice/` and its strip (step 5), `/fees/` (step 9). (b) `/about/`'s arc and the Person JSON-LD, live now | -| **Q47** | **`Person.jobTitle` is published without `worksFor`, and the two halves of one §4 row are separated in machine-readable form.** §4's row is *"Director of Firm Operations, **Toronto litigation and ADR boutique**"* — one row, one fact, two halves. Visible copy always pairs them (`/about/`: *"Director of Firm Operations at a Toronto litigation and ADR boutique"*). The JSON-LD emits `jobTitle: 'Director of Firm Operations'` with **`worksFor` deliberately omitted**, on a `Person` node whose `url` is this ADR practice's `/about/` — so a consumer may attach the title to **this** entity, which is not what the row says. **This is a structural bind, not an oversight:** `docs/04` instructs the omission and D16 bars naming the employer, so there is no value `worksFor` may take. The options are (i) drop `jobTitle` from the graph and let the visible copy carry the role, (ii) keep it and accept the implication, or (iii) get a §4 row for the half-claim. Flagged twice by `claims-auditor`, which declined to choose. Raised by Claude Code 2026-08-28 | Nothing visible. The Person node on `/` and `/about/`, live now | +| ~~Q44~~ | **ANSWERED 2026-08-28 — all four current; R10 DISCHARGED, and it changes shape rather than closing.** Pouya: *"All four are current as of today."* ADRIC, ADRIO, the three OBA sections, the CTF. §4 re-stamped and `/about/` now renders the Memberships group. **Two consequences came with the answer and both are applied:** (1) **no currency warranty on the page** — the struck sentence stays struck and nothing replaces it, because he **declined renewal-date tracking** and so nothing in this repo could support one; (2) **R10 stays live and now fires on an EVENT, not a date** — re-confirm before any cutover or major republish. His reason, recorded because it is the general lesson: *"§4 already carries OCNI as lapsed and unpublishable, and that was found roughly a year late. A stamp with no trigger behind it goes stale silently, which is exactly how OCNI got onto a list of things to feature."* **Two things this answer did NOT settle**, both flagged to him rather than assumed: the stamp date (he wrote 2026-08-26, the original confirmation; the stamp reads **2026-08-28**, when he re-confirmed — a currency stamp records when the assertion was made), and `memberOf` in the JSON-LD, which is **still withheld** now that the visible group ships — an open judgement rather than a settled one, tracked as **Q53**. See §4, §12 R10, `src/data/schema.ts` | — | +| ~~Q45~~ | **DEFERRED 2026-08-28 with a recorded trigger — now §12 R16.** Pouya: *"The one-page PDF bio is a derived artifact — generating it before `/about/` and `/fees/` are final just means generating it twice. Ship it at step 9 alongside `/fees/`, since an appointment proposal needs both. Record the trigger so it doesn't become another quiet interim."* Same disposition and same reasoning as Q40/R15: deferred with a build-step trigger rather than left as an untracked gap. The two decisions the question raised — generated-at-build vs authored once, and whether it carries anything the site does not — are **not** answered by the deferral and travel with R16 to step 9. The reason it is a credential document rather than a marketing one also travels: it circulates **detached from the site**, where no reviewer sees it again and no build can re-check it | Nothing. Tracked as R16, due at build step 9 | +| **Q46(a)** | **STILL OPEN AND STILL BLOCKING — see the row below for the full text.** Pouya ruled 2026-08-28 that ENE, dispute-system design and pre-dispute technical advisory *"pass all three gates"*. **Gate 0 (partisan) and gate 2 (competence) are his and are answered. Gate 1 (is the activity gated?) is not his**, and it requires **an artefact rather than a decision**: a source a reviewer can check, per activity and per jurisdiction. None exists in `docs/reference/` for any of the three and the ruling named none, so the three §4 Offerings rows stay **not yet publishable**. **This row exists because the combined Q46 row was struck through while this half was live** — §9's convention is that strikethrough means answered, three §4 rows say Q46(a) blocks step 5, and a reader scanning §9 for live blockers would have seen only Q48 and Q38. Found by `adversarial-reviewer`. What would close it is named in §4's ENE row: the *Law Society Act* s. 1 definition of "providing legal services" and LSO By-Law 4, committed verbatim, with the application left to Pouya or to counsel | `/practice/`'s "also offered" strip and `docs/07-fees.md` pricing — **build step 5**. Nothing on the site today | +| ~~Q46(b)~~ | **(b) RATIFIED AND NOW SOURCED, 2026-08-28. (a) RULED, AND THE RULING DOES NOT CLOSE IT — now tracked as its own live row above.** **(b):** §11 Glossary is the source for **definitional expansions**; §4 remains the only source for claims about Pouya. Pouya: *"The line is the same one the Offerings ruling drew — 'Q.Med stands for Qualified Mediator' is a fact about the designation's name, not about him… You were right that one standard or the other had to apply."* He attached a condition — commit the source — and `docs/reference/adrio-designations.md` satisfies R14: all five expansions in ADRIO's own words, four independent fetches, reproducible sha256. **That fetch immediately earned itself** by catching that §11's `C.Med-Arb` expansion was wrong and had shipped to a public page. **(a):** he ruled that ENE, dispute-system design and pre-dispute technical advisory *"pass all three gates"*. Gates 0 and 2 are his and are answered. **Gate 1 is not his** — §4 says so twice — and it requires **an artefact, not a decision**: a checkable source, per activity and per jurisdiction. None exists for any of the three and the ruling named none, so the three rows stay **not yet publishable** and this half of Q46 remains open as **Q46(a)**. Nothing on the site turns on it; it blocks **step 5**. What would close it is named in the ENE row | (a) `/practice/`'s "also offered" strip and `docs/07-fees.md` pricing — **step 5**. (b) closed | +| ~~Q47~~ | **ANSWERED 2026-08-28 — set both. THEN BOTH FIELDS WERE REVERTED THE SAME DAY, AND THE OPEN HALF IS Q49.** ⚠️ **Read this first, because the text below describes an implementation that does not exist.** Measured against `dist` 2026-08-28: the Person node ships `jobTitle: "Mediator"` and **no `worksFor` key at any depth**. `jobTitle`'s ruled value was struck by **both** review agents as the role-shaped claim `claims-auditor` had removed from this same node's `description` the previous day; `worksFor` was struck because §4 rows "**alongside** the practice" where the ruling says "operates **through**", and because `ProfessionalService.provider` is this Person, making the same-entity inference transitive. **Q49** carries both open rows. *This row was written describing the pre-revert state and not updated when the revert happened hours later — verbatim the failure Q44's own history records ("four documents recording a page state that had been reversed and not swept"), reproduced inside the change set that records it. Found by `adversarial-reviewer` on re-review.* **Pouya's ruling, and the reasoning that still stands, follows.** **ANSWERED 2026-08-28 — set both.** Pouya: *"A Person with a jobTitle and no worksFor is incomplete; a worksFor naming the boutique would breach D16. This satisfies both."* The bind is broken by changing what `jobTitle` is **about**: it now describes **this practice** rather than the boutique role, so `worksFor` can name **SML Company Ltd** — verified, federally incorporated, the entity the practice operates through — without going near D16. `ROLE.title` is unchanged and still carries "Director of Firm Operations" in **visible** copy; the graph gets its own constant (`PRACTICE_JOB_TITLE`), which is the separation the ruling actually turns on. **`worksFor` carries the NAME ONLY** — no address, no jurisdiction, no legal form: §4 verifies the federal incorporation and in the same row records it as *not published*, and cautions that it must never be read together with the **Licence status — NOT ESTABLISHED** row into an implication neither makes. A JSON-LD field is exactly where that pairing would travel unedited. **One flagged deviation:** he ruled `"Mediator and Arbitrator"`; it ships as **"Mediator and Commercial Arbitrator"**, because the same message instructs that *"Q39's struck universal must not reappear in any form"* and an unscoped "Arbitrator" is that form. One word to revert, deliberately | — | +| **Q48** | **Does retaining `Q.Med` depend on ADRIO membership currency — and if so, does §4's Q.Med row inherit R10's shelf life?** Raised by `docs/reference/adrio-designations.md` Finding 4, and it is an asymmetry **in ADRIO's own materials** rather than in a reading of them. ADRIO states a retention condition for both senior designations — verbatim, of C.Med: *"There is an annual fee to maintain your C.Med designation… You must also remain a member in good standing with the ADR Institute of Ontario™ to retain this designation"*, and the C.Arb page says the same — while the **Q.Med / Q.Arb page states no condition at all** (`good standing` 0, `annual` 0, `maintain` 0, `retain` 0 on the extracted text). **So this establishes nothing about Q.Med, which is the point:** it must not be inferred in either direction from the Chartered pages. **Why it matters more than it looks:** Q.Med is the site's central credential — it is in the `` of `/about/`, in the designation line, in `hasCredential`, and in the substitution principle's approved stat set. If its retention is membership-contingent, then the one credential everything rests on inherits the shelf life of the memberships Pouya has **declined to track by date** (Q44, R10) — and OCNI is the precedent for how that ends. **Not answerable from this source.** It needs either the Q.Med criteria document (ADRIO notes *"Q.Med criteria vary across affiliates"* and points to the application-form checklist for Ontario) or a direct answer from ADRIC/ADRIO. Raised by Claude Code 2026-08-28 | Nothing today. §4's Q.Med row, and whether R10's event trigger must also cover the designation | +| **Q49** | **Q47 REOPENED ON TWO ROWS THE RULING NEEDS AND §4 DOES NOT HAVE. Both fields were set as ruled, then reverted the same day when both review agents struck them.** **(a) `jobTitle` — is there a row for arbitrator-as-PRACTISED-ROLE?** The ruled value was `"Mediator and Arbitrator"`; it shipped for one pass as `"Mediator and Commercial Arbitrator"` and **that is the string `claims-auditor` struck from this same node's `description` on 2026-08-27** — §4 verifies *"Has completed multiple sole mediations"* and has **no counterpart row for a completed arbitration**, only that appointments are *accepted*. `jobTitle` is the most role-asserting field in the vocabulary and consumers render it beside `name`. **Claude Code flagged the wrong defect here** — the note argued about scoping ("Commercial") and neither the note nor its author noticed the whole string had already been struck on other grounds; a flag aimed at the wrong thing reads as diligence and provides none. Now ships as **`"Mediator"`**, which §4 rows and which still serves the ruling's stated purpose (describe *this practice*, not the boutique role). The arbitration **offering** is unaffected — `description` and `serviceType` both carry it and both cleared audit. **Options: a §4 row for the practised role; or an offering-shaped value (`adversarial-reviewer` proposed `"Mediator; accepts commercial arbitration appointments"`); or leave it narrow.** **(b) `worksFor` — is there a row for the CORPORATE RELATION?** §4 says *"Operator of SML Company Ltd. **alongside** the practice"*; the ruling says *"the entity the practice **operates through**"*. Different structural relations, and only the first has a row. Three grounds for the revert: the missing row; that `/about/` **already removed** a sentence of this exact class from visible copy (*"the company through which the engineering work is done" — a corporate-structure claim*), so publishing it machine-readably is stricter-in-public and looser-in-metadata; and that it **defeats a guard in its own file** — `ProfessionalService.provider` is this Person, so `provider → Person → worksFor → SML` asserts transitively the same-entity claim ``src/pages/about.astro` deleted from visible prose as *"a corporate-structure claim"* (an earlier version of this row cited a guard in `schema.ts` that does not exist — the citation was empty, found by `adversarial-reviewer`) declines to assert. Also: the original omission had **two** grounds (*"either names the boutique (D16) **or misstates the employer**"*) and Q47 answers only the first. **One line from Pouya on each closes it.** Raised by Claude Code 2026-08-28 | The `Person` node on `/` and `/about/`, live now. Nothing visible | +| **Q50** | **Does Q33's ratification of the unscoped masthead form extend to a JSON-LD field?** `ProfessionalService.name` ships as **"Pouya Lajevardi — Mediation & Arbitration"** — unscoped — while `jobTitle` and `serviceType` **in the same node** are scoped, `serviceType` under an explicit instruction not to widen. Measured 2026-08-28: that string mirrors `/`'s `<title>` (*"Pouya Lajevardi · Mediation & Arbitration · Toronto"*) and the masthead tagline (*"Mediation · Arbitration · Toronto"*, which renders on `/about/` and **not** on `/`), and **Q33 ratified the unscoped masthead/title form**. **Claude Code's position, declined rather than fixed:** a `name` is a name and mirrors a ratified string; a `serviceType` enumerates services and is a claim. **`claims-auditor`'s position:** the change set now holds both positions inside one node, and *"Q33 ratified the masthead/`<title>` form, not a graph field"* — which is correct, and is why this is a question rather than a judgement. Needs one ruling applied consistently across the node. Raised by Claude Code 2026-08-28 | Nothing visible. The `ProfessionalService` node on `/` | +| **Q51** | **Does listing the OBA sections on `/about/` carry the licensure implication that excludes the LSO?** §4 excludes the Law Society because *"listing the Law Society among memberships implies licensure, which D13 bars"*, and Forbidden bars *"any phrasing that **implies** entitlement to practise law"*. Since 2026-08-28 the page publishes **"Ontario Bar Association — Construction & Infrastructure, ADR, and Civil Litigation sections"** beside "JD, Bond University" and "Director of Firm Operations at a Toronto litigation and ADR boutique", on the page an appointing body reads. **`grep -n OBA AGENTS.md` returns rows on renewal, scope and stamping and NOTHING on implication** — so the question has never been asked, which is the finding. Raised by `adversarial-reviewer` at *moderate-low confidence that it is a defect, high confidence that it is unasked*, and explicitly assigned to Pouya rather than to a reviewer: **OBA membership eligibility is not established anywhere in this repo**, so nobody here can say whether the inference is available. It sits beside **R1** — same subject, same page, same reason it cannot be settled internally. If the answer is that it does carry the implication, the fix is the LSO fix: exclude it deliberately and record that it was excluded, not omitted | The Memberships group on `/about/`, live now | +| **Q52** | **Commit the `adr-sml-deploy` verification output — §7 downgraded a High risk on evidence no reviewer can reach.** §7 now records the IAM user as provisioned and least-privilege, and §10 declares the scoped policy *"tested against the thing it protects"*, on the strength of nine `simulate-principal-policy` results and a `get-bucket-policy` call. **None of that output is in the repository.** `aws-inventory.txt` is dated 2026-08-26 and does not mention the user. That is the **Q24 / Q32 shape R14 exists for** — a claim whose supporting artefact is unreachable, so no reviewer can check it and it is unverifiable by construction rather than merely unverified. `adversarial-reviewer` drew the contrast itself: it **independently reproduced** every digest in `docs/reference/adrio-designations.md` and could reproduce **nothing** here. **What to commit to `docs/reference/`:** the `simulate-principal-policy` JSON for all nine checks, the `adr-sml-deploy-minimal` inline policy document, and the `get-bucket-policy` response — each with the command that produced it, and **the access key ID redacted** (the key itself must never reach the repo — D3, and §10 on the jointly-administered instance). **Only Pouya can close this**: he ran the commands and Claude Code has no AWS credentials. Raised by `adversarial-reviewer` 2026-08-28 | Nothing on the site. The evidential basis for §7's provisioned row and §10's two downgraded rows | +| **Q53** | **Should `memberOf` be emitted after all? The ground for withholding it may not survive.** Q44 closed and `/about/` publishes all four memberships visibly; `memberOf` is still withheld, and the reason has now been restated twice. First version: *cacheability* — struck by `adversarial-reviewer` for **proving too much**, since it is equally true of `hasCredential`, which ships. Second version: *volatility* — a renewing membership versus a designation. **`adversarial-reviewer` argues the second does not survive either, and the argument is hard to answer:** the memberships are already in `/about/`'s HTML, so the volatile claim is **already crawlable, scrapable and cacheable**. Withholding the triple reduces no exposure; it only makes the graph less complete than the page. If the concern is real it argues for a renewal date — which Pouya declined — not for a field-level omission. **So the honest options are: (a) emit `memberOf`, matching the page; (b) keep withholding it and record a ground that survives; or (c) accept that the page and the graph should differ and say why.** Claude Code has been carrying (b) as a judgement, and it was stated as settled in five places, two of them the version already rejected — now reduced to `src/data/schema.ts` and this row. **Note the interaction with Q48:** if `Q.Med` retention is membership-contingent, `hasCredential` — which ships — carries the higher exposure of the two, which cuts against the withholding rather than for it. Raised by `adversarial-reviewer` 2026-08-28 | The `Person` node on `/` and `/about/`. Nothing visible | | **Q38** | **A true vector master for the infinity mark.** The mark is a shaded ribbon — variable-width band, maroon flowing into champagne, twisting in three dimensions and passing over itself at the crossing. That is gradient-mesh artwork, and there is no honest way to express it as the flat vector paths `docs/02` assumes. An SVG **is** held — `src/assets/brand/sml-logo-source.svg` — and **it renders faithfully**: rasterised at 8333 px it reproduces the master exactly, at the same 1.566:1 `[verified 2026-08-26 — rendered and measured]`. *The characterisation has now moved twice and Pouya has settled it.* This row first called the file **"a raster in a vector wrapper"**; a later draft withdrew that as unfair. **The withdrawal went too far, and Pouya's ruling of 2026-08-27 restores the substance:** *"It renders faithfully because it IS the raster. Your first characterisation was accurate and the walk-back went too far."* Both things are true at once and the row must hold both — the file is a faithful rendering **and** it is faithful because seven base64 PNGs are carried inside it, which is why fidelity was never the question. **The Canva SVG does not close this question.** Pouya: *"Keep it committed, keep the AVIF render path. R13 stays open for a true vector master."* What rules it out is **payload and composition**: 257,278 bytes against **3,063 B** for the AVIF a Retina browser takes in the header — **84×** — plus **seven embedded base64 PNGs** and a 1,225-stop gradient mesh, so inlining it would breach `CLAUDE.md`'s rule against base64-inlining images. *Restated 2026-08-27, because the single number stopped covering the case:* build step 2 added a **232 px** call site (the home page's approach section, rendering at 225.5 px) beside the existing 64 px one, and at that size a DPR-2 device takes **14,555 B** and DPR-3 **22,639 B** — a ratio of ~11×, not 84×. `adversarial-reviewer` caught the three copies of the old figure going stale together, which is the SES-DKIM duplication in a new place. Both ladders are in `docs/reference/brand-assets.md`; **quote the size with the call site, never on its own.** Also worth knowing before someone reads it as a regression: the PNG fallback at 232 px runs **38,094 / 91,618 / 150,215 B**. Nothing that negotiates content types takes it — a DPR-3 device with neither AVIF nor WebP does not exist in practice — and the AVIF above is what real clients fetch. Accepted deliberately rather than capped, because capping it would blunt the mark on the high-DPI desktops that are the only place the 696 px variant is used at all. What is wanted is a master that is faithful **and** light. **Pouya is commissioning a proper vector master.** Until it lands, `InfinityMark.astro` renders an optimised raster and that is a **documented, temporary exception to `docs/02`'s inline-SVG rule** (R13 keeps it from becoming permanent). When the master arrives: replace the component's `<Picture>` with inline SVG, regenerate the favicons from it, and delete the exception from `docs/02` and this row. Raised by Claude Code 2026-08-26; scoped by Pouya the same day | Nothing — the mark renders correctly. This is fidelity and payload, not function | | ~~Q32~~ | **ANSWERED 2026-08-26 — and the answer was that the reconstruction was WRONG.** Pouya rendered the committed path against the master (`SML Company Just Logo Transparent.png`, 3000×3000) and rejected it on three counts. Two reproduce from the path alone: **(a) TANGENT, NOT CROSSING** — all four cubic branches meet the origin at exactly 90°, so the loops are mutually tangent on a vertical line and at stroke-width 28 render as *two kissing circles*, the one thing an infinity mark must not be `[verified 2026-08-26 — tangent vectors computed per segment, independently reproduced]`. Both lobes are strictly confined to their own half-plane (x is monotone on every segment), so the signed crossing number is **0** — they cannot cross anywhere, not merely at the node. Worse at the size actually shipped: the two strokes stay fused into one mass wherever the centreline separation `y²/192` is under 28, i.e. across **61% of the mark's height** — at 2rem that is a 16.8px blob out of a 27.4px-tall mark. No stroke-width, viewBox or scale change can produce a crossing from this centreline; **(b) WRONG PROPORTION** — the master's ink bounding box is **2668 × 1704 = 1.5657:1** `[verified 2026-08-26 — measured]`, and **(c)** the master is a shaded ribbon where the trace was two flat uniform strokes. ***1.23:1 — RECONCILED, and it was a real measurement, not a slip.*** It is the bounding box of the path's **coordinates** rather than of the **curve**. The control points sit at y = ±160 while the curve only reaches ±120 — the standard 3/4 pull-in of a cubic — so a coordinate-hull box is 400 × 320 = 1.2500, and with stroke-width 28 applied on all four sides it is **428 × 348 = 1.2299**. Pouya's figure to four significant figures, from one method applied consistently `[verified 2026-08-26 — derived]`. **It is a trap rather than a slip:** because x is monotone on every segment, the control points give the *correct* width (±200) and a 33% inflated height, so the obvious sanity check — "does the width look right?" — passes. Any tool that reads a bbox from parsed coordinates lands here; `getBBox()` would have returned 400 × 240. **And the direction is inverted from how it read:** measured from the curve, the traced path is 6.4% *wider and flatter* than the master, not squatter. **Consequence worth keeping:** the declared viewBox 440:280 = 1.5714 is within **0.35%** of the master's 1.566, so re-tuning the layout to the true ratio was ~0.18px of work at the shipped 2rem — and **re-tuning to 1.23 would have actively broken it** — at any given width 1.2299 allocates 1.5657/1.2299 = **27% more height** than the mark occupies, so the header would have been rebuilt around a box a quarter too tall. The ratio was never sufficient grounds on its own; **(a) tangency is, and it is exact.** **The traced path is deleted, not kept as a fallback**, on Pouya's instruction: *a wrong mark that renders is worse than a missing one, because it stops looking wrong.* Now closed by Q38 for the vector master | — | | ~~Q32-orig~~ | *(superseded — the original wording of this question is preserved in entry (v))* | `src/components/InfinityMark.astro` is built from geometry lifted verbatim from the deployed site's own loading-thumbnail SVG — the element it labels `smlMark`, fetched from `https://adr.smlcompany.ca/` on 2026-08-26. Path, both stroke widths (28 / 6) and the 0.7 inner opacity are the source's; the only change is folding a `translate(60 0)` into the coordinates. So it is SML's own artwork rather than a redrawing — but a loading placeholder is not necessarily the canonical file, and D7 says the mark carries over *unchanged*. If a master SVG or AI/EPS exists, supply it and the component gets replaced. Raised by Claude Code, 2026-08-26 | Nothing — the mark renders. This is about fidelity, not a blocker | @@ -644,22 +712,50 @@ Nothing below can be invented. Each needs an answer from Pouya. | Personal data in the intake pipeline without a retention policy | Medium — PIPEDA | `docs/05-backend-spec.md` sets retention, and `/legal/privacy/` states it | | Cutover breaks the live site (D11 is a single-shot deploy) | Medium | Full pre-cutover checklist in `docs/06-deployment.md`; CloudFront can be rolled back to the prior origin path | | Twenty pages of thin copy rank worse than six good ones | Medium | Each page must justify itself with substantive content. Ship fewer pages rather than padded ones | -| **`user/pouya` is a broadly-permissioned personal IAM user, and it is what has been authenticating to this account.** Q22 confirms the scoped deploy user does not exist yet | **High** | Fine at an interactive keyboard; **never** in CI, never in a Gitea secret, never in `scripts/deploy-local.sh`. That script refuses to run if `sts get-caller-identity` returns `user/pouya`. Create `adr-sml-deploy` before the first automated deploy `[verified 2026-08-26]` | -| **The deploy secret will live on jointly-administered infrastructure.** git.larsnolden.com has a second administrator. An instance admin can generally reach repository secrets, or register a runner that receives them — that is inherent to how Actions runners are fed credentials, not a flaw in this setup | **High** | This does not change the plan; it changes **what the scoped IAM policy is for.** The policy is no longer hygiene — it is the actual control standing between a shared Gitea instance and an AWS account holding another business's client-database backups. Four actions, one bucket, one distribution. **Never widen it**, and treat any request to as a security decision, not a convenience one `[verified 2026-08-26]` | -| **Deploy-credential blast radius.** AWS account `327082975128` is not a single-project account. It also holds `meshkinilaw.ca` and its preview site, `demesne.media`, `orynenergy.ca`, `lajirugs.ca`, and **`mlp-clientdb-prod-backups-327082975128`** (recorded in an earlier entry with the account suffix; the short form `mlp-clientdb-prod-backups` is used elsewhere in the docs) — which **by its name** holds production client-database backups. Only the name was ever observed; the contents were not inspected and the owner is not established | **High** | A static deploy key for a personal website must never be able to reach a client database. The scoped IAM policy in `docs/06-deployment.md` grants four actions on one bucket and one distribution and nothing else — that narrowness is now load-bearing, not hygiene. Never widen it. Never reuse the `user/pouya` credentials in CI `[verified 2026-08-26 — inventory]` | +| **`user/pouya` is a broadly-permissioned personal IAM user, and it is what has been authenticating to this account.** *Q22 closed 2026-08-28: the scoped deploy user now **exists**, so the mitigation below is available rather than pending — but this risk does not close, because `user/pouya` still exists, is still broadly permissioned, and is still what runs the local deploy path* | **High** → **Medium** for CI; unchanged interactively | Fine at an interactive keyboard; **never** in CI, never in a Gitea secret, never in `scripts/deploy-local.sh`. That script refuses to run if `sts get-caller-identity` returns `user/pouya`. **`adr-sml-deploy` now exists and is verified least-privilege (§7), so there is no longer any reason to reach for `user/pouya` in an automated context** `[verified 2026-08-28 — Q22]` | +| **The deploy secret will live on jointly-administered infrastructure.** git.larsnolden.com has a second administrator. An instance admin can generally reach repository secrets, or register a runner that receives them — that is inherent to how Actions runners are fed credentials, not a flaw in this setup | **High** | This does not change the plan; it changes **what the scoped IAM policy is for.** The policy is no longer hygiene — it is the actual control standing between a shared Gitea instance and an AWS account holding another business's client-database backups. Four actions, one bucket, one distribution. **Never widen it**, and treat any request to as a security decision, not a convenience one `[verified 2026-08-26]`. **THE CONTROL NOW EXISTS AND HAS BEEN TESTED AGAINST THE THING IT PROTECTS** — `adr-sml-deploy` returns `implicitDeny` for `s3:ListBucket` and `s3:GetObject` on the client-backup bucket under `simulate-principal-policy`, and that bucket has no bucket policy (§7, Q22) `[verified 2026-08-28]`. The severity stays **High** because the exposure is unchanged: a static key on shared infrastructure, and the key is only as narrow as the next person to edit the policy leaves it | +| **Deploy-credential blast radius.** AWS account `327082975128` is not a single-project account. It also holds `meshkinilaw.ca` and its preview site, `demesne.media`, `orynenergy.ca`, `lajirugs.ca`, and **`mlp-clientdb-prod-backups-327082975128`** (recorded in an earlier entry with the account suffix; the short form `mlp-clientdb-prod-backups` is used elsewhere in the docs) — which **by its name** holds production client-database backups. Only the name was ever observed; the contents were not inspected and the owner is not established | **High** | A static deploy key for a personal website must never be able to reach a client database. The scoped IAM policy in `docs/06-deployment.md` grants four actions on one bucket and one distribution and nothing else — that narrowness is now load-bearing, not hygiene. Never widen it. Never reuse the `user/pouya` credentials in CI `[verified 2026-08-26 — inventory]`. **TESTED 2026-08-28 (Q22), and both halves were tested, which is the part that matters:** `simulate-principal-policy` returns `implicitDeny` for `s3:ListBucket` and `s3:GetObject` on `mlp-clientdb-prod-backups-*`, **and** `get-bucket-policy` on that bucket returns `NoSuchBucketPolicy` — so there is no resource-based grant, IAM is the only path, and this user has none. A policy read alone could not have established the second half `[verified 2026-08-28 — Pouya]` | | ~~SES is in the sandbox~~ | ~~High~~ → **RESOLVED 2026-08-26** | Q19 closed: production access granted in `ca-central-1`, confirmed in writing. Residual, tracked in §7: the `ses-alerts` SNS email subscription is **pending confirmation**, so the bounce and complaint alarms currently notify nobody `[verified 2026-08-26]` | | ~~No SPF and no DMARC on `smlcompany.ca`~~ | ~~High~~ → **RESOLVED 2026-08-26** | Both records added by Pouya and independently verified (Q20). SPF authenticates Google Workspace mail; SES satisfies DMARC through DKIM alignment on the three resolving CNAMEs. DMARC sits at `p=none` — the residual task is to review reports and tighten to `quarantine`, which is monitoring, not a risk `[verified 2026-08-26 — DNS query]` | ## 11. Glossary +> ✅ **THIS SECTION IS A PUBLISHABLE SOURCE — for DEFINITIONAL EXPANSIONS ONLY.** +> Ratified by Pouya 2026-08-28 (Q46(b)): *"§11 Glossary is the source for +> DEFINITIONAL expansions; §4 remains the only source for claims about Pouya. The +> line is the same one the Offerings ruling drew — 'Q.Med stands for Qualified +> Mediator' is a fact about the designation's name, not about him."* +> +> So a page may expand an abbreviation on this section's authority. It may **not** +> say he holds the thing, has commenced it, or is progressing toward it — those +> are §4 Verified rows, and §4 remains the only gate for them. +> +> **The five ADR designations are sourced, not asserted here.** +> `docs/reference/adrio-designations.md` carries all five in ADRIO's own words +> with reproducible digests (R14). Pouya attached that fetch to the ratification +> as a condition, and it caught the error below. +> +> ⚠️ **CORRECTION, 2026-08-28 — `C.Med-Arb` WAS WRONG IN THIS TABLE FROM THE +> FILE'S CREATION.** It read *"Chartered Mediator-Arbitrator"*. ADRIO's term is +> **"Chartered Med-Arbitrator"**. Pouya raised it himself: *"I took the expansion +> from the strategy brief and never sourced it… It is the practice's stated +> long-term designation, so getting its name wrong on a public page is not +> cosmetic."* It **had** reached a public page — `/about/`'s credential arc, and +> `dist/about/index.html` — and four adversarial review passes read that string +> without catching it, because each checked whether it was *sourced*, not whether +> it was *right*. Swept from four files; the sweep command is in Change Log (y). + | Term | Meaning | |---|---| | ADR | Alternative dispute resolution | | ADRIC | ADR Institute of Canada — national credentialing body | | ADRIO | ADR Institute of Ontario — provincial affiliate | -| Q.Med | Qualified Mediator — ADRIC/ADRIO designation | -| Q.Arb | Qualified Arbitrator — ADRIC/ADRIO designation | -| C.Med-Arb | Chartered Mediator-Arbitrator — senior hybrid designation; the long-term goal | +| Q.Med | **Qualified Mediator** — ADRIC / ADRIO designation | +| Q.Arb | **Qualified Arbitrator** — ADRIC / ADRIO designation | +| C.Med | **Chartered Mediator** — ADRIC / ADRIO designation | +| C.Arb | **Chartered Arbitrator** — ADRIC / ADRIO designation | +| C.Med-Arb | **Chartered Med-Arbitrator** — ADRIC / ADRIO designation. *Do not write "Mediator-Arbitrator", and do not call it "senior" or "the senior hybrid designation": this row said that until 2026-08-28, and it is a ranking claim about a third party's credential structure with no source. ADRIO applies "most senior" to **C.Med**, not to this one — and §4 Forbidden bars superlatives on the site regardless of who said them first. That it is Pouya's long-term goal is a §4 row; that it ranks above anything is not.* | +| CTF | Canadian Tax Foundation | | Med-Arb | Hybrid process: mediation that converts to binding arbitration if unresolved | | SABS | Statutory Accident Benefits Schedule — Ontario auto insurance benefits | | LAT | Licence Appeal Tribunal — hears Ontario SABS disputes | @@ -688,12 +784,14 @@ never being raised again. | R5 | **Fee review at 12 months.** Published rates are sticky; the right moment to move them is deliberate, not reactive | 2026-08-26 | D14 is priced for where the practice is going, not where it is | | R6 | **Booking tool.** Parked by Pouya on 2026-08-26; `/contact/` ships with the intake form and a reserved slot for an embed | 2026-08-26 | He asked to be reminded. D10 committed to booking because it removes the back-and-forth that loses appointments — the form alone is a partial answer | | R9 | **The SES alarms notify nobody until the `ses-alerts` email subscription is confirmed.** `SES-BounceRate-High` and `SES-ComplaintRate-High` are configured and live; the SNS email subscription to `info@smlcompany.ca` is **pending confirmation**, and an unconfirmed subscription drops every message | 2026-08-26 | A monitoring control that exists but does not deliver is worse than none, because it reads as covered. At this volume five bounces can cross the ~5% suspension threshold. Tracked in §7 and on the cutover checklist, but a one-click task nobody owns is exactly what §12 is for | -| R10 | **RAISED 2026-08-28 AND NOT DISCHARGED — AND THE PROHIBITION HELD.** Pouya's instruction for this session was *"R10 first: re-confirm the memberships, which now includes CTF"*. The re-confirmation is a fact only he holds, so it is now **Q44**, and `/about/` ships **without a memberships group** — this row is written as a prohibition on shipping such a page, and documenting a prohibition is not discharging it. *An earlier version of this row said `/about/` had shipped with all four; that was true for part of one session and was reversed on review. Three other documents recorded the same reversed state and have been corrected.* Four yes/no answers and four **renewal months** close it; the months are the part that matters, because they turn this row from a reminder into a date. Original text follows. **Annually-renewing memberships.** §4 verifies the **OBA sections** (Construction & Infrastructure, ADR, Civil Litigation) and the **Canadian Tax Foundation** as of 2026-08-26 — *for now*. Both renew yearly. *Widened 2026-08-26 when CTF was added; it was OBA-only before* | 2026-08-26 | A credential that lapses quietly is the failure mode §4 exists to prevent, and OCNI already did exactly this (§4 records it as "not current, do not publish"). Re-confirm at each renewal, and before any page listing memberships ships — `/about/` at build step 3 is the first one that will | +| R10 | **DISCHARGED AS WRITTEN 2026-08-28 — AND RE-ARMED WITH AN EVENT TRIGGER INSTEAD OF A DATE. STILL LIVE.** Pouya re-confirmed all four memberships as current (Q44), which discharges the prohibition this row carried, and `/about/` now publishes the Memberships group. **The row does not close, because he declined renewal-date tracking**, and that was his instruction for what to do about it: *"Without renewal months it cannot fire on a date, so make it fire on an event: re-confirm memberships before any cutover or major republish, and re-stamp §4 when confirmed."* **THE TRIGGER: re-confirm before any cutover, and before any major republish. Then re-stamp §4 the same day.** **His reason, kept verbatim because it is the general principle and not a membership detail:** *"§4 already carries OCNI as lapsed and unpublishable, and that was found roughly a year late. A stamp with no trigger behind it goes stale silently, which is exactly how OCNI got onto a list of things to feature."* **Two things the discharge did NOT license.** (1) **No currency warranty on the page** — list the memberships, promise nothing about their future state; the struck sentence stays struck and nothing replaces it. (2) **`memberOf` stays out of the JSON-LD**, which is now a *stricter* standard than the visible page. **That is an open judgement, not a settled one — see Q53**, which carries the reasoning and `adversarial-reviewer`'s argument that it does not survive: the memberships are already crawlable in `/about/`'s HTML, so withholding the triple reduces no exposure and only makes the graph less complete than the page. The reasoning lives in `src/data/schema.ts` and in Q53, and nowhere else — it was in five places, two of them the version the review rejected. **Renewal periods, stated once and not widened again:** the OBA sections and the CTF renew yearly; §4 records **nothing** about ADRIC's or ADRIO's period, and the widened form ("all four renew yearly") reached four files before it was swept. *Previous text described the prohibition and the withheld group; it held for one session and did its job.* | 2026-08-26 | A credential that lapses quietly is the failure mode §4 exists to prevent, and OCNI already did exactly this. The group is on a public page now, which raises the cost of a lapse rather than lowering it — and **Q48 may raise it further**: if `Q.Med` retention depends on ADRIO membership currency, this row covers the site's central credential too, not just a list | | R11 | **Re-check dependency currency at every phase boundary in the build order** (`docs/01-architecture.md` §Build order, 11 steps). Run `npm view <pkg> version` across **every** pin in `package.json` and compare; do not wait for something to break. Verified does not mean latest — record the reason for any deliberate hold in §7. **Carries one specific re-add trigger: at step 7, put `@lhci/cli` back.** Check for a patched release — do not assume `0.15.1` is still the ceiling just because it was on 2026-08-26 — pin it against `npm view` that day, write a `lighthouserc` with the budgets from `docs/04-seo-spec.md`, and delete the UNAVAILABLE notices this repo now carries in six places (§7 lists them). If the advisories are still unfixed, that is a decision to take deliberately, not a reason to leave the gap unstated | 2026-08-26 | `astro: "^5.0.0"` was recalled rather than checked and was two majors stale the day it was written, which meant a framework carrying high-severity XSS advisories. Between phases is cheap; after a phase of pages is written is not. The build order has ten more boundaries | | R12 | **`compressHTML: true` is a deliberate deviation from the Astro 7 default (`'jsx'`).** Measured 2026-08-26: in an `.astro` template an inline pair split across two lines renders as `<em>a</em><strong>b</strong>` under the default — the space is silently deleted. MDX prose is unaffected | 2026-08-26 | It is a deviation, and undocumented deviations become folklore. Revisit **with a measurement**, not a preference — and re-measure after any Astro major, since the behaviour could change again | | R13 | **The infinity mark ships as a RASTER, and that is temporary. RAISED 2026-08-27; Pouya ruled the committed SVG does NOT close it** — *"Keep it committed, keep the AVIF render path. Your own measurement is the reason: 257 KB wrapping seven embedded base64 PNGs. It renders faithfully because it IS the raster."* So the exception stands and the reminder stays live. `InfinityMark.astro` renders an optimised AVIF/WebP from `src/assets/brand/sml-infinity-mark.png` — a deliberate, documented exception to `docs/02`'s "inline SVG, never a PNG", because the mark is gradient-mesh artwork and no true vector master exists yet (Q38). **Removal trigger: the commissioned vector master lands.** Then replace the `<Picture>` with inline SVG, regenerate `favicon.ico` and `apple-touch-icon.png` from it, and delete the exception from `docs/02`, from the component, and from Q38 | 2026-08-26 | Pouya flagged this himself when he made the ruling: *an interim raster is exactly the kind of temporary measure that becomes permanent by never being raised.* It costs ~8 KB and works, which is precisely why nobody will notice it again. There is no build error to prompt anyone — only this row | | R14 | **Anything a spec makes a claim about must be reachable from the repository.** If the artefact lives only in Drive, in a console, or on someone's disk, no reviewer can check the claim and the claim is unverifiable by construction — see the rule now in `CLAUDE.md` | 2026-08-26 | **This has now cost twice.** Q24 was `AWS-Hosting-Guide.md`, the only record of how the infrastructure was hand-built, living outside the repo. Q32 was the infinity mark: Claude Code traced it from the old site's *loading placeholder*, wrote a scrupulous provenance comment recording exactly that doubt — and **two adversarial review passes still could not catch it**, because the artwork they would have had to compare against was not in the repo. The doubt was correctly stated and structurally uncheckable. That is the failure mode: not a missing warning, a missing artefact | | R15 | **Every page shares ONE Open Graph image — the portrait — and that is an interim for seventeen of the nineteen. RULED, DEFERRED, AND TRACKED HERE ON POUYA'S INSTRUCTION:** *"Record the trigger so it cannot quietly become permanent."* Q40, 2026-08-27. The portrait is the **decided** card for `/` and `/about/` — a face is the strongest social preview for a personal brand. It is the wrong card for the other seventeen, where a typed card carrying the page title does the work. **Removal trigger: build step 7**, where Insights needs per-article cards anyway — one generator (`satori` or `astro-og-canvas`, pinned against `npm view` that day per R11), one dependency, one review. Then delete the interim note from `docs/04` and the cutover line from `docs/06`. **Blocks cutover; does not block steps 3–6** | 2026-08-27 | Nobody on this project will ever see the defect. A link preview is rendered by LinkedIn, Slack and Teams for a reader who is not us, and `docs/04` requires a **unique** title and description per page — nineteen unique pages that all preview identically is the failure, and it is invisible from inside the repo. It costs nothing and works, which is exactly the R13 shape | +| R16 | **The one-page PDF bio does not exist, and it is deferred to build step 9 — not dropped. RULED AND TRACKED HERE ON POUYA'S INSTRUCTION:** *"Record the trigger so it doesn't become another quiet interim."* Q45, 2026-08-28. His reasoning: it is a **derived artefact**, so building it before `/about/` and `/fees/` are final means building it twice — and an appointment proposal needs the fee card as much as the bio. **Removal trigger: build step 9, alongside `/fees/`.** Two decisions travel with it and are **not** settled by the deferral: (a) generated at build (a dependency and an `npm audit` surface, against R11) or authored once as a designed artefact; (b) whether it carries anything the site does not — a matter list, a fee summary, referees — **each of which is a §4 question of its own**, and the matter list would collide with §4 Forbidden directly. Then delete `docs/01` §`/about/` item 7's pending note | 2026-08-28 | **It is the one artefact class this project's review apparatus cannot reach.** A web page is re-reviewed by every audit and re-checked by every build; a PDF circulated with an appointment proposal is read once, by the reader who matters most, and never seen by a reviewer again. `/about/` currently ships with no link to it, which is correct — a dead link on the page an appointing body reads is worse than the absence — and that means **nothing on the site will ever prompt anyone about this.** Only this row will | +| R17 | **THE DEPLOY KEY'S FIRST ROTATION IS DUE 2026-11-26, AND THAT DATE IS THE WHOLE ROW.** Access key for `adr-sml-deploy` created **2026-08-26**; D3 commits to **quarterly** rotation. Pouya's instruction when Q22 closed: *"Put the DATE in the R-series reminder, not the intention."* **Rotation procedure is in `docs/06-deployment.md` §Key rotation** — create the second key, update the Gitea secrets, verify a deploy, **then** delete the first; never delete before verifying, or the next push fails with no way to authenticate the fix. **Then set the next date here (2027-02-26) rather than deleting the row.** Also re-run the eight `simulate-principal-policy` checks after any policy edit — the narrowness is the control (§10), and a widened policy is invisible from inside the repo. **The key is currently UNUSED — `LastUsed` null** — because deploys still run locally via `npm run deploy`; that does not pause the clock, and an unused long-lived key is exactly the one nobody remembers to rotate | 2026-08-28 | This is the reminder D3 has been waiting for a subject since 2026-08-26. §10 records the reason it matters more here than on a normal project: the secret lives on **jointly-administered** infrastructure, and the account also holds another business's client-database backups. A static key on shared infrastructure is only as safe as its age and its scope, and **nothing in the repo, the build, or AWS will prompt anyone on either.** §7 carries the inventory; this row carries the date | | ~~R7~~ | **RATIFIED / SUPERSEDED 2026-08-26.** (a) Cache-policy table matching the pipeline — **accepted**; documenting what the pipeline does beats documenting an intention. (b) `s3:AbortMultipartUpload` omitted — **accepted, reasoning corrected**: the lifecycle rule does not exist and is therefore not the cover; the actual cover is that `aws s3 sync` only goes multipart above 8 MB and the largest asset is a 357 KB portrait. Recorded in `docs/06-deployment.md` with a revisit trigger. (c) The `aws s3 ls` pre-flight — **superseded** by the variable guard now running as the workflow's first step | 2026-08-26 | — | | ~~R8~~ | **PROMOTED TO A RULE 2026-08-26.** A reminder was too weak for a pattern that survived three entries. *A sweep is a command, not a claim* now sits in `CLAUDE.md` under Conventions, in `/build` Phase 6, and in `/wrap` step 3: any claim that a change was applied across files must cite the command and be written only after reading its output | 2026-08-26 | — | @@ -701,6 +799,3688 @@ never being raised again. # Change Log +## 2026-08-28 (y) — Six rulings applied; Q22 closed on execution; and the ruled value of Q47 was struck by both review agents the same day it was set + +**Pouya's rulings this session:** Q44 (memberships current — ship the group), +Q45 (PDF bio deferred to step 9), Q46(a) (the three offerings pass all gates), +Q46(b) (§11 ratified as the source for definitional expansions — *fetch and +commit the source*), Q47 (set both `jobTitle` and `worksFor`), the +legal-advice formulation **ratified without change**, plus **Q22 closed on his +own execution evidence** and a new `CLAUDE.md` convention. + +### The headline: a ruled value that reversed a standing audit correction + +Q47 ruled `jobTitle: "Mediator and Arbitrator"`. It shipped for one pass as +**"Mediator and Commercial Arbitrator"** — and **both review agents struck it +independently**, which is this loop's strongest signal. + +The reason is not the one Claude Code flagged. The implementation carried a +prominent note arguing about **scoping** ("Commercial", on the ground that Q39's +struck universal must not reappear) — and *"Mediator and commercial arbitrator in +Toronto"* is **the exact string `claims-auditor` struck from this same node's +`description` on 2026-08-27**, on entirely different grounds: §4 verifies *"Has +completed multiple sole mediations"* and has **no counterpart row for a completed +arbitration**, only that appointments are *accepted*. The reasoning was still +sitting in `schema.ts` thirty lines above the property that now said it. + +**A flag aimed at the wrong defect reads as diligence and provides none.** That +is the lesson worth keeping: the note was scrupulous, specific, and pointed at a +real-but-secondary issue, and its presence made the diff look reviewed. + +`worksFor` was set and reverted the same way, on a defect the careful "name +only, nothing else" scoping did not touch: **`ProfessionalService.provider` is +this Person**, so `provider → Person → worksFor → SML Company Ltd` asserts +transitively the same-entity claim that `about.astro` **deleted from visible prose** as *"a corporate-structure claim"*. + +*Corrected on re-review: this paragraph first cited a guard in `aboutGraph`'s +comment as declining the same-entity claim. That comment covers `ProfilePage`, +`BreadcrumbList` and `memberOf` and says nothing about SML — **the citation was +empty**, in the argument for a revert. The transitive inference stands on its +own; the evidence offered for it did not. `adversarial-reviewer` read the +referent rather than the claim, which is the whole rule.* + +Both now ship in the narrowest rowed form — `jobTitle: 'Mediator'`, no +`worksFor` — and **Q49** asks Pouya for the two §4 rows the ruling needs. Q47's +stated purpose still holds: `jobTitle` describes *this practice*, not the +boutique role. + +### Q46(b): ratified, sourced, and the fetch immediately earned itself + +`docs/reference/adrio-designations.md` — all five expansions in ADRIO's own +words, four independent fetches, reproducible sha256. R14 satisfied; §11 no +longer asserts its own content. + +**It 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 had reached a public page — +`dist/about/index.html` carried it. **Four adversarial review passes read that +string** and none caught it, because each checked whether it was *sourced*, not +whether it was *right*. + +Three instrument notes, all recorded in the reference file: + +- The URL Pouya gave **301-redirects**; the first fetch without `-L` wrote a + **0-byte file**, which reads as "the page is empty". +- Digests **are** stamped here where `lat-case-conference.md` could not stamp + them, and the difference was checked rather than assumed: no `__uzdbm` nonce, + and the 17 `?ver=` strings are **static plugin versions**, not rotating + cache-busters. +- The parent page extracts at **3.5%**, the `adric.ca` shell signature — but it + is not a shell; it is genuinely a stub. **Read the ratio against the page, not + against a threshold.** + +### The review found a defect in this session's own artefact + +`claims-auditor` noticed that the reference file argued a **Qualified-vs-Chartered** +retention asymmetry from a two-page sample, while having fetched a third Chartered +page and never run the count on it — **C.Med-Arb, the designation §4 records as +the practice's goal**, and the one most load-bearing for Q48. Run: + +``` +qualified-mediator-q-med / q-arb good standing 0 annual 0 maintain 0 retain 0 +chartered-mediator-c-med 1 1 1 1 +chartered-arbitrator-c-arb 1 1 1 1 +chartered-med-arbitrator-c-med-arb 0 0 0 0 +``` + +**The framing was wrong.** The split is by **page type** — long application FAQs +versus short descriptions that link out — not by designation level. And it cuts +the *opposite* way from how it was written: a stub page's silence is evidence +about the page, so Q.Med's silence is most likely "this page does not cover +retention", not "no condition exists". Finding 4 rewritten; **Q48 stands, better +explained.** + +### Q22 — closed on execution, by Pouya, and the verification is the point + +IAM user `adr-sml-deploy` exists (created 2026-08-26T15:45:18Z), one inline +least-privilege policy, one unused access key. §7 goes from **NOT PROVISIONED** +to provisioned; §9 Q22 closes; three §10 risk rows updated. + +**Verified by execution rather than by reading** — eight +`simulate-principal-policy` calls, `allowed` on the four intended actions and +`implicitDeny` on the client-backup bucket, on `s3:DeleteBucket`, on another +site's bucket, and on `iam:CreateUser`. **And the one gap a policy read cannot +close was closed too:** `get-bucket-policy` on the backup bucket returns +`NoSuchBucketPolicy`, so no resource-based grant exists and IAM is the only path +in. §10's control now exists *and has been tested against the thing it protects*. + +**Rotation has a date, not an intention** — key created 2026-08-26, first +rotation **2026-11-26**, in §12 **R17** on Pouya's explicit instruction. +Flagged back to him, unresolved: `implicitDeny` is the weakest form of "no" — +absence-of-Allow, not explicit Deny — so the protection is "nothing grants it" +rather than "something forbids it". + +### New `CLAUDE.md` convention — never suppress stderr in a verification script + +Pouya's, from that verification: `2>/dev/null` hid an `InvalidInput` error, all +eight checks returned empty, and **a cause was then guessed** (*"probably lacks +the permission"*) — which is the answer the check existed to produce, reached +without the check running. Actual cause: a **zsh parameter-expansion bug**, +`$ACCT:user/` parsing `:u` as a history modifier and yielding +`327082975128ser/`. + +His framing: this is *a command that did not run is not evidence of absence* from +the other direction, and the more dangerous one — **suppression converts "it +failed" into "it found nothing", and those are opposite results.** + +**Corroborated twice the same day, both in zsh, both while verifying this change +set:** `grep -rn $EX '…'` printed an option error and **no matches** (reads as +clean) because zsh does not word-split unquoted variables; and a digest +comparison using `set -- $pair` printed **`DIFFER` on all five rows** (reads as +"the source changed under me") because the loop body got one argument and the +comparison never ran. + +### Q44 — shipped with a prohibition attached, and R10 re-armed rather than closed + +All four memberships re-confirmed; the group renders on `/about/`. **No currency +warranty** — his words, *"list the memberships; promise nothing about their future +state"*. He **declined renewal-date tracking**, so **R10 fires on an event now, +not a date**: re-confirm before any cutover or major republish. + +Two things flagged back rather than assumed: the **stamp reads 2026-08-28**, not +the 2026-08-26 his ruling wrote, because a currency stamp records when the +assertion was made; and **`memberOf` stays out of the JSON-LD**. The ground for +that was restated on `adversarial-reviewer`'s finding that the first version +**proved too much** — "a scraped claim is cached" applies equally to +`hasCredential`, which ships. The real distinction is **volatility**, and the +sharper consequence is recorded: *if Q48 resolves against Q.Med, `hasCredential` +carries the higher exposure of the two.* + +### Review findings resolved — 23 across two agents + +`claims-auditor`: **FAIL, 12** (5 published, 7 internal). `adversarial-reviewer`: +**2 blocking, 9 should-fix, 5 consider.** Fixed: the two Q47 fields; the +untracked reference file that **four places already cited** (`git commit -a` does +not pick up untracked files — R14 would have been unsatisfied in the Q24/Q32 +shape); `"workshop series"` → §4's **"sequence"**; `"alongside both"` → +**"alongside the practice"**; two §4-Forbidden breaches in specs where *"the Q.Arb +**designation** commenced"* reads as **held**, one of them model copy an +implementer is told to lift; a third unapproved D13 phrasing in the positioning +statement earmarked for the PDF bio; `docs/04`'s still-unscoped `serviceType` +and its restatement of a literal string with a live revert trigger on it; a §4 +misquotation *inside the comment written to stop widened paraphrase of that exact +sentence*; a duplicated block in one comment whose two copies **already +disagreed** on the highest-stakes item. + +Two structural fixes worth naming: + +- **The offering test enumerated two questions while the rows cited three + gates.** The partisan question — this register's highest-value catch, the one + that struck settlement counsel — existed only as unnumbered prose in the worked + example, so an implementer reading *The offering test* would not have found it. + It is now **gate 0**, numbered to record that it runs first and disposes of a + candidate on its own. +- **§9 struck Q46 while half of it was live and blocking.** Split into + `~~Q46(b)~~` and a live **Q46(a)**; the worked-example table's citations + updated. + +And one of this session's own additions failed its own test: the new +`[unestablished]` **checklist item would have failed the very sentence the +section exists to bless** — it greps for "do not", and the ratified copy is *"I +**do not** act for a party in a matter I take"*. Scoped to *giving legal advice, +practising law, or holding a licence*, with attempt 3 added as the worked pass. + +### Sweeps — commands and output, per R8 + +> ⚠️ **THIS BLOCK'S FIRST VERSION COULD NEVER REPRODUCE, AND THE REASON IS +> STRUCTURAL: pasting a search pattern into `AGENTS.md` adds occurrences of that +> pattern to the file the sweep counts.** `Chartered Mediator-Arbitrator` went +> from 8 matches to 10 the moment this entry was written; `workshop series` and +> `designation commenced` went from 0 to 1–2. A later reader re-running them +> cannot distinguish that from drift — which defeats the entire point of R8, in +> the entry that invokes it. Found by both review agents independently. +> +> **Every sweep below therefore excludes `AGENTS.md`** via +> `':!AGENTS.md'`, so the commands reproduce as written. The excluded file's own +> occurrences are prohibitions and historical quotes; they were read. + +``` +$ git grep -c 'Chartered Mediator-Arbitrator' -- . ':!AGENTS.md' +docs/03-content-spec.md:1 +docs/reference/adrio-designations.md:4 +src/pages/about.astro:2 +$ grep -ro 'Chartered Mediator-Arbitrator' dist/ | wc -l +0 + -> all 7 read: every one a prohibition ("never write…") or a historical quote + inside a correction note. Zero live uses. dist clean. + +$ git grep -c 'workshop series' -- . ':!AGENTS.md' -> 0 +$ git grep -c 'designation commenced' -- . ':!AGENTS.md' -> 0 +$ git grep -in 'in progress' -- . ':!AGENTS.md' | grep -ci arb -> 0 + +$ git grep -c 'alongside both' -- . ':!AGENTS.md' +docs/03-content-spec.md:1 +src/pages/about.astro:1 + -> both read: corrective comments naming the removed wording. + +$ git grep -n -A1 'as in**Line-wrapping defeated an anchor or a sweep THREE times this session** — S5's +`as in\n * progress`, the `SiteFooter` masthead sentence, and `docs/03`'s +blockquote-wrapped phrase recorded in an earlier entry. Sweep the wrapped form. + +### Verified + +`astro check` **0 / 0 / 0**; `eslint` clean; `prettier --check` clean (noting +`.prettierignore` excludes `*.md` and `docs/reference/`, so it says nothing about +the new doc); `npm run build` 2 pages; **0 `.js` emitted**; the only `<script>` +on either page is `application/ld+json`; minifier guard silent and +`animation-timeline` intact in `dist` (longhands only; the sole `animation:` +shorthand is `animation:none!important` in the reduced-motion block); **no gold +text on cream** anywhere; one `<h1>` on `/about/` with h1→h2→h3 and no skips +across 17 headings; JSON-LD parses on both pages with `jobTitle: "Mediator"`, no +`worksFor`, no `memberOf`, `hasCredential` Q.Med-only, no `LegalService`; **no +currency-warranty phrasing in the built HTML** (`renewed annually`, +`listed as current`, `current as of`, `are current` — all 0). + +Layout re-measured by `adversarial-reviewer` after it discarded its own first +instrument: **headless Chrome clamps `--window-size` to ~500px minimum on +macOS**, so its "320px" was really 500px. Via CDP `setDeviceMetricsOverride`: +320×800 DPR2, 1024 and 1280 → **0 document overflow**; at 320px with root +font-size 32px → 63px, **all of it the pre-existing header brand name**, with +every credential `<li>` right edge at 272 against a 320 viewport. The new +Memberships group contributes no overflow. + +### NOT run, stated rather than omitted + +- **Lighthouse — tool unavailable.** `@lhci/cli` removed 2026-08-26; returns at + step 7 under R11. Nothing here adds bytes to a route: no new images, no runtime + font request, no third-party script, no base64 inlining, JS still zero. +- **HTML validator — not run.** The duplicate-`1x` srcset conformance error from + step 2 stands. +- **Q46(a)'s gate 1 — no source fetched.** Deliberate: it is legal research, it + was not asked for, and §4 bars this register from concluding it. The candidate + source is named in the ENE row. + +### The re-review found 25 more, and most were in the fixes + +**Two full review rounds ran. The second found 14 (`claims-auditor`) and 16 +(`adversarial-reviewer`) — and the majority were defects introduced by the first +round's fixes.** That is the pattern this project keeps paying for, and this +entry is the sharpest instance yet. Named, because the shape is the lesson: + +- **The `memberOf` rationale, rewritten to be more rigorous, re-widened §4.** It + said a membership list is *"a set of **yearly renewing** facts"* — the widened + form, **fourth occurrence**, twenty lines above the same comment's own warning + that *"all four renew yearly… is still wrong and still must not be written"*. + And it was the stated ground for withholding `memberOf`, so the withholding + rested on a widened premise. +- **The argument for reverting `worksFor` cited a guard that does not exist.** It + said `aboutGraph`'s comment "explicitly declines" the same-entity claim; that + comment covers `ProfilePage`, `BreadcrumbList` and `memberOf` and never + mentions SML. **The citation was empty, in four places.** The real referent was + `about.astro`'s deleted *"corporate-structure claim"* sentence. This repo's own + rule — a claim whose referent cannot be reached is unverifiable by construction + — applied to the argument for a revert. +- **§9's `~~Q47~~` was struck as answered while describing the pre-revert + state.** Both its assertions were false against `dist` within hours. Verbatim + the failure Q44's history records — *"four documents recording a page state + that had been reversed and not swept"* — reproduced inside the change set that + records it. +- **The gate renumbering left two live "Gates 2 and 3" references, both written + in this same change set**, four paragraphs from the note explaining the + renumbering. +- **The new `[unestablished]` checklist item would have failed the sentence the + section exists to bless** — it greps for "do not", and the ratified copy is *"I + **do not** act for a party in a matter I take"*. +- **`SiteFooter.astro`: a five-line insertion landed in the middle of a + sentence**, leaving *"…third wrapping miss in one session; §4 permits the + arbitration half…"*. Unspliced, and the session diary removed with it. + +**Three findings were one lift away from a public page, and none was in the +change set's own diff:** + +- `docs/03`'s `/for-parties/` directive said the mediator *"is not your lawyer + and cannot give you legal advice"* — **both halves breach D13**: "not your + lawyer" presupposes lawyer status, and "cannot" is attempt 2 from that file's + own ratified table. It sat fifty lines below the warning added this session + that `/for-parties/` is *"the exact place the 'cannot' phrasing feels most + natural and is most wrong"*. **And `about.astro` cited it as the sanctioned + example**, quoting the half that suited and not the half that was struck. +- `docs/01` told an implementer the "also offered" strip **may ship** because + each offering "now has a §4 Offerings row" — all three rows read **NOT YET + PUBLISHABLE**. `docs/07` priced them at $500/hour with no gate note at all. +- Model copy in `docs/03` and `docs/07` offered arbitration **unscoped** — the + struck universal, one file over from the same defect fixed earlier the same day. + +**And the sweep record itself could not reproduce** — see the block above. Plus +the count misread: `git grep -c` prints one line per *file*, and "3 hits" was 3 +files. + +### Structural criticism accepted, and acted on in part + +`adversarial-reviewer` counted the diff: **342 lines added to `src/`, eight of +them functional** — a ratio near 42:1 — and named the concrete failure rather +than the aesthetics: **four of its own findings were stale or fabricated +statements living inside exactly those comments**, each duplicating something +`AGENTS.md` already records. Its rule: **keep the *rule* in the source, move the +*history* to the Change Log, and cite it.** + +Acted on for `SiteFooter.astro` (five lines of session diary deleted) and for the +worst of `about.astro`. **Not yet done systematically**, and recorded here rather +than quietly dropped: the remaining comment mass in `about.astro`, `site.ts` and +`schema.ts` is a real maintenance liability on the same evidence, and step 4 is +the moment to trim it rather than extend the pattern across three new pages. + +### Evidence committed that was previously unreachable + +`docs/reference/adrio-extract/` — the extraction script and the five extracted +text files every term count in `adrio-designations.md` was run against. The +digests covered the **raw HTML** and said nothing about the extraction, so the +counts were unverifiable by construction even while the digests were not. The +committed extracts reproduce all four rows of Finding 4 exactly. + +**The equivalent gap for Q22 is NOT closed and is now Q52:** §7 downgraded a +**High** §10 risk and declared the scoped policy "tested against the thing it +protects" on nine `simulate-principal-policy` results that exist nowhere in the +repository. `adversarial-reviewer` drew the contrast itself — it reproduced every +ADRIO digest independently and could reproduce nothing here. Only Pouya can close +it; he ran the commands. + +### Open after this entry + +**Q46(a)** (gate 1 unsourced — blocks step 5) · **Q48** (Q.Med retention vs +membership currency) · **Q49** (the two §4 rows Q47 needs) · **Q50** +(`ProfessionalService.name` scoping) · **Q51** (OBA and the D13 implication — +**now on the cutover checklist**) · **Q52** (commit the IAM verification output — +R14) · **Q53** (should `memberOf` be emitted after all?) · **Q23**, **Q34**, +**Q38**. Live reminders: **R1** (licensure — surfaced again, +and `/about/` is now the page that makes it live), **R10** (event-triggered), +**R11**, **R13**, **R14**, **R15**, **R16** (PDF bio, step 9), **R17** (key +rotation, 2026-11-26). + + +## 2026-08-28 (x) — Build step 3: `/about/` ships without its memberships. Q40–Q43 close; four review passes found nine defects in their own predecessors' fixes + +**Task, in Pouya's words:** rulings on **Q42**, **Q41(a)(b)(c)**, **Q43** and +**Q40**, then *"step 3, `/about/` — and R10 first: re-confirm the memberships, +which now includes CTF."* + +**Headline, because it is the one thing to read if nothing else:** `/about/` +ships **without a memberships group**. R10 is written as a prohibition on +shipping a page that lists memberships before they are re-confirmed; the +re-confirmation is a fact only Pouya holds; it was not obtained. The first +version of the page published all four and *disclosed* the gap in five places +instead — both review agents rejected that, and they were right. **Q44** carries +the exact question. + +--- + +### Standing reminders surfaced (§12) + +- **R1 — licensure. Raised again, and `/about/` is why the stakes moved.** It is + the site's credential spine, it now carries designations, education, + certifications and the boutique role, and it states no licence status either + way. On `/` that reads as brevity; on a dedicated credentials page a + sophisticated reader notices. Q41(a)'s ruling is now load-bearing on the same + page — the copy says the legal half is *"training I hold"*, which is the closest + the site comes to addressing the question. **Nothing here asks to change D13.** +- **R10 — raised and NOT discharged.** See the headline. Now Q44. +- **R13 — the mark is still a raster.** Unchanged; no vector master has landed. +- **R11 — phase-boundary currency check RUN, not recalled.** Every pin in + `package.json` against `npm view`: 13 of 14 exact. The one hold is + `typescript ^6.0.3` against `7.0.2`, and the reason was re-verified rather than + carried forward — `@astrojs/check` peers `^5.0.0 || ^6.0.0` and + `typescript-eslint` peers `>=4.8.4 <6.1.0`. Both bar 7. `npm audit`: **0 + vulnerabilities.** `[verified 2026-08-28]` +- **R15 — NEW.** The single portrait OG image across nineteen pages, per Pouya's + Q40 ruling, with build step 7 as the removal trigger. + +### Rulings applied + +**Q42 — three offerings rowed, settlement counsel struck.** ENE, dispute-system +design and pre-dispute technical advisory gained rows; `settlement counsel` was +struck as Pouya's own error in `docs/01`, on the ground he named first — +*"it undercuts the brand's central claim"* — with the D13 half as aggravation +rather than reason. Swept by command; output below. + +**And the strike exposed a hole in the offering test.** Settlement counsel fails +neither question 1 nor question 2; run mechanically the test would have **passed** +it. It fails a prior question the test does not ask. §4 now states that prior +question — *is this a role in which the practice is partisan between the parties +to a dispute?* — with the Q42 worked example kept as the 3–1 table. + +**Q41(a) — Q37 reaches prose, and prose is held to a HIGHER bar.** Deleting the +parallel was half the fix; a reader supplies the missing symmetry from silence. +The sentence that names which half is which is now **one constant**, +`ASYMMETRY_LINE`, because it had been typed into two pages and the two copies had +**already diverged inside the same session** — a comma on one, full stops on the +other. + +**Q41(b) — not restored, and the comparative turned out to be in three places, +not one.** Pouya's replacement wording is used verbatim in `docs/03`'s core +positioning statement. Then the second audit found the implication had been +*relocated, not removed*: a new instance written into the `/about/` biography, +plus **two pre-existing instances on `/` that had survived the sweep that closed +Q41(b) the day before** — *"usually arrives as a separate expert report"* and +*"not something a party has to commission and wait for"*. All three gone. + +**Q41(c) — verified against the Tribunal's own materials, and the interim was +ambiguous in the one word that mattered.** New extract: +`docs/reference/lat-case-conference.md`. Rule 2.4 makes *"Pre-Hearing +Conference"* the LAT's own term for a **case conference**; Rule 14.3 puts a +**Member** in the chair and disqualifies them from the hearing panel; Rule 14.6 +makes attendance mandatory; the Rules contain **zero** occurrences of `mediat` or +`arbitrat` in 66,593 characters. The affirmative basis is the Tribunal's own AABS +page: *"you may want to consider negotiation or mediation services… including +before filing at the LAT-AABS, and continuing… after a claim has been filed."* + +**Q43 — the timings are service commitments; framing, not a row.** Numbers +unchanged. `PROCESS_FRAMING` renders adjacent to the strip, not in a lede above +it, because a reader who scans the strip and skips the lede has read a +commitment. `docs/03` §Process amended to record that its *"real timing"* +requirement had been over-read as barring the word "typical". + +**Q40 — bundled to step 7, not shipped as a second interim.** Portrait is the +*decided* card for `/` and `/about/`; the generated typed card covers the rest, +built once with Insights. Tracked as **R15**, blocking cutover, not step 3. + +### `/about/` — what shipped + +Six of `docs/01`'s seven items. Item 6 (Speaking) omitted on the spec's own +instruction. Item 7's PDF **not** shipped — **Q45**. Item 3 ships Designations, +Education and Certifications; **Memberships withheld** — Q44. Sections ordered +4-before-3 deliberately: the arc is the part a reader has a question about. + +### Four review passes, and what they cost + +Two agents, twice. **28 findings, then 15 more.** Nine of the second round's +findings were defects in the first round's fixes — which is the measurement +`/build` Phase 4 exists on. + +**Three that must never have shipped, all mine:** + +1. **The false universal Q39 struck, on a public page.** The arc's Q.Arb body + read *"arbitral appointments are not gated behind it, which is why I accept + them now"* — unscoped, first person, publishing a proposition of Ontario law + §4 holds only in scoped form and deliberately does **not** stamp. Q39 swept + three instances on 2026-08-27; this was the **fourth** and the first outside a + comment. Found independently by both agents. +2. **A public warranty of currency over an undischarged R10** — *"Memberships are + renewed annually and are listed as current."* Also **widened §4**, which + records yearly renewal for the OBA sections and the CTF only and says nothing + about ADRIC or ADRIO. The widened form had propagated to four files. +3. **A licensure denial** — *"Nothing above asserts a licence to practise law, in + either direction"* — on the page §4 marks `[unestablished]`, where the rule is + *do not assert it, do not deny it*. No spec asked for it. + +**And the same sentence was wrong in both directions, which is the finding worth +keeping.** Audit 1 flagged *"I do not give legal advice"* — "do not" describes an +election, and an election implies the entitlement. So it became *"I cannot give +legal advice"*. Audit 2 flagged that — "cannot" is a **denial**. Both readings +are correct and they point in opposite directions, because **both sentences make +a claim about capacity**. The third version does not: it states the role and its +consequence for the reader. + +**Defects in my own fixes, all found by measuring the fix rather than reading it:** + +- `:where(.prose) > p + p` is **additive with a flex `gap`** — `/`'s approach + paragraphs went 24px → **48px**. My comment said *"Verified: with `:where()` + the flex container's gap governs and this contributes nothing."* False, and + measured false minutes after being written: `:where()` lowers specificity, + which only matters when two rules set the **same property**. +- The 1440w portrait rung removed a 1.07× upscale and imposed **+27,273 B** on + DPR-3 phones (48,799 vs 21,526). Added 1080; that sample is now 27,594 B and + exact. +- Gating the italic preload behind a new prop and **never setting it on `/`**, + which uses the face in a 96px headline. +- `Pill`'s type fix, twice: `interface Props {}` is rejected by eslint and means + "any non-nullish value" anyway; `Record<string, never>` passes eslint and + rejects `class` **and also rejects `children`**, breaking two real call sites + while the probe page went green on exactly what it tested. +- `.designation-part { white-space: nowrap }` fixed an orphaned separator and + took `/about/` to **108px of overflow at 320px** at a 200% default font size. +- The print override, scoped by class, **missed two elements** and then a third: + `.approach-metaphor`, `.btn-gold`, and — after the token rewrite — the hero + `.btn-primary` at **1.07:1** against white paper, which sits on cream inside no + inverse section at all. + +**The portrait defect was the expensive one, and it was on the shipped home page +too.** Below 66rem the hero is one column, so the portrait is the **full content +width** — 592 to 928 CSS px — while `sizes` declared 52–60vw and the ladder +stopped at 960w. Measured **1.40× upscale at 768/DPR2 and 1.93× at 1024/DPR2**, +identical on both pages, surviving a cleared cache. `/`'s own comment derived the +960 ceiling from the ≥66rem layout: **the range where the image is widest was +never in the arithmetic.** + +**Declined, with reasons:** + +- *"I will tell you whether I am the right neutral for it"* flagged as an unrowed + service commitment. It is a statement about a conversation, not a metric a + slipped date could falsify, and it ships identically on `/`. +- Empty-collection guards on `CREDENTIAL_GROUPS` and `litigationAreas`. Both are + `as const` tuples; neither is reachable without a source edit. +- `Person.hasCredential` currency (Q.Med as `Held`, present tense, on a + `[verified 2026-08-25]` row under a *"currency is not confirmed"* preamble). + The row exists, so it traces. Noted for Pouya rather than resolved. +- The `ContactBand` CTA invites matter details on pages carrying no no-retainer + notice. `docs/03` scopes `NO_RETAINER_NOTICE` to `/contact/`, which is where the + CTA goes. Worth a ruling before the band reaches nineteen pages. + +**Reversed a review finding once, deliberately** — the designation-name +expansions. Audit 1 struck them as §11-Glossary-only; audit 2 then found the page +also publishes *"Provincial Offences Act"*, *"the ADR Institute of Canada and the +ADR Institute of Ontario"* and `recognizedBy`, all on the same footing — +*"one standard or the other."* Standard chosen: **§11 is the source for +definitional expansions; §4 remains the only source for claims about Pouya.** +Sourcing externally was tried and failed — `adric.ca/designations/` redirects and +serves **zero** occurrences of `Q.Med`, `Qualified Mediator` or `Chartered +Mediator` in 114,985 bytes. **Q46(b)** asks Pouya to ratify the standard; if he +declines, all four classes come out together. + +### The third review round, and a process defect of my own + +The code re-review returned **8 more findings**, and it opened with a criticism +of how I ran the loop that is correct and is recorded here rather than softened: +**I edited the tree while it was measuring.** It anchored to SHA-256, re-verified, +and reported that four of the defects it had measured *"were repaired under me +mid-review"* — so its certification covers a snapshot, not the tree, and the +repairs it watched me make **were reviewed by nobody**. `/build` Phase 4 says to +re-review material fixes; it does not say to hold the tree still while a review +is in flight, and it should. Next session: snapshot, review, then fix. + +The four it watched being repaired were all real and all measured: the lost +italic preload on `/`, the 24→48px prose regression, three elements the print +block missed (rasterised from `printToPDF` at 100 dpi: 2.49:1 and 3.96:1 against +white), and dead page-scoped CSS whose compiled selectors carried the old page +cids while the rendered elements carried `ContactBand`'s. + +**Two of the eight were defects in fixes from this same session:** + +- **`/` kept `fetchpriority="high"` while `/about/` withheld it on the identical + measurement.** Portrait visible px: **0 at 320, 0 at 360, 0 at 390**, with LCP + measured as `P.hero-lede` — so the attribute promoted 27–49 KB of image the + reader cannot see above the face that paints the actual LCP element, on the + axis the ≥95 budget is measured on. Removed. `loading="eager"` stays; the + portrait is the LCP element from 768px up. +- **The 1080 rung I added closed the 390px gap and missed the two largest current + iPhones.** 428@3 and 430@3 need 1140/1146 and took **1440 — 48,799 B**, against + 27,594 for the device the rung was tuned for: **+21,205 B, 13% of page weight.** + A 1200 rung closes it at 1.05x. Third iteration of this ladder. + +**And one of my stated reasons was simply wrong about ARIA.** I removed +`role="list"` from the arc `<ol>` on the ground that it *"re-announces an ordered +list as an unordered one"*. It does not — **both `<ul>` and `<ol>` map to the +`list` role**, so on an `<ol>` it is a no-op for ordering. What it is for is the +WebKit heuristic that strips list semantics from a list with +`list-style-type: none`, which `.arc` sets. Restored, and `.arc`'s hand-written +`padding: 0; list-style: none` deleted because `global.css`'s `ol[role='list']` +reset already supplies both. **Not verified: whether WebKit's heuristic covers +`<ol>`.** No Safari instrument here, so the role stays on the precautionary side. + +Also fixed: `ContactBand` shipped `eyebrow?`, `cta?` and a named `heading` slot +with **zero call sites overriding any of them** — the pattern this repo has +already deleted twice, in `Eyebrow` and `SectionHeading`, with the reasons written +into the source. All three gone; the empty `Props` guard stays, because that is +what makes `<ContactBand class="x" />` a build error. `.section-head` moved to +`global.css` (byte-identical in two pages, seventeen to come). `sizes` corrected +in the 66rem–80rem band, where `42vw`/`38vw` described neither track — measured +36.0% and 32.5% — costing up to **1.45x** over-fetch at 1200/DPR 1. + +Two residual over-fetches left deliberately and recorded in the source: 320@2 at +1.18x (no rung between 480 and 640, and 480 would be an upscale) and 1056@2 at +1.26x, where 380.2 x 2 = 760.4 misses the 760 rung **by four tenths of a pixel**. +Declaring 35vw to duck under it would make `sizes` less truthful across the band +for a 0.05% upscale. The declaration stays honest. + +`docs/02`'s reflow table is corrected (65 → **63** px, re-measured) and now +carries an `/about/` row — the first page measured *against* that table rather +than establishing it. It records that `.designation-part { white-space: nowrap }` +was itself introduced as a fix, for an orphaned separator, and created a +**108px** reflow regression at 320px. + +### Register defects the audits found in §4 itself + +`claims-auditor` caught the register answering **its own question 1 with the +subject's words** — twice, the second time inside the paragraph added to explain +the first. The three new Offerings rows carried gating conclusions +(*"no designation is required to give a non-binding evaluation"*) under a +`[verified — Pouya]` stamp, which §4's own box says cannot carry a proposition of +law. Q1 is now `[unestablished]` on all three, the worked example's Q1 column is +emptied, and **Q46(a)** carries it. Nothing publishes on it today; it blocks +`/practice/` at step 5. + +Also: **four documents recorded that `/about/` publishes memberships** after the +page had been changed not to — §9 Q44, §12 R10, `docs/06` and `schema.ts`. And +the widened *"all renew yearly"* survived in three of them plus +**`.claude/agents/claims-auditor.md` itself**, which the auditor found in its own +brief. Third stale claim located inside that file. + +### Verified — measured, not asserted + +``` +npm run check 0 errors / 0 warnings / 0 hints +npm run lint eslint clean; prettier clean +npm run build 2 pages, no errors +npm audit 0 vulnerabilities +grep -rE 'animation:[^;}]*(scroll\(\)|view\(\))' dist --include='*.css' → no match +``` + +- **Portrait ladder: 0 upscaling** — across 24 synthetic samples and then across + **11 real device profiles** on both pages (was 1.40× / 1.93×). Worst oversize + 1.26×, at one viewport, recorded in the source with the reason. +- **`.section-head`: 48 px on all seven wrappers** after the rule moved to + `global.css` — re-measured, because moving a rule that exists to work around + the parent/child scope trap is exactly where that trap recurs. +- **Overflow 0 and 0 over-wide elements** at 13 widths on both pages — elements + measured, not only the document. +- **Contrast: 0 failures** of 127/127/128 painted pairs on `/` and 86/86/88 on + `/about/`, at 390/768/1280. +- **Print, against white paper: 0 failures** of 89 and 48 visible text elements + under print-media emulation (was 1.07:1 on the arc, the contact band and both + CTAs). +- **200% default font size: `/about/` 63 / 23 / 0** px overflow at 320/360/390, + against `/`'s 63 / 23 / 3. The 320/360 residual is the header `A.brand`, which + `docs/02` already accepts. +- **Reveal: 0 of 10 and 0 of 4 hidden** under `prefers-reduced-motion: reduce` + and under print. +- One `<h1>`; outline `h1 → h2 → h3` with no skips; 30 tabbable elements of 37 in + the DOM (the 7 are closed `<details>` contents, correctly untabbable and + correctly ringed when open). +- **Bio: 409 words by my count, 411 by `adversarial-reviewer`'s** (spec 400–600). + The two differ on whether a standalone em-dash is a token; both are inside the + range and neither is presented as the number. It was **385** at first review, + which is the point of measuring it — the source comment then claimed the count + had been verified against *"the verify step of this session's Change Log + entry"*, a document that did not yet exist. +- **Zero `<script>`** other than `application/ld+json`; no `.js` in `dist`. +- **Lighthouse: NOT RUN — tool unavailable** (R11, step 7). +- **HTML validator: NOT RUN.** The duplicate-`1x` srcset conformance error + recorded at step 2 stands; no "validator clean" claim is made. + +### Sweeps — the command, then the output + +``` +$ grep -rni "settlement counsel" . --include='*.md' --include='*.ts' --include='*.astro' +AGENTS.md:293 (§4 scope enumeration — REMOVED from the list, pointer added) +AGENTS.md:567 (§9 Q42 — now ANSWERED, records the strike) +AGENTS.md:3298 (Change Log entry (d) — history, not edited) +docs/07-fees.md:128 → three services, not four +docs/01-architecture.md:235 → struck from the strip, with Pouya's reasoning +src/data/site.ts:236 → FEES.hourly comment +src/pages/index.astro:423 → areas-more comment +``` + +Every live instance struck or converted to an explicit prohibition. A +**whitespace- and blockquote-insensitive** sweep was needed to find them all: a +plain `grep` for `take on faith` returned four hits and **missed `docs/03` +entirely**, because the phrase wrapped across a newline behind a `>` marker — the +positioning statement, i.e. the one that mattered. + +``` +$ (normalised sweep for "all renew yearly" / "/about/ publishes") +→ every remaining match is a QUOTATION INSIDE A CORRECTION, read individually. +$ (rendered-text-only forbidden sweep, printed with context) +→ 4 matches, all read: "a licence question" (software licence, x2), + "I do not act for a party" (the protective negation), "their own legal advice" + (advising the reader to get advice). The `aLSO` / `pLEADINGs` family. +$ grep -rn "law degree on one side" --include='*.astro' --include='*.ts' --include='*.md' . +docs/03-content-spec.md (spec quotation, canonical form) +src/data/site.ts (the constant) +→ one authoring location. +``` + +### Instrument errors caught before acting — six this session + +`CLAUDE.md`'s rule earned its place again. None of these reached a report: + +1. A `<title>` probe using a regex that **cannot match a `<title>` element** → + reported "MISSING" on both pages. +2. A link checker counting `?v=1` query strings as missing files. +3. `/` at 390/DPR1 reading as **2.81× oversized** — an HTTP-cache artefact. + Cleared: 0.90, correct. +4. "**7 focusables with no focus ring**" — closed `<details>` contents, correctly + untabbable, correctly ringed when open. +5. A `<picture>` regex that grabbed the **header's infinity mark** instead of the + portrait, reporting the AVIF ladder as 0 bytes. +6. `/about/`'s print button reading as gold **because print media was emulated + after navigation on one page and before it on the other.** + +And one non-error worth recording: `adric.ca/designations/` really does serve +zero designation names — but only checking the **raw bytes** established that, +because 4,840 characters extracted from 114,985 is the signature of a +JS-rendered shell, not of an absence. + +### Corrections to comments that asserted the opposite of the measurement + +Recorded because the confident ones were the false ones: + +- *"The `<picture>` WRAPPER carries no cid, so it needs `:global()`"* — false. + The emitted markup is `<picture data-astro-cid-ta2fbyqs="true">`, and + InfinityMark's **bare** `picture` selector compiles to + `picture[data-astro-cid-usztftas]` and works. `:global()` dropped on both pages. +- *"The LCP element on this page is the `<h1>` — two words of 96px serif"* — + false twice. LCP at 1280 is `IMG.portrait-img` (229,679 vs the h1's 51,484), and + `--text-5xl` computes to **76px**, not 96. +- *"above the fold at every width"* — false. The portrait is **entirely** below + the fold at 320 and 360, the two widths `docs/02` names. +- *"`--text-meta` on cream measures 3.07:1"* — false, in two files. It is + **5.47:1**; 3.07 is the ratio on **ink**, which is what `tokens.css` says. +- *"the components have had their `class` props deleted so passing one is a build + error"* — false for `Pill`, which had **no `Props` interface at all**, so its + call sites were unchecked. `CLAUDE.md` names `Pill` as the next place the + parent-scope defect will happen; the guard documented as protecting it was + absent on exactly it. +- A comment citing *"the word-count assertion in the verify step of this session's + Change Log entry"* — **which did not exist yet.** The same shape §9's Q39 row + already records as a fair catch. + +### Files + +New: `src/pages/about.astro`, `src/components/ContactBand.astro`, +`docs/reference/lat-case-conference.md`. Changed: `AGENTS.md` (§4, §9, §12), +`CLAUDE.md`-adjacent agent brief, `docs/01`, `docs/03`, `docs/04`, `docs/06`, +`docs/07`, `src/data/{site,schema}.ts`, `src/layouts/BaseLayout.astro`, +`src/components/Pill.astro`, `src/styles/global.css`, `src/pages/index.astro`. + +### Open for Pouya + +**Q44** memberships (blocks the group + `memberOf` + cutover) · **Q45** the PDF +bio · **Q46** (a) ENE / DSD / advisory gating, (b) §11 as a source for +definitional expansions · **Q47** `jobTitle` without `worksFor` · plus +**Q23**, **Q34**, **Q38**. Live reminders: **R1**, **R10**, **R13**, **R15**. + +**Next:** step 4 — `/mediation/`, `/arbitration/`, `/med-arb/`. `/arbitration/` +is where §4's paired-disclosure condition is hardest: it offers all three forms +and must state the Q.Arb stage plainly, *"and neither half may be dropped."* + +## 2026-08-27 (w) — Build step 2: `/` ships. Q35, Q37 and Q39 close, and Q39's answer was that this register had been reasoning from a falsehood + +**Pouya ruled on all five parked items in one message.** Four are implemented +here; R1 is acknowledged and stays live by design. The most important of them +did not confirm this file — it corrected it. + +### Q39 — ANSWERED, and my assertion was FALSE as a universal + +His words: *"My assertion was FALSE as a universal; correct it, then close the +question simply."* He checked rather than defended, against +`ontario.ca/page/training-family-arbitrators`. + +**Family arbitration in Ontario is gated.** Prescribed training: 14 hours on +screening for domestic violence and power imbalances, 30 hours of Ontario family +law for arbitrators outside the Ontario or another Canadian bar, and 10 hours +ongoing per two-year period with five on domestic violence or power imbalance. +**`claims-auditor` produced this counter-example from inside the repo on +2026-08-26 and it was right.** + +**The source is now IN THE REPO** — `docs/reference/ontario-family-arbitration- +training.md`, retrieved 2026-08-27 with its provenance and method. That closes +R14 for the half of the proposition it covers, and §4 now says which half that +is, because the distinction matters more than the citation: + +- The extract establishes the **family** gate **directly**. +- It establishes the **commercial** half only by **absence** — it neither + mentions nor excludes commercial arbitration. A government page about family + arbitrators is not authority for what a commercial arbitrator needs. + +So *"commercial arbitration in Ontario requires no licence and no designation"* +is recorded as **Pouya's stated position, deliberately unstamped**, with the +citation attached to the family half only. **A footnote must not be allowed to +promote the scoped form back into a universal.** + +**What actually disposes of the question is the scope exclusion, not the law.** +Pouya does not do family arbitration. §4 Offerings carries it as **NOT +OFFERED — a scope exclusion, not a gating problem**, so the prescribed-training +requirement never bears on this practice at all. `Shareholder & Family Business` +means commercial disputes among family shareholders; its page must say plainly +that family law matters are not accepted — **one sentence, not a section**, on +his instruction that it earns its place only by saving a wasted intake call. +Recorded in `docs/01` §`/practice/shareholder/` for build step 5. + +### The false universal had survived in three more places, and the grep found them + +Correcting the paragraph that carried it was not the fix. `grep -rn "Anyone may +be appointed"` plus a paraphrase sweep for `No designation is required`: + +``` +$ grep -rn "anyone may be appointed\|Anyone may be\|No designation is required" \ + --include='*.md' --include='*.astro' --include='*.ts' . +AGENTS.md:238 <- my new text, quoting what was struck (correct) +AGENTS.md:313 <- §4 BOUNDARY bullet: "Mediation and arbitration are ungated" FIXED +AGENTS.md:548 <- §9 Q33 closure row, bolded as an assertion FIXED +AGENTS.md:774 <- Change Log entry (v), append-only history (correct) +src/components/SiteHeader.astro:141 <- a live comment in shipped source FIXED +``` + +The §4 instance is the one worth dwelling on: it was in the paragraph headed +**THE BOUNDARY, AND IT IS NOT NEGOTIABLE**, which is the worst place in this +file for an unscoped claim about a class of activity. The boundary paragraph was +breaching its own boundary. + +### Q35 — ANSWERED, all four items, and the answer supplied a gate that was missing + +- **Med-Arb** — *"he holds Q.Med and now accepts arbitration appointments, so + both halves are live. Keep it in the nav. Removing it unilaterally orphaned + the page — restoring it was right."* Now its own §4 Offerings row. It stays in + the footer sitemap; `docs/01` keeps it out of the *primary* nav deliberately + and that is unchanged. +- **The six subject-matter labels** — *"subject-matter labels, already governed + by `docs/03`'s 'positioning, not history'. They pass test 1; test 2 is the + page's job."* +- **THE GATE** — *"Add the publication gate you identified was missing... That + hole is why Med-Arb sat in the footer under a paragraph telling readers not to + infer it."* §4 gains **Subject-matter areas — the publication gate**: a + practice area may be named where (1) he can competently accept an appointment + in that subject matter, and (2) the page frames it as positioning without + claiming history. Condition 1 is about the label; condition 2 is about the + page. **Nothing in the nav or footer is unrowed or ungated any more.** + +### Q37 — ANSWERED. The label changes, and the reasoning is the finding + +`JD + ML` is labelled **"Legal training and engineering practice"**, not "Law and +engineering". Pouya: *"The parallel was doing the implying — a degree and a +practice under one noun. The asymmetry is the honest part."* A JD is a degree; +engineering is a verified practice. Rendering them as two instances of one thing +invited the reader to supply the symmetry, and for "Law" the missing half is a +licence. It is longer and deliberately lopsided; `CredentialRow` carries a +comment telling the next reader not to tidy it back into a parallel. + +### Q38 / R13 — the committed SVG does not close it, and my walk-back went too far + +Pouya: *"Keep it committed, keep the AVIF render path. Your own measurement is +the reason: 257 KB wrapping seven embedded base64 PNGs. It renders faithfully +because it IS the raster. Your first characterisation was accurate and the +walk-back went too far."* Q38 and `docs/02` now hold both halves at once — the +fidelity is real, and it is bought with embedded raster, which is exactly why +fidelity was never the question. R13 stays open. + +### Q32 — Pouya ratifies the reconciliation, and identifies that his own step 3 would have broken the layout + +*"My 1.23:1 was measured from the path's coordinate hull rather than the curve, +and step 3 of my Q32 ruling would have broken the layout had you followed it. +Your reconciliation was right. The tangency was the only sound ground of the +three."* Recorded because a ruling that turns out to be wrong in one of its three +grounds is exactly the thing this file exists to keep visible. +### Build step 2 — `/` ships. Zero JavaScript, and six components + +Eight sections specified in `docs/01` §`/`; **seven are built.** Hero · +credential row · the approach · two processes · six practice areas · process +preview · contact band. New components, all from `docs/02`'s list: `Eyebrow`, +`SectionHeading`, `Pill`, `CredentialRow`, `PracticeCard`, `ProcessStep`, plus +`src/data/schema.ts` for the JSON-LD. + +**Section 7, Latest insights, is NOT built, and that is the only spec item this +page does not deliver.** `src/content/insights/` is empty; the collection, the +`ArticleCard` component and the drafted slate all arrive together at step 7 +(`docs/01` §Build order, D9). Rendering it now means shipping a component's +scoped CSS to every visitor for an empty block, plus a props surface with no +call site — already an open finding against `InfinityMark`. `SiteHeader` gates +the Insights nav item on the same collection, so the page and the nav appear +together. The omission is commented in the page source, not just here. + +**Deviations from spec, each deliberate and each recorded in place:** + +- **The credential row has FOUR slots, not `docs/01`'s three.** §4 Offerings' + paired-disclosure condition is the higher authority and requires the stage of + the arc stated wherever arbitration is offered; `/` says *arbitration + appointments* in its second sentence, so the stage belongs on this page and + not only in the footer. `docs/03` already authorised a fourth slot and now + records that on `/` it is required. +- **No booking link in the contact band**, which `docs/01` item 8 asks for. + Booking is parked (R6) and `CONTACT.bookingUrl` is `null`. Stated, not + silently dropped. +- **The masthead tagline is suppressed on `/`.** It is the same string as the + hero eyebrow, so at ≥76 rem the page opened with the same six words twice — + step-1 review finding #10, left open to "decide at step 2". The hero keeps it + (`docs/01` puts it there and gives it copy underneath to qualify it); the + masthead drops it, because the masthead is the placement Q33-orig objected to. + This only ever removes a claim from one page. +- **The step-1 proof sheet at `/type-scale/` is deleted**, as its own comment, + `InfinityMark`'s comment and `astro.config.mjs`'s sitemap filter all said it + would be. Five live references to it survived the deletion and were found by + `grep`, including §7's Client JS row, which cited + `dist/type-scale/index.html` as the file proving the site ships no JavaScript. + +### R11 at the phase boundary — two pins were stale, one hold was too wide + +Run before writing any code, which is what R11 asks. `astro` **7.2.7 → 7.2.9** +(two patches inside 48 hours). `typescript` **^5.9.3 → ^6.0.3** — a full major +behind and installable. §7 had recorded the TypeScript hold as "held at 5.x", +which was **too wide by a whole major**: 7.0.2 is genuinely blocked +(`typescript-eslint@8.68.0` peers `>=4.8.4 <6.1.0`, `@astrojs/check@0.9.10` +peers `^5 || ^6`), but 6.0.3 is stable and both peers accept it. The row now +names the version, the blocker, and the condition that ends the hold. Committed +separately as `8a2f513` so step 2's verification is not confounded by a +toolchain change. +### What the claims audit found — ten defects, and every one was implication or scope + +`claims-auditor` returned **FAIL**. Not one finding was a fabrication of the kind +the old site carried; all ten were implication, scope, or a fact restated +loosely — *which is exactly where D13 says the risk lives.* All ten are fixed or +escalated. The four highest-value ones: + +- **`I mediate and arbitrate commercial disputes`.** §4 verifies that he + **accepts** arbitral appointments, and separately verifies *"multiple completed + sole mediations"* — **there is no counterpart row for a completed + arbitration.** Present-indicative "arbitrate" beside "mediate" invites the + reader to supply a track record for both. Now offering-shaped: *"I mediate + commercial disputes from Toronto, and I accept arbitration appointments."* The + clean form was already on the same page, in the arbitration card. + +- **The JSON-LD asserted arbitration twice and stated the stage nowhere.** The + visible page satisfied §4's paired-disclosure condition with the fourth + credential slot; the machine-readable graph did not. Both node descriptions + now carry *"the Q.Arb pathway commenced August 2026"*, and `hasCredential` + stays Q.Med-only — the stage belongs in prose, never in a field that means + *holds*. **A crawler-only claim is still a claim**, and this is the first time + the register has had to say so. + +- **`at one published rate with preparation time included` misdescribed money.** + Checked against `docs/07-fees.md`: D14's card sets **two** day rates ($2,000 + half, $4,000 full), so "one published rate" reads as one price for both. And + `docs/07` says in terms that the bundled prep is a **capped** allowance which + *"must be stated on the page — 'including 2 hours of preparation'... Do not + quietly fold it into the hours figure."* A home card is the wrong place to + state it properly and stating it improperly is worse than silence, so the fee + claim is gone from `/` in both places it appeared. "Published" was also + forward-looking: `/fees/` ships at step 9. + +- **`Law and engineering are not blended here`** — Q37's struck parallel, + relocated from the credential label into body copy **one day after Pouya + struck it**, and strengthened by attributing both halves to him personally. + The section now reads *"what the documents say, and what the engineering + says"*: asymmetric, which was Pouya's whole point. The **argument** `docs/01` + and `docs/03` specify is unchanged. Whether Q37 formally reaches prose is his + call — **Q41(a)**. + +Also fixed: *"what else is offered"* asserted four processes with no §4 row +(**Q42**); *"LAT pre-hearing mediation"* was a `docs/01` **search intent** read +as a service (**Q41c**); *"facts most neutrals take on faith"* is an +unverifiable comparative about third parties, replaced with *"the documents +rather than the pleadings"* (**Q41b**); the editorial *"with real timing"* is +gone while the timings themselves stand as specified (**Q43**); and the Q.Arb +noun is now §4's own — *pathway*, not *designation*. + +**And the auditor found a stale copy of a fact in §9 itself.** Q8 still listed +memberships as *"ADRIC, ADRIO, OBA sections"* — **the Canadian Tax Foundation +was missing**, added to §4 on 2026-08-26. A second copy of a fact in a place +nobody re-reads is the failure mode §7's single-source rule exists to stop, and +this is the same shape as the stale enumeration that was found inside +`claims-auditor`'s own brief. Fixed, and rewritten as a pointer to §4 rather +than a second list. It would have bitten at step 3, the first page to publish +memberships. + +### Seven defects I found in my own work before the reviewers reported + +Kept because the pattern in them is the point, not the count. Full list in the +verification section; the three worth reading: + +- **`<Picture widths>` declared the untouched 1600 px master as the `<img src>` + fallback** — 254,626 bytes, for a 476 px slot. Passing `width`/`height` + alongside `widths` pins it to the 960 variant (78,665 B) and the 1600 px file + stops being generated. **The build log hid it completely**: it printed + "before: 349kB" for every variant either way. Found by reading the emitted + `src` and that file's real dimensions. + +- **Naming a prop `as` silently turned off prop type-checking for a whole + component.** `astro check` reported it only as `ts(6196) 'Props' is declared + but never used`, which reads like lint noise. It is not: `<Eyebrow dot as="h9" + bogusProp={1} />` compiled with **0 errors**, while the same probe against the + four other new components produced `ts(2322)` on all four. Renaming the single + identifier to `tag` restored it. **Do not silence a `ts(6196)` with + `Astro.props as Props`** — that hides the warning and leaves every call site + unchecked. + +- **96 px of cream sandwiched between the maroon contact band and the ink + footer.** Found by looking at a full-page screenshot, not by reading CSS. + +### And one alarm of my own that was wrong, in the direction of panic + +Measuring the marks, `img.naturalWidth` came back **64 at every DPR** — which +looks exactly like *the density ladder is not being generated at all*, i.e. a +shipped step-1 defect on the header mark of every page. **It is not.** For an +image chosen from a `srcset` with an `x` descriptor, `naturalWidth` is +**density-corrected**: a 192 px file selected at 3x correctly reports 64. +Ground truth from disk: 64×41, 128×82, 192×123, in all three formats. + +The real defect underneath was smaller and mine: the home page added a **225.5 +px** call site to a component whose ladder was sized for 50 px and 56 px, so it +upscaled 3.52× at DPR 3. `InfinityMark` now takes `width` and `loading`; the +approach mark passes `width={232}` (→ 232/464/696, covering 676 device px) and +`loading="lazy"`, since it sits a screen and a half down. All three instances +now measure ≤1.0× upscale at DPR 1, 2 and 3. + +**That is the fifth time on this project that my own instrument misread**, and +the pattern across all five is the same: a number that looks like a finding, from +a probe nobody checked. `naturalWidth` joins `timeout`, the coordinate-hull +bbox, the worst-deviating-instance filter, and the document-level overflow check. +`CLAUDE.md` gains the general rule. + +### What the code review found — and finding 1 is the same defect for the FOURTH time + +`adversarial-reviewer` returned **fourteen findings, three blocking.** It also +noted that the working tree moved under it mid-review, because the claims fixes +above were being applied while it ran, and it re-verified each finding against +the current tree so it could say which were still live. That is the right +behaviour and it is worth recording as the reason the two reviewers should not +be run against a moving target next time — brief them, then stop editing. + +**1. BLOCKING. `class="section-head"` on `<SectionHeading>` never matched, and +three section headings collided with their content.** + +This is the defect `CLAUDE.md` already records twice under *"A parent cannot +style a child component's root element"*, which then recurred a third time with +`<Picture>` inside `InfinityMark` — and I wrote a fresh warning about it into +`Eyebrow` and `Pill` in this very diff and then did it again in the page. + +The emitted evidence, side by side: + +``` +dist/_astro/index.*.css .section-head[data-astro-cid-lcdefpme]{margin-block-end:var(--space-7)} +dist/index.html <div class="heading-block section-head" data-astro-cid-ypavld2q> +``` + +Measured before the fix: `margin-block-end: 0px` and a **0 px gap** to the next +block on all three call sites — 48 px of intended separation gone. Not merely +tight: `.display` sets `line-height: 0.98`, so the glyphs overflow the line box +and *"Two processes."* sat over the top edge of the Mediation and Arbitration +cards. **`astro check` reported 0 errors and `eslint` was clean**, which is +exactly what `CLAUDE.md` says this failure looks like: no error, no warning, and +the CSS reads correctly in the source. + +**I had looked at a full-page screenshot of this section and passed over it.** +The gap looked plausible because a serif's descender space reads as air. A +screenshot is not a substitute for a computed-style assertion, and the reverse is +also true — three of my own findings today came only from looking. + +Fixed by wrapping each in a page-owned `<div class="section-head">`. Measured +after: **48 px margin, 48 px gap, all three.** And the prop is gone — +`SectionHeading` no longer accepts `class`, so passing one is now a **build +error** rather than a silent no-op. Same deletion applied to `CredentialRow`, +`Pill`, `ProcessStep`, `PracticeCard` and `Eyebrow`, all of which declared a +`class` prop with no call site: five more invitations to the same mistake. + +**2. BLOCKING, already fixed in flight — the mark was upscaled 3.5× on the home +page.** Covered above. The reviewer added the follow-up that mattered: the fix +**invalidated a figure cited as load-bearing reasoning in three places.** +`docs/02` §Components and §9 Q38 both argued *"257,278 ÷ 3,063 = 84×"* against +the committed SVG, and none was updated when a second, larger ladder appeared — +the home page's mark takes **14,555 B** at DPR 2, so the ratio there is ~11×. +That is the SES-DKIM duplication in a new costume: the copy nobody re-reads goes +stale. All three now carry both ladders and the instruction to **quote the size +with the call site, never on its own.** + +**3. BLOCKING, partly fixed in flight — 234 px of horizontal content loss at a +large default font size.** The three `minmax(Nrem, 1fr)` grids were mine to fix +and were fixed; the reviewer then re-measured and found **83 px still going**, +from two elements this diff introduced: + +- `.feature` measured **411 px in a 342 px container** — `padding: var(--space-7)` + is 192 px a side at root 32 px, and `.feature-title`'s min-content did not + shrink because **`overflow-wrap: break-word` permits a break at layout time + but does not reduce min-content size.** Now a clamped padding plus + `overflow-wrap: anywhere`. +- `.contact-action { flex: none }` is `0 0 auto`, so the button could not shrink + below its **425 px** max-content. Now `0 1 auto` with `min-inline-size: 0`. + +**4. The credential row was never "two up on a phone", and its comment said it +was.** `repeat(auto-fit, minmax(11rem, 1fr))` resolved to a **single 342 px +track** at 390 px with all four items stacked and the band ~430 px tall — with +`Q.Arb / Commenced August 2026`, which §4's paired-disclosure condition puts on +this page, at the bottom of it. The arithmetic is not subtle: two 176 px tracks +plus a 24 px gap need 376 px and the container is 342. **A measured-sounding +comment that was false**, which is this project's own named failure mode, written +by me on the same day I added the rule about it to `CLAUDE.md`. + +Now explicit: `repeat(2, minmax(0, 1fr))`, becoming four at 56 rem where four +genuinely fit. Measured after: **2 rows at 320 / 390 / 640 / 768** (band height +296 / 280 / 272 / 260 px, down from ~430), **1 row from 896 px.** + +**5. A §9 row cited a `grep` "in the Change Log" before the entry existed.** Q39 +said so in the present tense while the newest heading was still `(v)` — because +`/build` writes the entry at Phase 6, after review. Fair catch, and the reviewer +independently re-ran the sweep and confirmed it was genuinely complete. Q39 now +names the entry. + +**7. `PROCESS` was hardcoded in the page, against the reason written in +`site.ts` for centralising the practice blurbs.** *"`/` and `/practice/` both +render them and two copies of a claim-bearing sentence is one copy that will +eventually be wrong."* `PROCESS` is the same shape of content, `/process/` +renders the same five steps at step 6, and the staged step-3 body carried the +fee claim the claims audit had just found to be **wrong**. It existed in one +place today and would have existed in two. Moved to `src/data/site.ts`. + +**8. The section-7 omission was recorded only in a comment in the file that +deviates.** `docs/01` was edited in this same diff and not amended. Compare +`SiteHeader`'s sticky-threshold deviation, which was written back into `docs/02` +— the project's own precedent. `docs/01` §`/` item 7 now records it. + +**9. Two of FOUR above-the-fold faces were not preloaded, and the comment said +"the two faces used above the fold".** Network probe on a cold cache: `/` +requests four. The **serif italic** sets `<em class="it">the room</em>` inside +the `<h1>`, and a swap there moves the last line of a 96 px headline — now +preloaded. **Geist Mono** sets the eyebrow, which is the first visible text, and +is deliberately **not**: preloading it puts 95,688 B of font on the critical path +instead of 72,560 B, for one short line of 12 px reflow. A trade, stated as one, +revisited against Lighthouse at step 7. *The reviewer was straight about its own +limit here: throttled to slow 4G + 4× CPU it measured **LCP 896 ms, CLS 0.000** +and could not reproduce a shift.* + +**10. Dead API surface.** `Eyebrow`'s `tag` prop had zero call sites, so its +`<span>` branch was unreachable and the file carried two near-identical +templates for it — deleted, keeping the `as`-naming discovery. `PORTRAIT_ALT` in +`schema.ts` was exported and referenced nowhere — deleted. `SectionHeading` +exposed both a `title` prop and a `heading` slot for one job — the prop is gone. +Five `class?: string` props — gone, per finding 1. + +**11–14, all `consider`, all recorded rather than churned.** The +duplicate-density `srcset` and the `/about/`-404-in-JSON-LD note are now **§7 +rows** so neither is re-discovered as a defect in this repo. The portrait's 1:1 +declaration under a 4:5 crop stays, with its reasoning already in the source and +CLS measured at 0. The named-landmark inconsistency is fixed by **removing** +`aria-labelledby` from the four content sections that have visible `<h2>`s and +keeping `aria-label` only on the credential band, which has no heading — the rule +being *name a region only where it has no heading of its own.* That takes the +region list from eleven entries to six. + +**And one of its findings was wrong, which it said itself.** The reviewer +reported seeing **two** portrait fetches at 390 px / DPR 3, flagged it +low-confidence, and named the likely artefact — `setDeviceMetricsOverride` +applied around navigation. Checked: **one fetch at 390/DPR 1, 2 and 3 and at +1280/DPR 2 and 3**, cache cleared each time. It was the artefact. A reviewer that +states its own uncertainty is doing the job; the answer was to run the probe, not +to dismiss it. + +**What it checked and found clean**, so the gap is auditable: 26 real `Tab` +keydowns dispatched, all 26 focused elements matched `:focus-visible` with a +visible ring, skip link first; **72/72** hit-test points across eight cards +resolved to the card's link; heading outline dumped, 23 headings, no skips; every +computed contrast pair recomputed from scratch including `.approach-metaphor` at +**11.09:1**; zero `client:*` directives and zero non-JSON-LD `<script>` tags; +**41 KB total transfer** cold-cache at 1280/DPR 2 with **zero JS bytes**; zero +`data:` and zero `base64,` in the HTML and CSS; no third-party host; and both +minifier traps re-verified in the emitted CSS. + +### Verification — run, not asserted + +Harness: a zero-dependency CDP driver (Node 22+ has a global `WebSocket`) +against `--headless=new` Chrome, serving `dist/` over `python3 -m http.server`. +Every figure below came from a command whose output was read. + +| Gate | Result | +|---|---| +| `npx tsc --version` | 6.0.3 | +| `npm run check` | **0 errors, 0 warnings, 0 hints** (19 files) | +| `npm run lint` | clean — ESLint + Prettier | +| `npm run build` | complete, 1 page | +| `npm audit` | **0 vulnerabilities** | +| **Lighthouse** | **NOT RUN — tool unavailable.** `@lhci/cli` removed 2026-08-26; R11's re-add trigger is step 7. Stated, not omitted | + +**Zero JavaScript, in the emitted page.** `dist/index.html` carries **1** +`<script>` and it is `type="application/ld+json"`; non-JSON-LD scripts **0**; +`dist/_astro/*.js` no matches. With script execution disabled at the protocol +level: **444 DOM nodes, 6,578 characters of visible text, 5,665 px of content** — +the identical page. + +**Phase 5, the minifier check.** `grep -o 'animation:[^;}]*' dist/_astro/*.css` +returns only `animation:none!important` twice, which is the reduced-motion and +print override. No `animation` shorthand beside `animation-timeline`. Both +longhand blocks survived: `animation-timeline:scroll()` with +`animation-name:header-lift`, and `animation-timeline:view()` with +`animation-name:reveal-in`. + +**Layout, 14 widths (320 → 1920).** Document overflow **0 at every one**, with +zero elements past the viewport. **And the elements were measured, not only the +page** — this is the correction entry (v) owed: every rendered infinity mark +came back at aspect **1.5654–1.5657** against the master's 1.5657, at all 14 +widths. Header **189 px** ≤414, **141 px** 640–1024, **81 px `sticky`** from +1056, matching `--header-h`. + +**Accessibility.** One `<h1>`; heading levels never skipped (outline dumped and +read). Landmarks 1/2/1/1. **Focus order == DOM order** across 44 focusables. +Every `<img>` has `alt` and explicit `width`/`height`; 0 missing either; 0 empty +links. **Contrast: 32 distinct foreground/background/size triples computed from +what the browser actually painted, at 390 / 768 / 1280 px — 0 failures.** Print +media: 0 revealed elements at opacity < 1 (10 targets). Reduced motion: 0 hidden. + +**Touch targets, and the instrument mattered here.** The eight cards report +26–39 px-tall `<a>` boxes and are **not** a finding: hit-testing nine points per +card at three widths put **9/9 inside the link on all 24 cards** — the whole card +is the target via `::after { inset: 0 }`. Two standalone paragraph links **were** +real at 18 px tall and are fixed. One inline link (164 × 21) is deliberately left +under WCAG 2.5.8's sentence exception. + +**Reflow, and one case that is not clean.** Page zoom passes: 1280 at 200% is the +640 column and at 400% is the 320 column, both 0 overflow, so WCAG 1.4.4 and +1.4.10 are covered. With the reader's **default font size** at 200% (root 32 px — +not page zoom) `/` started at **234 px** of overflow at 390 and came down in +three measured steps to **3 px at 390 and 65 px at 320**: the three +`minmax(Nrem, 1fr)` grids guarded with `min()`, then `.credentials` made +explicit, then `.feature`'s padding clamped with `overflow-wrap: anywhere` on its +title and `.contact-action` allowed to shrink. **`overflow-wrap: break-word` +permits a break at layout time but does not reduce min-content size** — +`anywhere` does, and that was the whole of one fix. The residual is the header's +deliberate `flex-wrap: nowrap` above 66 rem (**602 px** at 1280) plus +`white-space: nowrap` on the brand name and the headline's 104 px floor; undoing +either re-opens the measured step-1 header decision, so they stand. Beyond what +`docs/02`'s floor requires, since page zoom is clean — a robustness margin, not a +failure. The table is in `docs/02`. + +**Payload.** HTML **27,334 B** · CSS **26,572 B** (linked, over the 4 kB inline +threshold) · hero portrait AVIF **5.6 / 7.3 / 11.1 / 14.8 / 21.5 kB** across five +widths, `<img src>` fallback now the 960 variant at **78,665 B** · mark AVIF +**1,720 / 3,063 / 4,843 B** at 64 px and **6,017 / 14,555 / 22,639 B** at 232 px +· fonts ~50 kB preloaded. **JS 0 B** against a 100 kB budget. + +**Not verified, and named as such.** Lighthouse (above). **The HTML validator was +not run, and the page carries a known conformance error:** 4 of 12 `srcset` +attributes declare two candidates at 1x, because Astro's `densities` emits +`url, url 1x, url 2x, url 3x` and a descriptor-less candidate is implicitly 1x. +Harmless in browsers; step-1 review finding #8, still open. **Do not claim +"validator clean".** *(And my first check of it reported "ok" — it compared +`undefined` against the string `'1x'`.)* + +### Sweeps — the commands, not the claims (R8) + +``` +$ grep -rn "anyone may be appointed\|Anyone may be\|No designation is required" \ + --include='*.md' --include='*.astro' --include='*.ts' . + -> 5 hits: 2 correct (my new text quoting the struck line; entry (v) history), + 3 FIXED (§4 boundary bullet, §9 Q33 row, SiteHeader comment) + +$ grep -rn "Med-arb\|med-Arb" --include='*.astro' --include='*.ts' --include='*.md' . + -> 1 hit, FIXED (index.astro:313 -> Med-Arb, the form §4 and docs/01 use) + +$ grep -rn "Law and engineering" --include='*.md' --include='*.ts' --include='*.astro' . + -> label FIXED in site.ts + docs/03; the PROSE instance on / is reworded and + the two spec instances (docs/01:136, docs/03:150) are Q41(a) for Pouya + +$ grep -rn "type-scale\|proof sheet" ... | grep -v dist + -> 5 live references to the deleted page, all FIXED (§7 Client JS row, + robots.txt, docs/05, brand-assets.md, InfinityMark.astro). Change Log + entries (u) and the struck Q33-orig row keep theirs — append-only history + +$ grep -cEi 'OCNI|Law Society|LSO|testimonial|Since 20|London|New York' dist/index.html + -> 1, and it is a FALSE POSITIVE: "I aLSO practise". Case-sensitive: 0 + +$ grep -cEi 'leading|premier|top-rated|best|proven|guarantee|extensive' dist/index.html + -> 2, both FALSE POSITIVES: "the pLEADINGs" twice. No superlative on the page + +$ grep -cE 'LegalService|worksFor|priceRange|aggregateRating' dist/index.html + -> 0 +``` + +### Superseded + +**Entry (v)'s "⏸ RESUME HERE" section is spent.** All five items it listed as +awaiting a ruling — Q35, Q39, Q37, Q38/R13, R1 — were ruled on 2026-08-27 and are +handled above. Its six non-blocking review findings: **#7 fixed** (`--text-2xs`, +`--space-05`, `--focus-offset` added), **#8 still open and now measured** (4 of 12 +srcsets; see Verification), **#9 unchanged** (`--header-h` has 0.81 px of +headroom), **#10 fixed** (the masthead tagline is suppressed on `/`), **#11 +unchanged** (~3.16 MB of brand binaries), **#12 fixed, and by deletion rather than by +use** — `InfinityMark`'s `class` prop is **removed**. It had no call site and +`class:list` put it on the `<img>`, so a parent writing +`<InfinityMark class="foo" />` would have got a rule compiled against the +parent's cid that never matches: the exact defect `CLAUDE.md` records twice on +this project, offered as an API. `label` stays with its reason written down (all +three current call sites are decorative; the next one may not be), and `width` +and `loading` are new and used. Entry (v) is not edited; this is where the +state lives now. + +--- + +## 2026-08-26 (v) — The mark was wrong; §4 gains an Offerings category; and two of my own tools lied to me + +**Who:** Pouya ruled on the mark (Q32), on arbitration (Q33, Q36), and on the +asset convention. Claude Code implemented; `adversarial-reviewer` and +`claims-auditor` ran on the result. **The claims audit returned FAIL with 13 +findings, and the sharpest of them were against text written an hour earlier in +this same entry's work.** Most of what follows is those findings. + +### Q32 — the infinity mark was a wrong shape, and it had shipped + +Pouya rendered the committed path against the master and rejected it. Two of his +three grounds reproduce from the path alone and are now verified here: + +- **TANGENT, NOT CROSSING.** All four cubic branches meet the origin at exactly + 90°, so the loops are mutually tangent on a vertical line rather than crossing. + At stroke-width 28 that renders as **two kissing circles** — the one thing an + infinity mark must not be `[verified 2026-08-26 — tangent vector computed per + segment]`. This alone disqualifies the shape. +- **WRONG PROPORTION.** The master's ink bounding box is **2668 × 1704 = + 1.5657:1** `[verified 2026-08-26 — measured]`. +- **FLAT.** Two uniform strokes standing in for a shaded ribbon: a band of + variable width twisting in three dimensions, maroon into champagne, passing + over itself at the crossing. + +**The 1.23:1 figure is reconciled, and it was a real measurement.** It is the +bounding box of the path's **coordinates**, not of the **curve**: control points +sit at y = ±160 where the curve reaches only ±120, so the coordinate hull is +400 × 320, and with stroke-width 28 on all four sides **428 × 348 = 1.2299**. +Pouya's number exactly. It is a trap rather than a slip — x is monotone on every +segment, so the control points give the *right* width and a 33% inflated height, +and the usual "does the width look right?" check passes. + +Two consequences worth keeping. **The direction was inverted:** measured from the +curve, the traced path is 6.4% *wider* than the master, not squatter. And the +declared viewBox 440:280 = 1.5714 sits within **0.35%** of 1.566 — so step 3 of +the ruling, re-tune the layout to the true aspect, was **0.18px of work at the +shipped 2rem**, and re-tuning to 1.23 would have *broken* it: for any +given width, 1.2299 allocates 1.5657/1.2299 = **27% more height** than the mark +actually occupies, so the header would have been rebuilt around a box a quarter +too tall. Where 1.566 does matter is step 2: a tight crop to ink is +exactly the measurement where 1.667 and 1.566 differ visibly, which is why the +render source is cropped to the master's ink box and pinned at `667 / 426` rather +than inheriting 11:7. **The ratio was never sufficient grounds on its own. +Tangency was, and it is exact** — both lobes are confined to their own +half-plane, so the signed crossing number is 0, and at 2rem the strokes fuse into +a single mass across 61% of the mark's height. + +**The traced path is deleted, not kept as a fallback**, on Pouya's instruction: +*a wrong mark that renders is worse than a missing one, because it stops looking +wrong.* `public/favicon.svg` deleted with it; the favicon chain is regenerated +from the real artwork. + +### Why two review passes could not catch it — and the rule that follows + +`InfinityMark.astro` carried a scrupulous provenance comment stating that the +path was traced from the **old site's loading placeholder** and that a +placeholder is not necessarily canonical. It was correct, it was prominent, and +**it did not help**, because the artwork it would have to be checked against was +not in the repository. The doubt was stated and structurally uncheckable. + +**New rule in `CLAUDE.md`, and R14:** *anything a spec makes a claim about must +be reachable from the repository.* If the artefact lives only in Drive, in a +console, or on a laptop, the claim is **unverifiable by construction**, not +merely unverified. Second occurrence — Q24 was `AWS-Hosting-Guide.md`, the only +record of how the infrastructure was built, living outside the repo. + +### Two process failures of my own, both in the same shape + +1. **I reported the brand assets unreachable. They never were.** Four commands of + the form `timeout 60 ls "$DRIVE"` returned empty output; I read that as an + empty directory and told Pouya the ruling could not be executed. **`timeout` + is not installed on macOS** — the commands had never run. The Drive was fully + readable the whole time and the masters were found within a minute of using a + tool that exists. +2. **I reported malformed HTML** — `<picture="true">` and + `style="block-size:2rem"="true"` — and rewrote a component around it. It was + **my own regex**, stripping an attribute's name and leaving its value. The + markup was always valid. The rewrite was reverted. + +Both are the same failure as *a sweep is a command, not a claim*: an assertion +resting on output that was never produced, or was produced by my own filter. +**New rule in `CLAUDE.md`:** *a command that did not run is not evidence of +absence* — check the tool exists, read exit status, not just stdout. + +### What the mark is now + +`src/assets/brand/` holds the master (3000 × 3000, alpha), the tight crop that is +the render source (2668 × 1704, so **the file's aspect ratio is the mark's**), +the full lockup, and the SVG Pouya added. `InfinityMark.astro` renders it through +Astro's `<Picture>`; a browser downloads **3,063 bytes** of AVIF on a Retina device. + +**Correction inside this entry.** The SVG was first described here and in three +files as "a raster in a vector wrapper". That was unfair: rasterised at 8333 px +it **reproduces the master exactly, at the same 1.566:1** `[verified 2026-08-26]`. +What rules it out is **payload and composition** — 257,278 bytes against 9,468, +plus seven embedded base64 PNGs that would breach `CLAUDE.md`'s no-base64 rule. +Corrected in the component, `docs/02`, Q38 and `docs/reference/brand-assets.md`. + +**`width={320}` on `<Picture>` is load-bearing.** Without it Astro emits the +untouched 2668 px master as the `<img src>` fallback — **1,146,406 bytes** — sitting +in `dist` looking like an optimisation had happened. + +**Documented, temporary exception to `docs/02`'s "inline SVG, never a PNG"**, +tracked as **Q38** (a vector master that is faithful *and* light) with **R13** so +it cannot become permanent by neglect — Pouya's own warning when he made the +ruling. + +### Q33 and Q36 — arbitration, and a new §4 category + +**Both answered: Pouya accepts arbitration appointments now** — sole, +party-appointed and co-arbitration. His reasoning: ADR designations are +**voluntary credentials, not licences**, so the constraint was always +**positional**, never legal. `Mediation · Arbitration · Toronto` is **restored to +the masthead**; `docs/04`'s home `<title>` stands as specified. + +**§4 gains an Offerings subsection** — a second category beside the credential +register, with the test: **competence for an offering, permission for a +credential.** Three specs that asserted the converse were swept +(`docs/01`, `docs/03`, `docs/07-fees.md`) — and that sweep had been *claimed* in +the Q36 closure before it was *run*, which `claims-auditor` caught. `docs/03`'s +model sentence was wrong in **both** halves and in opposite directions, which is +why it had survived two audits. + +### What the claims audit found in the new section, and how it was resolved + +Four structural defects in text written the same hour: + +- **The masthead justification answered the wrong objection.** Q33-orig had + objected to **placement** — a line under his name on every page *"where nothing + qualifies it"* — not to entitlement. The section refuted an entitlement + objection nobody raised. Corrected, and the substitution is recorded rather + than tidied away. +- **§4's own paired-disclosure condition was unmet by the shipped build.** The + section says the site *"makes the first while stating the second plainly"* and + *"neither half may be dropped"* — yet the masthead shipped on every page while + the Q.Arb stage shipped on none, and `CREDENTIALS.inProgress` existed in + `site.ts` rendered nowhere. **The footer designation strip now reads + `Q.Med (ADRIC / ADRIO) · Q.Arb — commenced August 2026` on every page.** +- **The offering test handed the gating question to the subject.** Its closing + sentence, *"that is his call, not the register's"*, attached to the whole + preceding question including *whether the activity is gated* — a clean + walk-through for a future writer. Split in two: **gating is this register's + question and needs a checkable source; competence is his and only his.** +- **The category had no gate and no defined extent.** No rule said an offering + needs a row before it may be published, and `Med-Arb` was sitting in the + site-wide footer as an offering three sentences below a paragraph saying not to + infer exactly that. Both fixed: the publication rule is stated, scope is + defined (**an offering is a PROCESS; a subject-matter area is not**), and + **Med-Arb is removed from the footer pending Q35(a)**. + +**And the finding that matters most: four unsourced propositions of Ontario +law.** *"Anyone may be appointed an arbitrator in Ontario. Nothing in law gates +the role behind a designation."* `[verified — Pouya]` means *the subject reported +it*, which can establish what he offers and **cannot establish a proposition of +law**. The auditor produced a counter-example from inside the repo: the site +ships a **Shareholder & Family Business** practice area, and **family** +arbitration in Ontario is understood to be one of the places where arbitrator +qualification *is* prescribed. §4 now carries the proposition as **the +architect's stated basis, deliberately unstamped**, scoped to **commercial** +arbitration, with the universal removed — and **Q39** opened. This record will +not assert Ontario law, and neither will a self-report. + +### Questions and reminders + +**Closed:** Q32 (the reconstruction was wrong), Q33, Q36. +**Narrowed:** Q35 — `Arbitration` resolved; **Med-Arb** and the two +subject-matter labels remain, now under the scope note that says which rule +governs them. +**Opened:** **Q38** (vector master), **Q39** (family arbitration and gating). +**§12:** **R13** (the raster is temporary), **R14** (assets must be in-repo). + +### Verification — run, not asserted + +`npm run check` 0/0/0 · `npm run lint` clean · `npm run build` 0 errors · +`npm audit` **0 vulnerabilities**. + +Measured in headless Chrome at 320/375/640/768/1000/1023/1024/1100/1199/1200/1201/1279/1280/1281/1440/1600, +**with a seventh nav item injected** for the step-7 state: + +- **0 overflow, 0 focus-order inversions, 0 tap targets under 44 × 44** at every + width; closed `<details>` panels contribute 0 hidden tab stops +- Header a constant **81px** at every sticky width — 32 padding + 48 reserved + brand block + **the 1px border I had forgotten**, which is why `--header-h` is + measured rather than added up +- Restoring the tagline **broke the 64rem fit** (84px past the content box at + 1024 with seven items) and was re-tuned: tagline gated at 75rem, nav gap moved + to **80rem so two things do not grow at one breakpoint** — 4px of spill at + exactly 1200px caught that +- **0 `<script>` tags, 0 `.js` files**; both scroll-driven animations attach live +- Print: all four revealed cards present · **760 words** with no JavaScript + +### ⏸ RESUME HERE — session ended mid-flight, 2026-08-26 + +Pouya went mobile. The tree is committed and green; nothing is half-applied. +**Pick up at the numbered list below.** + +**State:** `npm run check` 0/0/0 · `npm run lint` clean · `npm run build` 0 +errors · `npm audit` 0 vulnerabilities. Both `adversarial-reviewer` blocking +findings on the mark are fixed and re-measured. Build step 1 is complete; step 2 +is `/` (`docs/01` §Build order). + +**Waiting on Pouya — nothing proceeds on these without a ruling:** + +1. **Q35** — may the nav and footer name `Med-Arb`, `Energy, Grid & Regulatory` + and `Shareholder & Family Business`? Both halves go to him **together**; + `Med-Arb` was removed from the footer for a few hours and restored, because + acting on one half unilaterally was wrong and orphaned the page. +2. **Q39** — family arbitration. §4's arbitration rows are scoped to + **commercial** pending an answer. This one has a legal dimension the register + cannot resolve from a self-report. +3. **Q37** — is `JD + ML → "Law and engineering"` the right label? Answer before + step 2 renders the credential row. +4. **Q38 / R13** — the commissioned vector master. Until it lands the mark ships + as a raster under a documented exception. +5. **R1** — the licensure framing is interim and now carried by shipped pages. + +**Unresolved review findings, all non-blocking, none shipped-defect:** + +- `adversarial-reviewer` #7: `gap: 2px` and `font-size: 0.6875rem` in + `SiteHeader` are magic numbers; add `--text-2xs` / `--space-05` or record the + deviation. +- #8: Astro's `<Picture>` + `densities` emits a duplicate `1x` descriptor in + `srcset` — an HTML conformance error, harmless in browsers. Do not claim + "validator clean" on a page carrying it. +- #9: `--header-h` has 0.81 px of headroom at ≥76 rem. A font-metric change + pushes the brand past its 48 px reservation with no build error. +- #10: the masthead tagline duplicates the home hero eyebrow, so `/` will open + with the same words twice. Decide at step 2. +- #11: ~3.16 MB of brand binaries; the 1.1 MB derived crop is reproducible from + the committed master and could go if Astro could crop at build time. +- #12: `InfinityMark`'s `label` and `class` props have no call site. + +**One correction owed to the record.** Entry (v)'s verification section says +"0 overflow at every width". That was true and **misleading** — the page-level +check passed *because* the brand block absorbed the deficit by crushing the +logo. The harness now asserts the rendered aspect ratio of every mark instance, +not just document overflow. Measure the elements, not only the page. + +### Declined and deferred + +- **The remaining Q35 labels** — locked architecture; not an implementer's call. +- **A verification workflow was run and half of it was wasted, which is worth + recording rather than hiding.** It was launched while the artwork was believed + unreachable, and briefed accordingly; the premise died four minutes later when + the assets were found. Its *design* strand — three proposals for coping without + the artwork — was answered by reality and discarded. Its *geometry* strand did + not depend on that premise at all, and it is what **reconciled 1.23:1** above, + proved the zero crossing number, and computed the fused-waist figure. The + lesson is not "don't delegate" but "scope a brief to what cannot change under + it": a premise about the environment goes stale, a question about the contents + of a committed file does not. +- **`Technology, AI & Data` and the other three practice labels**, raised as + offering claims with no rows: answered structurally rather than individually — + subject-matter areas are **not** offerings, so the Offerings table is not the + rule that governs them. `docs/03`'s framing rule and Q35 are. +- **`docs/reference/brand-assets.md` reproducing R14** — the auditor was right + that every measurement derived from a master outside the repo. **Fixed, not + declined:** the uncropped master is now committed, so the crop is re-derivable + in-repo, and every figure carries a stamp. + +--- + +## 2026-08-26 (u) — Build step 1. Zero JavaScript, and both review passes found defects in the first pass's fixes + +**Who:** Pouya ruled on CTF, Q30, Q31 and the Lighthouse gap, and set the +direction for step 1. Claude Code implemented under `/build`; +`adversarial-reviewer` and `claims-auditor` each ran **twice**, and the second +pass is where most of this entry comes from. + +### What Pouya decided + +- **Canadian Tax Foundation membership** added to §4 and to + `CREDENTIALS.memberships`, `[verified 2026-08-26 — Pouya]`, **for now** — it + renews yearly, so **R10 was widened** from "OBA section membership" to + "annually-renewing memberships" covering both. +- **Not a seventh practice area at launch.** CTF is a credential none of the six + areas touch and tax-adjacent disputes are ADR territory, but there is no track + record to point at. Recorded in `docs/01` beside the Indigenous-engagement + omission, and **R3 widened from one candidate to two** — one month 12–18 + review, two questions. +- **Q31 CLOSED — Plausible**, decided rather than defaulted. Pouya checked and + found his own assumption wrong: Fathom is Canadian-owned but stores non-EU + traffic on US servers, isolating in the EU only for EU visitors; Plausible + holds everything in the EU. **D15 amended** from "Plausible **or** Fathom" to + Plausible, with that reasoning and with Fathom recorded as rejected on data + residency rather than on quality. +- **Q30 CLOSED — SML Company Ltd is incorporated FEDERALLY, under the CBCA.** + Two facts were being conflated and one was wrong: `site.ts` carried + `'SML Company Ltd. · Ontario, Canada'`, which reads as a jurisdiction of + incorporation and named the wrong one. Jurisdiction of incorporation is + federal; place of business is Toronto, Ontario; they are different facts. + **Neither is published** — the footer reads `© <year> SML Company Ltd` and + stops, on Pouya's direction given twice. No corporation number: none is held + and none is needed. §4 carries the caution that "federally incorporated" says + nothing about licensure and nothing about where the practice may operate, and + must not be read together with the **Licence status — NOT ESTABLISHED** row + into an implication neither makes. +- **The Lighthouse gap, ratified and closed as a documented-control problem.** + Removing `@lhci/cli` was right — seven high-severity advisories for a tool + that could not run — but it left `docs/04`, `CLAUDE.md` and `/build` Phase 5 + all requiring a check that had silently become impossible. That is Q22's + defect in a different costume. The unavailability is now stated in **six + places**, listed in §7, and `adversarial-reviewer` is told **not** to raise the + absence as a finding. **R11 carries the re-add trigger** for step 7, including + "check for a patched release; do not assume `0.15.1` is still the ceiling". + +### What shipped + +`src/layouts/BaseLayout.astro`, `src/components/{SEO,SiteHeader,SiteFooter,Button,InfinityMark}.astro`, +`public/fonts/` (six cuts), `public/favicon.{svg,ico}`, `public/apple-touch-icon.png`, +and a temporary proof sheet at `/type-scale/` 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. The design system had +never once rendered as specified. Six cuts committed, **123,804 bytes** (not the +136 K `du -sh` reports — that is disk blocks, and §7 is read in a performance +context), provenance and SIL OFL licences in `docs/reference/fonts-provenance.md`. +Every URL carries `?v=1` because the deploy script serves `/fonts/*` `immutable` +for a year and no invalidation reaches a browser cache. + +**The infinity mark was recoverable, and is not a redrawing.** The deployed site +serves its own loading-thumbnail SVG labelled `smlMark`; `InfinityMark.astro` is +that path verbatim, with the source's `translate(60 0)` folded into the +coordinates. Stroke widths (28/6) and the 0.7 inner opacity are the source's. +Geometry verified to fit its viewBox with 6 units of margin, so it cannot clip at +any size. **Q32 opened** — a loading placeholder is not necessarily the canonical +file, and D7 says the mark carries over *unchanged*. + +**The proof sheet computes rather than restates.** It reads `tokens.css` at build +time and runs the WCAG luminance formula over it. All eleven ratios reproduce +`docs/02`'s measured table exactly — 16.81, 11.75, 12.29, 8.95, 5.47, 3.11, 2.10 +on cream; 16.81, 11.09, 8.00, 3.07 on ink. It cannot drift from the tokens +because it is derived from them. + +**Insights is gated, not hardcoded.** `docs/01` keeps the section out of primary +nav until two pieces are live, so `SiteHeader` reads the collection count at +build time. It does not render today and appears by itself at step 7. + +### Decisions taken during implementation + +- **ZERO JavaScript, not "minimal".** 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, and a per-build hash drifts from the + policy pinning it. Replaced with `animation-timeline: view()` behind + `@supports`. **0 `<script>` tags and 0 `.js` files in `dist/`.** `docs/02` + §Motion amended: the `IntersectionObserver` route is now ruled out, not merely + second choice. `docs/05` gained the converse note — inline `style=` attributes + are now load-bearing, so hashing `style-src` would collapse the infinity mark. +- **Header sticky from 64rem, not `docs/02`'s "sticky".** Measured: the one-row + header must hold brand + **seven** nav items + CTA, which it does at 1024px + with 32px clearance and not below. Below 64rem the nav takes its own row and + the header is 137px (tablet) / 185px (phone) — more of a small viewport than a + sticky header is worth. `docs/02` amended with the measured numbers. +- **"Condenses on scroll" is now a rule and a shadow, not a size change.** A + `position: sticky` header stays in normal flow, so shrinking its padding + shortens its layout box at the top of the document and lifts every page below + it — a scroll-linked layout shift on every page, against the CLS < 0.05 budget. +- **`--section-y` corrected.** `6vw + 2rem` reaches its own upper bound only at a + 2133px viewport, so the "160px desktop" half of `docs/02` was never delivered + (measured 108.8px at 1280, 128px at 1600). Now `9vw + 1rem` — 160px at 1600px. +- **The measure is opt-in.** A global `p { max-inline-size: 68ch }` capped every + paragraph in every card and footer, forced components to opt back out, and made + `.prose` a class with no effect. Moved onto `.prose`. +- **`robots.txt` disallows nothing.** `Disallow` + `noindex` on the same path + cancel out: a crawler forbidden to fetch a URL never reads the `noindex`. The + legal pages are footer-linked from every page, so the pair would likely have + produced bare-URL listings with the suppressing directive unread. `docs/04` + amended. + +### What the reviews found — including in each other's fixes + +**Round 1 — code (5 blocking, 7 should-fix).** All fixed and re-measured: +the `animation` shorthand silently collapsed by Lightning CSS (dead in every +production build, alive in dev); a seven-item nav that fit at no width; parent +styles that never reach a child component's root in Astro; gold text shipped at +**1.76:1**; 27 touch targets under 44px; revealed content printing blank; a skip +link landing behind the sticky header; 72px of overflow at 320px masked by +`body { overflow-x: hidden }`. + +**Round 1 — claims (FAIL, 8).** The masthead tagline `Mediation · Arbitration · +Toronto` — never specified for the header, and unqualified `Arbitration` beneath +a name reads as a held capability against §4's Q.Arb row. Removed; **Q33 opened** +for the form the question takes at step 2. A four-stage service timeline and two +unverified assertions about the previous build, both removed from a page that +exists to demonstrate CSS. + +**Round 2 found defects in round 1's fixes — four of them.** + +1. **The minifier bug was written back into its own fix.** Having just diagnosed + that `animation:` beside `animation-timeline` gets folded into an invalid + declaration, the replacement reveal used the same shorthand. Caught only + because the print test still failed. Both are longhand-only; + **`/build` Phase 5 now greps `dist` for it** and `CLAUDE.md` carries the rule. +2. **The claims fixes were silently lost.** The patch applying all four aborted + on a later assertion *before* writing the file, having already reported four + successes. The service timeline was still in the source and still in the + build. +3. **The colour-alone fix used the banned pairing.** Nav state was given a gold + underline so colour would not carry meaning alone — gold on cream is 2.10:1, + below WCAG 1.4.11's 3:1 for a state indicator, so it carried nothing and the + state reverted to colour alone. Now maroon at 12.29:1, 2px, dotted for section + and solid for current page. +4. **`--header-h` was stamped `[measured]` before anything was measured.** It + said 4.75rem. Actual is **77px** at every sticky width, six items and seven. +5. Plus: a retracted "470 KB PNG" figure surviving in a file written the same + day; two "measured" comments giving 34px and 14px for the same measurement; + `docs/02` amended to a 60rem threshold the code no longer used; flex `order` + putting focus order out of step with visual order between 640 and 1023px. + +**Round 2 — claims (FAIL, 10).** The most serious was inside the review +apparatus: **`.claude/agents/claims-auditor.md` said "Memberships. ADRIC, ADRIO, +OBA sections **only**"** — contradicting a §4 that had gained CTF that morning. +It would have flagged a verified membership as unverified and would not have +noticed CTF being dropped. That file has now hosted a stale claim **twice**, so +the list was not updated — it was **removed**, replaced by an instruction to read +the §4 row at audit time. Also fixed: two specs instructing a public phone onto +pages against a §4 row that records none (Q3, answered four entries ago); a +`robots.txt` reproduced inline in `docs/04` that had already drifted; Q.Arb +described as "in progress" where §4 pins "commenced August 2026"; and headline +option 3 struck as asserting party, counsel *and* neutral. + +**`ROLE` added to `site.ts`** — there was no constant for *"Director of Firm +Operations"* or *"active litigation exposure"*, the two highest-risk strings on +the site, and both were headed for hand-typing at step 3 and in the `Person` +JSON-LD. `npm run check` then caught a temporal-dead-zone error in that fix. + +### Declined, with reasons + +- **The nav and footer naming `Arbitration`, `Med-Arb`, `Energy` and + `Shareholder`** — raised on both claims passes. Every one is locked + architecture (D5, §6, `docs/01`), and §4 registers claims about Pouya rather + than enumerating service lines. Removing them is not an implementer's call. + **Opened as Q35** so the judgement is visible rather than missed. +- **Inlining critical CSS.** `docs/04` names it, but the bundle is 22.5 KB + against a 4 KB `inlineStylesheets: 'auto'` threshold; inlining it into all + nineteen pages costs more than the one round trip it saves and destroys + cross-page caching. Revisit at step 11 against real Lighthouse numbers. +- **Simplifying `PRACTICE_SLUGS` / `PRACTICE_AREAS`.** A fair simplicity finding, + but it touches the content schema a prior review round hardened, and rewriting + it as a rider on step 1 is exactly how defects 1 and 2 above happened. + Deferred to its own change before step 7. +- **The sitemap 404.** `<link rel="sitemap">` removed as inert (it is not a + registered link relation and no crawler consumes it); the `robots.txt` + `Sitemap:` line resolves at step 2. **Step 1 is not deployed** — no deploy + credential exists (Q22) and deploys are manual. +- **Second-person copy on the proof sheet.** `docs/03` bars it on counsel-facing + pages; an internal proof sheet is not one, and the page is deleted at step 2. + +### Verification — run, not asserted + +`npm run check` 0/0/0 · `npm run lint` clean · `npm run build` 0 errors · +`npm audit` **0 vulnerabilities** · **R11 dependency sweep: 13 of 14 pins at +registry `latest`**, the only drift being the deliberate `typescript` hold. + +Measured in headless Chrome across 320/375/640/768/900/1000/1023/1024/1100/1200/1280/1440/1600, +**with a seventh nav item injected** to test the step-7 state that does not exist yet: + +- Header **77px, one row, sticky** at every width ≥1024 with six items and seven; + 137px static below; **0 overflow at every width including 320px** +- **0 tap targets under 44×44** at any width +- **0 focus-order inversions** (`checkVisibility`-filtered); closed `<details>` + panels contribute **0** hidden tab stops +- State indicators **12.29:1**; `--section-y` reaches exactly **160px at 1600px** +- `scroll-padding-top` computes to **93px** = 77 + 16, matching `--header-h` +- **0 `<script>` tags, 0 `.js` files**; both scroll-driven animations attach live + (`header-lift`/`scroll()`, `reveal-in`/`view()`) +- Printed to PDF: all four revealed cards present (they were absent before the + print override) +- **755 words** of body text from `curl` with no JavaScript — the old site + returns three + +### Sweeps — the commands, not the claims (R8) + +``` +$ grep -rE 'animation:[^;}]*(scroll\(\)|view\(\))' dist --include='*.css' + (no output) + +$ grep -rn "OBA sections only" . --exclude-dir={node_modules,.git,dist,.astro} + .claude/agents/claims-auditor.md:58:enumerate "ADRIC, ADRIO, OBA sections only"; the Canadian Tax Foundation was + (the sole hit is the note recording its removal) + +$ grep -c '<script' dist/type-scale/index.html -> 0 +$ find dist -name '*.js' | wc -l -> 0 +$ grep -c "Mediation · Arbitration · Toronto" dist/type-scale/index.html -> 0 +``` + +The `470 KB` sweep is the one worth recording as a near-miss: after retracting +the figure from `docs/02`, `grep -rn "470 KB"` found it **still asserted in +`src/components/InfinityMark.astro`, a file written the same day**. Without the +grep this entry would have claimed a completed retraction. Three previous entries +made exactly that mistake. + +### Questions + +**Closed:** Q30 (federal, CBCA), Q31 (Plausible). +**Opened:** **Q32** (canonical vector for the infinity mark) · **Q33** (how +arbitration is described in one-line site-wide copy before Q.Arb) · **Q34** +(whether §2's measurements of the previous build still hold — a re-fetch found +zero `base64,` occurrences, but the real application is in nine unfetched +bundles, so this is a question and not a correction; §2 now carries the caveat +inline, and `CLAUDE.md`, `docs/02` and `adversarial-reviewer.md` all cite it +where they quote the figure) · **Q35** (may the nav name a service the register +does not establish) · **Q36** (is co-arbitration work available now — asserted in +three specs, in no §4 row) · **Q37** (is "Law and engineering" the right label +under `JD + ML`). + +**§12:** R3 widened to two candidates, R10 widened to all annually-renewing +memberships, R11 given the `@lhci/cli` re-add trigger. **R1 remains live and was +surfaced** — nothing in this change describes Pouya as licensed or as a legal +professional, and the header tagline that triggered Q33 is verified absent from +`dist`. + +### Commit shape + +Split in two on `adversarial-reviewer`'s own recommendation: instructions that +narrow a reviewer's scope should not travel in the same commit as the work that +reviewer is checking. The `.claude/` changes go in their own `chore:` commit so +the narrowing reads as a decision rather than as a line in a feature diff. + +--- + +## 2026-08-26 (t) — Astro 5 → 7. The review found a defect in the fix, twice + +**Who:** Pouya approved the upgrade and set the version-pin rule. Claude Code +implemented under `/build`; `adversarial-reviewer` and `claims-auditor` both ran +and both failed the first attempt. + +**This entry resolves the escalation left open at the end of entry (s).** That +entry recorded the upgrade as *proposed, not done*; it is done now. + +### D1 amended — the major is pinned, not inherited + +Old → new: *"Astro, static output"* → **"Astro, static output, v7.x"**, with the +reasoning in the decision itself so the next reader knows the version was chosen. + +Pouya's own account of the original pin, recorded at his instruction: `^5.0.0` +was **recalled, not checked, and was two majors stale on the day it was +written.** That is a different failure class from the sweep problem in entries +(l) through (o) — not a change that failed to propagate, but a fact asserted +that one command would have settled. + +Verified with `npm view`, and the staleness was not confined to Astro: + +| | was pinned | registry `latest` | +|---|---|---| +| `astro` | `^5.0.0` | **7.2.7** | +| `@astrojs/mdx` | `^4.0.0` | **7.0.8** — three majors | +| `eslint` | `^9.0.0` | **10.9.1**; npm flags 9.x deprecated | +| `sharp` | `^0.33.0` | 0.35.4 | +| `@lhci/cli` | `^0.14.0` | 0.15.1 | + +**The rule is now in `CLAUDE.md`**: a version pin is verified against the +registry, never recalled. **R11** requires re-checking currency at every phase +boundary in the build order — ten remain. + +A caveat the rule needs, learned here: **verified does not mean latest.** +`typescript` 7.0.2 exists and is unusable — `typescript-eslint` peers `<6.1.0` +and `@astrojs/check` peers `^5 || ^6`. `@eslint/js` latest is 10.0.1, but on +ESLint 9 it must track 9.x exactly. The check tells you the number; you still +have to know why you chose it. Both holds are now recorded in §7 so the next +agent running R11 does not re-derive them or break the build discovering them. + +**The rule was then not applied to its own manifest**, which the second review +caught: `eslint-plugin-astro` was left at `^1.3.0` while §7 asserted a hold at +1.7.0, and `typescript` at `^5.7.0` against an installed 5.9.3. Both re-pinned. +Every one of the twelve pins is now verified against `npm view`. + +### The migration + +Astro 5 introduced the Content Layer API and `src/content.config.ts`; **Astro 6 +removed the legacy `src/content/config.ts` fallback**. Verified by moving the +file back and reproducing `LegacyContentConfigError` — an earlier draft of this +entry attributed the move to Astro 6, which `claims-auditor` caught as a version +fact recalled rather than checked, *in the change that raised recalling-versions +to a rule.* + +`type: 'content'` → `loader: glob(...)`, `z` from `astro/zod`. `schema: ({ image +}) => …` still works — verified, not assumed. + +**An empty build proves nothing**, so a throwaway page and article exercised +`getCollection`, `render(entry)`, `entry.id`, MDX rendering, the `image()` +helper resolving to a hashed asset, and sitemap emission at `/sitemap-0.xml` +with no trailing-slash conflict. Then deleted. + +### `compressHTML` — held at `true`, and the first rationale was wrong + +Astro 7 changed the default to `'jsx'`. I asserted this would eat spaces in +prose, measured **MDX**, and found no difference — the premise was unsupported +as written. Measuring the `.astro` path instead: + +``` +'jsx': <em>inline</em><strong>pair</strong> ← space silently deleted +true: <em>inline</em> <strong>pair</strong> +``` + +Real hazard, wrong file. `adversarial-reviewer` reproduced both outputs +independently. The comment now names `.astro` templates specifically and records +that MDX is unaffected, so nobody inherits the original claim. **R12** makes the +deviation revisitable only with a measurement. + +### What the review caught — seven defects in the fix itself + +**Both reviewers, independently:** two source files cited *this entry* before it +existed. Current Truth had been rewritten in place with no append-only record, +and `astro.config.mjs` pointed at it as the authority for a measurement. Rules +1–3 of this file's own constitution, broken in the change that adds a rule about +not recalling things. Writing this entry is the fix. + +**`z.coerce.date()` turned a plausible typo into 1970.** Reproduced: unquoted +`publishDate: 20260801` — valid YAML, the obvious slip for `2026-08-01` — coerces +from epoch milliseconds to **1970-01-01** with no error, and would ship as +`datePublished` in the article's JSON-LD and sort the piece last in a +reverse-chronological index. The reviewer also tested my justification for the +coercion and found it false: plain `z.date()` accepts unquoted YAML dates fine. +Replaced with a bounded union — `z.date()` or an ISO-shaped string — which +accepts both real forms and rejects numbers. + +**The title bound made the SEO spec unsatisfiable.** `docs/04-seo-spec.md` puts +50–60 characters on the *rendered* `<title>`, whose pattern is +`"<headline> · Pouya Lajevardi"`. The suffix is 18 characters, so applying 50–60 +to the headline guaranteed a rendered title of **68–78** — over the spec's own +ceiling on every article — while `.min(50)` hard-failed the build on a good short +headline (`"What Med-Arb Actually Is"`). The schema now enforces the *rendered* +length, adds an optional `seoTitle` override, and reports the computed title in +the failure message. `docs/01-architecture.md` updated to match. + +**An article could ship an image with no alt text** — `image` and `imageAlt` were +independently optional, and the schema is the only gate that exists before the +`/insights/` route is written. Now coupled. + +**Two comments asserted controls that did not exist**: "every piece must link to +a practice-area page" (`.min(1)` checks a *declaration*, not a link) and "an +article with `draft:false` and `reviewedByPouya:false` is a bug" (nothing +enforced it). The second is now true — a refinement fails the build. All four +invariants were then tested, each with a failing and a passing case; each fires. + +**The schema diverged from two specs** — `docs/01` and `docs/02` both specify +`topics[]` plural and `readingTime`; the collection had singular `topic` and no +reading time. Pre-existing, carried through a wholesale rewrite without notice. +Fixed to the specs. + +**`eslint.config.js` imported two undeclared packages**, one resolving by +hoisting accident: `globals` was 14.0.0 at the root against 16.5.0 nested under +the Astro plugin, so which major linting used depended on npm's hoisting. + +### The second review pass found six more, four of them in the first round's fixes + +The loop requires re-review after material fixes, and this is why. + +**`frontmatterDate` accepted impossible dates** — the fix for the 1970 defect +introduced its own. The regex was unanchored at the end and nothing checked the +parsed result, so `2026-13-45` and `2026-08-01 nonsense` both **passed**, each +producing an `Invalid Date` bound for `datePublished` in the article's JSON-LD; +and `2026-02-30` silently rolled over to **2026-03-02** — a wrong date shipped +with no error, which is worse than a failed build. The comment claimed it +accepted "both real forms and nothing else." Now anchored, date-only, parsed as +UTC and **round-tripped** so the day that comes back must be the day written. +A time component is rejected rather than guessed at: quoted +`2026-08-01T10:00:00` parses as local time while the unquoted YAML form parses +as UTC, so the same frontmatter would mean different instants on a laptop and on +a CI runner. + +**The title rule rejected all five planned launch articles.** The arithmetic was +right and the rule was still wrong. Every headline in `docs/03-content-spec.md`'s +launch slate is 50–67 characters; with the ` · Pouya Lajevardi` suffix they +render at 68–85 and **5 of 5 fail**, making `seoTitle` mandatory on every article +— a second title field to hand-keep in sync forever, on the highest-volume +content type. Two specs contradicted each other and the schema enforced one. +Resolved by making articles the documented exception: **an article's headline is +its `<title>`, with no suffix.** Under that rule 4 of 5 launch headlines pass and +`seoTitle` is a genuine exception. `docs/04-seo-spec.md` — which owns the title +rule and had not been swept — now states it. + +**`PRACTICE_SLUGS` and `PRACTICE_AREAS` could drift silently.** Splitting one +derived source into two literals bought back the literal types but lost the +guarantee: deleting an area while leaving its slug declared passed `astro check` +cleanly, so an article could name a practice area with no page, no nav child and +no chip. My first completeness check was written as a conditional type and +**did not fire** — verified by deleting a row and getting 0 errors. Replaced with +an `AssertNever` constraint that does: a missing area now fails with +`ts(2344)`, and a typo'd slug fails with `ts(2820)` plus a "did you mean". +Zero runtime cost. + +**Three narrower schema gaps**, each reproduced: `imageAlt: " "` passed, so an +image could ship with a whitespace-only accessible name — the exact thing the +coupling check exists to prevent; duplicate `topics` and `practiceAreas` passed +and would render duplicate pills; and `seoTitle` was bounded *and* re-checked, +so one mistake produced two errors. Trimmed, de-duplicated, and the field bound +dropped so the refinement is the single check. + +**`scripts/deploy-local.sh` claimed to do "EXACTLY" what CI does.** It did not: +the workflow guards six values, the script guarded four, and the workflow runs +`npm run check` before building while the script ran neither check nor `npm ci`. +A local deploy — currently the **only** way this site ships, since Q22 and Q23 +are open — was skipping the type and template gate. Guards brought to parity, +`npm run check` added, and the claim rewritten to name the two remaining +differences instead of denying them. + +**Sweep misses:** `README.md` stated an engines floor of `>=22.12.0` after +`package.json` had moved to `>=22.13.0` for ESLint 10 — a duplicated version fact +of exactly the kind §7 exists to prevent, now replaced with a pointer. +`package-lock.json`'s root `engines` still carried the pre-bump value because the +bump was made without reinstalling. `engines.node` was described as "the +intersection of every dependency's floor" and was not one — `>=22.13.0` admits +Node 23.x, which ESLint 10 excludes; it now reads `^22.13.0 || >=24`. +`eslint.config.js` still called itself an "ESLint 9 flat config", and +`.gitea/workflows/deploy.yml` still carried the Gitea version as `[assumed]` +after Q23 verified it as 1.27.2. + +**Three claims in `src/data/site.ts` bound for public pages**, all pre-existing +and all found by `claims-auditor`: `entity: 'SML Company Ltd. · Ontario, Canada'` +asserted a jurisdiction of incorporation §4 does not verify (**Q30**); +`provider: 'plausible'` was a guessed value where D15 records the choice as +undecided, in a file whose own header says not to guess one to make the build +pass (**Q31**); and `NO_RETAINER_NOTICE` was missing the third element +`docs/01-architecture.md` requires — that submitting the form does not itself +create a conflict check. The notice is fixed; the other two are nulled with +`TODO(pouya)` and numbered. + +**One finding declined.** `claims-auditor` reported that no build order exists in +the repository and that R11's "ten more boundaries" was therefore untraceable. It +does exist — `docs/01-architecture.md` §Build order, eleven numbered steps. The +audit grepped lowercase `"build order"` and missed the capitalised heading. R11 +now carries the file and section so the next reader does not repeat the search. + +### Declined, with reasons + +**Accessibility linting is ON, and I was wrong about it twice.** +`adversarial-reviewer` recommended `eslint-plugin-astro@3.1.0` for the +`eslint-plugin-jsx-a11y` peer. I tested that upgrade, hit ERESOLVE (v3 requires +`eslint >=10` *and* peers `jsx-a11y >=6.10.2`, whose latest peers `eslint ^3..^9`), +and concluded it was "not installable" — recording in §7 that +**"there is no automated accessibility linting"**. + +Wrong the first time: **the already-installed `eslint-plugin-astro@1.7.0` ships +36 `jsx-a11y/*` rules and a `flat/jsx-a11y-recommended` config.** I had tested a +different upgrade path and generalised its failure to the capability. The stale +peer range is a *declaration*, not a runtime incompatibility. + +Wrong the second time: having added a one-line `overrides` entry to fix that +declaration, I retested v3.1.0 — **and it installs cleanly.** The ERESOLVE was +never about v3; it was about the missing `overrides`. So the plugin is now on the +current major, not held two behind, and there is no stale pin left in the +manifest except `typescript`, whose hold is forced by peer ranges. + +Verified by execution at each step — rules fired on a deliberately inaccessible +`.astro` file: `html-has-lang`, `alt-text`, `heading-has-content`, +`click-events-have-key-events`, `no-static-element-interactions`, +`no-noninteractive-tabindex`, `tabindex-no-positive`. Those are the checks +`docs/02-design-system.md` §Accessibility floor names. + +One cost, recorded rather than discovered later: v3.1.0 declares +`node ^22.22.3 || ^24.16.0 || >=26.3.0`, which **excludes Node 25.6.0** — so +`npm install` prints EBADENGINE on Pouya's machine. Dev-time only; `nvm use` +clears it, and `.nvmrc` already says 22. + +This mattered more than the ERESOLVE did. **§7 is the single source of +operational truth, and it carried a false capability claim on the eve of the +step that writes every landmark, heading and focus state**, under a CLAUDE.md +rule that accessibility is a build requirement rather than a polish pass. + +**`@lhci/cli` advisories carried, not fixed.** All ten remaining findings trace +to it alone; 0.15.1 *is* `latest`, so there is no clean upgrade, and +`npm audit fix --force` installs `@lhci/cli@0.1.0` — a fourteen-minor downgrade, +which is not a fix. Dev-only, never on the CloudFront origin. + +**Two `Consider` items taken rather than deferred**, both in files already being +edited: `image.service` was dead configuration (it set Astro's own default) under +a comment describing a convention it did not enforce — deleted, convention stays +in `CLAUDE.md`; and `sitemap({ lastmod: new Date() })` stamped every URL with the +build time, telling crawlers all 17 pages changed whenever one did, which spends +the signal `docs/04-seo-spec.md` wants. Removed, with step 7 named as the place +to reinstate it per-entry from `updatedDate`. + +**Two `Consider` items declined:** the six extraneous `@img`/`@emnapi` packages +are cosmetic and `npm ci --dry-run` is clean; and no `.npmrc` with +`engine-strict` was added — the engines floor is a declaration, and making it +fatal is a decision with its own blast radius. + +### `npm audit` — the actual result, and it is now zero + +``` +after the upgrade: 10 vulnerabilities (2 low, 1 moderate, 7 high) + npm audit --omit=dev: found 0 vulnerabilities +after removing @lhci/cli: found 0 vulnerabilities +``` + +**Every Astro advisory is cleared** — zero findings against `astro`, +`@astrojs/mdx`, `@astrojs/sitemap` or `sharp`. `adversarial-reviewer` confirmed +the rationale independently by installing `astro@^5.0.0` in a scratch directory +and reproducing **8 high-severity advisories, 6 of them distinct XSS**. + +`npm ls` traced all 10 residual findings to `@lhci/cli` alone. It was first +carried as acceptable dev-only risk; on the second pass that was reconsidered +and it is now **removed**. The reasoning: 0.15.1 *is* `latest`, so there was no +clean upgrade; `npm audit fix --force` would install `@lhci/cli@0.1.0`, a +fourteen-minor downgrade; and the tool **cannot run at all today** — no pages, +no `lighthouserc`. Carrying seven high-severity advisories for an unusable tool +is not a trade worth making when deferring it to step 7 costs nothing. Recorded +in §7; R11 forces a fresh pin when it returns. + +**A discrepancy with entry (s), stated rather than quietly dropped.** Entry (s) +recorded 16 vulnerabilities and attributed the high-severity set to Astro ≤ +7.0.9. After the upgrade the high count was still 7, all from `@lhci/cli` — so +(s)'s attribution cannot have been right as written. (s) is append-only and +stands; this is the correction. What is verifiable now is the audit output +above. + +### Verification + +Run, not asserted: `npm run check` (0 errors, 0 warnings, **0 hints** — three +`ZodIssueCode is deprecated` hints appeared mid-change and were fixed to the +string literal), `npm run build`, `npm run lint` (ESLint clean, Prettier clean). +`npm audit` and `npm audit --omit=dev` as above. `npm install --dry-run` for both +candidate lint upgrades. Each of the four schema invariants exercised with a +failing and a passing article. A deliberately broken `.astro` file linted to +confirm the plugin is live under ESLint 10. `node -v` → v25.6.0. + +Not run: Lighthouse (removed — see above), the no-JavaScript render check (no +pages), link resolution (no pages). Those belong to build step 1 +(`docs/01-architecture.md` §Build order), which entry (s) began and which +continues after this. + +**Still open:** Q23 (runner registration — needs the second administrator), R6. +**Standing reminders surfaced at the start of this build:** R1 (licensure — the +layout about to be written is what carries it), R9 (the SES alarms still notify +nobody until the `ses-alerts` subscription is confirmed), R6, R10. + +--- + +## 2026-08-26 (s) — Q22/Q23/Q27/Q28 answered; toolchain installed; build step 1 begun + +**Who:** Pouya answered four questions mid-session and corrected one earlier +instruction. Claude Code implemented and started build step 1. + +### Q22 — ANSWERED, and the answer is that it does not exist + +`aws iam get-user --user-name adr-sml-deploy` returns **`NoSuchEntity`**. §7 now +carries **Deploy credential — NOT PROVISIONED**, and it is a **to-do** rather +than a question: the creation commands are with Pouya. Swept by command; no file +describes the credential as existing. + +**Pouya has been authenticating as `user/pouya`** — the broadly-permissioned +personal user the Q10 inventory captured. Recorded in §7 as interim, and in §10 +as a **High** risk: fine at an interactive keyboard, never as a CI credential. +`scripts/deploy-local.sh` **refuses to run** if `sts get-caller-identity` returns +that ARN, so the rule is enforced rather than merely written down. + +### Q23 — correction: the version is verified, and the blocker is a person + +**Old → new:** entry (r) recorded the Gitea version `[assumed]` on Pouya's +instruction. It is now **1.27.2** at git.larsnolden.com +`[verified 2026-08-26 — /api/v1/version]`, comfortably above the ~1.21 floor for +the `vars` context. The first-step guard is therefore belt-and-braces rather than +load-bearing — which is the right outcome: it was built so the answer would not +matter, and now it does not. + +**What remains is not a fact to look up.** The instance is **jointly +administered**, so enabling Actions in `app.ini` and registering an `act_runner` +both depend on a second administrator. Q23 is rewritten to say so. + +**So the local path is documented, not treated as a workaround.** +`npm run deploy` → `scripts/deploy-local.sh` (new) performs *exactly* what the +workflow performs: same guard, same three sync passes in the same order with the +same cache headers, same invalidation. At this scale the pipeline changes only +**how a deploy is triggered**, not what it does. `docs/06` leads with it, and +both files say the script and the workflow are one artefact in two places. + +### §10 — a new risk that changes what the IAM policy is for + +The deploy secret will live in a repository on **jointly-administered +infrastructure**, where an instance admin can generally reach repo secrets or +register a runner that receives them. That is inherent to how Actions runners are +fed credentials, not a flaw in this setup, and it does not change the plan. + +It changes the **reading** of the scoped policy. Four actions, one bucket, one +distribution is no longer hygiene — it is the actual control standing between a +shared Gitea instance and an AWS account holding another business's +client-database backups. §10 now says so, and says that any request to widen it +is a security decision rather than a convenience one. + +### Q27 and Q28 — answered, and both are facts with obligations attached + +**Q27 — two business days.** In `src/data/site.ts` as `responseTime`, with a +derived `responseTimeShort` so the confirmation email cannot drift from the page. +Added to §4 Verified as a **public commitment** that must read identically on +`/contact/`, in the inquirer email, and in any bio. `docs/05` says to render it +from `SITE`, never retype it. Swept for the superseded "one business day": no +occurrences. + +**Q28 — OBA Construction & Infrastructure, ADR, and Civil Litigation** +`[verified 2026-08-26 — Pouya]`, **for now**. §4's row and `site.ts` both carry +the "for now". Section membership renews yearly, so this is a fact with a shelf +life — **R10** added, with OCNI as the precedent: §4 already records it as +lapsed and not publishable, which is exactly this failure arriving a year late. + +### Build step 1 — started + +**Dependencies installed; `package-lock.json` exists.** That alone closes a +blocker documented since entry (m): `npm ci` had no lockfile, so the CI pipeline +could not get past its first step. + +**`npm run check` and `npm run build` both pass** — 0 errors, 0 warnings. Worth +recording because entry (m) F6 asserted both would *fail* on an empty +`src/pages/`. `adversarial-reviewer` doubted that and was right: `astro build` +emits zero pages and exits 0. **Correcting it here rather than editing (m).** + +**ESLint and Prettier are now wired**, closing the "not yet wired" rows: + +- `eslint.config.js` — flat config, `js.configs.recommended` + + `typescript-eslint` + `eslint-plugin-astro`. **`typescript-eslint` added as a + devDependency** because `.astro` frontmatter *is* TypeScript and the plugin + cannot parse a component without it. Deliberately not type-aware: `astro check` + already type-checks, and running both would be slower and would disagree at the + edges. +- `.prettierrc.json` — 80 columns, single quotes, `prettier-plugin-astro`. +- **`.prettierignore` excludes `*.md` and `src/styles/tokens.css`, deliberately.** + Prettier's reformat of `AGENTS.md` alone is an **892-line diff** with no reading + benefit, and it collapses the aligned comment column in `tokens.css` that lets + the measured contrast ratios be scanned down the page — the one thing that file + exists for. Both exclusions carry their reason in the file. + +`npm run lint` now passes clean. `npm run lighthouse` remains unwired, and now +honestly so: there are no pages to measure. + +**`npm audit` reports 16 vulnerabilities (7 high) — not fixed, flagged.** The +high-severity set is Astro ≤ 7.0.9 (XSS via `define:vars`, spread attribute +names, `transition:*` values, slot names; SSRF in a prerendered error page) plus +transitive `esbuild`/`sharp`, and a `cookie` advisory reached only through +`@lhci/cli`. `npm audit fix --force` wants **Astro 7.2.7, a major upgrade**, and +`@lhci/cli@0.1.0`, a catastrophic downgrade. Most of the Astro advisories need +authoring patterns this project does not use (no server islands, no +`define:vars`, no view transitions, static output, no spread props yet). **This +needs a deliberate decision, not an automated fix** — see the escalation below. + +### Escalated + +**Astro major upgrade.** The project pins `astro@^5.0.0`; the advisories are +fixed in 7.x. Doing it now, before any pages exist, is far cheaper than doing it +after — there is nothing to migrate. Doing it later means shipping on a +known-vulnerable major. This is a D-series decision (D1 names Astro but not a +version), so it is yours. + +### Verification + +`npm run check` — 0 errors, 0 warnings, 5 files. `npm run build` — completes, +0 pages, as expected. `npm run lint` — ESLint clean, Prettier clean. +`bash -n scripts/deploy-local.sh` — syntax OK. `node --check astro.config.mjs` — +OK. `package.json` re-parsed as JSON after editing. Sweeps run as commands with +output read: `adr-sml-deploy` (no file claims it exists), `one business day` (no +occurrences), operational identifiers in `docs/*.md` (no matches). + +**One error of mine, caught by my own sweep and recorded rather than quietly +fixed:** the three new §7 rows initially landed in the **§3 decisions table**, +overwriting D15's label, because the anchor I matched on (`| Analytics |`) +appears in both sections. The `adr-sml-deploy` sweep surfaced it. §3 is restored +— `git diff` over the decisions table is empty — and the rows are in §7. An +anchor that is not unique is not an anchor. + +**Closed:** Q22, Q27, Q28, and the version half of Q23. **Still open:** Q23 +(runner registration — needs the second administrator), R6 (parked). **Added:** +R9 (SES subscription pending), R10 (OBA renewal). + +--- + +## 2026-08-26 (r) — Q19 closed; SES monitoring recorded; §7 made the single source of operational truth + +**Who:** Pouya closed Q19, supplied the monitoring configuration, ruled on Q29, +and made the structural call below. Claude Code implemented. + +### Q19 — CLOSED. Nothing now blocks `/contact/` + +**Production access granted** in `ca-central-1`, confirmed by AWS in writing, +effective immediately. §7's SES account row and §9's Q19 both record it; §10's +**High** risk row for the sandbox is struck as resolved. + +The per-region trap is kept in §7 as a **standing caution rather than an open +task** — it was avoided, and it applies again to any future SES request. Deleting +the row would delete the lesson. + +### Monitoring exists, and one part of it does not work yet + +Recorded in §7 (the facts) and `docs/05-backend-spec.md` (why it matters): + +- **SNS topic `ses-alerts`**, `ca-central-1`. The email subscription to + `info@smlcompany.ca` is **PENDING CONFIRMATION**, stamped that way deliberately. + An unconfirmed SNS subscription **drops every message**, so as things stand the + alarms below fire into nothing. That is now a cutover checklist item in its own + right, checked with `sns list-subscriptions-by-topic` rather than assumed. +- **`SES-BounceRate-High`** (≥ `0.03`) and **`SES-ComplaintRate-High`** + (≥ `0.001`), both `ca-central-1`, `treat-missing-data: notBreaching`. +- **Bounce and complaint handling is SES email feedback forwarding** — the + default — **not an SNS feedback topic**, deliberately. Under 100 messages a + month there is nothing to consume a programmatic feed, and an unused topic is + one more thing to keep correct. Revisit when code needs to *act* on a bounce: + suppression lists, retry logic, marking a record undeliverable. + +`docs/05` records why these are a real control rather than a formality: **SES +suspends sending above roughly a 5% bounce rate, and at this volume five bounces +crosses it.** An intake form is exactly where mistyped addresses arrive. The +alarms sit well below that line so there is room to react. + +### The structural fix — §7 is the single source of truth for operational facts + +**Old → new.** Specs in `docs/` carried their own copies of resource IDs, +regions, DNS records, and service state. They now **cite** §7 instead. + +The reasoning is entry (q)'s DKIM inversion, generalised: the same operational +fact lived in §7 and in `docs/05`, a correction reached one of them, and the +stale copy ended up instructing an operator to delete the three records that +authenticate outbound mail — under the heading "Never delete". Same class as the +D3 amendment surviving three sweeps. **A duplicated fact is a fact that will +eventually be wrong in one place, and the copy that goes stale is the one nobody +re-reads.** + +The rule is now in `CLAUDE.md` under Conventions, with that incident as its +stated reason so it is not softened later by someone who does not know the cost. + +**Swept.** `docs/05` no longer restates the DKIM token sets, the DNS records, the +MX, the region, or the table name — it cites §7 and keeps only the two facts it +*depends* on, stated as dependencies. `docs/06` no longer restates the region, +bucket, distribution ID, intake endpoint, or account ID; its variable table now +points at §7 rows, and the IAM substitutions say explicitly that they are not +repeated and why. Verified by command: + +``` +grep -rn "ca-central-1\|adr-smlcompany-site\|E1OK7G98KNKUTA\|4tl0m5igkj\|327082975128\|adr-intake-submissions\|d26v23dhgsp2ta\|jkddzztszm" docs/*.md +``` + +Output read: **no matches.** Every operational identifier in `docs/` is now a +reference. + +### Q29 — the guard is widened on both counts + +Both gaps `adversarial-reviewer` found are closed: + +- **`AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` are guarded.** By Q22 nobody + has confirmed the IAM user or its key exists, so an unset key is the single + likeliest first-run failure — excluding it defeated the guard's stated purpose. + **Only emptiness is tested and no value is ever echoed**, so nothing can leak + into a run log. +- **`INTAKE_ENDPOINT` promoted to job-level `env:` and guarded.** An empty one + does not fail a build; it **ships a live contact form posting to nothing**. A + silent production defect is worse than a failed build. + +The build step still reads `${{ vars.INTAKE_ENDPOINT }}` rather than the `env` +context — depending on Gitea's expression-context support is the exact thing the +guard exists not to do. Coverage checked against every `vars.*` and `secrets.*` +the workflow consumes: all guarded except `BOOKING_URL`, which is empty by +decision (R6). + +### Also done + +**`docs/06`: the account ID is out of the backup-bucket callout**, pointing at +§10 instead — the same removal entry (m) made in `README.md`. Operational +usefulness does not outweigh pairing a live account number with a statement about +what the account holds, in a file that gets pasted around. The billing check now +derives the account from `sts get-caller-identity` rather than hard-coding it. + +**`astro.config.mjs`: `prefetch` removed entirely** — recorded here as a decision, +not a silent deletion. *Any* prefetch setting ships Astro's prefetch script to +every page, against CLAUDE.md's "default to zero JS", for a marginal gain on a +small static site already served from CloudFront. **Revisit only against real +Lighthouse numbers**, once pages exist to measure. Entry (q) had set it to +`hover`; that was still JS on every page. + +**Gitea version stays `[assumed]`** at Pouya's direction — he is running the +check. The guard is designed not to need the answer. + +### Verification + +The widened guard's `run:` block was **executed** under `sh -e` across four input +states — all set, all empty, secret empty, intake empty. Exit 0 only when +everything is present; exit 1 naming exactly the missing items otherwise; no +value printed in any case. `node --check astro.config.mjs` passes. The +duplication sweep was run as the `grep` above and its output read — no matches. + +`npm run lint`, `check` and `build` still **cannot run**: `node_modules` is +absent and `npm ci` needs a lockfile. Installing dependencies is the first +concrete task of build step 1. + +**Closed:** Q19 (and with it the last blocker on `/contact/`). **Still open:** +Q22 (deploy credential), Q23 (runner registration), Q27, Q28, R6 (parked). +**Q29 closed by implementation.** + +--- + +## 2026-08-26 (q) — Guard built; and the audit found an inverted DKIM table that would have broken production mail + +**Who:** Pouya ruled on entry (o)'s escalations, ratified R7, promoted R8, and +reversed his own F5. Claude Code implemented, ran `claims-auditor` and +`adversarial-reviewer` in parallel, and resolved 31 + 17 findings. + +### The six rulings, implemented + +1. **Q23 hardened, not checked.** `.gitea/workflows/deploy.yml` now runs a guard + as `steps[0]` — before checkout, before `npm ci`, before any AWS call — that + fails the run naming any of `AWS_REGION`, `S3_BUCKET`, + `CLOUDFRONT_DISTRIBUTION_ID` that is empty. It tests the env names + (`AWS_DEFAULT_REGION`) and reports the **Gitea variable** names, which is the + mapping most likely to be got wrong. `adversarial-reviewer` executed the + extracted block under `bash -e`, `sh -e`, and `bash -euo pipefail` across + all-unset / all-set / one-empty / whitespace-only and confirmed it fails + closed and is POSIX-clean. +2. **R7(3) dropped** — the `aws s3 ls` pre-flight is out; the guard supersedes it. +3. **R7(1) ratified** — the cache table stays matched to the pipeline. +4. **R7(2) reasoning corrected.** Old → new: "the intended cover is an S3 + lifecycle rule" → **no lifecycle rule exists and is not the cover**; the cover + is that `aws s3 sync` only goes multipart above 8 MB. Corrected once more + after audit: the figure now measures **what is uploaded**, with + `src/assets/pouya-lajevardi.jpg` at 357,627 bytes `[verified — stat]` as the + largest source asset and an instruction to re-measure `./dist` after the first + build. The old wording measured the repository, which is not what syncs. +5. **R8 promoted to a rule** in `CLAUDE.md`, `/build` Phase 6, `/wrap` step 3. +6. **R1 put in the conditional** — there is no site; `src/pages/` is empty. + +### The finding that mattered most was nowhere near the diff + +**`docs/05-backend-spec.md` had the two SES DKIM sets exactly inverted.** It +labelled `3zsn…` / `jejgp…` / `xpiwy…` "**Live.** Matches SES exactly. Never +delete", and `f5pu…` / `jdue…` / `kznn…` "Orphans from an earlier verification. +Inert." §7 records the opposite, `[verified 2026-08-26 — DNS]`: the `f5pu` set is +the one that **resolves** and backs the healthy `ca-central-1` identity; the +`3zsn` set is NXDOMAIN and belongs to a stray `us-east-1` identity. + +Entry (j) corrected this. **The correction reached §7 and never reached +`docs/05`.** An operator tidying DNS from that table deletes the three CNAMEs +that make SES DKIM work — and since SES has no custom MAIL FROM, DKIM is the +*only* thing satisfying DMARC. Outcome: intake mail from `ca-central-1` starts +failing authentication, silently, and the table said "Never delete" over the +wrong three records. Both rows rewritten from §7. The "six CNAMEs" claim below +them now says three, which is how many answer. + +### Current Truth was stale in three more places + +**§7 SPF and DMARC still read "ABSENT"** `[verified 2026-08-26]`, and §10 still +carried a live **High** risk row for it — while Q20, in the same file, records +both records added and independently verified the same day. Rule 2 requires +Current Truth updated in place; it was not. Both §7 rows now record the live +values; the §10 risk row is struck as **RESOLVED**, with the residual +`p=none` → `quarantine` tightening described as monitoring rather than risk. +`docs/05` opened with "**it is not in place**" and a table headed "Add both of +these" for records that already exist — rewritten, with the superseded state kept +visible as a caution. + +**§9 carried Q24, Q25 and Q26 twice each, struck and open, with opposite +verdicts.** The live Q25 still asserted §4's boutique-naming permission stands — +against D16 — after entry (p) had struck it. This is the duplicate-question +defect entry (o) fixed for Q22, reintroduced three times in one session: entry +(p) added struck rows rather than striking the existing ones. The three +superseded open rows are deleted. + +### The guide added in entry (p) was a live procedure for the architecture being replaced + +`docs/reference/AWS-Hosting-Guide.md` was added **untracked** — so Q24's answer +("copied into `docs/reference/`") was true of one working tree and false of the +repository — with no reference-only marker, in fully executable imperative voice. +Following it creates an IAM user with `AdministratorAccess` in account +`327082975128`, rebuilds the site through the standalone-HTML pipeline D1 and D3 +replace, and wires SES to `adr@` / `intake@smlcompany.ca` against D18's +`info@`. It is now `git add`ed and carries a **do-not-execute** banner tabulating +seven contradictions with Current Truth, each resolved in Current Truth's favour. + +**It also called Pouya a lawyer** — "**Audience:** You (a lawyer, not a +sysadmin)" — and proposed public copy reading "does not create a lawyer-client +relationship", which is what `NO_RETAINER_NOTICE` in `src/data/site.ts` was +written to avoid. Both corrected. + +**The R8 sweep command recorded in entry (o) could not have caught either.** +`grep -rn -i "licensed\|legal professional"` does not match "lawyer". The rule +promoted this session is right; the pattern it was demonstrated with was +incomplete. The corrected sweep is: + +``` +grep -rn -iE "\blawyer\b|licensed|legal professional|litigator" \ + --include="*.md" --include="*.ts" --include="*.astro" . +``` + +Run, output read. Every surviving hit is rule text, Change Log history, or +"lawyer" referring to the *reader* or a third party (`docs/03:20`, `docs/03:161`, +`docs/01:291`, `docs/08:111`) — none describes Pouya. + +### Copy defects one step from shipped pages + +- **"a working litigator"** — `AGENTS.md` §1's positioning sentence and + `docs/03-content-spec.md:71`, the line designated for the hero, the About page + and the PDF bio. Not in §4; in Ontario it asserts conducting litigation, which + §4 Forbidden bars. §1's own line asserted "each element is verified"; it was + not. Both now read "close to live litigation". §1's correction is annotated in + place rather than silently rewritten. +- **"an active litigation practice"** — `docs/03:118`, `docs/01:211`, + `docs/01:246`. §4's Verified row was itself corrected from "practice" to + "**exposure**" in entry (l); the copy decks kept the barred word. Fixed to the + register's own substitute. +- **`LegalService` JSON-LD** — `docs/04-seo-spec.md` specified it for the home + page. schema.org defines `LegalService` as a business providing legal advice + and **representation**: it asserts in machine-readable form precisely what D13 + bars. Changed to `ProfessionalService`, with the reason recorded so it is not + changed back. `worksFor` on the `Person` node had no register-safe value — + populating it either names the boutique (D16) or misstates the employer — so + it is dropped in favour of `jobTitle`. +- **Tribunal-secretary work** — `docs/01:173,180` and `docs/03:32` instructed + offering it; `docs/07-fees.md:116` records Pouya removing the rate and barring + the offer. Three files against one; the one was right. +- **§4's Forbidden table and `docs/03:52`** justified the superlative ban with + "LSO marketing rules" — the **fourth** surviving form of the licensure claim, + two rows below the `NOT ESTABLISHED` row. Restated on grounds that do not + depend on licence status. *(The §4 instance is the architect's to apply.)* +- **`docs/07-fees.md`** opened with "pending Pouya's sign-off — Q14" and + "**Nothing in this document publishes until Pouya confirms the figures**", + then contradicted itself 85 lines later with "This is the card. Build `/fees/` + from it." An implementer reading top-to-bottom blocks the page. Header + rewritten to D14 as confirmed. +- **Nine stale `Q` blockers** across five spec files — Q4, Q10, Q11, Q12, Q14, + Q20, Q5 — all answered or re-tracked, three of them gating `/fees/`, whose + figures are confirmed. Swept. + +### Code defects + +- **`src/data/site.ts`** published `responseTime: 'Inquiries are answered within + one business day.'` — a service level a reader can hold him to, not in §4. Set + `null` with a `TODO(pouya)`; **Q27**. +- **The memberships block** carried a blanket `[verified]` stamp over the OBA + section names, which §4 marks `[assumed]`. Downgraded, flagged; **Q28**. +- **`src/content/config.ts`** — `/** Drafts are excluded from the build, the + index, and the sitemap. */` describes three controls, **none implemented**; + the sitemap filter covers `/legal/` only. Same defect class as Q22. Restated + as intent with a deadline. Its `title`/`description` bounds also contradicted + `docs/04` (max 70 / min 70 against 50-60 / 140-160); tightened to the spec. +- **`astro.config.mjs`** set `prefetch: { prefetchAll: true, defaultStrategy: + 'viewport' }`, injecting Astro's prefetch script and an IntersectionObserver + into **every** page and speculatively fetching every link that scrolls into + view — against CLAUDE.md's "default to zero JS" and §7's "most pages ship zero + JS", with no Change Log entry. Set to `prefetchAll: false` / + `defaultStrategy: 'hover'`, the setting the written conventions imply. If + prefetch-all is wanted, it needs a decision entry. +- **`src/styles/tokens.css`** attached the ink contrast figure (11.09:1) to both + ink and maroon; on maroon `--gold-l` measures 8.11:1. Both pass AA, so no + accessibility consequence — but the token file is what developers read. + +### Also corrected + +`docs/06` cited a billing **alarm** verified by `cloudwatch describe-alarms`; the +guide set up an AWS **Budget**, which that command never returns — and nothing +records either as created. Now names `budgets describe-budgets` and says confirm, +do not assume. The booking cutover check is marked conditional on R6, since +`BOOKING_URL` is empty by decision. `scripts/aws-discover.sh` and `docs/06` +claimed "every call is a list or describe" — four are not (`sts +get-caller-identity`, `apigatewayv2 get-apis`, `s3api get-bucket-versioning`, +`configure get`); all are genuinely read-only, so the substance held and the +wording did not. Four stale `AWS-Hosting-Guide.md` paths repointed at +`docs/reference/`. The reference workflow still said "Two passes" above three +sync steps — the one file entry (o)'s three-pass sweep missed, and a +twelve-character grep would have caught it. The IAM procedure had 22 lines of +multipart prose between "attach this policy" and "create an access key", which +also broke the ordered list in CommonMark; moved below step 3. + +### Declined, with reasons + +**The guard was not widened.** `adversarial-reviewer` showed it does not cover +the secrets — and by Q22, an unset key is the *most likely* first-run failure, so +the stated benefit ("one second instead of a full build") does not apply to the +likeliest case — nor `vars.INTAKE_ENDPOINT`, whose absence would **ship a live +form posting to an empty endpoint**. Both are real. Neither was done: the ruling +named three variables, and `INTAKE_ENDPOINT` additionally needs promoting to +job-level `env:`. **What was fixed instead is the guard's comment**, which +claimed it converted the problem "on every Gitea version" into a clean failure — +broader than what it implements. It now states its scope and points at **Q29**. + +**The Gitea 1.21 claim is stamped `[assumed]`, not verified.** The version could +be confirmed with one command on the instance. It was not run here; the guard is +designed to work without knowing the answer, so the stamp is the honest record. + +**`docs/06` still pairs the account ID with the backup-bucket callout** — the +pairing entry (m) removed from `README.md` as an inference vector. `docs/06` is +an operational document where the account ID is load-bearing, unlike the README. +Flagged rather than changed; if you want it out, it moves to `aws-inventory.txt`, +which is gitignored. + +### Verification + +The guard's `run:` block was extracted from parsed YAML and **executed** by +`adversarial-reviewer` under three shells and four input states — fail-closed +confirmed. Both workflow YAMLs parse. The barred-word sweep was run as the +`grep -iE` above and its output read. `stat` gave 357,627 bytes. `npm run lint`, +`check` and `build` were **not run**: `node_modules` is absent and `npm ci` +cannot install without a lockfile, so the `astro.config.mjs`, `site.ts` and +`config.ts` edits are **unverified by any type-checker** — they are small and +syntactically simple, and that is the whole of the assurance. + +**Opened:** Q27, Q28, Q29. **Still open:** Q22, Q19 (blocking), Q23 (runner +half), Q5/R6 (parked). **Closed by entry (p), confirmed here:** Q24, Q25, Q26. + +**Lesson.** Entry (o) said the sweep must be a command whose output is read. +This entry adds what that costs when the command is wrong: the pattern +`licensed|legal professional` cannot match "lawyer", so a compliant sweep still +missed a file added in the same session. **And the largest finding of the session +was in a file nothing had asked either reviewer to look at.** Both reviewers were +pointed at a diff; the destructive defect was three files away, left by a +correction that reached one file and stopped. Scope the audit to the *decision* +that changed, not the lines that changed. + +--- + +## 2026-08-26 (p) — Q24, Q25, Q26 answered; R7 ratified; R8 promoted to a rule + +**Who:** Pouya relaying Claude Code's session close. Claude (architect) deciding. + +**Q25 — struck. This was the dangerous one and it was mine.** §4's Verified table +carried "The boutique **may be named on the site**", authorising precisely what +**D16 — never named** forbids. Sequence: Pouya said it could be named, then +reversed; D16 recorded the reversal; **the permission was never removed.** A +locked decision and the table copy is written from disagreed, and the table was +the more permissive of the two. Struck. + +The general defect: reversing a decision requires removing the permission it +granted, not only recording the new position. Same shape as the D3 amendment that +went unswept three times. + +**Q26 — answered, and the third form of the same claim is gone.** §4's opening +asserted "Every public claim on this site is subject to Law Society of Ontario +marketing rules" — which asserts regulatory status by implication, since those +rules bind licensees. Claude Code was right that this is the same half-measure as +the "legal professional" reversal, one level further down. + +Old → new: the register's rationale no longer rests on licensure at all. It rests +on the fabricated-credentials history, which is documented, sufficient, and true +regardless of licence status. The paragraph's own history is kept in place as a +caution — three progressively weaker forms of one unverified claim, each +surviving a sweep. + +**§4 now carries a `Licence status — NOT ESTABLISHED` row.** Stamped +`[unestablished]`, a new stamp for this case. It records the honest position: this +file does not know, Pouya's instruction was about the *site* and not a statement +of fact either way, and nothing may assert, deny, or infer it. Claude Code was +also right that the two licensure rows were stamped `[verified]` as *directives*, +which is a different thing from a verified fact — this row separates the two. + +**Q24 — closed.** `AWS-Hosting-Guide.md` copied to `docs/reference/`. It is the +only record of how the hand-built infrastructure was created, so it belongs in +the repo rather than in a Drive folder the repo cites but cannot reach. Scanned +before copying: no access keys, no secrets, no account ID. + +**Q23 — answered by hardening rather than by version-checking.** The risk is real +— on Gitea below ~1.21, `${{ vars.* }}` interpolates empty and the sync target +becomes `s3://`. But a version check is a fact that goes stale. Ruling: add a +**pre-flight guard step** to `.gitea/workflows/deploy.yml` that fails the run if +any required variable is empty, before any AWS call. That converts a silent +destructive misfire into a clean failure on every Gitea version, and it +subsumes R7's third item. + +**R7 ratified, with one amendment.** +1. Cache-policy table amended to match the pipeline — **accepted.** Documenting + what the pipeline does beats documenting an intention. `robots.txt` and + `sitemap*.xml` at `max-age=0, must-revalidate` is immaterial at this size. +2. `s3:AbortMultipartUpload` omitted, lifecycle rule as intended cover — + **accepted, with the reasoning corrected.** The lifecycle rule does not exist, + so it is not the cover. The actual cover is that `aws s3 sync` only goes + multipart above 8 MB and the largest asset in the repo is a 357 KB portrait. + Record *that*, and add a note to revisit if any asset ever approaches 8 MB. + Do not document a control that does not exist — that is Q22's defect again. +3. `aws s3 ls` pre-flight documented but not implemented — **superseded** by the + guard step above, which covers more. + +**R8 promoted from a reminder to a rule.** *"A sweep is a command whose output is +read, not a claim."* Entries (l), (m) and (n) each asserted a completed sweep; +instances survived all three — one of them inside `claims-auditor.md`, the +definition of the agent whose job is to catch it. A reminder is the wrong +instrument for something this reliable. It belongs in `/build` Phase 6 and +`/wrap`: any claim that a change was applied across files must cite the command +and be made only after reading its output. + +**R1's wording corrected:** it says "the site currently asserts the JD only". +There is no site — `src/pages/` is empty. Restated in the conditional. + +**Closed:** Q23, Q24, Q25, Q26. **Still blocking the build:** nothing. +**Still blocking `/contact/`:** Q19. **Still open:** Q22, Q5 (parked). + +--- + +## 2026-08-26 (o) — Five rulings implemented; both reviewers run; the D3 sweep finally completed + +**Who:** Pouya ruled on entry (m)'s escalations and reversed his own F5 ruling. +Claude Code implemented, ran `claims-auditor` **and** `adversarial-reviewer` in +parallel on the diff, and resolved 27 + 17 findings. + +### The five rulings, implemented + +1. **§4 and §10 "licensed"** — the architect's, done in entry (n). +2. **Reversal on "a legal professional's"** — cut from `README.md:35` and + `CLAUDE.md` (twice). The sentences now assert nothing about professional + status and state the reason instead. +3. **`s3:PutObjectAcl` dropped** from the policy in `docs/06-deployment.md`. §10's + "four actions" is now accurate without §10 being touched, and every file that + states a count agrees with the policy: `README.md:77`, `docs/06:82`, + `.gitea/workflows/deploy.yml:13`, `AGENTS.md` §10. +4. **`.github/workflows/deploy.yml` → `docs/reference/github-actions-oidc.yml.example`** + via `git mv`; `.github/` removed entirely. It held exactly one file — no + CODEOWNERS, no dependabot, no templates — and nothing referenced the path. + References updated in `README.md`, `CLAUDE.md`, `docs/06`, `.gitea`, and §7. +5. **Q22** left open with the designed-not-confirmed phrasing intact. + +### The reviewers found that the D3 sweep had never actually reached `docs/06` + +Both agreed on the same blocking defect, independently. `docs/06-deployment.md` +is the file `README.md` points to as "Full procedure, IAM policy, runner setup" — +and it still opened with: + +- `Authority: AGENTS.md §3 D3 (git + GitHub Actions → ...)` — D3 as amended says + Gitea; +- a topology diagram, **the first content block in the file**, reading + `GitHub push to main → GitHub Actions → assume AWS role via OIDC (no stored + keys)`. That is the exact sentence entry (l) called "the serious one", six + lines above the section that contradicts it; +- an entire 19-line section, `## Why OIDC and not access keys`, in the + imperative — *"IAM → Identity providers → add OIDC provider..."* — with **no + marker that it does not apply**, naming a third principal `adr-site-deploy` + that conflicts with `adr-sml-deploy`, and citing Q9, which is answered. + +`adversarial-reviewer` named the concrete failure: an operator working the +document top-to-bottom adds a GitHub federation trust to account `327082975128` +— the account §10 rates High blast-radius — that nothing will ever use, and +plausibly never creates `adr-sml-deploy` at all. Two mutually exclusive +credential procedures in one file with no signpost saying which is live. + +**Fixed.** Authority line cites D3 as amended. Topology rewritten to Gitea + +static key. The OIDC section is retitled *Why OIDC would have been better — and +why it is unavailable*, opens with a **do not execute** block, and its executable +steps are gone. + +### The "licensed" sweep had missed three more files, including the auditor's own persona + +Entry (n) scoped the reversal to "`README.md`, `CLAUDE.md` (twice), and this +file." Five instances survived in three files it did not name: + +- **`.claude/agents/claims-auditor.md:8`** — *"You audit public copy for a + **licensed legal professional's** marketing site."* This is the system prompt + of the agent that enforces the rule. Its opening sentence asserted the exact + claim its own §"Licensure (D13)" instructs it to flag. +- **`.claude/agents/adversarial-reviewer.md:9`** — *"a legal professional's + dispute resolution practice"*, the precise phrase entry (n) reverses. +- **`docs/08-execution-protocol.md:63`** — *"a licensed professional's public + marketing page"*. **This file was edited in that same diff**, eleven lines + above the surviving phrase. + +Entry (n) said "twice in two entries that a claim about a sweep was made without +the sweep being verified. The pattern, not the instances, is the finding." This +was the third. It is now swept by command, not by recall: + +``` +grep -rn -i "licensed\|legal professional" --include="*.md" --include="*.yml" . +``` + +Every surviving hit is either rule text stating the prohibition, or Change Log +history, which rule 3 forbids editing. + +### Also fixed + +**Register and rule accuracy.** §4's internal-docs rule cited a `[assumed]` stamp +on licensure that **does not exist** — the two licensure rows are stamped +`[verified]` as *directives not to publish*, which is a different thing. A reader +following the pointer found nothing there, in the sentence stating the rule. +Reworded here and in `CLAUDE.md:30` to say what is true: the Verified table does +not establish licence status either way. **Duplicate `Q22`** — two rows, two +scopes, one number, one of them mine; merged into the fuller statement, keeping +the architect's `aws iam get-user` check command. **§7 Node** re-stamped +`[verified]` — it was `[assumed]` for something directly checkable. + +**Claims that overstated what exists.** `CLAUDE.md:164` still said *"deploys use +OIDC role assumption"* — verbatim the F1 claim, in a file both prior sweeps +touched; it and `CLAUDE.md:119` are corrected. `.gitea/workflows/deploy.yml` and +`CLAUDE.md` asserted the deploy credential in the present tense; both now cite +Q22. `docs/06` asserted five blocking PR checks — the workflow has **no +`pull_request` trigger** and neither `lint` nor `lighthouse` is wired, so nothing +gates a merge today; retitled *planned, not implemented*. `README.md:5` and +`docs/06`'s "every push deploys" both hedged against the never-run-green fact the +same files establish elsewhere. + +**The moved reference file carried the defect the move was meant to contain.** +Its line 16 still read *"OIDC role assumption — no long-lived AWS credentials in +this repository"*: present tense, about this repository, and false. It also +carried a live `TODO(pouya): AGENTS.md Q9, Q10` against two struck rows — which +`CLAUDE.md`'s definition of done treats as a build failure — for a variable that +will never be set. Both fixed, along with its claim that the file is usable on +GitLab (different CI schema entirely; it is the design there, not the +implementation). + +**Two security-posture claims narrowed.** `docs/06` said the workflow's +`aws sts get-caller-identity` pre-flight means "a credential problem fails loudly +and early rather than halfway through a sync." `sts:GetCallerIdentity` requires +**no IAM permission** — it succeeds for any valid key regardless of policy. It +catches a missing or revoked key and misses an under-scoped one, which is exactly +the risk this diff introduced by removing an action. Narrowed, with the one-line +`aws s3 ls` check that would make it load-bearing. And `README.md` had re-dropped +§10's *"which by its name is"* hedge on `mlp-clientdb-prod-backups` — the defect +entry (m) F2 records as fixed — as had `docs/06:113`, escalated in entry (n) and +not done. Both restored. + +**Documentation matching implementation.** The cache section described **two** +sync passes; the workflow runs **three**, and two ordering dependencies are +load-bearing and undocumented — pass 3 re-walks the tree and preserves pass 2's +image headers only because `sync` skips just-uploaded objects, and pass 3's +excludes also exclude those prefixes from `--delete`, which is why hashed assets +from old deploys are kept deliberately. Both now stated. The `robots.txt` / +`sitemap*.xml` row claimed `max-age=3600`; nothing implements it, so the table +now records what the pipeline does. Two conflicting variable tables for the same +five names — one under **Secrets** with real values, one under **Variables** with +placeholders — merged; entering those as secrets would have masked them in the +logs the doc says to read them from. Duplicate booking references (Q5 vs R6) +resolved to R6. `README.md` said "no `src/pages/`"; the directory exists and is +empty, which is not what a reader would find. + +**`docs/08-execution-protocol.md`** — entry (n)'s inserted block landed between +*"`claims-auditor` reads the copy..."* and its follow-up *"It is a separate agent +on purpose"*, leaving "It" twelve lines from its antecedent and reading as though +the frontmatter were a separate agent. Block moved below. + +### Declined, with reasons + +**`s3:AbortMultipartUpload` not added.** `adversarial-reviewer` traced every AWS +call in the workflow against the policy and found the happy path fully covered, +with this one gap: objects over 8 MB upload multipart, and an interrupted +transfer cannot clean up its own parts. It recommended against adding the +permission — an S3 lifecycle rule aborting incomplete uploads after 7 days solves +it without widening the policy. Agreed, and left as an operational item below +rather than a policy change. + +**The `aws s3 ls` pre-flight is documented, not implemented.** Adding it changes +the deploy pipeline, which was not in scope. It is written into `docs/06` as the +fix for the narrowed claim. + +**§4's tables untouched.** Two findings land in the register itself; both are +escalated below rather than edited. §4 is the architect's instrument. + +### Escalated — for the architect + +*(All four now tracked: 1 and 2 as **Q25** and **Q26** in §9; 3 folded into Q26; +4 left in R1, which already owns the licensure framing.)* + +1. **§4's Verified table authorises what D16 forbids.** `AGENTS.md:153` reads + *"The Toronto litigation and ADR boutique **may be named on the site** ... the + name itself is pending, see Q7."* D16 says **"Never named."** Q7 is answered: + *"Pouya reverted to generic. The boutique is never named."* A **Verified** row + currently permits publication of the exact thing a locked decision bars — the + same shape as the F5 defect in entry (l), in the same table, and the register + is where copy is written from. +2. **§4's opening asserts regulatory status by implication.** *"Every public + claim on this site is subject to Law Society of Ontario marketing rules"* — + LSO marketing rules bind licensees. Stating flatly that they govern this site + asserts the licensure §4 declines to verify, in the sentence that replaced + "Pouya is a licensed legal professional". A half-measure of the same shape as + the "legal professional" reversal. +3. **Consider an explicit §4 row** — *"LSO licence status | UNKNOWN / not + verified either way"* — which would make the internal-docs rule's pointer land + somewhere real instead of being reworded around. +4. **R1 (§12)** describes "the site currently asserts the JD only". There is no + site; `src/pages/` is empty. R1 is the reminder that must not ossify, so it + should be accurate about what it describes. +5. **Operational:** add an S3 lifecycle rule aborting incomplete multipart + uploads after 7 days; and once Q22 is answered, run + `aws s3 sync ./dist s3://adr-smlcompany-site --dryrun` under the new key to + confirm no `s3:GetBucketLocation` call is needed. +6. **Minor:** `.yml.example` is not a Prettier-recognised extension, so the moved + reference file has silently dropped out of `prettier --check` coverage. Frozen + reference material, so near-harmless — but nothing validates it as YAML now. + +**Q23–Q26 opened, none blocking the build.** Q23: is an `act_runner` registered, and is the Gitea +instance ≥ 1.21 for the `vars` context the workflow depends on throughout? On an +older instance `vars.S3_BUCKET` interpolates empty and the sync target becomes +`s3://`. Q24: `AWS-Hosting-Guide.md` is cited by `docs/06` as the source for +existing infrastructure and two cutover checks, and **does not exist in the +repository**; the two dependent checks have been restated self-containedly, so +nothing is blocked. Q25 and Q26 carry the two §4 escalations above. + +**R7 and R8 added to §12.** R7 records three spec decisions made on Pouya's +behalf and not ratified — the amended cache-policy row, the omitted +`s3:AbortMultipartUpload`, and the documented-not-implemented `aws s3 ls` +pre-flight. R8 records the sweep-verification lesson as a standing discipline +rather than a lesson buried in one entry, which is what let it recur three times. + +### Verification + +`npm run lint`, `npm run check`, and `npm run build` were **not run** — +`node_modules` is absent, and `npm ci` cannot install without a lockfile. No +JavaScript, TypeScript, or Astro source was touched. The `.gitea` workflow and +the `.yml.example` were not YAML-parsed either: PyYAML is unavailable in this +environment and the project has no YAML tooling installed. Both were changed only +in comment blocks, and the indentation of every edited comment was checked by +eye. The "licensed" sweep was executed as the grep above and its output read, not +asserted. Every prose line added to `README.md` and `CLAUDE.md` is ≤ 80 columns. + +**Lesson.** Entry (m) recorded that a correction is a change and gets reviewed +like one. This pass adds the sharper version: **the sweep must be a command, and +its output must be read.** Three consecutive entries claimed a completed sweep; +three times instances survived, and the third time one of them was inside the +definition of the agent whose job is to catch it. The `/wrap` step should require +pasting the grep, not describing it. + +--- + +## 2026-08-26 (n) — Register corrected; a declined finding reversed on appeal + +**Who:** Pouya relaying Claude Code's re-audit. Claude (architect) recording. + +**Correction to entry (l), which was false.** It claimed all three files had been +rewritten off "licensed". Two were. **This file still said it twice** — §4's own +opening sentence ("Pouya is a licensed legal professional") and §10's risk row +("professional-conduct exposure for a licensed practitioner"). The register was +asserting as established fact the very thing it marks `[assumed]`, in the section +that exists to prevent exactly that. Entry (l) stands as written per rule 3; this +is the correction. Both lines are now fixed. + +That is twice in two entries that a claim about a sweep was made without the +sweep being verified. The pattern, not the instances, is the finding. + +**Reversal — "a legal professional's" is out too.** `claims-auditor` wanted the +phrase cut entirely, arguing that in Ontario it reads as an LSO licensee and so +trips the same bar as "licensed". Claude Code declined it, correctly, because it +was my explicit ruling — and recorded the reasoning rather than silently keeping +it, which is what let it be revisited. + +**On appeal the auditor is right and I was wrong.** "Legal professional" was a +half-measure: a weaker assertion of the same unverified thing. The fix is to +assert nothing about professional status and state the reason instead — the +previous site carried fabricated credentials, which is true regardless of licence +status and carries the full force of the rule. Applies to `README.md`, +`CLAUDE.md` (twice), and this file. + +Worth preserving: **the mechanism worked because the decline was reasoned rather +than silent.** A finding dropped quietly is a finding that cannot be appealed. + +**Q22 opened — does `adr-sml-deploy` exist?** Claude Code caught that its own +README rewrite asserted a control nothing records as in place. `docs/06` is +written imperatively — "Create the user", "Create an access key" — a procedure, +not a record. Nothing in this file says it was performed. Its framing of this as +"same failure class, inverted" is exactly right: the original README understated +the credential risk, its replacement overstated the control. **The §10 rotation +obligation has no subject until Q22 is answered.** + +**Accepted — §10's "four actions" resolves by tightening the policy, not editing +the count.** `docs/06` grants five: `ListBucket`, `PutObject`, `PutObjectAcl`, +`DeleteObject`, `CreateInvalidation`. `s3:PutObjectAcl` is unused by `aws s3 sync` +without `--acl`, and inert under OAC with ACLs disabled. Dropping it makes §10 +accurate **and** the policy tighter — strictly better than correcting the number. +Handed to Claude Code. + +**Accepted — move the GitHub workflow out of `.github/`.** Gitea falls back to +`.github/workflows` when `.gitea/workflows` is absent, so a live `push:` trigger +sitting there is conditionally inert, not inert. Moving it to +`docs/reference/github-actions-oidc.yml.example` makes it structurally inert. +Handed to Claude Code. + +**Also noted, no action:** Claude Code reported that `npm run lint` and +`npm run check` could not run because `node_modules` is absent, and said so +rather than reporting a check it did not run. That is the Phase 5 rule working. + +**Opened:** Q22. **Still blocking the build:** nothing. **Still blocking +`/contact/`:** Q19. + +--- + +## 2026-08-26 (m) — README corrected against D3-as-amended; second audit found nine more + +**Who:** Pouya ruled on the five findings in entry (l); Claude Code implemented, +re-ran `claims-auditor` on the result, and resolved the second pass. + +### The architect's rulings, applied + +**F5 — no change, as ruled.** D13 bars "practice" for the boutique role, not for +Pouya's own ADR practice. `README.md:3` and `package.json:5` stand. + +**F2 — scope corrected, wording changed.** The Forbidden table governs published +pages, not repository documentation; that scope is now stated in §4. The real +defect was different and the architect identified it: licensure is `[assumed]` +in §4, so no file should call Pouya "licensed". `README.md:36` now reads *a legal +professional's public marketing surface* — the clause that follows, about the +previous site's fabricated credentials, already carries the reasoning. + +**F1, F3, F4 — Deployment section rewritten** against §7 and +`docs/06-deployment.md`. The section had been written against D3 as originally +decided and never swept when D3 was amended to Gitea. It now names +`.gitea/workflows/deploy.yml` as the live pipeline, says Gitea Actions rather +than GitHub Actions, states plainly that a long-lived AWS credential is involved +and why (Gitea is not an AWS OIDC provider), and names the quarterly rotation +obligation. `format` and `lighthouse` added to the scripts table. + +### The second audit found nine findings in the replacement text + +Seven fixed, one declined, one escalated. The re-audit was worth running: the +rewrite traded the original defect for its mirror image. + +**F1 (fixed) — the replacement asserted a control state that may not exist.** +The new text said deploys *do* authenticate as IAM user `adr-sml-deploy` with a +key in Gitea secrets. Only the **decision** is verified (D3 as amended, §7). +`docs/06-deployment.md` is written entirely in the imperative — "Create the +user", "Create an access key" — i.e. a procedure to perform, not a record of one +performed, and `adr-sml-deploy` appears nowhere else in this file. The old README +understated the credential risk; the new one asserted a control that nothing +records as in place. Same failure class, inverted. Now phrased as designed-not- +confirmed, and **raised as Q22**. + +**F2 (fixed) — a hedge was dropped, and an account number was disclosed.** §10 +says `mlp-clientdb-prod-backups` is "**which by its name is** a law firm's +production client-database backups" — only the bucket name was ever observed. +The README stated the contents flatly. It also paired the live account ID with +that statement in the repo's most pasteable file, and D16 says the boutique is +never named — "this account holds a law firm's client database" is an inference +vector that costs nothing to remove. The account number and the bucket name are +both now out of the README; the security reasoning stays, pointing at §10. + +**F3 (fixed).** The bullet led with "**The key is rotated quarterly**" — a +description of an operating control — and conceded four lines later that the +task has no owner. Now an obligation: *must be rotated quarterly, and nobody +owns that yet.* + +**F4 (fixed).** "It does not run. Editing it changes nothing." is conditional, +not absolute: Gitea falls back to `.github/workflows` when `.gitea/workflows` is +absent, and that file carries a live `push` trigger on `main`. Realised risk is +low — it would fail on `role-to-assume` with no OIDC provider rather than +mis-deploy — but describing a trigger-eligible file as inert invites someone to +treat it as safe. Now states the condition. **The auditor's better fix was +declined for scope:** moving it to `docs/reference/github-oidc-deploy.yml.example` +would make the claim structurally true instead of dependent on Gitea's +resolution order. Worth doing; not done here. + +**F6 (fixed) — "Pushes to `main` build and deploy automatically" was not true.** +Verified against the filesystem, not inferred: there is no `package-lock.json`, +so `.gitea/workflows/deploy.yml:46`'s `npm ci` exits non-zero at step one; there +is no `src/pages/`, so both `npm run check` and `npm run build` fail; and whether +an `act_runner` is registered is recorded nowhere, which `docs/06:125-130` warns +"looks exactly like a broken pipeline." The README now says the pipeline has +never run green and names all three reasons. + +**F7 (fixed).** "No wildcard actions, no wildcard resources" is literally false — +the policy uses `arn:aws:s3:::BUCKET_NAME/*`, correctly scoped but a wildcard. In +a paragraph whose entire job is to stop a future maintainer widening the policy, +an overstatement is the wrong error: the first reader who notices it discounts +the rest. Now: no `Action: "*"`, no `Resource: "*"`, nothing outside one bucket +and one distribution. + +**F8 (fixed).** `npm run lint` and `npm run lighthouse` are listed in a table a +reader takes as "these work." Neither does — there is no ESLint flat config, and +ESLint 9 (pinned `^9.0.0`) errors without one, so the command dies before +Prettier runs; and there is no `lighthouserc`, so `lhci autorun` has no budgets +even though `docs/06:221-222` makes Lighthouse a blocking check. Both rows are +now marked **not yet wired**. + +**F9 (fixed).** Two precision defects. The README restated the project's single +most important rule more narrowly than §4 states it — "no factual claim **about +the practice**" versus §4's "him, his credentials, his experience, or his +practice" — in the file a new contributor reads first. And it said `/build` runs +two review agents unconditionally, where `.claude/commands/build.md:52-53` allows +skipping `claims-auditor` when no copy changed. Both now mirror their sources. + +**F5 (declined) — the auditor asked to cut "a legal professional's" entirely,** +on the grounds that in Ontario the phrase reads as an LSO licensee and so trips +§4's bar on "phrasing that *implies* entitlement to practise law." Declined +because the architect ruled this exact wording four hours earlier, having already +considered and rejected "licensed", and because the same phrase now appears +deliberately in `CLAUDE.md`. Recorded rather than silently kept: the auditor's +reasoning is not obviously wrong, and if the phrase is judged to imply licensure +it needs changing in three files at once, not one. + +### Escalated to the architect — not fixed here + +1. **Entry (l) records `CLAUDE.md`, `AGENTS.md`, and `README.md` as all rewritten + off "licensed". Two of the three were.** `CLAUDE.md` is clean. **This file + still says it twice** — line 110, "Pouya is a licensed legal professional", + in the opening sentence of §4 itself, and line 303, "professional-conduct + exposure for a licensed practitioner", in §10. The register is asserting as + fact the thing it marks `[assumed]`, in the section whose whole purpose is to + stop that. Not edited here because §4 is the architect's instrument. + +2. **§10 says the deploy policy "grants four actions on one bucket and one + distribution."** It grants five: `s3:ListBucket`, `s3:PutObject`, + `s3:PutObjectAcl`, `s3:DeleteObject`, `cloudfront:CreateInvalidation`. The + discrepancy resolves in a useful direction — `s3:PutObjectAcl` is unused by + `aws s3 sync` and inert under OAC with ACLs disabled (`docs/06:205-206`), so + the policy is one action wider than it needs to be. Dropping it makes the + §10 count correct and the policy tighter at the same time. `docs/06:108` also + drops §10's "by its name" hedge on the backup bucket. + +3. **The `.github` workflow's location** — see F4 above. + +### Verification + +`npm run lint` and `npm run check` were **not run**: `node_modules` is absent, so +neither can execute. This change touches only `README.md`, which is outside +`astro check` and ESLint; Prettier has no config in the repo, so its default +`proseWrap: "preserve"` leaves markdown prose unreflowed. Line widths were +checked by hand and every line Claude Code wrote is ≤ 80 columns. + +**Lesson, extending entry (l)'s.** (l) recorded that amending a decision requires +sweeping every file that referenced the original. This pass adds the corollary: +**a correction is a change, and gets reviewed like one.** Seven of the nine +findings above were in text written specifically to fix an audit finding. The +first rewrite of a false claim is the most dangerous moment for it, because +everyone involved is now confident the area is clean. + +--- + +## 2026-08-26 (l) — First adversarial review run; it found defects in the specs + +**Who:** Pouya ran `claims-auditor` against `README.md` to verify the agents load. +It loaded, and returned five findings before any site code exists. + +**The agents are confirmed working.** R1 was surfaced unprompted, as §12 requires. +F2 and F5 were escalated rather than silently edited — the behaviour the brief +asks for on judgement calls. + +**Two register-level defects fixed here (architect's, not Claude Code's):** + +**F5 root cause — §4 contradicted D13.** Old → new: the Verified table read +*"Active litigation practice: personal injury, construction, regulatory (POA), +insurance (SABS)"* → **"Active litigation exposure: …"**. The row quoted the +strategy brief verbatim and used the exact word D13 bars in exactly the context +D13 bars it. Anyone writing copy from the register would have inherited the +violation **from the register itself** — the worst place for it to live. + +D13 now also states the distinction explicitly: "practice" is barred **for the +boutique role**, not for Pouya's own ADR practice. So "the dispute resolution +practice of Pouya Lajevardi" is correct — `README.md:3` and `package.json:5` need +no change. **F5 resolved, no edit to the README.** + +**F2 — the Forbidden table's scope was overbroad.** Old → new: heading read "must +not appear **anywhere**" → **"must not appear on the site"**, with the scope +stated: published pages including JSON-LD, not repository documentation. + +The auditor was right that something was wrong, though the rule it cited was the +wrong one. `README.md`, `CLAUDE.md`, and this file all called Pouya "a licensed +professional" while §4 marks licensure **`[assumed]`**. Internal docs were +asserting as fact what the register cannot vouch for. A new rule now covers this +directly. The three phrases are rewritten to state the *reason* for the +strictness — the previous site carried fabricated credentials — rather than a +credential we cannot confirm. + +**F1, F3, F4 — handed to Claude Code.** One root cause: `README.md`'s Deployment +section was written against D3 as originally decided and never updated when D3 +was amended to Gitea. `CLAUDE.md`, `docs/06`, and this file were all updated; the +README was missed. + +F1 is the serious one. "Deploys via OIDC — there are no long-lived AWS credentials +in this repository" is **false**, and dangerous in the specific way the auditor +identified: it is narrowly defensible, since the key is not tracked in git — which +is exactly why it would suppress the quarterly rotation obligation in D3, in an +account §10 rates High blast-radius because it holds `mlp-clientdb-prod-backups`. + +**Lesson recorded.** Amending a decision requires sweeping every file that +referenced the original, not the files that happen to come to mind. The review +caught it; the amendment process should have. Worth adding to `/wrap`. + +--- + +## 2026-08-26 (k) — Q21 resolved: nothing broken; SES sandbox is per-region + +**Who:** Pouya ran the per-region check. + +**Q21 closed — the good case.** + +| Region | Verified | DKIM | Tokens | +|---|---|---|---| +| `ca-central-1` | `true` | **SUCCESS** | `kznn…` `jdue…` `f5pu…` — resolve correctly | +| `us-east-1` | `false` | PENDING | `3zsn…` `jejgp…` `xpiwy…` — doubled domain | + +The region that matters is healthy. The three broken CNAMEs belong to a stray +`us-east-1` identity that nothing in this project uses; it is PENDING precisely +*because* those records were entered with the domain doubled. **No fix required.** + +Recommendation recorded: **leave the three dead CNAMEs in DNS.** They are inert, +and the only way to cause harm is deleting the wrong row from a list of six +visually similar records. Optionally delete the `us-east-1` identity itself so it +stops reporting PENDING — that is a control-plane action with no DNS risk. + +**New finding, and it would have cost a day: the SES sandbox is per-region.** +`ProductionAccessEnabled: false` was read from `ca-central-1`, which is where the +intake Lambda, DynamoDB, and API Gateway all live. The AWS console defaults to +`us-east-1`, and the panel Pouya screenshotted was `us-east-1` — so the natural +path would have been to request production access in the wrong region, wait a +day, and find the confirmation email still failing. Flagged in §7 and on Q19. + +**Also worth noting for the record:** entry (j)'s correction was itself only +half the story. DNS proved which records resolved; it could not prove which +*mattered*. That needed the control plane. Neither source is sufficient alone — +the data plane says what exists, the control plane says what is expected, and a +discrepancy between them is the finding. + +**Closed:** Q21. **Still blocking:** Q19 only. + +--- + +## 2026-08-26 (j) — SPF/DMARC live; and a correction: three DKIM records are broken + +**Who:** Pouya added the two TXT records. Claude verified independently. + +**Q20 closed.** SPF and DMARC are both live and correct, confirmed by direct DNS +query rather than taken on report. Also confirmed unchanged: both existing `@` +TXT records, `google._domainkey`, `MX 1 smtp.google.com`, and +`adr.smlcompany.ca` → CloudFront. Nothing was disturbed. + +**Correction to entries (h) and (i) — I had the two DKIM sets backwards.** + +- Old → new: "`3zsn…`/`jejgp…`/`xpiwy…` are the live set; `f5pu…`/`jdue…`/`kznn…` + are inert orphans" → **the opposite.** The `f5pu` set resolves NOERROR at the + correct names. The `3zsn` set returns **NXDOMAIN**. +- **Root cause found.** `3zsnvsjg…._domainkey.smlcompany.ca.smlcompany.ca` + resolves; the correct name does not. Those three were entered into Namecheap's + Host field with the **full name including the domain**, so Namecheap appended + the domain a second time. This is precisely the gotcha flagged in entry (h) — + which was written before checking whether the existing records had already + fallen into it. +- **Why I got it wrong:** I inferred "live" from the SES console listing them and + did not verify against DNS. The console shows what SES *expects*, not what + exists. Lesson worth keeping: a control-plane listing is not evidence about the + data plane. +- **No harm done.** The advice in (i) was "leave both sets alone", which happened + to be the safe action either way. + +**Q21 opened.** SES is regional, and `ca-central-1` reported +`VerifiedForSendingStatus: true` — only consistent with the `f5pu` set. So the +console panel screenshotted was probably a different region's identity. Until +that is confirmed per region, it is unknown whether the broken records matter. +Nothing should be deleted before that check. + +**Closed:** Q20. **Opened:** Q21. **Still blocking:** Q19 (SES production access). + +--- + +## 2026-08-26 (i) — SES DNS panel resolves the DKIM ambiguity; MAIL FROM absent + +**Who:** Pouya sent the SES "Domain DNS records" panel. + +**The six DKIM CNAMEs are now fully explained.** SES lists exactly three for +`smlcompany.ca`: `3zsnvsjg…`, `jejgp7na3…`, `xpiwyftpo…`. The other three in +Namecheap — `f5puwearz…`, `jdue2r22c…`, `kznn3cklv…` — are **not** referenced by +SES and are residue from an earlier verification of the same domain. Note the +TTLs corroborate this: the live set reads "1 min", the orphans "Automatic", +consistent with two separate additions. + +**Recommendation recorded: leave the orphans in place.** They are inert. The only +way this becomes a problem is deleting the wrong three, which would break SES +DKIM and therefore DMARC. There is no upside to tidying a DNS zone. + +**Custom MAIL FROM is not configured** — "No MAIL FROM records found". This +independently confirms the correction in entry (h): SES's envelope sender is at +`amazonses.com`, its SPF pass is unaligned with `smlcompany.ca`, and DMARC is +satisfied through DKIM alone. Configuring a custom MAIL FROM would add SPF +alignment as belt-and-braces; it is optional and not on the critical path. + +**AWS's suggested DMARC value is `v=DMARC1; p=none;`** — valid but minimal, with +no `rua`, so it produces no reports. Using `v=DMARC1; p=none; rua=mailto:info@smlcompany.ca; fo=1` +instead so the monitoring period actually yields data before tightening to +`quarantine`. + +**Net action for Q20 is two TXT records and nothing else.** + +--- + +## 2026-08-26 (h) — DNS inspected; earlier SPF reasoning corrected + +**Who:** Pouya sent the Namecheap DNS panel, asking exactly what to change +without breaking anything. + +**Correction to entry (g) — the SPF reasoning was wrong.** Old → new: "SES needs +SPF or mail lands in spam" → **SES authenticates via DKIM, not SPF.** Without a +custom MAIL FROM domain, SES's envelope sender sits at `amazonses.com`, so its +SPF pass is not aligned with `smlcompany.ca` and contributes nothing to DMARC. +The six `*.dkim.amazonses.com` CNAMEs already in Namecheap are what make SES +DMARC-compliant, and they are working. The SPF record's real value is +authenticating **Google Workspace** mail, which has none. `include:amazonses.com` +stays because it is harmless and becomes live if a custom MAIL FROM is added. +Entry (g) is left as written per rule 3; this is the correction. + +**Also found in the DNS panel:** +- Six SES DKIM CNAMEs where three are needed — the domain was verified twice. + Harmless, but do not prune without checking SES first. +- Two ACM validation CNAMEs → `jkddzztszm.acm-validations.aws`. **Flagged as + never-delete**: they auto-renew the `adr.smlcompany.ca` certificate, and + removing them breaks HTTPS silently at the next renewal rather than + immediately. This is the only genuinely destructive mistake available in that + panel. +- `@` carries a Namecheap URL Redirect to `sml-coming-soon.ca`. TXT records + coexist with it, so adding SPF does not disturb the redirect. + +**DMARC `rua` changed** from `pouya@` to `info@smlcompany.ca` — the mailbox +confirmed to exist. + +**Still blocking:** Q19 (SES production access), Q20 (the two TXT records). + +--- + +## 2026-08-26 (g) — SES purpose clarified; D18; SPF and DMARC found missing + +**Who:** Pouya asked why SES is needed given he already has an `info@` mailbox. +Fair question — the answer exposed two things. + +**The distinction, recorded because it will come up again.** A mailbox receives +mail and a person logs into it. SES lets *code* send mail — the intake Lambda has +no mailbox and no login. They are complementary, not alternatives: SES sends +**to** `info@smlcompany.ca`. Verifying the address in SES did not create a +mailbox; it authorised sending. + +**D18 — two emails per submission (new decision).** The sandbox blocks only one +of the two: the notification to Pouya works (his address is verified), the +**receipt to the inquirer** does not. That receipt was Claude's addition in +`docs/05-backend-spec.md`, not part of the original AWS-guide build, so it was +put back to Pouya as a real choice rather than treated as a defect. **He confirmed +he wants it** — so Q19 is genuinely blocking rather than optional. + +**Q20 opened — the domain has no email authentication at all.** A DNS query of +`smlcompany.ca` on 2026-08-26 returned: + +- TXT: only `anthropic-domain-verification` and `google-site-verification`. + **No `v=spf1` record of any kind.** +- `_dmarc.smlcompany.ca`: **no record.** +- MX `1 smtp.google.com` and `google._domainkey` present — Google Workspace with + DKIM configured. +- `adr.smlcompany.ca` CNAME → `d26v23dhgsp2ta.cloudfront.net`, as expected. + +Old → new (planned): no SPF, no DMARC → one SPF record covering **both** Google +and Amazon SES, plus a DMARC record starting at `p=none`. + +**This is wider than this project.** Pouya's existing business email from +`smlcompany.ca` is sending unauthenticated today. Google Workspace's DKIM carries +it, but Gmail and Yahoo both penalise missing SPF and DMARC, so mail he sends as a +human is already more likely to be filtered than it should be. Raised to **High** +in §10 and flagged to him directly. Both records should go in before the SES +production-access request — AWS weighs domain authentication when reviewing, so +it improves the odds of first-time approval as well. + +**Opened:** Q20. **Still blocking:** Q19, Q20. + +--- + +## 2026-08-26 (f) — SES sandbox confirmed; execution protocol built into the repo + +**Who:** Pouya. Claude recording. + +**Q18 closed, Q19 confirmed as a live blocker.** `smlcompany.ca` **is** verified +for sending (`true`) — the earlier `None` was a query artefact, not a fault. But +`ProductionAccessEnabled: false`: **the account is in the SES sandbox.** Mail +reaches only pre-verified addresses, so an inquirer's confirmation email fails +silently. Raised from Medium to **High** in §10: this is the failure mode where +the site looks like it works and the inquirer concludes they were ignored. +Production access must be requested; ~24 h turnaround, and it is the only +dependency on this project with external lead time. + +**D17 — working method, made structural (new decision).** +- Old → new: an implicit understanding that Claude Code implements what Pouya + decides → **an explicit six-phase loop encoded in the repository**, so it + applies without being restated in each prompt. +- Why: Pouya's direction — he architects, Claude Code programs and then + adversarially reviews, with deep reasoning on, permanently. +- Added: + - `.claude/agents/adversarial-reviewer.md` — code, accessibility, + crawlability, performance, security, simplicity. Instructed to **treat + uncertainty as a defect** and told that an approving review which misses a + real defect is a failure. + - `.claude/agents/claims-auditor.md` — every factual assertion traced to §4. + Separate agent on purpose: a generic reviewer consistently under-weights + professional-conduct checks, which is this project's highest-stakes failure + mode. It also audits JSON-LD, since a machine-readable misrepresentation is + still a misrepresentation. + - `.claude/commands/build.md` — the loop. `/review` — phase 3 alone. + `/wrap` — the session-end `AGENTS.md` ritual. + - `.claude/settings.json` — thinking on, high effort, and a read-deny on + `.env*` and `aws-inventory.txt`. + - `CLAUDE.md` — the protocol and the reasoning behind it. + - `docs/08-execution-protocol.md` — the prompt template Pouya writes from. +- **The design decision worth preserving:** the reviewers are given the diff and + the specs, and deliberately **not** the implementer's rationale. Explaining why + the work is correct anchors the reviewer and converts review into agreement. + Independence is the mechanism, not a courtesy. If a future change to this + protocol removes that, it removes the value. + +**Closed:** Q18. **Still blocking:** Q19 (SES production access). + +--- + +## 2026-08-26 (e) — AWS inventory captured; Q10 closed; blast-radius risk logged + +**Who:** Pouya ran `scripts/aws-discover.sh`. Claude recording. + +**Q10 closed.** All identifiers in §7. Bucket `adr-smlcompany-site`, +distribution `E1OK7G98KNKUTA`, region `ca-central-1`, intake API +`4tl0m5igkj`. Certificate ISSUED. **S3 versioning is already Enabled**, so the +rollback path in `docs/06-deployment.md` works as written — no change needed. + +**Data residency confirmed.** Hosting, Lambda, and DynamoDB are all in +`ca-central-1`. `docs/05-backend-spec.md` treated Canadian residency as a +selling point conditional on the table's region; it is now a verified fact and +`/legal/privacy/` can state it plainly. + +**New risk logged — deploy-credential blast radius.** The inventory shows this is +a shared account across at least five unrelated properties, including +`mlp-clientdb-prod-backups-327082975128`. A Gitea runner holding a static AWS key +for this site sits in the same account as a law firm's client-database backups. +Nothing about the plan changes — the scoped IAM policy was already correct — but +its narrowness is now load-bearing rather than good practice, and that is +recorded so nobody widens it later for convenience. + +**Q18 and Q19 opened — SES.** `list-email-identities` returned +`VerifiedForSendingStatus: None` for all six identities, and sandbox status was +not checked. Either condition means the intake confirmation email silently fails. +This is the failure mode where the site appears to work and inquirers think they +have been ignored, so it is on the cutover checklist, not the nice-to-have list. + +**Closed:** Q10. **Opened:** Q18, Q19. + +--- + +## 2026-08-26 (d) — Memberships, analytics, prep time, firm naming; one blocker left + +**Who:** Pouya. Claude recording. + +**Q16 closed — preparation time is bundled and stated.** 2 h in the half day, +3 h in the full day, printed on `/fees/`. The carried-forward assumption is now a +decision. At $4,000 a day counsel will assume preparation happened; saying so +converts the assumption into a selling point and forecloses an argument about +what the fee covered. + +**Q15 and Q17 closed.** Non-mediation hourly (ENE, settlement counsel, +dispute-system design, technical advisory) and mediation overtime both **$500/h**, +matching the arbitration rate. + +**Q8 closed — memberships.** Old → new: five `[assumed]` bodies from the strategy +brief → **ADRIC, ADRIO, and OBA sections, verified.** OCNI is **not current** and +must not be published; the brief listed it as aspirational positioning for the +nuclear niche, which is a different thing from a membership. + +- **LSO was deliberately not offered as an option and is not published.** Listing + the Law Society in a credentials block implies licensure, which D13 bars. Worth + recording explicitly so a later reader does not "helpfully" add it back. +- Which OBA sections remains `[assumed]` — the brief names Construction & + Infrastructure, ADR, and Civil Litigation. Low stakes; confirm in passing. + +**D15 — analytics (new decision).** Old → new: unchosen → **privacy-first and +cookieless**, Plausible or Fathom. No GA4, no consent banner, no personal data +leaving the site, one honest line in the privacy policy. Consistent with a +practice whose privacy posture is part of its offer, on a site where visitors are +often describing live disputes. + +**D16 — the boutique is never named (new decision).** Old → new: "may be named, +name pending" → **generic throughout**: *a Toronto litigation and ADR boutique*. +Pouya reversed his earlier answer. Trade-off, recorded for the record: naming a +recognisable firm is a meaningful credibility signal to appointing bodies, and +the generic phrasing gives that up in exchange for zero coordination cost and no +dependency on anyone else's sign-off. Do not infer the name from his email domain +or from anything else. + +**Closed:** Q7, Q8, Q11, Q15, Q16, Q17. **Opened:** none. + +**Q10 is now the only blocker.** Everything else needed to build is answered. +R6 (booking) stays parked by choice and does not block `/contact/`. + +--- + +## 2026-08-26 (c) — Contact, headshot, LinkedIn; booking parked + +**Who:** Pouya. Claude recording. + +**Closed.** Q3 — contact is `info@smlcompany.ca`, no public phone, consultations +by scheduled call. Q6 — headshot supplied; committed as +`src/assets/pouya-lajevardi.jpg` (1600×1600 master, for Astro to derive AVIF and +WebP from at build) and `src/assets/og-portrait.jpg` (1200×630, cropped high so +the face is not centred under the fold of a link preview). Q12 — LinkedIn URL, +which now feeds `sameAs` in the `Person` JSON-LD. + +**Q5 parked, not closed.** Old → new: "choose a booking tool" → **deferred at +Pouya's request**; `/contact/` ships with the intake form and a reserved slot for +an embed, so adding one later is a drop-in rather than a rebuild. He asked to be +reminded, so it is now **R6** in §12 rather than a question that quietly expires. +Worth restating when it comes back up: D10 chose booking because it removes the +scheduling back-and-forth that loses appointments, and the form alone only +half-solves that. + +**Q7 partially answered.** The boutique may be named. The name itself was not +given. His email domain (`meshkinilaw.ca`) points to **Meshkini Law**, but an +inferred firm name is exactly the kind of thing §4 exists to stop — asked for +confirmation rather than published. + +--- + +## 2026-08-26 (b) — Fees confirmed; Gitea; licensure wording; standing reminders + +**Who:** Pouya, answering the second round. Claude recording. + +**D14 closed — rate card confirmed, and it is not what was recommended.** +- Old → new: two-tier card (Tier A insurance/SABS at $1,800/day, Tier B + commercial at $3,200/day) → **one rate for all mediation matters: $2,000 half + day, $4,000 full day, $500 per party beyond two.** Arbitration $500/h, hearing + day $4,000, documents-only flat $6,500 simple / $9,500 complex. Tribunal- + secretary line removed. Cancellation terms adopted as recommended. +- Why: Pouya's decision. +- **Recorded dissent, for the 12-month review (R5).** A single premium rate puts + the insurance / SABS / LAT segment out of reach — the published market there + runs roughly $800–$1,200 a day, and $4,000 is three to five times it. That is + the segment the strategy brief (§IV.7) identifies as the highest realistic + near-term volume, flowing directly from the firm's existing accident-benefits + work. The trade is deliberate if it is deliberate: a premium specialist + position that forgoes volume. It is a mistake if the volume was being counted + on. Flagged once, implemented as directed. +- Three parameters were not specified and are carried forward as assumptions, + logged as Q15–Q17: non-mediation hourly ($500), bundled prep hours (2 h half + day / 3 h full day), mediation overtime ($500/h). + +**D13 refined — approved wording for the boutique role.** +- Old → new: "describe the role factually" → the specific approved phrases are + **"active litigation exposure"** and **"involvement in litigation and ADR + matters"**. The word **"practice"** is barred in that context. +- Pouya asked to be **continuously reminded** that this is interim. That request + is now structural rather than a note — see the new §12. + +**New §12, Standing Reminders.** Five items (R1–R5) that any agent must surface +at the start of a substantial session. Added because a parked decision otherwise +becomes permanent by never being raised again — and R1 is Pouya's explicit +instruction to keep raising it. + +**D3 amended again — Gitea.** +- Old → new: "private git server, software unknown" → **self-hosted Gitea with + Gitea Actions**, clone at `/Users/pouya/Dev/Websites/adr-sml`. +- Consequence: Gitea Actions uses GitHub Actions syntax, so the workflow ports + almost unchanged into `.gitea/workflows/deploy.yml`. But **Gitea is not an AWS + OIDC provider**, so the OIDC role assumption is replaced by a scoped IAM user + whose key lives only in Gitea's secret store. The IAM policy stays exactly as + narrow. Quarterly rotation is now an operational obligation that OIDC would + have made unnecessary — noted in `docs/06-deployment.md`. + +**Closed:** Q4, Q9, Q13, Q14. **Opened:** Q15, Q16, Q17. +**Still open:** Q3, Q5, Q6, Q7, Q8, Q10, Q11, Q12, Q15, Q16, Q17. + +--- + +## 2026-08-26 (a) — Licensure decision; Q.Arb dated; git host changed; fees researched + +**Who:** Pouya, answering the blocking questions from §9. Claude recording. + +**Date correction.** The entry below is stamped 2026-08-25. The correct date of +that work was **2026-08-26** — the session clock was a day behind. Per rule 3 the +entry is left as written rather than edited; this note is the correction. Facts +touched today are re-stamped `[verified 2026-08-26]`. + +**D13 — licensure left out of the site (new decision).** +- Old → new: "confirm LSO licence status before launch" → **the site asserts the + JD and makes no licensure claim at all.** +- Why: Pouya's direction. +- **Consequence, and it is not small.** The strategy brief describes an *"active + litigation practice in personal injury, construction, regulatory (POA), and + insurance (SABS) matters."* Copy written that way would imply entitlement to + practise law without stating it — which is the risk the decision is meant to + avoid, restated in different words. So the Forbidden table now bars implication + as well as assertion, and the About page describes the role factually: + *Director of Firm Operations at a Toronto litigation and ADR boutique*, plus + the matter types worked on. **Flagged back to Pouya**: if he is in fact + licensed and in good standing, that is a material credential for exactly the + audience this site targets, and omitting it costs more than it protects. + +**Q.Arb dated.** Old → new: `[assumed]`, stage unknown → **commenced August +2026** `[verified 2026-08-26]`. Describe as newly commenced. Not as held, not as +nearing completion. + +**D3 amended — the repository is not on GitHub.** +- Old → new: "git repo + GitHub Actions" → **repo `adr-sml` on a private git + server**; the GitHub Actions workflow in `.github/workflows/` is retained as a + working reference implementation, to be translated once the server software is + known (**Q13**). +- Why: Pouya is running his own git server. +- Knock-on: GitHub's OIDC provider is unavailable. GitLab CE can federate to AWS + by OIDC; Gitea/Forgejo and bare git cannot, so those need a scoped IAM user + with rotated keys, or deploys run from Pouya's machine. The choice is real and + waits on Q13. + +**D14 — fee structure recommended (new decision, pending sign-off).** Market +research completed against the Ontario mandatory-mediation tariff, ADR Chambers +published ranges, and four published Ontario practitioner rate cards. A two-tier +structure is recommended so the price-sensitive SABS/LAT volume work does not +anchor the commercial rate. Figures are in the response to Pouya and are **not +written into any page until he signs off (Q14).** + +**Still open:** Q3, Q5, Q6, Q7, Q8, Q10, Q11, Q12, Q13, Q14. + +--- + +## 2026-08-25 — Project initiated; architecture decided; repo bundle authored + +**Who:** Pouya Lajevardi with Claude (Cowork session), acting as architects. Claude Code to implement. + +**What was discussed.** Pouya asked for a modernization of `adr.smlcompany.ca` +going beyond appearance — content and codebase included — with Claude Code doing +the implementation and deploying to AWS. + +**What was found.** An audit of the live site and the local sources established +the facts in Current Truth §2. The headline finding: the site is a browser- +compiled single-file React bundle that serves crawlers three words of content. +For a personal-brand site whose function is discoverability, this is the +dominant problem, ahead of any question of looks or copy. + +**What was decided.** Twelve decisions, D1–D12, recorded in §3. In summary: an +Astro static rebuild, full content re-architecture, ~20 pages, English only, +git + GitHub Actions onto the existing S3/CloudFront, palette and infinity mark +retained with a modernized execution, a published rate card, an Insights section +launching with drafted content, a rebuilt intake form plus booking, and a single +clean cutover. + +- Old → new (framework): browser-compiled React single file → Astro static site +- Old → new (publishing): manual `rebuild-standalone.py` + console upload → git + GitHub Actions with OIDC +- Old → new (structure): one scrolling page → ~20 pre-rendered pages +- Old → new (content): partially-corrected placeholder template → written fresh against a claim register +- Old → new (record-keeping): none → this file, under the AGENTS constitution + +**Why.** Discoverability is the practice's growth constraint and the current +architecture forecloses it. Every other decision follows from fixing that, with +the content decisions following from the strategy brief of 2026-05-26. + +**Also decided, not yet discussed with Pouya:** no Indigenous engagement practice +page at launch (§6), on the reasoning recorded there. Flag this to him. + +**Planned, not yet done.** Astro implementation; all page copy; 3–5 Insights +drafts; intake backend rework; CI/CD wiring; pre-cutover audit. Twelve blocking +questions are open in §9 — several pages cannot be written until they are +answered. + -- src docs | grep -B1 progress +src/pages/about.astro: * ...which ended "...stated openly as in +src/pages/about.astro- * progress" — so THIS FILE cited docs/03 as REQUIRING... + -> the one hit is the corrective note itself. THE WRAPPED FORM IS WHY THIS + SWEEP MISSED FIRST TIME: 'as in\n * progress' does not match a one-line + grep, and about.astro cited docs/03 as both requiring and barring the + phrase, six lines apart. + +$ git grep -n 'worksFor' -- src | grep -cv '\*\|//' +0 + -> ZERO live properties. 13 lines mention it, all comments. + THE FIRST VERSION OF THIS BLOCK REPORTED "3 hits" — which was the number of + FILES 'git grep -c' printed, read as a number of matches. The instrument + shape CLAUDE.md catalogues, in the entry documenting instrument misreads. + +$ git grep -n 'NoSuchEntity|does not exist yet|has not been created|nobody owns that' -- README.md docs/ + -> 2 hits, both inside the corrective notes added this session. + THIS SWEEP DID NOT EXIST IN THE FIRST VERSION OF THIS BLOCK, and that was + the gap: Q22's flip to PROVISIONED was swept in AGENTS.md and NOWHERE ELSE. + docs/06 still told an operator "adr-sml-deploy does not exist… Create it", + and README asserted the same in three places. An operator would have + created a SECOND IAM user, or hand-provisioned one outside the + least-privilege policy. Same shape as the SES-DKIM inversion; found by + adversarial-reviewer. + +$ git show :docs/reference/adrio-designations.md | grep '^## Finding 4' + -> matches the working tree. THE STAGED COPY HAD THE FALSIFIED FINDING 4: + the file was 'git add'ed BEFORE the rewrite, so a staged-only commit would + have landed the version this entry claims to have fixed. The mirror of the + untracked-file hazard recorded above — once tracked, 'commit -a' works and + bare 'commit' does not. Verify with 'git diff --cached' before committing. +``` + +**Line-wrapping defeated an anchor or a sweep THREE times this session** — S5's +`as in\n * progress`, the `SiteFooter` masthead sentence, and `docs/03`'s +blockquote-wrapped phrase recorded in an earlier entry. Sweep the wrapped form. + +### Verified + +`astro check` **0 / 0 / 0**; `eslint` clean; `prettier --check` clean (noting +`.prettierignore` excludes `*.md` and `docs/reference/`, so it says nothing about +the new doc); `npm run build` 2 pages; **0 `.js` emitted**; the only `<script>` +on either page is `application/ld+json`; minifier guard silent and +`animation-timeline` intact in `dist` (longhands only; the sole `animation:` +shorthand is `animation:none!important` in the reduced-motion block); **no gold +text on cream** anywhere; one `<h1>` on `/about/` with h1→h2→h3 and no skips +across 17 headings; JSON-LD parses on both pages with `jobTitle: "Mediator"`, no +`worksFor`, no `memberOf`, `hasCredential` Q.Med-only, no `LegalService`; **no +currency-warranty phrasing in the built HTML** (`renewed annually`, +`listed as current`, `current as of`, `are current` — all 0). + +Layout re-measured by `adversarial-reviewer` after it discarded its own first +instrument: **headless Chrome clamps `--window-size` to ~500px minimum on +macOS**, so its "320px" was really 500px. Via CDP `setDeviceMetricsOverride`: +320×800 DPR2, 1024 and 1280 → **0 document overflow**; at 320px with root +font-size 32px → 63px, **all of it the pre-existing header brand name**, with +every credential `<li>` right edge at 272 against a 320 viewport. The new +Memberships group contributes no overflow. + +### NOT run, stated rather than omitted + +- **Lighthouse — tool unavailable.** `@lhci/cli` removed 2026-08-26; returns at + step 7 under R11. Nothing here adds bytes to a route: no new images, no runtime + font request, no third-party script, no base64 inlining, JS still zero. +- **HTML validator — not run.** The duplicate-`1x` srcset conformance error from + step 2 stands. +- **Q46(a)'s gate 1 — no source fetched.** Deliberate: it is legal research, it + was not asked for, and §4 bars this register from concluding it. The candidate + source is named in the ENE row. + +### Open after this entry + +**Q46(a)** (gate 1 unsourced — blocks step 5) · **Q48** (Q.Med retention vs +membership currency) · **Q49** (the two §4 rows Q47 needs) · **Q50** +(`ProfessionalService.name` scoping) · **Q51** (OBA and the D13 implication) · +**Q23**, **Q34**, **Q38**. Live reminders: **R1** (licensure — surfaced again, +and `/about/` is now the page that makes it live), **R10** (event-triggered), +**R11**, **R13**, **R14**, **R15**, **R16** (PDF bio, step 9), **R17** (key +rotation, 2026-11-26). + + ## 2026-08-28 (x) — Build step 3: `/about/` ships without its memberships. Q40–Q43 close; four review passes found nine defects in their own predecessors' fixes **Task, in Pouya's words:** rulings on **Q42**, **Q41(a)(b)(c)**, **Q43** and diff --git a/CLAUDE.md b/CLAUDE.md index 5784e69..cd8ea45 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -176,6 +176,32 @@ from a command that found nothing. Same family as *a sweep is a command, not a claim*: the claim must rest on output you actually read, from a command that actually ran. +**And never suppress stderr in a verification script.** *Pouya's convention, +2026-08-28, from verifying the deploy credential (`AGENTS.md` Q22).* This is the +rule above from the other direction, and it is the more dangerous direction: +**`2>/dev/null` converts "it failed" into "it found nothing", and those are +opposite results.** His first pass at eight `simulate-principal-policy` checks +returned empty for all eight; the suppression was hiding an `InvalidInput` error, +and the empty output was then explained with a guess — *"probably lacks the +permission"* — which is the answer the check was supposed to produce, arrived at +without the check running. The actual cause was a **zsh parameter-expansion bug**: +`$ACCT:user/` parses `:u` as a history modifier and yields `327082975128ser/`. +Braces fixed it. + +So: no `2>/dev/null` in anything whose output you intend to believe, read the +exit status, and when a result is empty **remove the suppression and look before +proposing a cause.** A guessed explanation for an empty result is worse than no +result, because it closes the question. + +*Corroborated the same day, twice, in the same session and both in zsh:* +`grep -rn $EX 'Mediator-Arbitrator'` printed an option error and no matches — +which reads as clean — because zsh does not word-split unquoted variables; and a +digest-comparison loop using `set -- $pair` printed **`DIFFER` on all five rows**, +which reads as "the source changed under me", because the loop body received one +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". + **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>` diff --git a/README.md b/README.md index a039f77..c407e88 100644 --- a/README.md +++ b/README.md @@ -59,11 +59,13 @@ both. `.gitea/workflows/deploy.yml` is the CI pipeline — **Gitea Actions**, not GitHub Actions. **It has never run**, for two reasons that are not oversights: -- The scoped IAM user does not exist. `aws iam get-user --user-name - adr-sml-deploy` returns `NoSuchEntity` (`AGENTS.md` Q22). - Actions are not enabled and no runner is registered. The Gitea instance is jointly administered, so both need its second administrator (Q23). +*(It previously listed a second reason — that the scoped IAM user did not exist. +**It exists**: `adr-sml-deploy`, created 2026-08-26, Q22 closed 2026-08-28. See +`AGENTS.md` §7 for the inventory and the least-privilege verification.)* + Its **first** step is a guard: the run aborts, naming what is missing, if any required variable or either AWS secret is empty. Only emptiness is tested and no value is echoed. @@ -75,11 +77,14 @@ Gitea falls back to that directory when `.gitea/workflows` is absent, so a workflow file left there with a `push` trigger would be only conditionally inert. As an `.example` under `docs/` it cannot be picked up at all. -**The pipeline is designed around a long-lived AWS credential, and it does not -exist yet.** Gitea is not an AWS OIDC provider, so there is no role to assume: -deploys are *to* authenticate as a scoped IAM user, `adr-sml-deploy`, with its -access key in the repository's Gitea Actions secrets. `aws iam get-user` -confirms that user has not been created (Q22). In the meantime the local script +**The pipeline is designed around a long-lived AWS credential, and that +credential now exists.** Gitea is not an AWS OIDC provider, so there is no role +to assume: deploys authenticate as a scoped IAM user, `adr-sml-deploy`, with its +access key in the repository's Gitea Actions secrets. **The user was created +2026-08-26 and verified least-privilege by execution — `AGENTS.md` §7, Q22 closed +2026-08-28.** Its access key has **never been used** (`LastUsed` null), because +deploys still run locally. *(This paragraph asserted the user "has not been +created" until 2026-08-28.)* In the meantime the local script **refuses to run as `user/pouya`**, the broadly-permissioned personal user — see `AGENTS.md` §10. Two things are meant to bound the risk, and neither is in place yet: @@ -93,11 +98,14 @@ place yet: narrowness is what keeps a compromised runner away from it, and it is load-bearing rather than hygiene. See `AGENTS.md` §10. If a deploy step needs a permission the policy lacks, question the step; do not widen the policy. -- **The key must be rotated quarterly, and nobody owns that yet.** Create a - second access key, update the Gitea secrets, confirm a deploy succeeds, then - delete the old one — rotation that leaves the old key active is not - rotation. OIDC would have removed the obligation entirely; it is - unavailable, so this is a standing calendar task still waiting on an owner. +- **The key must be rotated quarterly. It now has an owner and a date: first + rotation due 2026-11-26** (key created 2026-08-26) — `AGENTS.md` §12 **R17**. + Create a second access key, update the Gitea secrets, confirm a deploy + succeeds, **then** delete the old one — rotation that leaves the old key active + is not rotation, and deleting before verifying leaves no way to authenticate + the fix. OIDC would have removed the obligation entirely; it is unavailable, so + this is a standing calendar task. *(It read "nobody owns that yet" until + 2026-08-28; R17 is the owner, and the date is the whole point of the row.)* Full procedure, IAM policy, runner setup, and cutover checklist: `docs/06-deployment.md`. diff --git a/docs/01-architecture.md b/docs/01-architecture.md index c547fe6..b409b1d 100644 --- a/docs/01-architecture.md +++ b/docs/01-architecture.md @@ -167,7 +167,8 @@ to an appointment. This page carries the verifiable record. engineering, operating a company — told as one arc rather than three lists. 3. **Credentials**, structured and scannable: designations, education, certifications, memberships. Every line from `AGENTS.md` §4 Verified. -4. **The credentialing arc.** Q.Med held → Q.Arb in progress → C.Med-Arb as the +4. **The credentialing arc.** Q.Med held → Q.Arb **commenced August 2026** → + C.Med-Arb as the endpoint. The brief (§V) treats the arc itself as part of the story; say so openly rather than implying a finished state. 5. **Languages and cross-cultural practice.** @@ -176,8 +177,14 @@ to an appointment. This page carries the verifiable record. 7. `Person` JSON-LD. Downloadable one-page PDF bio — brief §VIII lists this as an asset for circulation with appointment proposals. -> **The PDF bio does NOT ship with build step 3, and the omission is stated -> rather than silent** — `AGENTS.md` Q45, opened 2026-08-28. No such file exists +> **The PDF bio ships at BUILD STEP 9, alongside `/fees/` — deferred by Pouya +> 2026-08-28 (Q45), tracked as `AGENTS.md` §12 **R16**.** His reasoning: it is a +> derived artefact, so building it before `/about/` and `/fees/` are final means +> building it twice, and an appointment proposal needs the fee card as much as +> the bio. The two decisions below are **not** settled by the deferral and travel +> with R16. Original note follows, and its reasoning is why this is R16 rather +> than a to-do. **The PDF bio does NOT ship with build step 3, and the omission +> is stated rather than silent** — `AGENTS.md` Q45, opened 2026-08-28. No such file exists > in the repo, and a link to one that does not exist is a broken link on the > page an appointing body reads. It is also not a formatting job: a one-page bio > is a **credential document** whose every line has to trace to §4 exactly as a @@ -214,8 +221,11 @@ neutral. 2. **Tracks:** documents-only, expedited, full hearing. 3. **Rules:** ADRIC, ADR Chambers, ad hoc. 4. Awards — form, reasoning, timing. -5. **Credentialing status, stated plainly.** The Q.Arb pathway is in progress; - the page says so. **What is available now is all three forms — sole, +5. **Credentialing status, stated plainly.** The Q.Arb pathway **commenced + August 2026**; the page says so in those words. *"In progress" was the + wording here until 2026-08-28 and it is barred — `docs/06`'s own cutover + checklist says "§4's wording, not the looser 'in progress'", and this is the + spec for the page that has to get it right.* **What is available now is all three forms — sole, party-appointed and co-arbitration** — and `AGENTS.md` §4 Offerings carries a row for each `[verified 2026-08-26 — Pouya]`. The page states that alongside the credentialing stage: Q.Arb commenced August 2026, C.Med-Arb is the @@ -247,8 +257,20 @@ long-term narrative. Six cards, one paragraph each, linking onward. Also the natural home for the "also offered" strip: **early neutral evaluation, dispute-system design, and -pre-dispute technical advisory** — three, and each now has an `AGENTS.md` §4 -Offerings row, which is what the strip needs before it may ship. +pre-dispute technical advisory** — three, and each has an `AGENTS.md` §4 +Offerings row. + +> 🚫 **THE STRIP MAY NOT SHIP YET, AND HAVING A ROW IS NOT WHAT UNBLOCKS IT.** +> All three rows read **"GATES 0 AND 2 ANSWERED; GATE 1 STILL HAS NO SOURCE — +> NOT YET PUBLISHABLE"**. Pouya ruled on 2026-08-28 that all three pass; §4's +> gate 1 asks *is the activity gated?*, which the register answers with a +> checkable source and not with a ruling, and **no source exists for any of the +> three**. Tracked as **Q46(a)**, which names this strip as the thing it blocks. +> +> This paragraph read *"each now has a §4 Offerings row, which is what the strip +> needs before it may ship"* until 2026-08-28 — **false as stated**, and it would +> have had an implementer at step 5 ship three offerings the register marks +> unpublishable. Found by `claims-auditor` on re-audit. > **`settlement counsel` IS STRUCK FROM THIS STRIP AND MUST NOT BE RESTORED.** > `AGENTS.md` Q42, 2026-08-27. Pouya struck it as his own error in this document: diff --git a/docs/03-content-spec.md b/docs/03-content-spec.md index aa1d438..1161a5b 100644 --- a/docs/03-content-spec.md +++ b/docs/03-content-spec.md @@ -13,6 +13,47 @@ table before writing any number, statistic, or superlative. If you need a fact you do not have, write `TODO(pouya): <exact question>` and log it in §9. Do not infer, do not soften, do not carry anything over from the old site. +### When a fact is `[unestablished]`, write around the capacity question + +**Ratified by Pouya 2026-08-28 as a reusable pattern, with the instruction that +it will recur.** §4 records licence status as `[unestablished]` and says: *do not +assert it, do not deny it.* Copy that addresses the question at all must +therefore pick neither side — and the trap is that **both obvious phrasings pick +one.** + +The worked example, which took three attempts and two audits: + +| Attempt | Copy | Why it failed | +|---|---|---| +| 1 | "I **do not** give legal advice" | *"Do not"* is an **election** — it implies entitlement withheld by choice. Flagged by audit 1 | +| 2 | "I **cannot** give legal advice" | *"Cannot"* is a **denial** of capacity. Flagged by audit 2 | +| 3 ✅ | "I act as a neutral. I do not act for a party in a matter I take, and each party should have their own legal advice." | Makes **no capacity claim at all** | + +**Both audits were right, and that is why the third version works.** Attempts 1 +and 2 are opposite answers to the same question, so flagging both is not +inconsistency — it is the correct finding twice. Pouya: *"'do not' elects, +'cannot' denies, and §4 says do neither. The shipped sentence makes no capacity +claim at all — it describes the role and points the reader somewhere useful."* + +**The pattern, stated for reuse:** + +> Do not look for a *softer* way to answer the capacity question. Any word that +> answers it — *cannot, do not, am not, is not permitted, is not qualified* — +> takes a side of a fact this register does not hold. Instead write the sentence +> so the question **does not arise**: state the **role**, state the +> **consequence** for the reader, and stop. + +Three tests before shipping such a sentence. It fails if any is yes: + +1. Could a reader infer from it that he **is** entitled to do the thing? +2. Could a reader infer from it that he is **not**? +3. Does it contain a verb of capacity or permission attached to him at all? + +**Where this will come up next:** `/practice/` (step 5) and `/for-parties/`, both +of which have to tell an unrepresented party what the neutral will and will not +do for them — the exact place the "cannot" phrasing feels most natural and is +most wrong. + --- ## Voice @@ -38,8 +79,18 @@ detect padding instantly and discount everything after it. The shape of the bullet still stands, so here is a sentence that fits it and clears the register: *"I accept sole, party-appointed and co-arbitration - appointments. The Q.Arb designation commenced in August 2026; C.Med-Arb is the - endpoint."* The limit being named is the **stage of the arc**, stated plainly — + appointments **in commercial matters**. The Q.Arb **pathway** commenced in + August 2026; C.Med-Arb is the endpoint."* **"in commercial matters" is not + optional** — every §4 Offerings arbitration row is scoped commercial, family + arbitration has its own NOT OFFERED row, and §4's NOT-NEGOTIABLE boundary + records the unscoped class form as the struck universal (Q39). This model + sentence was unscoped until 2026-08-28 while the shipped page it feeds was + scoped; found by `claims-auditor` on re-audit, one file over from the same + defect fixed in `docs/04` earlier the same day. **"Pathway", never "designation"** — a *designation* that + "commenced in August 2026" reads as in force since then, i.e. **held**, which + §4 Forbidden bars outright. This model sentence said "designation" until + 2026-08-28 and it is copy an implementer is told to lift; found by + `claims-auditor`. The limit being named is the **stage of the arc**, stated plainly — Pouya's instruction is that being open about it is the differentiator, so do not hedge it into vagueness and do not drop it. (**No tribunal-secretary work** — D14 @@ -58,8 +109,12 @@ detect padding instantly and discount everything after it. **The approved phrasing is "active litigation exposure" or "involvement in litigation and ADR matters" — never "practice" in that context.** Pouya's wording, 2026-08-26. So: *Director of Firm Operations at a Toronto litigation - and ADR boutique, with active exposure to construction, personal injury, POA, - and SABS matters.* Accurate, specific, and it claims nothing it should not. + and ADR boutique, with **active litigation exposure** across construction, + personal injury, POA, and SABS matters.* Accurate, specific, and it claims + nothing it should not. *(This example read "with active exposure to" until + 2026-08-28 — a **third** variant of the phrasing, three lines below the + sentence naming the only two approved forms, in the one place where the wording + IS the compliance. Found by `claims-auditor` on re-audit.)* This framing is **interim** — see `AGENTS.md` §12 R1. Raise it with Pouya rather than letting it settle in by default. @@ -83,7 +138,7 @@ detect padding instantly and discount everything after it. Reused, adapted, across the hero, the About page, and the PDF bio: > The dispute resolution practice of Pouya Lajevardi — a credentialed neutral -> who is also close to live litigation and a practising machine-learning and +> with active litigation exposure and a practising machine-learning and > infrastructure engineer. Built for commercial, construction, energy, > technology, and cross-cultural disputes that turn on the contract, the code, > the engineering documents, and the regulatory overlay around them. @@ -213,9 +268,16 @@ redrawing the loop into a line.* First person: "my mark", not "our mark". 400–600 words of narrative, then structured credentials. Tell the three tracks as one arc, not three lists: a JD and active litigation exposure; a parallel career in machine learning and infrastructure engineering; a company run -alongside both. The arc is the point — the credentialing pathway from Q.Med -through Q.Arb to C.Med-Arb is stated openly as in progress. The brief treats -that arc as part of the story rather than something to obscure. +alongside the practice — §4's wording; "alongside both" was a concurrency claim +the register does not make. The arc is the point — the credentialing pathway from Q.Med +through Q.Arb to C.Med-Arb is stated openly, **with Q.Arb described as +commenced August 2026** and never as "in progress", which is looser than §4 and +is barred by `docs/06`'s cutover checklist. The brief treats that arc as part of +the story rather than something to obscure. + +The designation names expand as **Qualified Mediator**, **Qualified Arbitrator** +and **Chartered Med-Arbitrator** — ADRIO's own forms, sourced in +`docs/reference/adrio-designations.md`. Never "Chartered Mediator-Arbitrator". Omit any section that would be empty. No "Speaking" heading until there is a talk to list. @@ -272,9 +334,26 @@ evasions, no "contact for pricing" after promising a rate card. ### For parties The one page in second person. Grade-9 reading level. Short sentences. Says -explicitly: the mediator is not your lawyer and cannot give you legal advice; the -mediator does not decide who is right. Answers what it costs and what happens if -you do not settle. +explicitly: **the mediator is a neutral and does not act for either party; each +party should have their own legal advice;** and the mediator does not decide who +is right. Answers what it costs and what happens if you do not settle. + +> ⚠️ **THIS DIRECTIVE READ *"the mediator is not your lawyer and cannot give you +> legal advice"* UNTIL 2026-08-28, AND IT BREACHED D13 TWICE** — in the file that +> warns, fifty lines above, that `/for-parties/` is *"the exact place the +> 'cannot' phrasing feels most natural and is most wrong"*. +> +> 1. **"not your lawyer" presupposes lawyer status.** §4 Forbidden bars *the word +> "lawyer" used of Pouya*, and D13 treats implication as hard as assertion. A +> negation still carries the presupposition. +> 2. **"cannot give you legal advice" is attempt 2** in this file's own ratified +> table — *"a **denial** of capacity"* — and it fails test 3 and the +> compliance-checklist item, both added to this file in the same change set +> that left this line untouched. +> +> The replacement is the ratified pattern applied verbatim: **role, then +> consequence for the reader, and no verb of capacity.** Found by +> `claims-auditor` on re-audit; the original sweep did not reach this section. ### Insights 1,200–1,800 words, monthly cadence (brief §VIII). Territories from §VII: @@ -313,3 +392,18 @@ Drafted by Claude, **every word reviewed by Pouya before publication**: - [ ] Contact page states that an inquiry creates no retainer and no mediator–party relationship - [ ] Any comparative claim is factual and verifiable +- [ ] No sentence answers the licence-capacity question in **either** direction — + see *When a fact is `[unestablished]`* above. Check for *cannot*, *do not*, + *am not*, *not permitted*, *not qualified* **attached to giving legal + advice, practising law, or holding a licence.** The objection is to + answering the *capacity* question, not to the words themselves — the + approved sentence contains "do not" and passes: *"I act as a neutral. I do + not act for a party in a matter I take, and each party should have their + own legal advice."* That is **role conduct**, which he may state freely. + *(This item shipped unscoped for one pass and `adversarial-reviewer` showed + it would fail the exact sentence the section exists to bless — and the + checklist is what gets grepped.)* +- [ ] Abbreviations expanded on §11 Glossary's authority only — and expansions + for the five ADR designations checked against + `docs/reference/adrio-designations.md`, not from memory. "Chartered + **Med**-Arbitrator", never "Mediator-Arbitrator" diff --git a/docs/04-seo-spec.md b/docs/04-seo-spec.md index f791d74..cfd7d09 100644 --- a/docs/04-seo-spec.md +++ b/docs/04-seo-spec.md @@ -101,8 +101,8 @@ JSON-LD only. Validate against Google's Rich Results Test before cutover. | Type | Where | Notes | |---|---|---| -| `Person` | `/about/`, referenced site-wide | `name`, `jobTitle`, `description`, `alumniOf` (Bond University), `knowsLanguage` (en, fa), `hasCredential` (Q.Med), `sameAs` (LinkedIn), `image`. **`jobTitle` = "Director of Firm Operations"; omit `worksFor`** — populating it either names the boutique (D16) or misstates the employer | -| `ProfessionalService` | Home | `areaServed` Toronto/Ontario, `serviceType` Mediation/Arbitration, `provider` → Person, `priceRange` once `/fees/` is real. **Never `LegalService`** — schema.org defines it as a business providing legal advice and *representation*, which asserts in machine-readable form exactly what D13 bars and §4 Forbidden calls out | +| `Person` | `/about/`, referenced site-wide | **Emitted:** `name`, `url`, `jobTitle`, `description`, `alumniOf` (Bond University), `knowsLanguage` (en, fa), `hasCredential` (Q.Med), `sameAs` (LinkedIn), `email`, `image`. **Withheld:** `worksFor`, `memberOf`. *(This enumeration listed `worksFor` as emitted while the same cell said it was withheld, and omitted `url` and `email`, which are — wrong in both directions. The enumeration is the part an implementer copies. Found by `adversarial-reviewer`.)* **CHANGED 2026-08-28 — Q47.** This row read *"`jobTitle` = 'Director of Firm Operations'; omit `worksFor`"*, which put the boutique title on a node whose `url` is this ADR practice's `/about/` — so a consumer could attach it to this entity. Pouya's ruling reframes the field: `jobTitle` describes **this practice**, not the boutique role, which D16 keeps unnamed. The visible role line is unchanged and still reads "Director of Firm Operations at a Toronto litigation and ADR boutique". **THE VALUE IS `PRACTICE_JOB_TITLE` IN `src/data/site.ts` AND THIS ROW DOES NOT RESTATE IT** — §7's rule, applied to a string with a live revert trigger on it: this row carried the literal text for one pass, and `adversarial-reviewer` noted it would go stale the moment the constant moved. Cite, do not copy. **`worksFor` IS WITHHELD** — set for one pass under Q47, then reverted: `ProfessionalService.provider` is this Person, so `provider → Person → worksFor` asserts the same-entity claim `schema.ts` explicitly declines, and §4 says "alongside the practice" where the ruling says "operates through". **`memberOf` is withheld too**, on volatility grounds, even though Q44 closed. Both are **Q49**. See `src/data/schema.ts` | +| `ProfessionalService` | Home | `areaServed` Toronto/Ontario, `serviceType` **Mediation / Commercial arbitration / Mediation-arbitration (med-arb)** — *scoped 2026-08-28 on `claims-auditor`'s finding; this row instructed the unscoped class form "Mediation/Arbitration" that Q39 struck and that `schema.ts` deliberately does not follow. Family arbitration carries prescribed training and has its own NOT OFFERED row, so unscoped "Arbitration" is the struck universal in a field nobody reads. Do not widen these strings without a §4 row to widen them from* — `provider` → Person, `priceRange` once `/fees/` is real. **Never `LegalService`** — schema.org defines it as a business providing legal advice and *representation*, which asserts in machine-readable form exactly what D13 bars and §4 Forbidden calls out | | `Service` | Each practice page | `serviceType`, `provider` → Person, `areaServed` | | `Article` | Each article | `headline`, `description`, `datePublished`, `dateModified`, `author` → Person, `image` | | `BreadcrumbList` | All nested pages | Matches visible breadcrumbs | diff --git a/docs/06-deployment.md b/docs/06-deployment.md index 3907dcf..87c269e 100644 --- a/docs/06-deployment.md +++ b/docs/06-deployment.md @@ -34,13 +34,27 @@ cache headers, and the same invalidation as the workflow — at this scale the pipeline changes only **how a deploy is triggered**, not what it does. Treat the script and the workflow as one artefact in two places: change one, change both. -Two things block the workflow, and neither is a fact to look up: +One thing blocks the workflow, and it is not a fact to look up: -- **`adr-sml-deploy` does not exist** — `aws iam get-user` returns - `NoSuchEntity` (§7, Q22). Create it from *Create the user* below. - **Actions are not enabled and no runner is registered** (Q23). The Gitea instance is jointly administered, so both need its second administrator. +> ✅ **`adr-sml-deploy` EXISTS — created 2026-08-26, Q22 closed 2026-08-28.** +> **DO NOT CREATE IT.** This bullet said *"`adr-sml-deploy` does not exist — +> `aws iam get-user` returns `NoSuchEntity`… Create it from Create the user +> below"* until 2026-08-28, and an operator following it would have created a +> **second** IAM user, or hand-provisioned one with a different scope from the +> `adr-sml-deploy-minimal` policy §7 now records. §7 carries the inventory and +> the eight `simulate-principal-policy` results. +> +> *Found by `adversarial-reviewer`: the Q22 flip to PROVISIONED was swept in +> `AGENTS.md` and nowhere else, and the Change Log entry's sweep block covered +> the copy corrections only. Same shape as the SES-DKIM inversion — the stale +> copy instructed an action against a High-risk credential.* +> +> *Create the user* below is retained as the **record of how it was +> provisioned**, not as an instruction. Read it that way. + The script **refuses to run as `user/pouya`** — the broadly-permissioned personal user that has been authenticating to this account. See §10. @@ -329,18 +343,47 @@ Then invalidate `/*`. **Content and compliance** - [ ] Every claim traced to `AGENTS.md` §4 Verified -- [ ] **Memberships re-confirmed with Pouya, then published** — `AGENTS.md` §12 - **R10** and **Q44**. ADRIC, ADRIO, the three OBA sections and the Canadian - Tax Foundation are `[verified 2026-08-26]`. **§4 records yearly renewal for - the OBA sections and the CTF only** — it says nothing about ADRIC's or - ADRIO's period, and an earlier version of this line asserted "all renew - yearly", which §4 does not support. **`/about/` currently publishes NO - memberships group**: R10 is a prohibition and the re-confirmation was not - obtained, so the group is withheld behind a `TODO(pouya)`. OCNI already - lapsed quietly and §4 records it as "not current, do not publish" — that is - the failure mode, and a stamp is not a renewal receipt. Re-confirm, - re-stamp §4 and `CREDENTIALS.memberships`, restore the group to - `CREDENTIAL_GROUPS`, and add `memberOf` to the Person JSON-LD +- [ ] **Memberships RE-CONFIRMED AGAIN, on the day of cutover** — `AGENTS.md` + §12 **R10**, which is now an **event trigger and cutover is one of its two + events.** Q44 closed 2026-08-28 and the group is published on `/about/` + (ADRIC, ADRIO, the three OBA sections, the CTF, `[verified 2026-08-28 — + Pouya]`), so this item is no longer "publish them" — it is **"ask him + again, then re-stamp §4 with the cutover date."** + **Pouya declined renewal-date tracking**, which is exactly why this sits on + the checklist: there is no date on which anyone would otherwise re-check. + OCNI lapsed quietly and §4 records it as "not current, do not publish" — + found roughly a year late. A stamp is not a renewal receipt. + **Do NOT add a currency sentence to the page while you are here** — his + ruling is *"list the memberships; promise nothing about their future + state"*, and the struck sentence stays struck. + **Do NOT add `memberOf` to the Person JSON-LD** unless Pouya has said to. + It is withheld deliberately and on narrower grounds than the visible page: + the reason is recorded in `src/data/schema.ts` and **it is an open + judgement, not a settled one — `AGENTS.md` Q53.** Do not restate the + reasoning here; a third copy is how the first two went stale. + **§4 records yearly renewal for the OBA sections and the CTF only** — it + says nothing about ADRIC's or ADRIO's period, and an earlier version of + this line asserted "all renew yearly", which §4 does not support. +- [ ] **`AGENTS.md` Q51 answered before cutover** — does listing the **OBA + sections** on `/about/` carry the licensure implication that excludes the + LSO? §4 excludes the Law Society precisely because *"listing the Law Society + among memberships implies licensure"*, and Forbidden bars *any phrasing that + **implies** entitlement to practise law*. The OBA sections **went live on + `/about/` on 2026-08-28** and Q51 was raised the same day, **after** Pouya's + Q44 ruling authorised the group — so the ruling did not consider it. + `adversarial-reviewer` rates it moderate-low confidence as a defect and + **high confidence that the question is unasked**: `grep -n OBA AGENTS.md` + returns rows on renewal, scope and stamping and nothing on implication, and + OBA membership eligibility is not established anywhere in this repo. It sits + beside **R1** — same subject, same page, and not settleable internally. If + the answer is yes, the fix is the LSO fix: exclude deliberately, and record + that it was excluded rather than omitted. + *(This item did not exist until 2026-08-28. Q48, which governs nothing + currently on the site, had a checklist item while Q51, which governs live + public copy, had none.)* + **Also re-check `AGENTS.md` Q48** before re-stamping: if `Q.Med` retention + turns out to depend on ADRIO membership currency, this item covers the + site's central credential and not just a list - [ ] No `TODO(pouya)` remains in any shipped page - [ ] No matter counts, rates, dollar figures, or testimonials anywhere - [ ] Q.Arb described as **commenced August 2026** everywhere it appears — §4's diff --git a/docs/07-fees.md b/docs/07-fees.md index 195df6e..0d05647 100644 --- a/docs/07-fees.md +++ b/docs/07-fees.md @@ -104,13 +104,18 @@ All figures **plus HST**. ### Arbitration -Sole, party-appointed and co-arbitration appointments are all accepted now — -`AGENTS.md` §4 Offerings carries a row for each `[verified 2026-08-26 — Pouya]`. +Sole, party-appointed and co-arbitration appointments **in commercial matters** +are all accepted now — `AGENTS.md` §4 Offerings carries a row for each +`[verified 2026-08-26 — Pouya]`. *("in commercial matters" added 2026-08-28: the +line was unscoped, and every §4 arbitration row is scoped commercial with family +arbitration separately NOT OFFERED — Q39's struck universal.)* *(This line previously read "sole appointments follow the Q.Arb designation", which understated the offering, and carried a caveat against a since-closed Q36.)* Whatever `/fees/` says about arbitration must state the Q.Arb stage plainly alongside it — §4 Offerings, "neither half may be dropped": the Q.Arb -designation commenced August 2026, with C.Med-Arb as the endpoint. See +**pathway** commenced August 2026, with C.Med-Arb as the endpoint. *("pathway", +not "designation" — a designation that commenced reads as held, which §4 +Forbidden bars. Corrected 2026-08-28 on `claims-auditor`'s finding.)* See `03-content-spec.md` for the wording. | Item | Fee | @@ -128,6 +133,17 @@ offer tribunal-secretary work on the site. Early neutral evaluation, dispute-system design, and pre-dispute technical advisory: **$500 / hour**. +> 🚫 **A RATE IS NOT A PUBLICATION LICENCE, AND THESE THREE ARE NOT PUBLISHABLE +> YET.** §4's ENE row says the pricing here *"is a fee-page question, not a +> publication licence"*, and all three Offerings rows read **NOT YET +> PUBLISHABLE** — gate 1 (*is the activity gated?*) has no source. **Q46(a)** +> names `docs/07-fees.md` pricing directly as something it blocks. +> +> So: the rate is recorded and settled; **the line item does not go on `/fees/` +> until Q46(a) closes.** This note did not exist until 2026-08-28, which meant +> the gate lived only in `AGENTS.md` while this file says "Build `/fees/` from +> it". Found by `claims-auditor` on re-audit. + **THREE services, not four. `settlement counsel` is struck and must not be priced** — `AGENTS.md` Q42, Pouya 2026-08-27, correcting his own entry in `docs/01`: diff --git a/docs/reference/adrio-designations.md b/docs/reference/adrio-designations.md new file mode 100644 index 0000000..69ac309 --- /dev/null +++ b/docs/reference/adrio-designations.md @@ -0,0 +1,251 @@ +# Reference — ADRIO's own expansions of the five ADR designations + +**Why this file exists.** `AGENTS.md` Q46(b) asked whether §11 Glossary may be +published as the source for **definitional expansions** — what `Q.Med`, `Q.Arb` +and `C.Med-Arb` stand for. Pouya ratified the standard on 2026-08-28 and +attached a condition: *"Fetch and commit +https://adr-ontario.ca/members-practitioners/professional-designations to +docs/reference/ per R14."* This is that fetch. + +It also settles a **correction Pouya raised in the same ruling**, and the +correction was his own: §11 had said *"Chartered Mediator-Arbitrator"* since the +file was created. ADRIO's term is **"Chartered Med-Arbitrator"**. See Finding 2. + +--- + +## Provenance — read this before quoting anything below + +| | | +|---|---| +| URL as given | `https://adr-ontario.ca/members-practitioners/professional-designations` | +| **Redirects to** | `https://adr-ontario.ca/professional-designations/` — HTTP **301**, one hop | +| Retrieved | **2026-08-28** | +| Method | `curl -sSL -o <file> '<url>'` — HTTP **200** on all five after the redirect | + +**The redirect is recorded because the first fetch did not follow it.** `curl -sS` +without `-L` returned HTTP 301 and wrote a **0-byte file**, which a reader of +the output could easily have taken for "the page is empty". It is not; it is +one hop away. `CLAUDE.md`: *a command that did not run is not evidence of +absence* — and a command that ran and returned nothing useful looks the same. + +### The five files, with digests + +| Page | Bytes | Text | `sha256` | +|---|---|---|---| +| `professional-designations/` | 54,961 | 1,932 | `5eca45791b3629d16186dd2a10df43fdd5981cbe89a6ce23d8b43ec7c4c415a8` | +| `qualified-mediator-q-med-qualified-arbitrator-q-arb/` | 57,174 | 2,814 | `c8cb8ad556b7ffd193cb672f136d4c0b0bdffdcaa8ac20739f31c1ccef84301f` | +| `chartered-mediator-c-med/` | 58,929 | 4,151 | `47cb8edb20681865b55103e265c693405a8dfde369fd5f4eefd340fb58f0c056` | +| `chartered-arbitrator-c-arb/` | 58,013 | 3,524 | `44526cb40f3e99bec03e3b45b13d4dc4b6cb5fd4e13b388ed533f7baa6fb1199` | +| `chartered-med-arbitrator-c-med-arb/` | 55,966 | 2,504 | `4c3a3214383c80209884125703e89625e855b550f01ea8141df496603cdd69c7` | + +*Text* = characters remaining after `<script>`/`<style>`/`<noscript>`/comments +and tags are stripped, entities unescaped, whitespace collapsed. + +> 📁 **THE EXTRACTED TEXT AND THE SCRIPT THAT PRODUCED IT ARE COMMITTED** — +> `adrio-extract/`. Every term count in this file was run against those `.txt` +> files, and `extract.mjs` is the extraction. **The digests above cover the raw +> HTML; they said nothing about the extraction**, so the counts were unverifiable +> by construction (R14) even while the digests were not — +> `adversarial-reviewer`, 2026-08-28. `adrio-extract/README.md` carries the +> reproduction command and the caveat that a future digest mismatch is most +> likely a WordPress plugin bump rather than a changed designation name. + +> ✅ **THESE DIGESTS ARE STAMPED, AND `lat-case-conference.md`'S ARE NOT — THE +> DIFFERENCE WAS CHECKED, NOT ASSUMED.** That file removed its hashes because the +> LAT pages could not reproduce one: `LAT-Rules.html` carries a per-request +> bot-detection nonce (`__uzdbm_1`, `__uzdbm_2`) and the AABS page carries +> rotating WordPress `?ver=` cache-busters. +> +> Both causes were looked for here and **both are absent**: +> +> - `__uzdbm` — **0 occurrences.** +> - `?ver=` — 17 occurrences, and they are **static plugin version strings** +> (`?ver=1.3.12`, `?ver=2.3.2`, `?ver=3.4.1`, `?ver=4.7.0`), not rotating +> values. Same string on every fetch. +> +> Then measured rather than reasoned about: **four independent fetches of each of +> the five URLs, and the file on disk re-hashed against a fresh fetch. All five +> MATCH.** The digests above are of the exact bytes the quotes below came from. +> +> **One instrument failure happened during that check and is recorded because of +> its shape.** The first comparison loop used `set -- $pair` under zsh, which +> does not word-split unquoted variables, so the loop body received one argument +> and every comparison silently failed — printing **`DIFFER` on all five rows**. +> That output reads exactly like *"the pages changed under me"*. It was the +> `timeout 60 ls "$DRIVE"` shape: the comparison had never run. Re-run with +> `while IFS=: read`, all five returned MATCH. + +**Instrument note on JS-rendered shells.** The parent page extracts to **1,932 +characters from 54,961 bytes — 3.5%**, which is the signature `adric.ca` produced +when it defeated an earlier attempt at this same sourcing (4,840 chars from +114,985). Here the low ratio is **not** a shell: the parent page really is nearly +empty — its body is a title and one sentence pointing elsewhere. The substance is +on the four child pages, which extract at 4.5–7.0% because ~1,800 characters of +the extraction on every page is the shared navigation. Read the ratio against the +page, not against a threshold. + +--- + +## Finding 1 — all five expansions, verbatim + +Present **twice** on the parent page (desktop and mobile navigation), and again +as the `<h1>` of each child page. ADRIO's own words, entities unescaped: + +| Abbrev. | ADRIO's expansion | Source | +|---|---|---| +| `Q.Med` | **Qualified Mediator** | nav + child `<h1>` | +| `Q.Arb` | **Qualified Arbitrator** | nav + child `<h1>` | +| `C.Med` | **Chartered Mediator** | nav + child `<h1>` | +| `C.Arb` | **Chartered Arbitrator** | nav + child `<h1>` | +| `C.Med-Arb` | **Chartered Med-Arbitrator** | nav + child `<h1>` | + +The navigation markup, verbatim: + +```html +<a href="https://adr-ontario.ca/qualified-mediator-q-med-qualified-arbitrator-q-arb/">Qualified Mediator (Q.Med) & Qualified Arbitrator (Q.Arb)</a> +<a href="https://adr-ontario.ca/chartered-mediator-c-med/">Chartered Mediator (C.Med)</a> +<a href="https://adr-ontario.ca/chartered-arbitrator-c-arb/">Chartered Arbitrator (C.Arb)</a> +<a href="https://adr-ontario.ca/chartered-med-arbitrator-c-med-arb/">Chartered Med-Arbitrator (C.Med-Arb)</a> +``` + +**The URL slugs corroborate independently of the link text** — `chartered-med-arbitrator-c-med-arb`, not `chartered-mediator-arbitrator`. + +## Finding 2 — the expansion this repo had wrong + +`AGENTS.md` §11 read **"Chartered Mediator-Arbitrator"** from the file's creation +until 2026-08-28. Pouya's ruling: *"§11 has said 'Chartered Mediator-Arbitrator' +throughout. ADRIO's own term is 'Chartered Med-Arbitrator'. I took the expansion +from the strategy brief and never sourced it."* + +**It had reached a public page.** `src/pages/about.astro`'s credential arc +rendered it as body copy, and `grep -c 'Chartered Mediator-Arbitrator' +dist/about/index.html` returned **1** — so the built artefact carried it too. Four +instances in the repo, swept 2026-08-28. + +The child page's own heading and first two sentences, verbatim: + +> **Chartered Med-Arbitrator (C.Med-Arb)** +> +> Med-Arb is a distinct, innovative standalone process that is not as well known +> or understood by consumers of ADR services compared to mediation and +> arbitration. +> +> Med-Arb is not merely the merging of separate mediation and arbitration +> processes, but a unique process designed to meet the needs of particular +> disputants. It involves nuances and complexities that can be fine-tuned to the +> needs of the parties as a customized dispute resolution process, which requires +> a high level of practitioner competence to do successfully. + +## Finding 3 — how ADRIO characterises the Q-level designations + +Verbatim, `qualified-mediator-q-med-qualified-arbitrator-q-arb/`: + +> **Qualified Mediator (Q.Med) / Qualified Arbitrator (Q.Arb)** +> +> These designations are to recognize practitioners who have completed sufficient +> mediation / arbitration and related dispute resolution training to be qualified +> to practice. They are an intermediate step for practitioners working to receive +> their Chartered designation. +> +> *Q.Med criteria vary across affiliates. For the criteria specific to Ontario, +> be sure to read the checklist on the application form.* + +⚠️ **Do not lift "qualified to practice" into copy, in any form.** It is ADRIO +describing its own designation, and on this site — where §4 records licence +status as `[unestablished]` and D13 bars any phrasing that *implies* entitlement +to practise law — the phrase would do work ADRIO never intended it to do. The +quote is here so a reviewer can see the full sentence, not so it can be reused. + +The *"intermediate step … working to receive their Chartered designation"* half +is the sourced basis for describing the arc as an arc. It is a fact about the +designation structure, not about Pouya. + +## Finding 4 — two of the four pages state a retention condition, and the split is by PAGE TYPE, not by designation level + +> ⚠️ **THIS FINDING'S FIRST VERSION WAS FRAMED WRONG, AND THE PAGE THAT +> FALSIFIED IT WAS ONE THIS FILE HAD ALREADY FETCHED.** It was headed *"the two +> Chartered pages state a retention condition; the Q page does not"* and argued a +> **Qualified-vs-Chartered** asymmetry. There are **three** Chartered pages. The +> count was never run on `chartered-med-arbitrator-c-med-arb/` — the designation +> §4 records as the practice's stated goal, and therefore the one most +> load-bearing for Q48. Found by `claims-auditor`, 2026-08-28. + +Counted on the extracted text of **all four** designation pages: + +| Page | `good standing` | `annual` | `maintain` | `retain` | `member of the ADR Institute` | +|---|---|---|---|---|---| +| `qualified-mediator-q-med-qualified-arbitrator-q-arb/` | 0 | 0 | 0 | 0 | 0 | +| `chartered-mediator-c-med/` | 1 | 1 | 1 | 1 | 1 | +| `chartered-arbitrator-c-arb/` | 1 | 1 | 1 | 1 | 1 | +| `chartered-med-arbitrator-c-med-arb/` | **0** | **0** | **0** | **0** | **0** | + +Verbatim, `chartered-mediator-c-med/`: + +> There is an annual fee to maintain your C.Med designation, payable to ADR +> Institute of Canada, Inc. The national organization bills you every year. You +> must also remain a member in good standing with the ADR Institute of Ontario™ +> to retain this designation. + +`chartered-arbitrator-c-arb/` says the same of C.Arb. + +**The corrected reading.** C.Med-Arb scores zero on every term, exactly like the +Q-level page — so the line does **not** fall between Qualified and Chartered. It +falls between **page types**: `chartered-mediator-c-med/` and +`chartered-arbitrator-c-arb/` are long application FAQs with numbered sections +("Are there prerequisites?", "Is there an ongoing cost?"), while the Q page and +the C.Med-Arb page are short descriptions that link out. The C.Med-Arb page says +so in as many words: *"To read more about the C.Med-Arb designation, including +how to apply, click here."* + +**And that cuts the opposite way from how the first version read it.** A stub +page's silence is evidence about the *page*, not about the designation — so +Q.Med's silence is most likely "this page does not cover fees or retention", not +"no such condition exists". ADRIC bills annually for the two designations that +say so, and ADRIO notes that *"Q.Med criteria vary across affiliates"*. + +**Still: this source does not answer it, in either direction, and must not be +read as doing so.** Raised as **Q48** — if `Q.Med` retention is contingent on +ADRIO membership currency, then §4's Q.Med row, this site's central credential, +inherits the shelf life of the memberships Pouya has declined to track by date +(R10). The answer needs the Q.Med criteria document or ADRIC/ADRIO directly. + +## Finding 5 — two superlatives, deliberately not lifted + +The Chartered pages call C.Med *"Canada's most senior official designation for +practising mediators"* and C.Arb *"Canada's only official designation for +practising Arbitrators"*. Both are ADRIO's words about its own designations and +both are quotable in principle. + +**Neither goes on the site.** §4 Forbidden bars superlatives outright +(*"best", "leading", "top-rated"*), and the reason given there is not only +verifiability — it is that *"they read as insecure to the audience this site is +for"*. A superlative does not stop being one because a third party said it first, +and the credential arc does not need it: **"the designation this practice is built +toward"** is Pouya's own stated goal and has a §4 row. + +--- + +## What this establishes, and what it does not + +**Establishes:** + +1. All five expansions, in ADRIO's own words, from ADRIO's own site, with + reproducible digests. **R14 is satisfied for Q46(b)** — the standard no longer + rests on §11 asserting its own content. +2. `C.Med-Arb` = **Chartered Med-Arbitrator**. The form this repo published was + wrong. +3. That the Q-level designations are, in ADRIO's characterisation, an + intermediate step toward the Chartered designations. + +**Does not establish:** + +- **Anything about Pouya.** Not that he holds Q.Med, not that he has commenced + Q.Arb, not that he is a member of ADRIO. Those are §4 Verified rows and this + file is not a substitute for one. The standard Pouya ratified is exactly this + split: *"§11 Glossary is the source for DEFINITIONAL expansions; §4 remains + the only source for claims about Pouya."* +- **Anything about gating** — see `AGENTS.md` §4's offering test, question 1. + ADRIO describes its designations as recognising completed training; it says + nothing about what any activity requires by law, and it is not a source that + could. Q46(a) is not advanced by this file. +- **Anything about Q.Med retention.** Finding 4. That is Q48. diff --git a/docs/reference/adrio-extract/README.md b/docs/reference/adrio-extract/README.md new file mode 100644 index 0000000..cff6758 --- /dev/null +++ b/docs/reference/adrio-extract/README.md @@ -0,0 +1,34 @@ +# The extracted text behind `../adrio-designations.md` + +**Why this directory exists.** `adversarial-reviewer` (2026-08-28, C10): the +`sha256` digests in that file cover the **raw HTML**, but Finding 4's term counts +were taken from **extracted text produced by an uncommitted script** — so the +counts were unverifiable by construction (R14) even though the digests were not. + +`extract.mjs` is that script. `*.txt` are its outputs, which are what every +count in `../adrio-designations.md` was run against. + +## Reproducing + +```sh +curl -sSL -o <slug>.html "https://adr-ontario.ca/<slug>/" +node extract.mjs <slug>.html > <slug>.txt +``` + +The five slugs are listed in the provenance table of `../adrio-designations.md`, +which also carries each file's raw-HTML byte count and `sha256`. + +**Expect small differences in the character totals if you re-implement the +extraction.** Both review agents reproduced every digest, every byte count and +every term count exactly; one got 1924 / 2806 / 4121 / 3510 / 2496 characters +against this script's 1932 / 2814 / 4151 / 3524 / 2504, because tag-stripping +inserts whitespace differently. **The term counts are the finding; the character +totals are only a size indicator.** + +⚠️ **The digests are valid until ADRIO's next WordPress plugin update.** The +served HTML carries 17 `?ver=` strings that are static plugin versions today +(`?ver=1.3.12`, `?ver=2.3.2`, …) — which is *why* these pages hash reproducibly +where the LAT pages could not. Those strings will move when ADRIO updates a +plugin. **A future digest mismatch is most likely a plugin bump, not tampering +and not a changed designation name** — re-run the term counts before concluding +anything from a mismatch. diff --git a/docs/reference/adrio-extract/chartered-arbitrator-c-arb.txt b/docs/reference/adrio-extract/chartered-arbitrator-c-arb.txt new file mode 100644 index 0000000..ee983c2 --- /dev/null +++ b/docs/reference/adrio-extract/chartered-arbitrator-c-arb.txt @@ -0,0 +1,100 @@ +Chartered Arbitrator (C.Arb) – The ADR Institute of Ontario +Skip to content +About +About Us +What is ADR? +Resolve a Dispute +ADRIO Board of Directors and Staff +Rules & Codes +ADRIO DEI Policy Framework +Professional Development +Event Calendar +Webcasts – Recorded Events +Approved Courses +Lead a Professional Development Workshop with us! +Sections +Communities of Practice and Sections +Committees +Membership & Benefits +Member Portal +Benefits and Application Process +Practical Ethics for Working Mediators +Insurance +Rules & Codes +FAQ +Designations +The Path to your Professional ADR designation +ADRIC Accredited Courses +Qualified Mediator (Q.Med) & Qualified Arbitrator (Q.Arb) +Chartered Mediator (C.Med) +Chartered Arbitrator (C.Arb) +Chartered Med-Arbitrator (C.Med-Arb) +Insurance +FAQ +News & Blog +Blog +Updates +Newsletter +ADRIO E-Mailing List Signup +President’s Circle +ADRIO STAR Award Recipients +Contact & Staff +About +- About Us +- What is ADR? +- Resolve a Dispute +- ADRIO Board of Directors and Staff +- Rules & Codes +- ADRIO DEI Policy Framework +Professional Development +- Event Calendar +- Webcasts - Recorded Events +- Approved Courses +- Lead a Professional Development Workshop with us! +Sections +- Communities of Practice and Sections +- Committees +Membership & Benefits +- Member Portal +- Benefits and Application Process +- Practical Ethics for Working Mediators +- Insurance +- Rules & Codes +- FAQ +Designations +- The Path to your Professional ADR designation +- ADRIC Accredited Courses +- Qualified Mediator (Q.Med) & Qualified Arbitrator (Q.Arb) +- Chartered Mediator (C.Med) +- Chartered Arbitrator (C.Arb) +- Chartered Med-Arbitrator (C.Med-Arb) +- Insurance +- FAQ +News & Blog +- Blog +- Updates +- Newsletter +- ADRIO E-Mailing List Signup +- President’s Circle +- ADRIO STAR Award Recipients +Contact & Staff +Chartered Arbitrator (C.Arb) +Please do not mail your applications to our head office. Please email your application to membership@adr-ontario.ca +1. What is a Chartered Arbitrator (C.Arb) designation? +The C.Arb Or Chartered Arbitrator designation is Canada’s only official designation for practising Arbitrators. Please click here for a more complete description of the requirements can be found. +2. Are there prerequisites? +The applicant must be a member of the ADR Institute of Ontario™ (or any other regional association). +There are extensive training and experience requirements which you should review before applying. +3. Where do I get the C.Arb Application Form? +The C.Arb application form is linked below. +4. Is there a fee for the C.Arb application? +Yes, the Application Fee is $500.00 (plus HST). This covers the costs of administering the accreditation process. This is a one-time application fee. +5. Is there an ongoing cost? +There is an annual fee to maintain your C.Arb designation. The national organization bills you every year. You must also remain a member in good standing with the ADR Institute of Ontario™ to retain this designation. +6. How do I apply? +Forward your completed application form, and payment along with any attachments necessary to verify the courses you have taken and the work you have done (think of it as marketing yourself to the accreditation committee), to: +Please do not mail your applications to our head office. Please email your application to membership@adr-ontario.ca +(Looking for courses that have been pre-approved to qualify for designation applications? Click here .) +View C.Arb Application Form +View C.Arb Criteria +Theme by Think Up Themes Ltd . Powered by WordPress . \ No newline at end of file diff --git a/docs/reference/adrio-extract/chartered-med-arbitrator-c-med-arb.txt b/docs/reference/adrio-extract/chartered-med-arbitrator-c-med-arb.txt new file mode 100644 index 0000000..b9340af --- /dev/null +++ b/docs/reference/adrio-extract/chartered-med-arbitrator-c-med-arb.txt @@ -0,0 +1,85 @@ +Chartered Med-Arbitrator (C.Med-Arb) – The ADR Institute of Ontario +Skip to content +About +About Us +What is ADR? +Resolve a Dispute +ADRIO Board of Directors and Staff +Rules & Codes +ADRIO DEI Policy Framework +Professional Development +Event Calendar +Webcasts – Recorded Events +Approved Courses +Lead a Professional Development Workshop with us! +Sections +Communities of Practice and Sections +Committees +Membership & Benefits +Member Portal +Benefits and Application Process +Practical Ethics for Working Mediators +Insurance +Rules & Codes +FAQ +Designations +The Path to your Professional ADR designation +ADRIC Accredited Courses +Qualified Mediator (Q.Med) & Qualified Arbitrator (Q.Arb) +Chartered Mediator (C.Med) +Chartered Arbitrator (C.Arb) +Chartered Med-Arbitrator (C.Med-Arb) +Insurance +FAQ +News & Blog +Blog +Updates +Newsletter +ADRIO E-Mailing List Signup +President’s Circle +ADRIO STAR Award Recipients +Contact & Staff +About +- About Us +- What is ADR? +- Resolve a Dispute +- ADRIO Board of Directors and Staff +- Rules & Codes +- ADRIO DEI Policy Framework +Professional Development +- Event Calendar +- Webcasts - Recorded Events +- Approved Courses +- Lead a Professional Development Workshop with us! +Sections +- Communities of Practice and Sections +- Committees +Membership & Benefits +- Member Portal +- Benefits and Application Process +- Practical Ethics for Working Mediators +- Insurance +- Rules & Codes +- FAQ +Designations +- The Path to your Professional ADR designation +- ADRIC Accredited Courses +- Qualified Mediator (Q.Med) & Qualified Arbitrator (Q.Arb) +- Chartered Mediator (C.Med) +- Chartered Arbitrator (C.Arb) +- Chartered Med-Arbitrator (C.Med-Arb) +- Insurance +- FAQ +News & Blog +- Blog +- Updates +- Newsletter +- ADRIO E-Mailing List Signup +- President’s Circle +- ADRIO STAR Award Recipients +Contact & Staff +Chartered Med-Arbitrator (C.Med-Arb) +Med-Arb is a distinct, innovative standalone process that is not as well known or understood by consumers of ADR services compared to mediation and arbitration. +Med-Arb is not merely the merging of separate mediation and arbitration processes, but a unique process designed to meet the needs of particular disputants. It involves nuances and complexities that can be fine-tuned to the needs of the parties as a customized dispute resolution process, which requires a high level of practitioner competence to do successfully. +To read more about the C.Med-Arb designation, including how to apply, click here . +Theme by Think Up Themes Ltd . Powered by WordPress . \ No newline at end of file diff --git a/docs/reference/adrio-extract/chartered-mediator-c-med.txt b/docs/reference/adrio-extract/chartered-mediator-c-med.txt new file mode 100644 index 0000000..a3ab37f --- /dev/null +++ b/docs/reference/adrio-extract/chartered-mediator-c-med.txt @@ -0,0 +1,100 @@ +Chartered Mediator (C.Med) – The ADR Institute of Ontario +Skip to content +About +About Us +What is ADR? +Resolve a Dispute +ADRIO Board of Directors and Staff +Rules & Codes +ADRIO DEI Policy Framework +Professional Development +Event Calendar +Webcasts – Recorded Events +Approved Courses +Lead a Professional Development Workshop with us! +Sections +Communities of Practice and Sections +Committees +Membership & Benefits +Member Portal +Benefits and Application Process +Practical Ethics for Working Mediators +Insurance +Rules & Codes +FAQ +Designations +The Path to your Professional ADR designation +ADRIC Accredited Courses +Qualified Mediator (Q.Med) & Qualified Arbitrator (Q.Arb) +Chartered Mediator (C.Med) +Chartered Arbitrator (C.Arb) +Chartered Med-Arbitrator (C.Med-Arb) +Insurance +FAQ +News & Blog +Blog +Updates +Newsletter +ADRIO E-Mailing List Signup +President’s Circle +ADRIO STAR Award Recipients +Contact & Staff +About +- About Us +- What is ADR? +- Resolve a Dispute +- ADRIO Board of Directors and Staff +- Rules & Codes +- ADRIO DEI Policy Framework +Professional Development +- Event Calendar +- Webcasts - Recorded Events +- Approved Courses +- Lead a Professional Development Workshop with us! +Sections +- Communities of Practice and Sections +- Committees +Membership & Benefits +- Member Portal +- Benefits and Application Process +- Practical Ethics for Working Mediators +- Insurance +- Rules & Codes +- FAQ +Designations +- The Path to your Professional ADR designation +- ADRIC Accredited Courses +- Qualified Mediator (Q.Med) & Qualified Arbitrator (Q.Arb) +- Chartered Mediator (C.Med) +- Chartered Arbitrator (C.Arb) +- Chartered Med-Arbitrator (C.Med-Arb) +- Insurance +- FAQ +News & Blog +- Blog +- Updates +- Newsletter +- ADRIO E-Mailing List Signup +- President’s Circle +- ADRIO STAR Award Recipients +Contact & Staff +Chartered Mediator (C.Med) +Please do not mail your applications to our head office. Please email your application to membership@adr-ontario.ca +1. What is a Chartered Mediator (C.Med) designation? +The “C.Med” or “Chartered Mediator” designation is Canada’s most senior official designation for practising mediators. +Clarification re Footnote #4 in the C.Med Criteria “The intended interpretation of Footnote #4 relating to a “Paid Mediation” is as follows: The criteria in Footnote #4 is intended to be applied individually to each of the 15 mediations presented by the applicant, and specifically where a mediation is not fee-paid, the RCMAC shall look at whether the mediation is demonstrably complex and involved, and may at its discretion accept the mediation being considered toward the 15 total mediations. There is no specific minimum number of fee paid mediations of the 15 total mediations required, providing this criteria is applied to each unpaid mediation.” +Use the Application for Chartered Mediator designation linked below. +2. Are there prerequisites? +The applicant must be a member of the ADR Institute of Ontario™. +There are extensive training and experience requirements which you should review before you consider applying. +3. Is there a fee for the C.Med application? +Yes, the Application Fee is $500.00 (plus HST) made payable to the ADR Institute of Ontario, Inc. This covers the costs of administering the accreditation process. This is a one-time application fee. +4. Is there an ongoing cost? +Yes. There is an annual fee to maintain your C.Med designation, payable to ADR Institute of Canada, Inc. The national organization bills you every year. You must also remain a member in good standing with the ADR Institute of Ontario™ to retain this designation. +6. How do I apply? +Forward your completed application form along with any attachments necessary to verify the courses you have taken and the work you have done (think of it as marketing yourself to the accreditation committee), to: +Please do not mail your applications to our head office. Please email your application to membership@adr-ontario.ca +(Looking for courses that have been pre-approved to qualify for designation applications? Click here .) +View C.Med Application Form +View C.Med Criteria +Theme by Think Up Themes Ltd . Powered by WordPress . \ No newline at end of file diff --git a/docs/reference/adrio-extract/extract.mjs b/docs/reference/adrio-extract/extract.mjs new file mode 100644 index 0000000..2da3261 --- /dev/null +++ b/docs/reference/adrio-extract/extract.mjs @@ -0,0 +1,14 @@ +import { readFileSync } from 'node:fs'; +const raw = readFileSync(process.argv[2], 'utf8'); +let t = raw + .replace(/<script\b[\s\S]*?<\/script>/gi, ' ') + .replace(/<style\b[\s\S]*?<\/style>/gi, ' ') + .replace(/<noscript\b[\s\S]*?<\/noscript>/gi, ' ') + .replace(/<!--[\s\S]*?-->/g, ' ') + .replace(/<[^>]+>/g, ' '); +const ents = { amp:'&', lt:'<', gt:'>', quot:'"', apos:"'", nbsp:' ', ndash:'–', mdash:'—', rsquo:'’', lsquo:'‘', ldquo:'“', rdquo:'”' }; +t = t.replace(/&([a-zA-Z]+);/g, (m,n)=> n in ents ? ents[n] : m) + .replace(/&#(\d+);/g, (_m,d)=> String.fromCodePoint(+d)) + .replace(/&#x([0-9a-f]+);/gi, (_m,h)=> String.fromCodePoint(parseInt(h,16))); +t = t.replace(/[ \t ]+/g,' ').replace(/\s*\n\s*/g,'\n').replace(/\n{2,}/g,'\n').trim(); +process.stdout.write(t); diff --git a/docs/reference/adrio-extract/professional-designations.txt b/docs/reference/adrio-extract/professional-designations.txt new file mode 100644 index 0000000..428b820 --- /dev/null +++ b/docs/reference/adrio-extract/professional-designations.txt @@ -0,0 +1,83 @@ +Professional Designations – The ADR Institute of Ontario +Skip to content +About +About Us +What is ADR? +Resolve a Dispute +ADRIO Board of Directors and Staff +Rules & Codes +ADRIO DEI Policy Framework +Professional Development +Event Calendar +Webcasts – Recorded Events +Approved Courses +Lead a Professional Development Workshop with us! +Sections +Communities of Practice and Sections +Committees +Membership & Benefits +Member Portal +Benefits and Application Process +Practical Ethics for Working Mediators +Insurance +Rules & Codes +FAQ +Designations +The Path to your Professional ADR designation +ADRIC Accredited Courses +Qualified Mediator (Q.Med) & Qualified Arbitrator (Q.Arb) +Chartered Mediator (C.Med) +Chartered Arbitrator (C.Arb) +Chartered Med-Arbitrator (C.Med-Arb) +Insurance +FAQ +News & Blog +Blog +Updates +Newsletter +ADRIO E-Mailing List Signup +President’s Circle +ADRIO STAR Award Recipients +Contact & Staff +About +- About Us +- What is ADR? +- Resolve a Dispute +- ADRIO Board of Directors and Staff +- Rules & Codes +- ADRIO DEI Policy Framework +Professional Development +- Event Calendar +- Webcasts - Recorded Events +- Approved Courses +- Lead a Professional Development Workshop with us! +Sections +- Communities of Practice and Sections +- Committees +Membership & Benefits +- Member Portal +- Benefits and Application Process +- Practical Ethics for Working Mediators +- Insurance +- Rules & Codes +- FAQ +Designations +- The Path to your Professional ADR designation +- ADRIC Accredited Courses +- Qualified Mediator (Q.Med) & Qualified Arbitrator (Q.Arb) +- Chartered Mediator (C.Med) +- Chartered Arbitrator (C.Arb) +- Chartered Med-Arbitrator (C.Med-Arb) +- Insurance +- FAQ +News & Blog +- Blog +- Updates +- Newsletter +- ADRIO E-Mailing List Signup +- President’s Circle +- ADRIO STAR Award Recipients +Contact & Staff +Professional Designations +To read more about the path to designations, click here . +Theme by Think Up Themes Ltd . Powered by WordPress . \ No newline at end of file diff --git a/docs/reference/adrio-extract/qualified-mediator-q-med-qualified-arbitrator-q-arb.txt b/docs/reference/adrio-extract/qualified-mediator-q-med-qualified-arbitrator-q-arb.txt new file mode 100644 index 0000000..0080b05 --- /dev/null +++ b/docs/reference/adrio-extract/qualified-mediator-q-med-qualified-arbitrator-q-arb.txt @@ -0,0 +1,91 @@ +Qualified Mediator (Q.Med) & Qualified Arbitrator (Q.Arb) – The ADR Institute of Ontario +Skip to content +About +About Us +What is ADR? +Resolve a Dispute +ADRIO Board of Directors and Staff +Rules & Codes +ADRIO DEI Policy Framework +Professional Development +Event Calendar +Webcasts – Recorded Events +Approved Courses +Lead a Professional Development Workshop with us! +Sections +Communities of Practice and Sections +Committees +Membership & Benefits +Member Portal +Benefits and Application Process +Practical Ethics for Working Mediators +Insurance +Rules & Codes +FAQ +Designations +The Path to your Professional ADR designation +ADRIC Accredited Courses +Qualified Mediator (Q.Med) & Qualified Arbitrator (Q.Arb) +Chartered Mediator (C.Med) +Chartered Arbitrator (C.Arb) +Chartered Med-Arbitrator (C.Med-Arb) +Insurance +FAQ +News & Blog +Blog +Updates +Newsletter +ADRIO E-Mailing List Signup +President’s Circle +ADRIO STAR Award Recipients +Contact & Staff +About +- About Us +- What is ADR? +- Resolve a Dispute +- ADRIO Board of Directors and Staff +- Rules & Codes +- ADRIO DEI Policy Framework +Professional Development +- Event Calendar +- Webcasts - Recorded Events +- Approved Courses +- Lead a Professional Development Workshop with us! +Sections +- Communities of Practice and Sections +- Committees +Membership & Benefits +- Member Portal +- Benefits and Application Process +- Practical Ethics for Working Mediators +- Insurance +- Rules & Codes +- FAQ +Designations +- The Path to your Professional ADR designation +- ADRIC Accredited Courses +- Qualified Mediator (Q.Med) & Qualified Arbitrator (Q.Arb) +- Chartered Mediator (C.Med) +- Chartered Arbitrator (C.Arb) +- Chartered Med-Arbitrator (C.Med-Arb) +- Insurance +- FAQ +News & Blog +- Blog +- Updates +- Newsletter +- ADRIO E-Mailing List Signup +- President’s Circle +- ADRIO STAR Award Recipients +Contact & Staff +Qualified Mediator (Q.Med) & Qualified Arbitrator (Q.Arb) +Qualified Mediator (Q.Med) / Qualified Arbitrator (Q.Arb) +These designations are to recognize practitioners who have completed sufficient mediation / arbitration and related dispute resolution training to be qualified to practice. They are an intermediate step for practitioners working to receive their Chartered designation. +Please do not mail your applications to our head office. Please email your application to membership@adr-ontario.ca +(Looking for courses that have been pre-approved to qualify for designation applications? Click here .) +Read more by downloading the following resources: +Qualified Arbitrator (Q.Arb) Requirements +Qualified Arbitrator (Q.Arb) Application Form +Qualified Mediator (Q.Med) Criteria and Application Form* +*Q.Med criteria vary across affiliates. For the criteria specific to Ontario, be sure to read the checklist on the application form. +Theme by Think Up Themes Ltd . Powered by WordPress . \ No newline at end of file diff --git a/src/components/SiteFooter.astro b/src/components/SiteFooter.astro index 440e93c..d47a79d 100644 --- a/src/components/SiteFooter.astro +++ b/src/components/SiteFooter.astro @@ -62,10 +62,11 @@ const aboutLinks = [ { /* The designation strip carries the credentialing STAGE, not just the held designation, and that is a §4 Offerings condition rather than a - flourish. The masthead says "Mediation · Arbitration · Toronto" on - every page; §4 permits the arbitration half on the condition that the - site "makes the first while stating the second plainly", and - "neither half may be dropped". Before this line rendered + flourish. The masthead names arbitration on every page except `/`, + where SiteHeader suppresses the tagline by design. §4 permits the + arbitration half on the condition that the site "makes the first while + stating the second plainly", and "neither half may be dropped". + Before this line rendered CREDENTIALS.inProgress, that condition was unmet on every page that ships — the constant existed in site.ts and was rendered nowhere. Q.Arb reads as commenced, never as held (§4). */ diff --git a/src/data/schema.ts b/src/data/schema.ts index 5a8d33b..f6883aa 100644 --- a/src/data/schema.ts +++ b/src/data/schema.ts @@ -16,15 +16,31 @@ * 1. `LegalService` — NEVER. docs/04: schema.org defines it as a business * providing legal advice and *representation*, which asserts in * machine-readable form exactly what D13 bars. `ProfessionalService`. - * 2. `worksFor` — omitted. Populating it either names the boutique (D16) or - * misstates the employer. `jobTitle` carries the role on its own. + * 2. `worksFor` — **STILL OMITTED, and the reason has changed.** The original + * ground was "either names the boutique (D16) or misstates the employer". + * Q47 (2026-08-28) answers the **D16 half**: `jobTitle` now describes this + * practice, so naming SML Company Ltd would not name the boutique. It was + * set on that basis for one pass and `adversarial-reviewer` found why that + * is not sufficient — **the second half was never addressed:** + * `ProfessionalService.provider` is this Person, so `provider → Person → + * worksFor → SML` asserts transitively a same-entity claim **no §4 row + * makes** — and one `src/pages/about.astro` DELETED from visible prose as + * *"a corporate-structure claim"*. *(This read "defeats a guard in this + * file… that `aboutGraph`'s comment explicitly declines to assert". That + * comment covers `ProfilePage`, `BreadcrumbList` and `memberOf` and says + * nothing about SML — the citation was EMPTY. Found by + * `adversarial-reviewer`: a claim whose referent cannot be reached is + * unverifiable by construction, this repo's own rule, applied to the + * argument for a revert. The transitive argument stands on its own.)* §4 also says "**alongside** the practice" where Q47 says + * "operates **through**" — different relations, and only the first has a + * row. **Q49** asks Pouya for the row. Until then, withheld. * 3. `priceRange` — omitted until `/fees/` exists (build step 9). docs/04 * gates it on that page being real. * * AND Q.Arb IS NOT IN `hasCredential`. It commenced August 2026 and is not * held. Q.Med is. That asymmetry is the whole point of the property. */ -import { CONTACT, CREDENTIALS, ROLE, SITE } from './site'; +import { CONTACT, CREDENTIALS, PRACTICE_JOB_TITLE, SITE } from './site'; /** Stable node ids, so pages cross-reference rather than duplicate. */ export const PERSON_ID = `${SITE.url}/about/#person`; @@ -63,7 +79,14 @@ export function personNode(imageUrl?: string) { '@id': PERSON_ID, name: SITE.name, url: `${SITE.url}/about/`, - jobTitle: ROLE.title, + /* Q47: PRACTICE_JOB_TITLE, not ROLE.title — the boutique role stays in + visible copy and out of this graph, which is what the ruling was for. + The VALUE is the narrowest form §4 rows; it shipped for one pass as + "Mediator and Commercial Arbitrator" and both review agents struck it as + the role-shaped claim removed from `description` the previous day. See the + constant in site.ts for the full reasoning, and Q49 for the open row. + NO `worksFor` beside it — withheld pending the same question. */ + jobTitle: PRACTICE_JOB_TITLE, description: 'Mediator in Toronto, accepting commercial arbitration appointments. ' + 'Q.Med designation through ADRIC and ADRIO; the Q.Arb pathway commenced ' + @@ -159,23 +182,57 @@ export function homeGraph(imageUrl?: string) { * no visible breadcrumb, and the header nav marks it as current — so * emitting one would assert a navigation structure the page does not show. * Breadcrumbs begin at the two-level pages: `/practice/<area>/`, `/insights/<slug>/`. - * 3. `memberOf` for the four memberships. Declined on R10 / **Q44** — and - * the visible page reached the same answer one round later, which is worth - * recording: `/about/` now publishes **no memberships group at all**, - * because R10 is a prohibition on shipping such a page and the - * re-confirmation was not obtained. So this field is not a stricter - * standard than the page; it is the same one. + * 3. `memberOf` — **STILL WITHHELD, AND NOW ON NARROWER GROUNDS THAN THE + * PAGE.** Q44 closed 2026-08-28 and `/about/` **does** publish all four + * visibly, so the earlier reasoning ("this field is not a stricter standard + * than the page; it is the same one") no longer holds. It is now + * deliberately stricter, for one reason that Q44 did not touch and in fact + * sharpened: * - * Two earlier versions of this comment were wrong on the facts. They said - * "the page publishes them visibly" (it does not, as of 2026-08-28) and - * "all four renew yearly" — §4 records yearly renewal for **the OBA - * sections and the CTF only** and says nothing about ADRIC or ADRIO. The - * widened form had propagated to four files. + * **The ground is VOLATILITY, not cacheability** — and the first version of + * this comment got that wrong in a way `adversarial-reviewer` showed proves + * too much. It said "a scraped claim is cached and re-served by systems that + * never re-read it", which is equally true of `hasCredential`, and + * `hasCredential` ships. A later reader applying that principle + * consistently would either strip Q.Med from the graph (wrong) or restore + * `memberOf` (possibly wrong), because the stated reason does not + * distinguish the two fields. * - * The reason a machine-readable membership claim is worse than a visible - * one stands regardless: a list on a page is corrected by editing the page, - * while a scraped claim is cached and re-served by systems that never - * re-read it. OCNI lapsed quietly once already. Add this when Q44 closes. + * **What distinguishes them:** a membership is a fact with a **renewal + * cycle** — §4 records yearly renewal for **the OBA sections and the CTF** + * and says **nothing** about ADRIC's or ADRIO's period — and Pouya has + * declined to track the dates, so the claim's truth can change with nobody + * holding the schedule. A designation is not on a renewal cycle this record + * knows of. *(This paragraph said "a membership list is a set of yearly + * renewing facts" until 2026-08-28 — the widened form, FOURTH occurrence, + * twenty lines above this same comment's own warning that it "is still + * wrong and still must not be written". It was also the stated ground for + * withholding `memberOf`, so the withholding rested on a widened premise. + * Found by `claims-auditor` on re-audit.)* Caching only matters because the + * underlying fact + * moves — so volatility is the reason and caching is the mechanism. + * + * ⚠️ **AND `hasCredential` IS NOT SAFE BY THAT TEST — see Q48**, raised in + * this same change set: ADRIO states a membership-in-good-standing retention + * condition for C.Med and C.Arb and states none for Q.Med, and the reason + * it states none looks like page type rather than absence of a condition. + * **If Q.Med retention IS contingent on ADRIO membership currency, then + * `hasCredential` — which ships — carries the higher exposure of the two.** + * That is an argument for answering Q48, not for adding `memberOf`. + * OCNI lapsed quietly once already; §4 still carries it as "not current, do + * not publish". + * + * **This is a judgement, not an instruction from Pouya.** Q44's Blocks + * column listed `memberOf` among the things it gated, so closing Q44 does + * unblock it; his ruling said "ship the group", which is the visible one, + * and said nothing about the graph. Reversing this is four lines and his + * call — it is flagged in the session report rather than buried here. + * + * *Two earlier versions of this comment were wrong on the facts: they said + * the page published them visibly when it did not, and that "all four renew + * yearly" when §4 records yearly renewal for the OBA sections and the CTF + * only. The first is now true again; the second is still wrong and still + * must not be written.* */ export function aboutGraph(imageUrl?: string) { return { diff --git a/src/data/site.ts b/src/data/site.ts index 3367d26..6d9fcac 100644 --- a/src/data/site.ts +++ b/src/data/site.ts @@ -49,19 +49,42 @@ export const SITE = { export const CREDENTIALS = { designations: ['Q.Med (ADRIC / ADRIO)'], inProgress: ['Q.Arb — commenced August 2026'], // [verified 2026-08-26] - goal: 'C.Med-Arb (Chartered Mediator-Arbitrator)', + /** + * "Chartered Med-Arbitrator" — ADRIO's own term + * (docs/reference/adrio-designations.md). This read "Chartered + * Mediator-Arbitrator" until 2026-08-28, which was wrong; Pouya caught it and + * it was his own error, carried from the strategy brief and never sourced. + * + * UNCONSUMED AS OF 2026-08-28 — nothing imports `CREDENTIALS.goal`. `/about/`'s + * credential arc hand-types all three designations instead, which is the drift + * shape this repo keeps paying for (see ContactBand's 52ch/46ch divergence). + * It is corrected rather than deleted because `/med-arb/` at build step 4 is + * its natural consumer: either that page uses it, or this line comes out. + */ + goal: 'C.Med-Arb (Chartered Med-Arbitrator)', education: ['JD, Bond University'], certifications: [ 'Kompass Arbitration Certificate Program', - 'Stitt Feld Handy — negotiation and ADR workshop series', + /* "sequence", NOT "series" — §4: "Stitt Feld Handy negotiation and ADR + workshop **sequence** — completed". This list said "series" while the bio + prose on the same page said "sequence": one certification, two names, one + page. Found by `claims-auditor` 2026-08-28. Same shape as the C.Med-Arb + error — a third-party programme name that four review passes read without + checking it was right. */ + 'Stitt Feld Handy — negotiation and ADR workshop sequence', ], languages: ['English', 'Farsi'], /** - * [verified 2026-08-26 — Pouya, AGENTS.md Q28 and the CTF addition of the same + * [verified 2026-08-28 — Pouya, AGENTS.md Q44] — re-stamped when Q44 closed; + * the original confirmation was 2026-08-26 (Q28 plus the CTF addition of the same * date] — and FOR NOW. * * WHAT §4 ACTUALLY SAYS ABOUT RENEWAL, because a widened version of it reached - * a public page. §4: *"Both the OBA sections and the CTF renew yearly."* It + * a public page. §4, quoted exactly: *"the OBA sections and the CTF renew + * yearly"* — NOT "Both the OBA sections…", which is how this comment quoted it + * until 2026-08-28. The substance was right and the quotation marks were not, + * in the comment written to stop a widened paraphrase of this exact sentence. + * Found by `claims-auditor`. It * says **nothing** about ADRIC's or ADRIO's renewal period. An earlier form of * this comment read "Both the OBA sections and the Canadian Tax Foundation * renew yearly, so every line below is a fact with a shelf life", which is two @@ -70,12 +93,21 @@ export const CREDENTIALS = { * `/about/`, and into §9 Q44. Exactly the SES-DKIM duplication shape: the copy * that goes stale is the one nobody re-reads, and this copy became public copy. * - * **NOT PUBLISHED AS OF 2026-08-28 — R10 / Q44.** R10 requires a - * re-confirmation *"before any page listing memberships ships"*, `/about/` is - * that page, and the re-confirmation is a fact only Pouya holds. It was not - * obtained, so `/about/` ships its Credentials section WITHOUT a memberships - * group and carries a `TODO(pouya)`. Do not render this array on a public page - * until Q44 closes. + * **PUBLISHED FROM 2026-08-28 — Q44 CLOSED.** Pouya re-confirmed all four as + * current, which discharges R10's prohibition, and `/about/` now renders a + * Memberships group from this array. Re-stamped `[verified 2026-08-28 — + * Pouya]`; the earlier stamp was 2026-08-26. + * + * ⚠️ **RENDER THE LIST; NEVER RENDER A CLAIM ABOUT ITS CURRENCY.** No + * "renewed annually", no "current as of", no "listed as current", no stamp + * date in the markup. Pouya's ruling: *"List the memberships; promise nothing + * about their future state. The list is a snapshot, and only §4's stamp says + * when it was taken."* He declined renewal-date tracking, so there is no date + * behind such a sentence and nothing in this repo could support one. + * + * R10 stays live and now fires on an **event** rather than a date: re-confirm + * before any cutover or major republish. OCNI is why — §4 carries it as lapsed + * and unpublishable, and that was found roughly a year late. * * NOT OCNI (lapsed — §4: "not current, do not publish") and NOT the Law * Society: listing the LSO implies licensure, which D13 bars. Do not add @@ -105,9 +137,22 @@ export const BOUTIQUE = 'a Toronto litigation and ADR boutique' as const; * these are the two where the wording IS the compliance. */ export const ROLE = { - /** §4 verbatim. docs/04: this is `jobTitle` in the Person JSON-LD, and - * `worksFor` is OMITTED — populating it either names the boutique (D16) or - * misstates the employer. */ + /** + * §4 verbatim, and it is the VISIBLE role only. + * + * NO LONGER THE JSON-LD `jobTitle` — Q47, ruled 2026-08-28. This string was + * both the visible role line and the Person node's `jobTitle`, which put + * "Director of Firm Operations" on a node whose `url` is this ADR practice's + * `/about/` — so a consumer could attach the boutique title to this entity. + * Pouya's ruling splits them: the graph carries PRACTICE_JOB_TITLE below, + * while this string stays exactly where it was in visible copy ("I am + * {ROLE.title} at {ROLE.at}"). + * + * **The graph carries NO `worksFor`.** This sentence said it did — "the graph + * now carries PRACTICE_JOB_TITLE below and `worksFor: SML Company Ltd`" — + * which was true for one pass and was reverted the same day (Q49(b)). Verified + * 2026-08-28: zero live `worksFor` properties in `src`. + */ title: 'Director of Firm Operations', // [verified 2026-08-25 — strategy brief §I] /** Always rendered with BOUTIQUE, never with a firm name (D16). */ at: BOUTIQUE, @@ -133,6 +178,105 @@ export const ROLE = { ], } as const; +/** + * The Person node's `jobTitle` — Q47, ruled by Pouya 2026-08-28. + * + * NOT `ROLE.title`, and that separation IS the ruling. §4's row is one fact with + * two halves — *"Director of Firm Operations, Toronto litigation and ADR + * boutique"* — and visible copy always pairs them. The JSON-LD emitted only the + * first half, on a `Person` whose `url` is this practice's `/about/`, so a + * consumer could attach the boutique title to this entity. `worksFor` could not + * fix it, because D16 bars naming the boutique and there was no value it could + * take. + * + * His ruling breaks the bind by changing what the field is about: *"jobTitle + * describes this practice, not the boutique role, which D16 keeps unnamed"* — + * and that half holds: this constant names no boutique. + * + * **THE `worksFor` HALF OF THE RULING IS NOT IMPLEMENTED — Q49(b).** This + * paragraph said *"`worksFor` becomes SML Company Ltd — verified, federally + * incorporated, and the entity the practice operates through. Both are set"*. + * Two defects, both found by `claims-auditor` on re-audit: **"Both are set" is + * false** (reverted the same day), and *"the entity the practice operates + * through"* was listed inside a run of verified attributes when **§4 rows only + * "Operator of SML Company Ltd. `alongside` the practice"** — a different + * structural relation, and precisely what Q49(b) is open on. Do not restate the + * ruling's phrasing as though the register carried it. + * + * ⚠️ **IT SHIPPED FOR ONE PASS AS "Mediator and Commercial Arbitrator" AND THAT + * WAS WRONG FOR A REASON I HAD NOT SEEN.** Both review agents found it + * independently on 2026-08-28, which is this loop's strongest signal. + * + * The string `claims-auditor` struck from **this same node's `description`** on + * 2026-08-27 was *"Mediator and commercial arbitrator in Toronto"*. The value + * ruled for `jobTitle` is the same words minus the city — **in the most + * role-asserting field in the vocabulary**, thirty lines below the comment in + * `schema.ts` that explains why the words were struck. §4 verifies *"Has + * completed multiple sole mediations"* and has **no counterpart row for a + * completed arbitration** — only that appointments are *accepted*. Consumers + * render `jobTitle` beside `name`: *Pouya Lajevardi — Mediator and Commercial + * Arbitrator*, which invites the reader to supply a track record for both halves. + * + * **I flagged the wrong thing.** My note argued about scoping ("Commercial"), + * and neither the note nor I noticed the whole string had already been struck on + * different grounds. A flag aimed at the wrong defect reads as diligence and + * provides none. + * + * **So this ships as the narrowest form §4 actually rows**, and Q47's purpose is + * still served: Pouya's ruling was that `jobTitle` describe *this practice* + * rather than the boutique role, and "Mediator" does exactly that. Nothing is + * lost from the graph — `description` ("accepting commercial arbitration + * appointments") and `serviceType` ("Commercial arbitration") both carry the + * arbitration **offering**, and both cleared audit. Only the role-assertion is + * gone. + * + * **AGENTS.md Q49 asks Pouya for the row.** If he wants the fuller title it + * needs either a §4 row for arbitrator-as-practised-role, or an offering-shaped + * value — `adversarial-reviewer` proposed `'Mediator; accepts commercial + * arbitration appointments'`, which is honest and reads oddly for a job title. + * His call, not one to take by tidying. + */ +// [derived from §4 — "Q.Med designation through ADRIC / ADRIO" + "Has completed +// multiple sole mediations". NOT a row stamp: §4 has no row reading "Mediator", +// and the row-level wording is what Q49(a) is open on. The 2026-08-25 date this +// comment first carried was inherited from ROLE.title's row.] +export const PRACTICE_JOB_TITLE = 'Mediator' as const; + +/* `PRACTICE_ENTITY` LIVED HERE FOR ONE PASS AND IS DELETED WITH `worksFor`. + * + * It existed only to populate `Person.worksFor`, which is withheld pending a §4 + * row (Q49). `adversarial-reviewer` found the defect that decided it, and it is + * one the "name only, nothing else" scoping did **not** address: the + * ProfessionalService node's `provider` **is** this Person, so + * `provider → Person → worksFor → SML Company Ltd` asserts transitively exactly + * what `src/pages/about.astro` declines to assert in prose — that the practice + * and the company are the same entity. **The referent matters and the first + * version of this sentence got it wrong:** it said "the comment four lines above + * it", pointing at `aboutGraph`'s note in `schema.ts`, which covers + * `ProfilePage`, `BreadcrumbList` and `memberOf` and says **nothing** about SML + * Company Ltd. `adversarial-reviewer` read it and found the citation empty — + * *"a claim whose referent cannot be reached is unverifiable by construction"*, + * this repo's own rule, applied to the argument for a revert. The real referent + * is `about.astro`'s deleted sentence: *"the company through which the + * engineering work is done" — a corporate-structure claim.* The transitive + * argument stands on its own; the evidence offered for it did not. + * + * Two further grounds, both recorded so this is not re-added casually: + * - §4's row says "Operator of SML Company Ltd **alongside** the practice". + * Q47's ruling says "the entity the practice **operates through**". Those are + * different structural relations and the second has no §4 row. + * - `/about/` already **removed** a sentence of this exact class from visible + * copy — see about.astro: *"the company through which the engineering work is + * done" — a corporate-structure claim*. Publishing it machine-readably while + * declining it in prose is the stricter-in-public, looser-in-metadata shape. + * + * The original omission had TWO grounds — "either names the boutique (D16) **or + * misstates the employer**". Q47 answers the first. The second is Q49. + * + * `SITE.entity` already carries the string for the footer. Re-adding a second + * constant for the same name would be the drift this file keeps paying for. + */ + /** * THE Q41(a) SENTENCE. It lives here for the reason `ROLE` above lives here: * *"these are the two where the wording IS the compliance."* diff --git a/src/pages/about.astro b/src/pages/about.astro index 2c2173b..99f2cb2 100644 --- a/src/pages/about.astro +++ b/src/pages/about.astro @@ -20,12 +20,22 @@ * section entirely until there is something in it. An empty 'Speaking' heading * is worse than no heading." Nothing to list. * - * ITEM 7'S PDF IS NOT SHIPPED, and the omission is stated rather than silent — - * AGENTS.md Q45. No such file exists, and a link to a missing file on the page - * an appointing body reads is worse than its absence. It is also not a - * formatting job: a one-page bio is a credential document circulated DETACHED - * from the site, where no build and no reviewer ever re-checks it. Two - * decisions there are Pouya's. + * ITEM 7'S PDF IS NOT SHIPPED, and the omission is stated rather than silent. + * **Q45 CLOSED 2026-08-28 — deferred by Pouya to build step 9, alongside + * `/fees/`, and tracked as AGENTS.md §12 R16.** His reasoning: it is a derived + * artefact, so building it before this page and the fee card are final means + * building it twice. No such file exists yet, and a link to a missing file on + * the page an appointing body reads is worse than its absence. + * + * It is also not a formatting job: a one-page bio is a credential document + * circulated DETACHED from the site, where no build and no reviewer ever + * re-checks it. Two decisions travel with R16 and are NOT settled by the + * deferral — generated-at-build vs authored once, and whether it carries + * anything the site does not. + * + * This paragraph also comes out at step 9 (R16), which now lists this file. + * *(It pointed at Q45 after Q45 closed; `adversarial-reviewer` found that + * `grep -rn R16 src` returned nothing at all.)* * * THE PARENT/CHILD SCOPE TRAP, because this page uses <SectionHeading> four * times. A parent CANNOT style a child component's root element — the rule @@ -35,15 +45,25 @@ * components have had their `class` props deleted so passing one is a build * error rather than a silent no-op. * - * R10 / Q44 — THE MEMBERSHIPS GROUP IS NOT ON THIS PAGE. R10 is written as a - * prohibition — re-confirm *before* any page listing memberships ships — and - * `/about/` is the page it names. The re-confirmation is a fact only Pouya holds - * and was not obtained, so the group is withheld and a `TODO(pouya)` sits on - * CREDENTIAL_GROUPS below with the exact question. §4 is NOT re-stamped: - * nothing was re-checked. Q44. + * R10 / Q44 — THE MEMBERSHIPS GROUP SHIPS, AND IT CARRIES NO CURRENCY + * WARRANTY. Q44 closed 2026-08-28: Pouya re-confirmed all four as current, so + * R10's prohibition is discharged and the group renders. Two conditions came + * with that ruling and both are load-bearing on this page: * - * A first version of this page published all four and disclosed the gap instead. - * Both review agents rejected that; the reasoning is on CREDENTIAL_GROUPS. + * 1. **Nothing here promises the memberships stay current.** The struck + * sentence ("Memberships are renewed annually and are listed as current") + * stays struck and nothing replaces it. His words: *"List the memberships; + * promise nothing about their future state."* The list is a snapshot, and + * only §4's stamp says when it was taken. + * 2. He declined renewal-date tracking, so **R10 no longer fires on a date — + * it fires on an event**: re-confirm before any cutover or major + * republish. That is why R10 stays live with the group shipped. + * + * The page held all three positions in three days — published-with-a-disclosure + * (rejected by both review agents), withheld-behind-a-TODO (correct while R10 + * was undischarged), now published-with-no-warranty. The middle state was not a + * detour; it is what "a build that fails on an unanswered question is a correct + * build" looks like from the inside. */ import { Picture, getImage } from 'astro:assets'; import BaseLayout from '../layouts/BaseLayout.astro'; @@ -127,9 +147,20 @@ const designationLine = [ /** * The credentialing arc — docs/01 item 4, and docs/03: "the credentialing - * pathway from Q.Med through Q.Arb to C.Med-Arb is stated openly as in - * progress. The brief treats that arc as part of the story rather than - * something to obscure." + * pathway from Q.Med through Q.Arb to C.Med-Arb is stated openly, **with Q.Arb + * described as commenced August 2026** and never as 'in progress', which is + * looser than §4 and is barred by docs/06's cutover checklist. The brief treats + * that arc as part of the story rather than something to obscure." + * + * ⚠️ THAT QUOTATION WAS STALE AND THE STALE HALF WAS THE BARRED PHRASE. It + * quoted docs/03's pre-2026-08-28 text, which ended "...stated openly as in + * progress" — so THIS FILE cited docs/03 as REQUIRING the phrase six lines + * above citing it as BARRING the phrase. Found by `adversarial-reviewer`. + * + * **And the Q.Arb-wording sweep missed it because the phrase was line-wrapped** + * as `as in\n * progress`: a grep for "in progress" on one line returns + * nothing. Same defect CLAUDE.md already records for a docs/03 phrase that + * wrapped behind a blockquote marker. Sweep the wrapped form too. * * `state` is the load-bearing column. "Commenced August 2026" is §4's exact * wording and the ONLY permitted wording — docs/03: not "in progress", because @@ -160,7 +191,12 @@ const designationLine = [ * credential structure, with no row and no source. * 5. The expansions — "Qualified Mediator", "Qualified Arbitrator", * "Chartered Mediator-Arbitrator". Flagged as being in §11 Glossary but - * not in §4 Verified. + * not in §4 Verified. **The third was also simply WRONG** — ADRIO's term + * is "Chartered Med-Arbitrator" — but that is not what this finding + * caught, and no review pass caught it either: four passes read the string + * and checked only whether it was *sourced*. Pouya caught it on + * 2026-08-28. The wrong form is quoted here because it is what was + * flagged; it is corrected in the arc below and swept from the repo. * * ⚠️ ITEM 5 WAS REMOVED AND IS NOW RESTORED, AND IT IS THE ONE PLACE THIS * SESSION WENT AGAINST A REVIEW FINDING. The reason is a SECOND finding, from @@ -170,22 +206,30 @@ const designationLine = [ * Institute of Ontario" — every one of them a §11 Glossary expansion, on exactly * the ground the designation names were struck. *"One standard or the other."* * - * The standard chosen is: **§11 Glossary is the source for DEFINITIONAL - * expansions** — what an abbreviation stands for — while §4 Verified remains the - * only source for claims ABOUT POUYA. Expanding `Q.Med` says nothing about him; - * "he holds it" is the claim, and that has a row. The alternative standard would - * have required stripping POA, SABS and the institute names from the prose and - * `recognizedBy` from the JSON-LD, which makes the page materially worse for a - * reader who does not already know the acronyms, in exchange for no reduction in - * risk. **Q46 asks Pouya to ratify that standard** and it is the only thing - * holding it up; if he declines, all four classes come out together. + * ✅ **RATIFIED BY POUYA 2026-08-28 (Q46(b)), AND NO LONGER RESTING ON §11 + * ASSERTING ITS OWN CONTENT.** The standard: **§11 Glossary is the source for + * DEFINITIONAL expansions** — what an abbreviation stands for — while §4 + * Verified remains the only source for claims ABOUT POUYA. Expanding `Q.Med` + * says nothing about him; "he holds it" is the claim, and that has a row. His + * words: *"the same line the Offerings ruling drew"*, and *"You were right that + * one standard or the other had to apply."* * - * Sourcing them externally was tried first and failed: `adric.ca/designations/` - * redirects to `/designations-cee/` and its HTML contains **zero** occurrences - * of "Q.Med", "Qualified Mediator" or "Chartered Mediator" in 114,985 bytes — - * navigation only, body assembled client-side. So R14 cannot be met from the - * obvious URL, which is why this rests on §11 and on Q46 rather than on a - * committed extract. + * The alternative standard would have required stripping POA, SABS and the + * institute names from the prose and `recognizedBy` from the JSON-LD — making + * the page materially worse for a reader who does not already know the acronyms, + * in exchange for no reduction in risk. + * + * **R14 IS NOW SATISFIED, which it was not when this comment was first written.** + * Pouya's ruling attached a condition — fetch and commit the source — and + * `docs/reference/adrio-designations.md` is it: all five expansions in ADRIO's + * own words, four independent fetches, reproducible sha256. The earlier attempt + * had failed on the obvious URL (`adric.ca/designations/` redirects to + * `/designations-cee/` and serves **zero** occurrences of "Q.Med", "Qualified + * Mediator" or "Chartered Mediator" in 114,985 bytes — navigation only, body + * assembled client-side), and that failure is why this rested on §11 alone for + * one day. `adr-ontario.ca` serves them server-side. **The lesson is that one + * dead URL is not a sourcing dead end** — the national body's page was + * client-rendered and the provincial affiliate's was not. */ const ARC = [ { @@ -209,8 +253,13 @@ const ARC = [ { name: 'C.Med-Arb', state: 'The endpoint', + /* "Chartered Med-Arbitrator", NOT "Chartered Mediator-Arbitrator". The + second form shipped in this string until 2026-08-28 and was in + dist/about/index.html; ADRIO's own term is the first + (docs/reference/adrio-designations.md, Finding 2). Pouya's correction, + and it was his own error carried from the strategy brief. */ body: - 'Chartered Mediator-Arbitrator. The designation this practice is built ' + + 'Chartered Med-Arbitrator. The designation this practice is built ' + 'toward.', }, ]; @@ -228,43 +277,52 @@ const ARC = [ * NOT PRESENT, AND EACH IS A §4 DIRECTIVE RATHER THAN A GAP: * - The Law Society. Listing it implies licensure, which D13 bars. §4: * "Excluded deliberately, not by oversight." - * - OCNI. Not current (§4), so it is not published. + * - OCNI. Not current (§4), so it is not published. **It is the precedent** — + * a membership lapsed quietly and the register now reads "not current, do + * not publish". Nothing told anyone when. * - Any licence status, in either direction. §4 records it `[unestablished]`. * - * TODO(pouya): Are ADRIC, ADRIO, the three OBA sections (Construction & - * Infrastructure, ADR, Civil Litigation) and the Canadian Tax Foundation all - * current TODAY, and in which month does each renew? — AGENTS.md Q44. + * ⚠️ MEMBERSHIPS RENDER, AND THE PAGE SAYS NOTHING ABOUT THEIR FUTURE STATE. + * That second clause is the whole ruling, so it is written here beside the + * array rather than in a change log nobody reads at edit time. * - * ⚠️ MEMBERSHIPS ARE DELIBERATELY NOT RENDERED, AND THIS IS A REVERSAL. + * **Q44 closed 2026-08-28.** Pouya re-confirmed all four as current — ADRIC, + * ADRIO, the three OBA sections, and the Canadian Tax Foundation — which + * discharges R10's prohibition and puts the group back on the page. §4 is + * re-stamped `[verified 2026-08-28 — Pouya]`. * - * The first version of this page published all four on §4's 2026-08-26 stamp and - * disclosed the outstanding re-confirmation in a note, in this comment, in - * `schema.ts`, in §9 Q44 and on the cutover checklist. Both review agents - * rejected that, and they are right. §12 **R10** is written as a PROHIBITION — - * *"Re-confirm at each renewal, **and before any page listing memberships - * ships** — `/about/` at build step 3 is the first one that will"* — and - * documenting a prohibition is not discharging it. `CLAUDE.md` gives the - * procedure for a fact you do not have, and it is this one: leave - * `TODO(pouya)`, log the question, let the gap be visible. *"A build that fails - * on an unanswered question is a correct build."* + * **DO NOT ADD A CURRENCY SENTENCE.** Not "renewed annually", not "current as + * of", not "listed as current", not a stamp date in the markup. His ruling is + * explicit: *"List the memberships; promise nothing about their future state. + * The list is a snapshot, and only §4's stamp says when it was taken."* The + * struck sentence is quoted in the comment further down this file with the + * three defects it carried; the second of those is now the live one. * - * The alternative was to ship them and call it disclosed. It was taken once and - * is recorded here as the decision it was, not as an oversight — and it came - * with a second defect on top: the note asserted *"Memberships are renewed - * annually and are listed as current"*, which (a) warranted currency the - * register cannot vouch for and (b) widened §4, which records yearly renewal for - * the **OBA sections and the CTF only** and says nothing about ADRIC or ADRIO. + * **WHY THE ABSENCE OF A WARRANTY IS THE HONEST FORM AND NOT AN EVASION.** + * Pouya declined renewal-date tracking. Without renewal months there is no date + * on which anyone could re-check, so any sentence asserting continued currency + * would be asserting something nothing in this repo can support — which is the + * OCNI shape exactly: §4 carries OCNI as lapsed and unpublishable, and that was + * found roughly a year late. R10 therefore fires on an **event** now (before any + * cutover or major republish), not on a date. That is recorded in §12 R10 with + * this reasoning attached, because a stamp with no trigger behind it goes stale + * silently. * - * OCNI is the precedent and it is in §4: a membership lapsed, quietly, and the - * register now reads "not current, do not publish". Nothing tells you when. + * "Canadian Tax Foundation" ships WITHOUT a "(CTF)" abbreviation, unlike ADRIC + * and ADRIO. Pouya's ruling wrote "(CTF)" when listing what to confirm, but the + * abbreviation appears nowhere else on this site — ADRIC and ADRIO earn their + * parentheses because "Q.Med (ADRIC / ADRIO)" uses them in the Designations + * group two entries above. An unused abbreviation is noise, so it is omitted; + * one word to reverse if he wants it. * - * The other three groups ship. Restoring this one is one array entry, the moment - * Q44 closes — and re-stamp §4 and `CREDENTIALS.memberships` that day. + * `memberOf` IS STILL WITHHELD FROM THE JSON-LD — see `src/data/schema.ts`. + * That is a narrower decision than this one and it is explained there. */ const CREDENTIAL_GROUPS = [ { title: 'Designations', items: CREDENTIALS.designations }, { title: 'Education', items: CREDENTIALS.education }, { title: 'Certifications', items: CREDENTIALS.certifications }, + { title: 'Memberships', items: CREDENTIALS.memberships }, ]; --- @@ -523,7 +581,17 @@ const CREDENTIAL_GROUPS = [ practice, the jurisdiction of incorporation and the place of business — not which work runs through which vehicle. */ } - <p>I run SML Company Ltd alongside both.</p> + { + /* §4 VERBATIM: "Operator of SML Company Ltd. **alongside the + practice**." This read "alongside both", where "both" resolved to the + law track and the engineering track — a concurrency claim §4 does not + make, flagged by `claims-auditor` 2026-08-28. Two neighbouring + additions were deleted from this section for the same reason (see + below), and the wording had propagated from docs/03, now corrected + too. NOT a corporate-structure claim either — see schema.ts on why + `worksFor` is withheld. */ + } + <p>I run SML Company Ltd alongside the practice.</p> <p> I have also completed the Kompass Arbitration Certificate Program and the Stitt Feld Handy negotiation and ADR workshop sequence. Neither is @@ -558,11 +626,19 @@ const CREDENTIAL_GROUPS = [ Both readings are correct and they point in opposite directions, because both sentences make a claim about CAPACITY. So this one does - not: it states the ROLE and its consequence for the reader, which is - the form `docs/03` actually sanctions on `/for-parties/` (*"the - mediator is not your lawyer"* — role, not capacity) and the only one - that asserts nothing and denies nothing. The underlying question is - R1's. */ + not: it states the ROLE and its consequence for the reader, and it is + the only form that asserts nothing and denies nothing. The underlying + question is R1's. + + AN EARLIER VERSION OF THIS COMMENT CITED `docs/03`'s + `/for-parties/` directive as the sanctioned example — *"the mediator + is not your lawyer" — role, not capacity*. That was wrong twice: + "not your lawyer" PRESUPPOSES lawyer status, which §4 Forbidden bars + of Pouya and D13 bars by implication; and the half of that sentence + this comment did not quote was "cannot give you legal advice", which + is the denial the comment itself says was struck twelve lines above. + `docs/03` has since been corrected. Do not re-import an example from + a spec without reading the whole sentence it sits in. */ } <p> I act as a neutral. I do not act for a party in a matter I take, and @@ -661,10 +737,13 @@ const CREDENTIAL_GROUPS = [ the OBA sections and the CTF only and says nothing about ADRIC or ADRIO. The widened form had already propagated to four places. (b) "listed as current" was an affirmative public WARRANTY of - currency stacked on top of an undischarged R10 — the reminder - whose entire purpose is that no such warranty be made without a - re-confirmation. The memberships group is now off the page - (Q44), so the sentence has nothing left to warrant either. + currency. **THIS IS NOW THE OPERATIVE DEFECT.** Q44 closed and + the group is back on the page, so the sentence has something to + warrant again — and it still must not return. Pouya, 2026-08-28: + *"NO CURRENCY WARRANTY on the page. The sentence you struck + stays struck, and nothing may replace it."* He declined renewal + tracking, which is exactly why the warranty cannot be made: + there is no date behind it. R10 fires on an event instead. (c) "Nothing above asserts a licence to practise law, in either direction" READS AS A DENIAL. §4 on licence status: "Do not assert it, do not deny it, do not infer it from anything else