feat: D19 bounds the review loop; apply nine rulings; close Q46(a) and Q48–Q53

D19 into §3 and swept to all six destinations Pouya named: both agent briefs
(scope + severity filter), /build Phases 2–4 (non-gating questions, scope, stop
signal, two-round cap), /wrap, and CLAUDE.md (comments record decisions, not
history). Sweep verified by command, not recalled.

Rulings applied:
  Q46(a) PUBLISHABLE — three §4 Offerings rows flipped; gate 1 records
         [Pouya's stated basis], never [verified]. Step 5 unblocked.
  Q48    closed, not site-relevant.
  Q49    one §4 row, "Mediator"; read as declining Q49(b), so worksFor stays out.
  Q50    DEVIATES — ships as name + slogan, not the concatenation. Flagged.
  Q51    OBA sections stay; the regulator/voluntary distinction recorded.
  Q52    docs/reference/deploy-credential-verification.md — 18 read-only AWS
         calls, re-run rather than transcribed, access key ID redacted.
  Q53    memberOf emitted on /about/'s Person node.

Two review rounds. The headline finding was this session's own: the Q53 sweep
was asserted and never run, leaving six in-scope records saying memberOf was
withheld — including §12 R10, which is read aloud every session. Round 2 then
found that round 1's simplification had put memberOf on / as well; the per-page
opt-in is restored, because Pouya's ruling turns on /about/'s visible HTML.

Also fixed: MEMBERSHIP_ORGS had orphaned BOUTIQUE's D16 JSDoc; /'s title now
derives from the constants; §7's deploy row stated and retracted three facts.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0148NztQskLKKApP5SzAA78e
This commit is contained in:
Pouya Lajevardi
2026-08-28 15:52:52 -04:00
co-authored by Claude Opus 5
parent 77a7b410b2
commit fd5f610982
15 changed files with 1165 additions and 280 deletions
+44
View File
@@ -27,6 +27,35 @@ A diff or a set of files, and the specs in `docs/`. You are deliberately **not**
given the implementer's account of why the work is correct — form your own view given the implementer's account of why the work is correct — form your own view
from the artefact. from the artefact.
## Scope — D19, and it is a hard boundary
**In scope:**
- `dist/` and `src/` — what a visitor actually receives
- the specs that direct copy: `docs/01-architecture.md`,
`docs/03-content-spec.md`, `docs/04-seo-spec.md`, `docs/07-fees.md`
- `AGENTS.md` **§3, §4, §7, §9, §12** — the operative sections
**Out of scope:**
- the `AGENTS.md` **Change Log**
- the agent briefs in `.claude/agents/`, including this one
- `AGENTS.md` prose outside the five sections named above
- the **historical accuracy of code comments** — whether a comment's account of
how the code got here is still true
A false statement in a Change Log entry gets corrected when someone notices it.
It does not get a review pass, because **no visitor reads it.** Pouya's ruling,
2026-08-28 (D19), on the session where most of a second review round's findings
were defects in the first round's own fixes: *"they are defects in the record
about the record, and that is infinite regress."*
**What this does not narrow.** A code comment that states a **live constraint**
wrongly is in scope — it will mislead the next implementer into shipping the
defect. What is out of scope is the comment's account of its own revision
history. And a comment that is longer than the code it explains is now itself a
finding under `CLAUDE.md`'s D19 convention: report it as **simplicity**, lens 6.
## Lenses — work all of them ## Lenses — work all of them
**1. Correctness.** Does it do what `docs/01-architecture.md` and **1. Correctness.** Does it do what `docs/01-architecture.md` and
@@ -84,5 +113,20 @@ For each finding:
rather than dressing up a preference as a bug. rather than dressing up a preference as a bug.
- **The fix**, specifically - **The fix**, specifically
### Severity filter — D19
**Report blocking and should-fix. Raise a `consider` only if acting on it would
change what ships.**
The standing bias above says an approving review that misses a real defect is a
failure. This is its twin, and Pouya added it 2026-08-28: **a review that reports
twenty things in order to produce twenty small edits has spent more than it
saved.** Both failures are real and they pull in opposite directions. The
resolution is *not* to soften a genuine defect — it is to stop promoting
preferences into findings.
If you are uncertain whether something is a defect, the standing bias still
applies: report it, at the severity your confidence supports.
If you genuinely find nothing at a given severity, say which lenses you applied If you genuinely find nothing at a given severity, say which lenses you applied
and what you checked, so the gap is auditable. **"Looks good" is not a review.** and what you checked, so the gap is auditable. **"Looks good" is not a review.**
+43
View File
@@ -13,6 +13,38 @@ The site this replaces contained a fictitious founder, invented matter values
and a testimonial attributed to a person who does not exist. Your existence is and a testimonial attributed to a person who does not exist. Your existence is
the control that stops that recurring. the control that stops that recurring.
## Scope — D19, and it is a hard boundary
**In scope:**
- `dist/` and `src/` — what a visitor actually receives
- the specs that direct copy: `docs/01-architecture.md`,
`docs/03-content-spec.md`, `docs/04-seo-spec.md`, `docs/07-fees.md`
- `AGENTS.md` **§3, §4, §7, §9, §12** — the operative sections
**Out of scope:**
- the `AGENTS.md` **Change Log**
- the agent briefs in `.claude/agents/`, including this one
- `AGENTS.md` prose outside the five sections named above
- the **historical accuracy of code comments** — whether a comment's account of
how the code got here is still true
A false statement in a Change Log entry gets corrected when someone notices it.
It does not get a review pass, because **no visitor reads it.** Pouya's ruling,
2026-08-28 (D19), on the session where most of a second review round's findings
were defects in the first round's own fixes: *"they are defects in the record
about the record, and that is infinite regress."*
**What this does not narrow, and read this carefully.** Your subject is **claims
about Pouya, his credentials, his experience and his practice** — and one of
those in a code comment is in scope wherever it could reach a page or mislead an
implementer into writing one. `src/data/site.ts` and `src/data/schema.ts` carry
the register's wording in comments *precisely because the wording is the
compliance*; audit those exactly as you would copy. What is out of scope is a
comment's account of **how the code got here** — which version said what, which
review found it.
## Method ## Method
1. Read `AGENTS.md` §4 in full — the Verified table, the Forbidden table, and 1. Read `AGENTS.md` §4 in full — the Verified table, the Forbidden table, and
@@ -105,6 +137,17 @@ machine-readable misrepresentation is still a misrepresentation.
A table: **claim quoted verbatim · location · verdict (VERIFIED / NOT IN A table: **claim quoted verbatim · location · verdict (VERIFIED / NOT IN
REGISTER / FORBIDDEN) · the register line it matches, or what to do instead.** REGISTER / FORBIDDEN) · the register line it matches, or what to do instead.**
### Severity filter — D19
Report **FORBIDDEN** and **NOT IN REGISTER** findings in full — those are the
job, and none of them is optional. Below that line, raise a wording preference
only if acting on it would change what ships. Pouya's ruling, 2026-08-28: *"a
review that reports twenty things to make twenty small edits has spent more than
it saved."*
This does not soften the rule above it. **A claim not in the Verified table does
not ship**, at any count.
Then a single line: **PASS** — every assertion traced — or **FAIL**, with the Then a single line: **PASS** — every assertion traced — or **FAIL**, with the
count of untraceable claims. count of untraceable claims.
+36 -1
View File
@@ -19,7 +19,7 @@ does not apply, say which and why before moving on.
Reminders** and surface anything live to Pouya before you start. Reminders** and surface anything live to Pouya before you start.
2. Read the specs in `docs/` that bear on this task. 2. Read the specs in `docs/` that bear on this task.
3. Restate the task in your own words, and name: 3. Restate the task in your own words, and name:
- which locked decisions (D1D18) it touches - which locked decisions (D1D19) it touches
- which specs govern it - which specs govern it
- which facts it needs from the §4 Verified register - which facts it needs from the §4 Verified register
4. **Stop and ask if you find a conflict** — between the task and a locked 4. **Stop and ask if you find a conflict** — between the task and a locked
@@ -36,6 +36,13 @@ hex, no magic numbers. Semantic HTML. Every page gets its metadata.
Where you need a fact you do not have: `TODO(pouya): <the exact question>` in the Where you need a fact you do not have: `TODO(pouya): <the exact question>` in the
source **and** a new numbered question in `AGENTS.md` §9. Do not invent it. source **and** a new numbered question in `AGENTS.md` §9. Do not invent it.
**But do not open a numbered question for something that gates nothing — D19.**
The Q-series is past 50 and most recent additions gate nothing. If an observation
does not block a page, a deploy or a claim, it is a **Change Log note**, not a
numbered question — and retire the non-gating ones you find. A `TODO(pouya)` in
source is not this case: it blocks the page it sits on, so it still gets a
number.
## Phase 3 — Adversarial review (this is not optional) ## Phase 3 — Adversarial review (this is not optional)
Invoke **both** review agents on the change, in parallel: Invoke **both** review agents on the change, in parallel:
@@ -49,6 +56,22 @@ work is correct.** Your rationale anchors the reviewer and produces agreement
instead of review. They form their own view from the artefact; that independence instead of review. They form their own view from the artefact; that independence
is the whole point of the phase. is the whole point of the phase.
### Scope — D19
Review is bounded. **In scope:** `dist/`, `src/`, the specs that direct copy
(`docs/01`, `03`, `04`, `07`), and `AGENTS.md` §3, §4, §7, §9, §12. **Out of
scope:** the Change Log, the agents' own briefs, `AGENTS.md` prose outside those
sections, and the historical accuracy of code comments. Both briefs carry the
same boundary — do not widen it in the prompt.
### The stop signal
**If a round's findings are predominantly about the record rather than the
output, stop the round and say so.** That is the symptom of the loop feeding on
itself, and noticing it is part of the job — not a licence to skip the phase.
The shape to watch for, from the session that produced D19: a Change Log sweep
that could not reproduce *because writing it changed the file it counted*.
If the change touches no user-facing copy, `claims-auditor` may be skipped — say If the change touches no user-facing copy, `claims-auditor` may be skipped — say
so explicitly. so explicitly.
@@ -69,6 +92,18 @@ under review pressure is exactly where the second defect lives.
> launch articles. None of the four existed before the review started. Skip the > launch articles. None of the four existed before the review started. Skip the
> re-review and you ship the repair, not the bug. > re-review and you ship the repair, not the bug.
### Two rounds is the cap — D19
Round 1 reviews the change. Round 2 reviews the material fixes. **There is no
round 3: fix what round 2 finds, and ship.**
The measurement above is why round 2 exists. The measurement below is why round 3
does not. On 2026-08-28 two rounds produced **48 findings, and most of round
two's were defects in round one's own fixes** — so each further round both finds
and manufactures defects, and past two the manufacture rate exceeds the value of
the marginal finding. Pouya's ruling. **State this reasoning when you stop at
two**, so a later reader does not read the cap as laxness.
## Phase 5 — Verify — run it, do not assert it ## Phase 5 — Verify — run it, do not assert it
```bash ```bash
+9 -3
View File
@@ -30,12 +30,18 @@ reasoning.
instances survived all three, one of them inside the definition of the agent instances survived all three, one of them inside the definition of the agent
whose job is to catch it. whose job is to catch it.
4. **Check §12 Standing Reminders.** Is anything now due? Should something new 4. **Do not open a numbered question for something that gates nothing — D19.**
The Q-series is past 50 and most recent additions gate nothing. If it does
not block a page, a deploy or a claim, it belongs in this entry as a note, not
in §9 as a number — and retire the non-gating ones you find while you are in
there. Pouya's ruling, 2026-08-28.
5. **Check §12 Standing Reminders.** Is anything now due? Should something new
be added — a decision Pouya parked, or one you made on his behalf that he has be added — a decision Pouya parked, or one you made on his behalf that he has
not yet ratified? not yet ratified?
5. **Leave the tree clean.** `git status` should show only intended changes. No 6. **Leave the tree clean.** `git status` should show only intended changes. No
stray build output, no `.env`, no credentials, no `aws-inventory.txt`. stray build output, no `.env`, no credentials, no `aws-inventory.txt`.
6. Report: what changed in `AGENTS.md`, what is open, and the single most useful 7. Report: what changed in `AGENTS.md`, what is open, and the single most useful
next action. next action.
+233 -42
View File
@@ -129,6 +129,7 @@ without an explicit instruction and a Change Log entry. `[verified 2026-08-25]`
| D15 | Analytics | **Plausible.** Privacy-first and cookieless: no cookie banner, nothing to consent to, one line in the privacy policy. *Amended 2026-08-26 (Q31):* the original read "Plausible **or** Fathom", i.e. undecided, and a guessed `'plausible'` had already leaked into `src/data/site.ts` from it. **Decided, not defaulted** — Pouya checked rather than assumed and found his own assumption wrong: Fathom is Canadian-owned, which is the intuitive answer here, but it stores non-EU traffic on **US servers** and isolates in the EU only for EU visitors. Plausible keeps all data in the EU. For a practice whose privacy posture is part of the offer, EU-only beats US-hosted, and ownership is not the axis that matters | GA4; no analytics at all; **Fathom** — rejected on data residency, not on quality | | D15 | Analytics | **Plausible.** Privacy-first and cookieless: no cookie banner, nothing to consent to, one line in the privacy policy. *Amended 2026-08-26 (Q31):* the original read "Plausible **or** Fathom", i.e. undecided, and a guessed `'plausible'` had already leaked into `src/data/site.ts` from it. **Decided, not defaulted** — Pouya checked rather than assumed and found his own assumption wrong: Fathom is Canadian-owned, which is the intuitive answer here, but it stores non-EU traffic on **US servers** and isolates in the EU only for EU visitors. Plausible keeps all data in the EU. For a practice whose privacy posture is part of the offer, EU-only beats US-hosted, and ownership is not the axis that matters | GA4; no analytics at all; **Fathom** — rejected on data residency, not on quality |
| D18 | Intake email | **Two emails per submission** — notification to `info@smlcompany.ca`, and a **confirmation receipt to the inquirer**. Pouya, 2026-08-26. The receipt is what requires SES production access (Q19) | Notification only; no email; no form at all | | D18 | Intake email | **Two emails per submission** — notification to `info@smlcompany.ca`, and a **confirmation receipt to the inquirer**. Pouya, 2026-08-26. The receipt is what requires SES production access (Q19) | Notification only; no email; no form at all |
| D17 | Working method | **Pouya architects; Claude Code implements and then adversarially reviews its own work.** Six-phase loop encoded in `.claude/commands/build.md`; two independent review agents in `.claude/agents/`; extended thinking on by default. Standing agreement — not restated per prompt | Implement-and-report; single generic reviewer; review only on request | | D17 | Working method | **Pouya architects; Claude Code implements and then adversarially reviews its own work.** Six-phase loop encoded in `.claude/commands/build.md`; two independent review agents in `.claude/agents/`; extended thinking on by default. Standing agreement — not restated per prompt | Implement-and-report; single generic reviewer; review only on request |
| D19 | Bounding the review loop | **Review scope is `dist/`, `src/`, the specs that direct copy (`docs/01`, `03`, `04`, `07`), and `AGENTS.md` §3, §4, §7, §9, §12. TWO ROUNDS IS THE CAP. Findings are blocking or should-fix, with a "consider" only where acting on it changes what ships. A non-gating observation is a Change Log note, not a numbered question. Comments record decisions, not history.** Pouya's ruling, 2026-08-28, on his own measurement: 48 findings across two rounds with most of round two being defects in round one's fixes; 342 lines added to `src/` for 8 functional; four findings that were stale statements inside comments written that same session; and a Change Log sweep that could not reproduce because writing it changed the file it counted. His words: *"Every one is a real defect — but they are defects in the record about the record, and that is infinite regress. My fault for never bounding scope."* **Out of scope: the Change Log, the agents' own briefs, `AGENTS.md` prose outside those five sections, and the historical accuracy of code comments.** A false statement in a Change Log entry is corrected when noticed; it does not get a review pass, because no visitor reads it. Swept into `.claude/agents/adversarial-reviewer.md`, `.claude/agents/claims-auditor.md`, `/build` Phases 24, `/wrap` and `CLAUDE.md` | Unbounded scope; a third round; reporting every "consider"; a numbered question per observation |
| D16 | Naming the boutique | **Never named.** Referred to throughout as *a Toronto litigation and ADR boutique*. Pouya's decision, 2026-08-26 | Naming the firm | | D16 | Naming the boutique | **Never named.** Referred to throughout as *a Toronto litigation and ADR boutique*. Pouya's decision, 2026-08-26 | Naming the firm |
## 4. Credential and claim register ## 4. Credential and claim register
@@ -171,6 +172,7 @@ since May.
| Active litigation **exposure**: personal injury, construction, regulatory (POA), insurance (SABS) | `[verified 2026-08-26]`. **Wording corrected** — this row previously read "practice", the exact word D13 bars in exactly the context it bars it. The register was quoting the strategy brief verbatim and contradicting its own rule. The underlying fact is unchanged | | Active litigation **exposure**: personal injury, construction, regulatory (POA), insurance (SABS) | `[verified 2026-08-26]`. **Wording corrected** — this row previously read "practice", the exact word D13 bars in exactly the context it bars it. The register was quoting the strategy brief verbatim and contradicting its own rule. The underlying fact is unchanged |
| Q.Med designation through ADRIC / ADRIO | `[verified 2026-08-25 — strategy brief §I]` | | Q.Med designation through ADRIC / ADRIO | `[verified 2026-08-25 — strategy brief §I]` |
| Has completed multiple sole mediations | `[verified 2026-08-25 — strategy brief §I]` — count deliberately not published, see below | | Has completed multiple sole mediations | `[verified 2026-08-25 — strategy brief §I]` — count deliberately not published, see below |
| **Practised role — "Mediator"** | `[verified 2026-08-28 — Pouya, Q49]`. **The row `Person.jobTitle` stands on, and the ruling grants exactly one.** Pouya: *"one row: 'Mediator', supported by Q.Med plus completed sole mediations."* Both supports are rows immediately above. **"Arbitrator" as a practised role is still NOT a row** — §4 Offerings verifies that appointments are *accepted* and records no completed arbitration, which is why `claims-auditor` struck *"Mediator and Commercial Arbitrator"* from the same node's `description` on 2026-08-27. The arbitration **offering** is unaffected: `description` and `serviceType` both carry it. **Q49(b) is declined by the same ruling** — one row was granted and the corporate relation *"the entity the practice operates through"* was not it, so `worksFor` stays out of the graph. The row that does exist is *"Operator of SML Company Ltd. **alongside** the practice"*, a different structural relation |
| Q.Arb credentialing pathway — **commenced August 2026** | `[verified 2026-08-26 — Pouya]`. Describe as newly commenced, never as held or nearing completion | | Q.Arb credentialing pathway — **commenced August 2026** | `[verified 2026-08-26 — Pouya]`. Describe as newly commenced, never as held or nearing completion |
| C.Med-Arb stated as long-term designation goal | `[verified 2026-08-25 — strategy brief §I, §IV]` | | C.Med-Arb stated as long-term designation goal | `[verified 2026-08-25 — strategy brief §I, §IV]` |
| Kompass Arbitration Certificate Program — completed | `[verified 2026-08-25 — strategy brief §I]` | | Kompass Arbitration Certificate Program — completed | `[verified 2026-08-25 — strategy brief §I]` |
@@ -180,7 +182,7 @@ since May.
| Iranian-Canadian; cross-cultural fluency with diaspora business communities | `[verified 2026-08-25 — strategy brief §I]` | | 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]` | | 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 `© <year> SML Company Ltd` and nothing further — the fact is verified and available, it is simply not on a page | | **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 `© <year> 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-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) | | 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 NOW EMITTED** on `/about/`'s Person node — Q53, ruled 2026-08-28; the withholding is dropped and this sentence said the opposite until the sweep that should have caught it was run. So the graph and the visible list assert the same four lines, and R10's event trigger covers both. `/`'s Person node omits it, because `/` shows no memberships. **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) **Q51 CLOSED 2026-08-28 — the OBA sections STAY, and the distinction is structural.** Pouya: *"the Law Society is the regulator, so membership IS licensure; the OBA is a voluntary association."* That is why the `~~LSO~~` row below excludes one and this row publishes the other, and it holds **independently of eligibility details** — which is what made the question unanswerable inside this repo. Recorded so it is not re-litigated: a voluntary professional association admits members it does not license, so listing it carries no licensure implication; a regulator's membership roll *is* the licence. |
| ~~OCNI~~ | **Not current. Do not publish** `[verified 2026-08-26 — Pouya]` | | ~~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]` | | ~~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]` | | Toronto, Ontario; by appointment | `[verified 2026-08-26]` |
@@ -374,9 +376,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 | | **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 | | **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 | | ~~**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)** | ⚠️ **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 | | **Early neutral evaluation (ENE)** | **PUBLISHABLE** — Pouya's second ruling on **Q46(a)**, 2026-08-28: *"ENE, dispute-system design and pre-dispute advisory pass all three gates. Flip the rows. Step 5 unblocked."* **Gate 0 (partisan?) — passes:** 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?) — `[Pouya's stated basis 2026-08-28]`, NOT `[verified]`, and there is still no source in `docs/reference/`.** This register held the row for one day on the ground that gate 1 needs a source a reviewer can check. He has now ruled with that objection in front of him, and **it is his call**: gate 1 is a proposition of Ontario law about his own practice, and §4 bars this file from concluding one in either direction. Same treatment as the commercial-arbitration proposition above — the ruling is **attributed**, not verified, and a later reader should read it as one. **Still the offering nearest the NOT-NEGOTIABLE boundary:** a neutral assessment of the *merits*, delivered to parties, sits closest to *"providing legal services"*, so `/practice/`'s strip must frame it as an assessment delivered to **both** parties and never as advice to one. **What would still upgrade the evidence** (an improvement now, not a gate): the Ontario *Law Society Act* s. 1 definition of "providing legal services" and LSO By-Law 4, committed verbatim to `docs/reference/`, with the application to ENE left to Pouya or to counsel — never drawn by this register or by an implementer. §4's worked-example prose cites this row for it. Priced hourly in `docs/07-fees.md`; the line item may now ship |
| **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 | | **Dispute-system design** | **PUBLISHABLE** — same ruling as the ENE row above; read it for how gate 1 was closed and on whose authority. **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]` — that sentence answers **neutrality**, which is gate 0, and it is not presented here as answering gating. **Gate 1 — `[Pouya's stated basis 2026-08-28]`.** Weakest gating concern of the three: advisory consulting to an organisation is furthest from the boundary |
| **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 | | **Pre-dispute technical advisory** | **PUBLISHABLE** — same ruling 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 — `[Pouya's stated basis 2026-08-28]`.** ⚠️ **The caution below is NOT a publication gate and does not lift with the ruling:** 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 — 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 | | ~~**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 | | ~~Tribunal secretary~~ | **Not offered.** D14 removed the rate and bars offering it |
@@ -423,9 +425,9 @@ candidates at once and one of them fails.** Pouya's instruction was literally
| 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 | | 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** | | Early neutral evaluation | **No** — delivered to the parties as a neutral | **`[Pouya's stated basis 2026-08-28]`** — ruled, no source. Q46(a) closed | *"sits inside a Q.Med's competence"* | **Publishable** |
| 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** | | Dispute-system design | **No** — advises an organisation; no party to be partisan between | **`[Pouya's stated basis 2026-08-28]`** — ruled, no source. Q46(a) closed | *"Consulting, no appointment, no neutrality question"* | **Publishable** |
| Pre-dispute technical advisory | **No** — precedes any dispute | **`[unestablished]`** — no source. **Q46(a)** | *"It is the moat"* | **Not publishable yet** | | Pre-dispute technical advisory | **No** — precedes any dispute | **`[Pouya's stated basis 2026-08-28]`** — ruled, no source. Q46(a) closed | *"It is the moat"* | **Publishable** |
| **Settlement counsel** | **YES — acts FOR a party. Disposed of here.** | *never reached* | *never reached* | **STRUCK** | | **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 *The gate-0 column was added 2026-08-28. Without it the only STRUCK candidate's
@@ -445,30 +447,32 @@ 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 — 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.** **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 **THE COLUMN IS STILL EMPTY OF A SOURCE, AND THE ROWS ARE NEVERTHELESS
FILE TO WRITE.** Pouya ruled on 2026-08-28 that all three *"pass all three gates PUBLISHABLE. BOTH HALVES OF THAT ARE DELIBERATE.** Pouya ruled on 2026-08-28
including the new partisan question"*. Gates 2 and 3 are his and they are that all three *"pass all three gates including the new partisan question"*.
answered. **Gate 1 is not his** — this section says so twice, in bold, and says Gates 0 and 2 are his and are answered. **Gate 1 is not usually his** — this
why: it was closed with his words twice already, and both times the closure was section says so twice, in bold, because it had twice been closed with his words
caught by an audit rather than by the register. and both closures were 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 **So the register declined to flip the rows, put that objection in front of him,
stay **not yet publishable**, because what gate 1 requires is not a decision but and he ruled a second time with it in view.** At that point the rows flip. Gate
an **artefact**: *"a source that a reviewer can check… answered per activity and 1 asks a proposition of Ontario law about his own practice; §4 bars this file
per jurisdiction, never as a class."* No such source exists in from concluding one in either direction; and a register that holds a row against
`docs/reference/` for any of the three, and the ruling did not name one. a repeated, informed ruling is substituting its judgement for the architect's,
which is not what it is for.
**This is not the register disagreeing with the architect about Ontario law** — **What survives, and it is the whole of the protection:** the gate-1 column
it has no view, and §4 is explicit that it cannot have one. It is the register records **`[Pouya's stated basis 2026-08-28]`** and **never `[verified]`**. A
declining to convert a decision into evidence. If a ruling could close gate 1, reviewer reading these rows sees an attributed position, not a sourced fact —
gate 1 would protect nothing, and the two audits that caught the earlier the same treatment §4 gives the commercial-arbitration proposition. Gate 1 was
closures would have been catching a rule that did not really exist. never a veto; it was a requirement to say *whose* answer it is, and it still
does that.
**What closes it** is named in the ENE row: the *Law Society Act* s. 1 definition **What would still improve it** is named in the ENE row: the *Law Society Act*
of "providing legal services" and LSO By-Law 4, committed verbatim, with the s. 1 definition of "providing legal services" and LSO By-Law 4, committed
application left to Pouya or to counsel. **Nothing on the site turns on this verbatim, with the application left to Pouya or to counsel. That is now an
today** — the three appear in no copy, and it blocks build **step 5**, not upgrade to the evidence rather than a gate on publication. **Step 5 is
step 4. unblocked.**
**The reason settlement counsel fails is the finding.** It did not fail question **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 1 and it did not fail question 2. It failed a prior question the test does not
@@ -617,7 +621,7 @@ the audience it targets. Revisit at month 1218. `[verified 2026-08-25 — dec
| Intake backend | API Gateway (HTTP API) → Lambda → DynamoDB, notifications via SES `[verified 2026-08-25 — AWS-Hosting-Guide.md]` | | 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]` | | 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 | | 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 — 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`.* | | **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]`. **No managed policies, no group memberships.** One inline policy, `adr-sml-deploy-minimal`: `s3:ListBucket` on the site bucket, `s3:PutObject` + `s3:DeleteObject` on `bucket/*`, `cloudfront:CreateInvalidation` on the distribution this section records. **One active access key, created 2026-08-26, NEVER USED**`AccessKeyLastUsed` returns `ServiceName: "N/A"` / `Region: "N/A"` with no `LastUsedDate` key at all, because deploys still run locally. **Verified by execution, not by reading**`iam simulate-principal-policy`, **nine** checks: `allowed` for the four intended actions (`s3:PutObject`, `s3:DeleteObject`, `s3:ListBucket`, `cloudfront:CreateInvalidation`); `implicitDeny` for the five that matter more`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 `*`. **The resource side is checked too:** `get-bucket-policy` on the backup bucket exits **254** with `NoSuchBucketPolicy`, so no resource-based grant exists and IAM is the only path in and the same call against the *site* bucket exits 0 with a real CloudFront OAC policy, which is what makes the first result an absence rather than a broken command. **✅ EVIDENCE IS IN THE REPOSITORY — R14 SATISFIED. `docs/reference/deploy-credential-verification.md`**, eighteen read-only calls, each with the command that produced it, the access key ID redacted; re-run 2026-08-28 rather than transcribed, and `adversarial-reviewer` independently reproduced every value including the `MatchedStatements` positions. Q52 closed. ⚠️ **GITEA ACTIONS SECRETS: `UNSET`** `[verified 2026-08-26]` — 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**. That is a different fact from the key being unused: a key can sit on shared infrastructure without ever authenticating. **Rotation: §12 R17 carries the date and the procedure** — this row deliberately does not restate it |
| **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]` | | **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]` | | **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 | | 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 |
@@ -652,7 +656,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 | — | | ~~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 | — | | ~~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 | — | | ~~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~~ | **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.** | — | | ~~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 **nine** `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 committed**`docs/reference/deploy-credential-verification.md`, Q52 closed 2026-08-28; R14 is satisfied for this row. | — |
| 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 | | 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) | — | | ~~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 | — | | ~~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 | — |
@@ -677,7 +681,7 @@ Nothing below can be invented. Each needs an answer from Pouya.
| ~~Q36-orig~~ | **Is co-arbitration work available now?** Asserted in three specs — `docs/01` §`/arbitration/`, `docs/03` §Voice as model copy, and `docs/07-fees.md`, which instructs *"The page must say so"* — and **it is in no §4 row.** §4 records the Q.Arb pathway as commenced August 2026 and nothing about what is available in the meantime. The sentence is offered under the heading *"Name the limits"*, so the unverified half travels inside advice about honesty, which is how it survived. All three files now cite this question; none has been deleted, because the *shape* of the sentence is right and only its second clause is unsourced. Raised by `claims-auditor`, 2026-08-26 | `/arbitration/` (step 4) and `/fees/` (step 9) | | ~~Q36-orig~~ | **Is co-arbitration work available now?** Asserted in three specs — `docs/01` §`/arbitration/`, `docs/03` §Voice as model copy, and `docs/07-fees.md`, which instructs *"The page must say so"* — and **it is in no §4 row.** §4 records the Q.Arb pathway as commenced August 2026 and nothing about what is available in the meantime. The sentence is offered under the heading *"Name the limits"*, so the unverified half travels inside advice about honesty, which is how it survived. All three files now cite this question; none has been deleted, because the *shape* of the sentence is right and only its second clause is unsourced. Raised by `claims-auditor`, 2026-08-26 | `/arbitration/` (step 4) and `/fees/` (step 9) |
| ~~Q37~~ | **ANSWERED 2026-08-27 — the label changes.** `JD + ML` is now labelled **"Legal training and engineering practice"**, not "Law and engineering". Pouya's reasoning, and it is the finding rather than the fix: *"The parallel was doing the implying — a degree and a practice under one noun. The asymmetry is the honest part."* A degree is not a practice, and a label that renders them as two instances of one thing invites the reader to supply the missing symmetry — which for "Law" is precisely the licensure implication D13 bars. The new label is longer and less tidy, deliberately. `docs/03`'s credential-row table is amended, and the `TODO(pouya)` is gone from `src/data/site.ts`. Original question follows | — | | ~~Q37~~ | **ANSWERED 2026-08-27 — the label changes.** `JD + ML` is now labelled **"Legal training and engineering practice"**, not "Law and engineering". Pouya's reasoning, and it is the finding rather than the fix: *"The parallel was doing the implying — a degree and a practice under one noun. The asymmetry is the honest part."* A degree is not a practice, and a label that renders them as two instances of one thing invites the reader to supply the missing symmetry — which for "Law" is precisely the licensure implication D13 bars. The new label is longer and less tidy, deliberately. `docs/03`'s credential-row table is amended, and the `TODO(pouya)` is gone from `src/data/site.ts`. Original question follows | — |
| ~~Q37-orig~~ | **Is "Law and engineering" the right label under `JD + ML`?** §4's substitution principle supplies the three credential-row **values** (`Q.Med` / `JD + ML` / `EN · FA`); the labels come from `docs/03` and are not themselves registered. `claims-auditor` reads this one as a D13 implication risk: "engineering" is shorthand for a **verified practising** claim, so the parallel invites "Law" to be read the same way, and D13 bars implication as hard as assertion. Left as written — it is approved copy and changing approved copy is not an implementer's call — with a `TODO(pouya)` on it in `src/data/site.ts`. Nothing renders it yet. Raised by `claims-auditor`, 2026-08-26 | The credential row on `/` (step 2) and `/about/` (step 3) | | ~~Q37-orig~~ | **Is "Law and engineering" the right label under `JD + ML`?** §4's substitution principle supplies the three credential-row **values** (`Q.Med` / `JD + ML` / `EN · FA`); the labels come from `docs/03` and are not themselves registered. `claims-auditor` reads this one as a D13 implication risk: "engineering" is shorthand for a **verified practising** claim, so the parallel invites "Law" to be read the same way, and D13 bars implication as hard as assertion. Left as written — it is approved copy and changing approved copy is not an implementer's call — with a `TODO(pouya)` on it in `src/data/site.ts`. Nothing renders it yet. Raised by `claims-auditor`, 2026-08-26 | The credential row on `/` (step 2) and `/about/` (step 3) |
| ~~Q33~~ | **ANSWERED 2026-08-26 — the question rested on a false premise.** It assumed the constraint on describing arbitration was about *entitlement*. ADR designations are voluntary credentials, not licences, and **commercial arbitral appointment in Ontario is not gated behind a designation** — so the constraint was always positional, never legal, and it was Pouya's to answer. *(This row said "anyone may be appointed an arbitrator in Ontario" until 2026-08-27. **Pouya checked it and it is false as a universal** — family arbitration is gated; see Q39. Corrected in place, because §9 is Current Truth. The Change Log entries that quote the original stand unedited, which is where the history lives.)* He accepts arbitration appointments now. `Mediation · Arbitration · Toronto` is **restored to the masthead one-liner**, and `docs/04`'s specified home `<title>` stands as written. See **§4 Offerings**, added for exactly this class of statement. The original question text follows for the record | — | | ~~Q33~~ | **ANSWERED 2026-08-26 — the question rested on a false premise.** It assumed the constraint on describing arbitration was about *entitlement*. ADR designations are voluntary credentials, not licences, and **commercial arbitral appointment in Ontario is not gated behind a designation** — so the constraint was always positional, never legal, and it was Pouya's to answer. *(This row said "anyone may be appointed an arbitrator in Ontario" until 2026-08-27. **Pouya checked it and it is false as a universal** — family arbitration is gated; see Q39. Corrected in place, because §9 is Current Truth. The Change Log entries that quote the original stand unedited, which is where the history lives.)* He accepts arbitration appointments now. `Mediation · Arbitration · Toronto` is **restored to the masthead one-liner**, and ~~`docs/04`'s specified home `<title>` stands as written~~**AMENDED 2026-08-28.** The literal is replaced by a composition of `SITE.name` + `SITE.tagline`, so the masthead constants and the title cannot drift; the shipped string is `Pouya Lajevardi · Mediation · Arbitration · Toronto`. Q33's substance is untouched — the unscoped masthead form is still ratified — only the instruction to keep a hand-typed literal is See **§4 Offerings**, added for exactly this class of statement. The original question text follows for the record | — |
| ~~Q33-orig~~ | **How is arbitration described in site-wide copy before Q.Arb is conferred?** Not a wording question — a positioning one, and it recurs on every page. §4 records the Q.Arb pathway as **commenced August 2026**, "never as held or nearing completion". `SITE.tagline` reads `Mediation · Arbitration · Toronto`, and `docs/01` specifies that exact string as the **Home hero eyebrow** — where the hero copy beneath it can qualify it. Build step 1 promoted it to a masthead line under Pouya's name on every page, where nothing qualifies it and it reads as a designation strip; `claims-auditor` flagged it and **it has been removed from the header**. But the question it exposed is still open and lands at build step 2: does the hero eyebrow keep `Arbitration` as specified, qualify it, or hold it until designation? `/arbitration/` (step 4) is separately specced to state the position plainly, which is the honest model — the issue is the one-line forms that have no room to. **Second pass, same day:** the removal from the header did not sweep the proof sheet, where the same string was **hand-typed** as a type specimen and rendered ten times at up to 96px. Both defects fixed — the specimen is now a neutral pangram — and the lesson is the sweep rule again: a removal is a `grep`, not a memory. The nav item `Arbitration` also survives, deliberately; that is Q35. Raised by `claims-auditor`, 2026-08-26 | The Home hero (step 2); `docs/04`'s specified home `<title>`; any bio or one-line descriptor | | ~~Q33-orig~~ | **How is arbitration described in site-wide copy before Q.Arb is conferred?** Not a wording question — a positioning one, and it recurs on every page. §4 records the Q.Arb pathway as **commenced August 2026**, "never as held or nearing completion". `SITE.tagline` reads `Mediation · Arbitration · Toronto`, and `docs/01` specifies that exact string as the **Home hero eyebrow** — where the hero copy beneath it can qualify it. Build step 1 promoted it to a masthead line under Pouya's name on every page, where nothing qualifies it and it reads as a designation strip; `claims-auditor` flagged it and **it has been removed from the header**. But the question it exposed is still open and lands at build step 2: does the hero eyebrow keep `Arbitration` as specified, qualify it, or hold it until designation? `/arbitration/` (step 4) is separately specced to state the position plainly, which is the honest model — the issue is the one-line forms that have no room to. **Second pass, same day:** the removal from the header did not sweep the proof sheet, where the same string was **hand-typed** as a type specimen and rendered ten times at up to 96px. Both defects fixed — the specimen is now a neutral pangram — and the lesson is the sweep rule again: a removal is a `grep`, not a memory. The nav item `Arbitration` also survives, deliberately; that is Q35. Raised by `claims-auditor`, 2026-08-26 | The Home hero (step 2); `docs/04`'s specified home `<title>`; any bio or one-line descriptor |
| **Q34** | **Do §2's measurements of the previous build still hold, and were they measured against the deployed file?** Two of `claims-auditor`'s findings were unverified old-site assertions published in copy, which sent Claude Code to measure the live URL on 2026-08-26. What came back does not straightforwardly match §2. **Reproduced:** the response is a single **2,206,032-byte** file, and `<title>` is still `SML Company · Dispute Resolution`. **Could not be reproduced from the served HTML:** there are **zero** `base64,` occurrences anywhere in it — §2 records "two logo PNGs ~1 MB, base64-inlined" — and no reference to `unpkg` or a React development build. **Why this is a question and not a correction:** the served document is a *bundler harness*. 2,210,921 bytes of it are inline `<script>`, the real `<head>` sits JSON-escaped inside a `<script type="__bundler/template">`, and the application is loaded from **nine UUID-named script files that were not fetched**. The logos and the CDN references may well be in those bundles. So §2 may be right, may be stale, or may have been measured against the local source rather than the deployment — this record cannot tell which. **Why it matters beyond tidiness:** `docs/02` and `CLAUDE.md` both cite the base64-logo figure as the *reason* for a standing convention, and §12 R8 exists because unverified premises propagate. Nobody should quote these numbers in public copy until the question closes. Raised by Claude Code, 2026-08-26 | Nothing structural. It governs whether §2's figures may be cited as fact | | **Q34** | **Do §2's measurements of the previous build still hold, and were they measured against the deployed file?** Two of `claims-auditor`'s findings were unverified old-site assertions published in copy, which sent Claude Code to measure the live URL on 2026-08-26. What came back does not straightforwardly match §2. **Reproduced:** the response is a single **2,206,032-byte** file, and `<title>` is still `SML Company · Dispute Resolution`. **Could not be reproduced from the served HTML:** there are **zero** `base64,` occurrences anywhere in it — §2 records "two logo PNGs ~1 MB, base64-inlined" — and no reference to `unpkg` or a React development build. **Why this is a question and not a correction:** the served document is a *bundler harness*. 2,210,921 bytes of it are inline `<script>`, the real `<head>` sits JSON-escaped inside a `<script type="__bundler/template">`, and the application is loaded from **nine UUID-named script files that were not fetched**. The logos and the CDN references may well be in those bundles. So §2 may be right, may be stale, or may have been measured against the local source rather than the deployment — this record cannot tell which. **Why it matters beyond tidiness:** `docs/02` and `CLAUDE.md` both cite the base64-logo figure as the *reason* for a standing convention, and §12 R8 exists because unverified premises propagate. Nobody should quote these numbers in public copy until the question closes. Raised by Claude Code, 2026-08-26 | Nothing structural. It governs whether §2's figures may be cited as fact |
| ~~Q39~~ | **ANSWERED 2026-08-27 — and the answer is that the register's premise was FALSE.** Pouya checked it rather than defending it. His words: *"My assertion was FALSE as a universal."* **(a) Is it gated? YES.** Family arbitrators in Ontario must complete 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. **Sourced, and the source is now in the repo** per R14: `docs/reference/ontario-family-arbitration-training.md`, retrieved 2026-08-27 with provenance. **(b) Does the offering extend to it? NO** — and that is what actually disposes of the question. Pouya does not do family arbitration, so it is a **scope exclusion, not a gating problem**, and the prescribed-training requirement never bears on this practice. `Shareholder & Family Business` means **commercial disputes among family shareholders** — shareholder and partnership disputes, co-founder breakdowns, business succession — and its page must state plainly that family law matters are not accepted. *One sentence, not a section: Pouya's instruction is that it earns its place only by saving a wasted intake call.* **(c) One honest limit on the source.** The extract establishes the family gate directly and the commercial half only by absence — it neither mentions nor excludes commercial arbitration. §4 therefore carries *"commercial arbitration in Ontario requires no licence and no designation"* as **Pouya's stated position, unstamped**, not as a sourced fact. Do not let the footnote promote it. **Also swept:** the false universal survived in three live places outside the paragraph that was corrected — §4's NOT-NEGOTIABLE boundary bullet, §9's Q33 closure row, and a comment in `SiteHeader.astro`. All three fixed; the `grep` and its output are pasted in **Change Log entry (w), §Sweeps**. *(`adversarial-reviewer` flagged this citation while it still pointed at nothing: the entry was written at Phase 6, after review, so for the duration of the review a §9 row asserted in the present tense that evidence "is in the Change Log" before it was. Fair catch. The row now names the entry, and the reviewer independently re-ran the sweep and confirmed it was genuinely complete.)* Original question follows | — | | ~~Q39~~ | **ANSWERED 2026-08-27 — and the answer is that the register's premise was FALSE.** Pouya checked it rather than defending it. His words: *"My assertion was FALSE as a universal."* **(a) Is it gated? YES.** Family arbitrators in Ontario must complete 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. **Sourced, and the source is now in the repo** per R14: `docs/reference/ontario-family-arbitration-training.md`, retrieved 2026-08-27 with provenance. **(b) Does the offering extend to it? NO** — and that is what actually disposes of the question. Pouya does not do family arbitration, so it is a **scope exclusion, not a gating problem**, and the prescribed-training requirement never bears on this practice. `Shareholder & Family Business` means **commercial disputes among family shareholders** — shareholder and partnership disputes, co-founder breakdowns, business succession — and its page must state plainly that family law matters are not accepted. *One sentence, not a section: Pouya's instruction is that it earns its place only by saving a wasted intake call.* **(c) One honest limit on the source.** The extract establishes the family gate directly and the commercial half only by absence — it neither mentions nor excludes commercial arbitration. §4 therefore carries *"commercial arbitration in Ontario requires no licence and no designation"* as **Pouya's stated position, unstamped**, not as a sourced fact. Do not let the footnote promote it. **Also swept:** the false universal survived in three live places outside the paragraph that was corrected — §4's NOT-NEGOTIABLE boundary bullet, §9's Q33 closure row, and a comment in `SiteHeader.astro`. All three fixed; the `grep` and its output are pasted in **Change Log entry (w), §Sweeps**. *(`adversarial-reviewer` flagged this citation while it still pointed at nothing: the entry was written at Phase 6, after review, so for the duration of the review a §9 row asserted in the present tense that evidence "is in the Change Log" before it was. Fair catch. The row now names the entry, and the reviewer independently re-ran the sweep and confirmed it was genuinely complete.)* Original question follows | — |
@@ -686,17 +690,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 | — | | ~~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 31 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) | — | | ~~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 31 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 | — | | ~~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~~ | **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` | — | | ~~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 Q53 then ruled should be emitted, 2026-08-28.** `/about/`'s Person node carries the four memberships as `Organization` nodes; this row said "still withheld" until that sweep was actually run. 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 | | ~~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(a)~~ | **RULED A SECOND TIME AND CLOSED 2026-08-28 — PUBLISHABLE, and gate 1 is closed by the architect rather than by a source.** Pouya: *"Q46(a) PUBLISHABLE — ENE, dispute-system design and pre-dispute advisory pass all three gates. Flip the rows. Step 5 unblocked."* The three §4 Offerings rows are flipped, the worked-example table's gate-1 column reads `[Pouya's stated basis 2026-08-28]`, and `docs/01` and `docs/07` no longer carry the 🚫 blocks. **What this register held out for, and why it yields:** gate 1 asks *is the activity gated?* and §4's own test says it *"needs a source that a reviewer can check"*; no source for any of the three exists in `docs/reference/`. Pouya ruled once, this file declined to flip the rows and put the objection in front of him, **and he ruled again**. That is the mechanism working as designed rather than failing: gate 1 is a proposition of Ontario law about his own practice, §4 bars this file from concluding one in either direction, and holding a row against a repeated ruling would be this file substituting its judgement for the architect's. **The trade is recorded in the rows themselves**`[Pouya's stated basis]`, never `[verified]` — so a reviewer sees an attributed position rather than a sourced fact. The framing constraints survive the ruling and are **not** discretionary: ENE is an assessment delivered to both parties, never advice to one; and the conflict caution on pre-dispute advisory is practice management, so no copy may imply the offering is free of it | — |
| ~~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 | | ~~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 existed and the ruling named none, so the three rows were held and the objection was put back to him as **Q46(a)****which he then ruled a second time, and Q46(a) is CLOSED. The rows are PUBLISHABLE and step 5 is unblocked;** gate 1 carries `[Pouya's stated basis 2026-08-28]`, not `[verified]`. Read the Q46(a) row above, not this sentence, for the disposition | Both 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 | — | | ~~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 `<title>` 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 | | ~~Q48~~ | **CLOSED 2026-08-28 — not site-relevant, and that is a scope answer rather than an answer to the underlying question.** Pouya: *"ADRIO retention governs whether Pouya keeps a designation, not what the site may say about holding it."* He holds Q.Med today (§4, `[verified 2026-08-28]`), so `hasCredential` and the designation line are correct today, and the retention mechanics are his to manage rather than the register's to publish. **The asymmetry in ADRIO's materials is still real and still recorded**`docs/reference/adrio-designations.md` Finding 4 — and nothing was inferred from it in either direction. **Consequence applied:** the `memberOf` comment in `src/data/schema.ts` no longer carries Q48 as an argument, because Q53 removed the withholding that argument was attached to | — |
| **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 | | ~~Q49~~ | **ANSWERED 2026-08-28 — ONE ROW, and it is the value already shipping.** Pouya: *"one row: 'Mediator', supported by Q.Med plus completed sole mediations."* §4 Verified now carries **Practised role — "Mediator"** with both supports named, so `Person.jobTitle` stands on a row instead of on a derivation. **(a) closed:** the narrow value is ratified; the reverted `"Mediator and Arbitrator"` is not restored, and *"Arbitrator"* as a practised role remains unrowed. **(b) declined by the same ruling** — one row was granted and the corporate relation was not it, so **`worksFor` stays out of the graph**. ⚠️ **Read as a decline rather than as silence, and flagged as such to Pouya**: Q49 asked for two rows, the ruling granted one and named which. One line reverses it if the reading is wrong | — |
| **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 `/` | | ~~Q50~~ | **ANSWERED 2026-08-28 — the masthead string, and one claim now has one form.** Pouya: *"`ProfessionalService.name` takes the ratified masthead string. Q33 reaches it; one claim should not have two forms."* `name` was a hand-typed third variant — *"Pouya Lajevardi — Mediation & Arbitration"*, em dash and ampersand — beside the masthead (*"Mediation · Arbitration · Toronto"*) and `/`'s `<title>`. ⚠️ **IMPLEMENTED AS TWO FIELDS, WHICH DEVIATES FROM THE LITERAL RULING AND NEEDS ONE LINE FROM POUYA.** What ships is `name: "Pouya Lajevardi"` and `slogan: "Mediation · Arbitration · Toronto"` — both read from `SITE.name` and `SITE.tagline`, so the hand-typed variant is gone either way, which is what the ruling was for. **Why not the concatenation:** on a `LocalBusiness`-family type `name` means the business's name, and a name plus a service list plus a city is the name-stuffing pattern a search engine discards a rich result for — on the one project whose entire purpose is crawlability. `areaServed` already carries Toronto and Ontario. schema.org has a field for each half of a masthead, so this is a decomposition rather than a refusal. **The half that is mitigated rather than answered:** `slogan` still carries an unscoped *"Arbitration"*, which was the second objection to the concatenation. Against that — the identical string already ships in `<title>`, `og:title`, `twitter:title` and `/`'s hero eyebrow, all ratified under Q33, so excluding it from one name-like field alone would be incoherent. `serviceType` stays scoped because it **enumerates services**. **One line reinstates the concatenation** if that reading is wrong | — |
| **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 | | ~~Q51~~ | **ANSWERED 2026-08-28 — KEEP THE OBA SECTIONS. The distinction is structural, not evidentiary.** Pouya: *"the Law Society is the regulator, so membership IS licensure; the OBA is a voluntary association. Structural distinction, independent of eligibility details."* That last clause is what closes it: the question was raised as unanswerable inside this repo **because OBA eligibility is not established here** — and the ruling makes eligibility irrelevant. A voluntary association admits members it does not license, so listing it carries no licensure implication; a regulator's membership roll *is* the licence. Recorded in §4's memberships row and in `.claude/agents/claims-auditor.md` so it is not re-litigated, and removed from `docs/06`'s cutover checklist. **R1 is unaffected** — same page, same subject, different question, still live | — |
| **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 | | ~~Q52~~ | **CLOSED 2026-08-28 — committed, and RE-RUN rather than transcribed.** Pouya: *"YES — commit the simulate results, the inline policy, and the `NoSuchBucketPolicy` response, access key ID redacted."* `docs/reference/deploy-credential-verification.md` — eighteen read-only calls, each with the command that produced it, generated from captured output with the key ID replaced by `AKIA…REDACTED`. **Every value in §7's row reproduced**, including all nine `simulate-principal-policy` decisions (four `allowed`, five `implicitDeny`). **Two things the re-run added that the original verification did not have.** (1) A **contrast call**: `get-bucket-policy` on the *site* bucket returns exit 0 and a real policy, which is what makes exit **254** / `NoSuchBucketPolicy` on the backup bucket a genuine absence rather than a command that failed to start — the rule `CLAUDE.md` records twice, applied to the evidence that closes a High risk. (2) A correction to §7's own wording on the key's `LastUsed` field shape. The **secret** access key was never requested; the API cannot return it | — |
| **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 | | ~~Q53~~ | **ANSWERED 2026-08-28 — EMIT IT. The withholding is dropped.** Pouya: *"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."* Option (a) of the three the question offered. `src/data/schema.ts` now emits `memberOf` — the four §4 memberships as `Organization` nodes — **on `/about/` only**, which is where the page shows them, so the graph and the visible page assert the same set. **This ends a judgement that was restated three times and wrong twice:** cacheability proved too much (equally true of `hasCredential`, which ships), volatility did not survive the page already carrying the claim, and the widened *"yearly renewing"* premise it rested on was itself a §4 misstatement found on re-audit | — |
| **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 | | **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~~ | **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 | | ~~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 |
@@ -784,14 +788,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 | | 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 | | 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 | | 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 | **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 | | 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~~**SUPERSEDED. Q53, ruled 2026-08-28: EMIT IT.** `/about/`'s Person node now carries the four memberships as `Organization` nodes. Pouya took `adversarial-reviewer`'s argument: they are already crawlable in `/about/`'s HTML, so withholding the triple reduced no exposure and only made the graph less complete than the page. **The consequence for THIS reminder is that it now covers two surfaces** — re-confirming before a cutover means `src/data/schema.ts` as well as the visible list, and they must not be allowed to diverge. **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 — *(This rationale ended by pointing at **Q48** as a possible widening of the row. Q48 closed 2026-08-28 as not site-relevant — ADRIO retention governs whether Pouya keeps a designation, not what the site may say about holding one — so the clause is struck. §12 is read aloud every session; a live reminder pointing at a struck row produces a false surface every time.)*, 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 | | 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 | | 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 | | 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 | | 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 36** | 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 | | 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 36** | 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 | | 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 | | 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 **all nine** `simulate-principal-policy` checks after any policy edit (they are listed and reproducible in `docs/reference/deploy-credential-verification.md` §5) — the narrowness is the control (§10), and a widened policy is invisible from inside the repo. **The key is currently UNUSED — `AccessKeyLastUsed` returns `ServiceName`/`Region` = `N/A` and no `LastUsedDate`** — 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 | — | | ~~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 | — | | ~~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 | — |
@@ -799,6 +803,193 @@ never being raised again.
# Change Log # Change Log
## 2026-08-28 (z) — D19 bounds the review loop; nine rulings applied; and the loop immediately proved the point by finding a sweep that was claimed and never run
**The session's own shape is the argument for D19.** Two review rounds, four
agent passes, and the two highest-consequence findings were both *this session's
fixes* — a partial sweep, and a simplification that silently reversed a scoping
four other files documented. D19 caps the loop at two rounds because the third
round's cost is defects like those, not findings.
### D19 — Pouya's ruling, and where it went
His measurement: *"48 findings across two rounds, most of round two being
defects in round one's fixes. 342 lines added to `src/` for 8 functional. Four
reviewer findings were stale statements inside comments written that same
session. A Change Log sweep that could not reproduce because writing it changed
the file it counted. Every one is a real defect — but they are defects in the
record about the record, and that is infinite regress. My fault for never
bounding scope."*
§3 D19 carries it. Six sweeps, all verified by command:
```console
$ python3 - <<'EOF' # each destination checked for its required text
.claude/agents/claims-auditor.md '## Scope — D19' x1
.claude/agents/claims-auditor.md 'Severity filter — D19' x1
.claude/agents/adversarial-reviewer.md '## Scope — D19' x1
.claude/agents/adversarial-reviewer.md 'Severity filter — D19' x1
.claude/commands/build.md '### Scope — D19' x1
.claude/commands/build.md '### The stop signal' x1
.claude/commands/build.md 'Two rounds is the cap — D19' x1
.claude/commands/build.md 'do not open a numbered question…' x1
.claude/commands/wrap.md 'Do not open a numbered question…' x1
CLAUDE.md 'Comments record decisions…D19' x1
AGENTS.md '| D19 | Bounding the review loop |' x1
EOF
D19 swept to all six destinations
```
`/build` Phase 1 also went `D1D18``D1D19`; that was the only stale
D-range reference in the repo (`git grep 'D1D18'`, 1 hit, fixed).
### The nine rulings
| # | Ruling | What changed |
|---|---|---|
| **Q46(a)** | PUBLISHABLE. Step 5 unblocked | Three §4 Offerings rows flipped; gate 1 records **`[Pouya's stated basis 2026-08-28]`**, never `[verified]`. §4's worked-example prose and `docs/01` / `docs/07`'s 🚫 blocks rewritten. Two framing constraints survive and are marked non-discretionary: ENE is an assessment **to both parties**, and pre-dispute advisory carries a conflict caution |
| **Q48** | Closed, not site-relevant | Struck. Removed as an argument from `schema.ts`; the ADRIO asymmetry stays recorded in `docs/reference/adrio-designations.md` Finding 4 |
| **Q49** | One row: *"Mediator"* | §4 Verified gains **Practised role — "Mediator"**, naming both supports. Read as **declining Q49(b)** — one row was granted and the corporate relation was not it — so `worksFor` stays out. Flagged as a reading, not an assumption |
| **Q50** | `name` takes the masthead string | **Deviates: shipped as `name` + `slogan`.** See the Q50 row — the concatenation is the name-stuffing pattern and `areaServed` already carries the city. One line reinstates it |
| **Q51** | Keep the OBA sections | §4's memberships row and `claims-auditor` now carry the structural distinction; the cutover-checklist item became a check rather than a question |
| **Q52** | Commit the evidence | `docs/reference/deploy-credential-verification.md`**re-run, not transcribed** |
| **Q53** | Emit `memberOf` | `/about/`'s Person node, four `Organization` nodes from `MEMBERSHIP_ORGS` |
| **Q23 / Q34 / Q38** | Unchanged | — |
### Q52 — re-run rather than transcribed, and the re-run added two things
Eighteen read-only AWS calls from the repository root, each with its command,
access key ID redacted. Every value in §7 reproduced; the nine
`simulate-principal-policy` decisions came back four `allowed` / five
`implicitDeny` unchanged, and `adversarial-reviewer` independently reproduced
them again including `MatchedStatements` positions.
1. **A contrast call.** `get-bucket-policy` on the *site* bucket exits 0 with a
real CloudFront OAC policy — which is what makes exit **254** /
`NoSuchBucketPolicy` on the backup bucket a genuine absence rather than a
command that failed to start. That call was not part of the original
verification, and without it the evidence was weaker than it read.
2. **A correction to §7's own wording.** The API returns no null `LastUsed`; it
returns `AccessKeyLastUsed` with `ServiceName`/`Region` = `"N/A"` and **no
`LastUsedDate` key**. Same conclusion, different field shape. Swept into §7,
§9 Q22 and §12 R17, which also went **eight → nine** checks.
### The headline finding: a sweep asserted and never run
Both agents found it independently. Q53 was applied to `schema.ts`, `docs/06`,
`docs/04`'s first half and §9 — and **six other in-scope records still said
`memberOf` was withheld**, including §4's memberships row and §12 **R10**, which
`CLAUDE.md` requires be read aloud to Pouya every session. `docs/04`'s Person
cell said *both*, in one table cell, directly below its own note about having
been caught doing exactly that with `worksFor`.
This is R8 — *a sweep is a command, not a claim* — and the claim was recall. The
sweep now exists and reads every match rather than counting them:
```console
$ # every in-scope memberOf statement, READ not counted
0 live stale claims
$ git grep -cn 'NOT YET PUBLISHABLE' -- ':!AGENTS.md' ; echo "exit=$?"
exit=1
```
### Two round-1 fixes that were themselves defects
**1. Simplifying `memberOf` reversed the scoping.** Round 1 argued the per-page
opt-in bought nothing (same `@id`, so a consumer merges) and it was removed.
Round 2 found the consequence: `memberOf` shipped on `/`, where no membership is
visible, and **six records said it did not**. The parameter is restored. The
deciding reason is not the mechanism but Pouya's: his Q53 ruling turns on *"the
memberships are already crawlable in `/about/`'s HTML"* — a page-specific
reason, so a page-specific field. `schema.ts` now carries a "do not delete this
as redundant" note, because the deletion argument is genuinely persuasive and
genuinely wrong.
**2. `MEMBERSHIP_ORGS` was inserted between `BOUTIQUE`'s JSDoc and `BOUTIQUE`.**
Verified by `adversarial-reviewer` against the TypeScript compiler API: the D16
warning — *"The Toronto boutique is NEVER named"* — became leading trivia for no
declaration, surfaced on hover for nothing. One of the two decisions that file
exists to protect, made invisible to tooling by a comment block landing four
lines too early. Moved below `BOUTIQUE`.
### Other findings resolved
- `/`'s `<title>` still hand-typed *"Mediation & Arbitration · Toronto"* while
Q50 claimed the variant was eliminated. Now `SITE.name` + `SITE.tagline`;
`docs/04`'s literal deleted and §9 Q33's *"stands as written"* amended.
- `about.astro` claimed the graph and the visible list *"cannot drift apart"*.
They can: different arrays, **length parity only**, content parity manual.
- The parity assertion was described as a build error. **Measured: it fails
`npm run check`, not `npm run build`** — the deploy path runs `check` first, so
it is covered, and the caveat is now written down. It was also probed rather
than assumed: adding a fifth entry produces `ts(2344)`.
- `MEMBERSHIP_ORGS` was said to differ from the display list on **one** line. It
differs on **three of four**.
- The `name`/`slogan` mapping was justified by the masthead rendering two
elements. **On `/` the masthead suppresses the tagline** (`!isHome`), and `/`
is the only page this node ships on. The true counterpart is the hero eyebrow.
- §12 R10 still cited Q48, closed in this same change set — a live reminder
pointing at a struck row, surfaced every session.
- §7's deploy row asserted three facts and retracted all three in the same cell.
Rewritten to state current facts once; the retractions live here.
- `docs/01` carried a second copy of a §4 currency stamp, already diverged
(2026-08-26 vs 2026-08-28). Replaced with a pointer.
### Declined
- **`memberOf`'s bare `Ontario Bar Association`.** `claims-auditor` notes the
section qualifiers are what visibly mark the OBA as voluntary. Declined: a
name that reconciles against no real entity gives up what the field buys, and
the short form is a **narrowing** of §4's row rather than an inference beyond
it. Q51's ruling — regulator versus voluntary association — is the substantive
answer and it is now recorded beside the array.
- **`slogan`'s unscoped "Arbitration".** Mitigated, not discharged, and said so
in the source. The identical string already ships in `<title>`, `og:title`,
`twitter:title` and `/`'s hero eyebrow, all ratified under Q33.
### D19 applied to this change set's own comments
Measured on the diff, not recalled: **`src/` net 6 lines, comments 56,
code +45.** Three narration blocks moved here from source — the withdrawal of
three superseded `memberOf` grounds, the `jobTitle` string's audit history, and
the account of the `name` variant that was replaced. The live constraints stayed:
do not widen `jobTitle`, do not put the tagline back in `name`, do not delete the
`memberOf` opt-in, the two membership arrays differ.
### Found and NOT fixed here — the Change Log was duplicated by entry (y)
`adversarial-reviewer` spotted it. Verified: 51 entry headings, **26 unique**;
everything from entry (x) back to 2026-08-25 appears twice. `git show` on each
commit locates it precisely — `c576b9a` has one copy, **`77a7b41` has two**, so
last session's own commit introduced it, almost certainly a patch script that
appended where it should have replaced. Block B is a strict prefix of block A
(3,252 identical lines, then B stops), so **nothing is lost by removing it**.
Removed in its own commit rather than buried in this one.
### Verified — run, not asserted
`npm run check` 0 errors / 0 warnings / 0 hints, 22 files · `eslint` clean ·
`prettier --check` clean · build 2 pages · **0 `.js` emitted** · non-JSON-LD
`<script>` tags **0** · minifier guard **0** hits, `animation-timeline` **5**
surviving in `dist` · `dist/about/` Person carries `memberOf` ×4, `dist/index.html`
Person does not · `jobTitle: "Mediator"`, no `worksFor` at any depth ·
`ProfessionalService` `name: "Pouya Lajevardi"`, `slogan: "Mediation · Arbitration ·
Toronto"` · credential scan over the full diff: 0 hits on seven patterns.
**NOT run:** Lighthouse — tool unavailable until step 7 (R11). HTML validator.
`.env.example` could not be re-read this session — the harness denies reads under
that path — so it is reported as *unchanged by this change set* (`git diff` and
`git status` both empty for it) rather than as re-verified safe.
### Open after this entry
**Q23**, **Q34**, **Q38** — and nothing else numbered. The Q-series went from
eleven live to three, which is D19 working. Live reminders: **R1** (surfaced
again), R2R6, R9, **R10** (event-triggered), **R11**, R12R16, **R17**
(2026-11-26).
---
## 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 ## 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), **Pouya's rulings this session:** Q44 (memberships current — ship the group),
+16
View File
@@ -313,6 +313,22 @@ sweep; instances survived all three, and one of them was inside
`.claude/agents/claims-auditor.md` — the definition of the agent whose job is to `.claude/agents/claims-auditor.md` — the definition of the agent whose job is to
catch exactly that. Recall is not evidence. catch exactly that. Recall is not evidence.
**Comments record decisions, not history — D19.** *"X because D13"* stays.
*"This was Y, then flagged, then became X"* belongs in the `AGENTS.md` Change
Log, which is where a reader looks for how something got here. **A comment
longer than the code it explains must justify itself. Trim on sight.**
Pouya's ruling, 2026-08-28, on his own measurement: **342 lines added to `src/`
in one session for 8 functional lines**, and four of that session's review
findings were stale statements living inside those comments. A comment that
narrates its own revision history becomes a second record to keep true, and then
a source of defects about the record rather than about the site.
This does **not** license deleting a comment that carries a live constraint. The
parent-scope trap, the `animation-timeline` minifier defect and the `as`-prop
hazard above are load-bearing and stay. The test is whether a future reader needs
it **to avoid breaking something** — not whether it is interesting.
**Commits.** Conventional Commits (`feat:`, `fix:`, `docs:`, `chore:`, `refactor:`). **Commits.** Conventional Commits (`feat:`, `fix:`, `docs:`, `chore:`, `refactor:`).
One logical change per commit. Never commit secrets, `.env` files, or AWS One logical change per commit. Never commit secrets, `.env` files, or AWS
credentials. Gitea is not an AWS OIDC provider, so the deploy key is designed as credentials. Gitea is not an AWS OIDC provider, so the deploy key is designed as
+18 -11
View File
@@ -99,7 +99,7 @@ Revisit at month 1218, once there is relationship history to point to.
## Not a practice area yet: tax-adjacent disputes ## Not a practice area yet: tax-adjacent disputes
**Canadian Tax Foundation membership is verified** (`AGENTS.md` §4, 2026-08-26) **Canadian Tax Foundation membership is verified** (`AGENTS.md` §4 — read the stamp there; a second copy of a currency stamp goes stale where nobody re-reads it, and this one had)
and it is the one credential none of the six areas above touch. Tax-adjacent and it is the one credential none of the six areas above touch. Tax-adjacent
disputes are genuinely ADR territory — valuation and purchase-price disputes on disputes are genuinely ADR territory — valuation and purchase-price disputes on
a share sale, indemnity and earn-out fights that turn on a tax position, a share sale, indemnity and earn-out fights that turn on a tax position,
@@ -260,17 +260,24 @@ Six cards, one paragraph each, linking onward. Also the natural home for the
pre-dispute technical advisory** — three, and each has an `AGENTS.md` §4 pre-dispute technical advisory** — three, and each has an `AGENTS.md` §4
Offerings row. Offerings row.
> 🚫 **THE STRIP MAY NOT SHIP YET, AND HAVING A ROW IS NOT WHAT UNBLOCKS IT.** > **THE STRIP MAY SHIP — Q46(a) closed 2026-08-28, on Pouya's second
> All three rows read **"GATES 0 AND 2 ANSWERED; GATE 1 STILL HAS NO SOURCE — > ruling.** All three §4 Offerings rows now read **PUBLISHABLE**. Read the ENE
> NOT YET PUBLISHABLE"**. Pouya ruled on 2026-08-28 that all three pass; §4's > row before writing the strip: gate 1 (*is the activity gated?*) is closed as
> gate 1 asks *is the activity gated?*, which the register answers with a > **`[Pouya's stated basis 2026-08-28]`** and **not** as `[verified]`, because no
> checkable source and not with a ruling, and **no source exists for any of the > source for any of the three exists in `docs/reference/`. That is a deliberate,
> three**. Tracked as **Q46(a)**, which names this strip as the thing it blocks. > attributed position of the architect's, not a sourced fact — do not describe it
> on the page or in a comment as settled law.
> >
> This paragraph read *"each now has a §4 Offerings row, which is what the strip > **Two framing constraints survive the ruling and are not discretionary:**
> 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 > 1. **ENE is an assessment delivered to BOTH parties**, never advice to one. It
> unpublishable. Found by `claims-auditor` on re-audit. > is the offering nearest §4's NOT-NEGOTIABLE boundary — a neutral assessment
> of the *merits* sits closest to *"providing legal services"*.
> 2. **Pre-dispute advisory carries a conflict caution**, and it is practice
> management rather than a publication gate: advisory work for one
> organisation can conflict against a later appointment in the same matter.
> **No copy may imply the offering is free of that tension** — this strip is
> where the temptation to imply it will arise.
> **`settlement counsel` IS STRUCK FROM THIS STRIP AND MUST NOT BE RESTORED.** > **`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: > `AGENTS.md` Q42, 2026-08-27. Pouya struck it as his own error in this document:
+7 -3
View File
@@ -48,8 +48,12 @@ D1.
Every page passes through one `SEO` component. A page without it is not finished. Every page passes through one `SEO` component. A page without it is not finished.
``` ```
title 5060 chars, unique. Pattern: "<Page> · Pouya Lajevardi" title 5060 chars, unique. Pattern: "<Page> · Pouya Lajevardi".
Home: "Pouya Lajevardi · Mediation & Arbitration · Toronto" `/` composes its own from the constants — `SITE.name` +
`SITE.tagline` — rather than a literal, so the masthead and
the title cannot drift. This spec carried the literal with an
ampersand after the composition shipped with interpuncts;
cite the constants, do not restate them (AGENTS.md §7 rule).
ARTICLES ARE THE EXCEPTION: no " · Pouya Lajevardi" suffix. ARTICLES ARE THE EXCEPTION: no " · Pouya Lajevardi" suffix.
The suffix is 18 chars, so a headline that already reads The suffix is 18 chars, so a headline that already reads
5060 renders at 6878 — over this ceiling. Measured against 5060 renders at 6878 — over this ceiling. Measured against
@@ -101,7 +105,7 @@ JSON-LD only. Validate against Google's Rich Results Test before cutover.
| Type | Where | Notes | | Type | Where | Notes |
|---|---|---| |---|---|---|
| `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` | | `Person` | `/about/`, referenced site-wide | **Emitted:** `name`, `url`, `jobTitle`, `description`, `alumniOf` (Bond University), `knowsLanguage` (en, fa), `hasCredential` (Q.Med), `sameAs` (LinkedIn), `email`, `image`. **Emitted on `/about/` only:** `memberOf` — the four §4 memberships as `Organization` nodes (Q53, ruled 2026-08-28). `/` shows no memberships, so its Person node omits it: structured data represents the page it sits on. **Withheld:** `worksFor` — Q49(b) declined the row 2026-08-28; `provider → Person → worksFor` would assert a same-entity claim §4 does not row. *(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 emitted** — see the sentence above; Q53 closed 2026-08-28. *(This cell asserted `memberOf` was both emitted and withheld for one pass, which is the defect it already records itself being caught for on `worksFor`, in the opposite direction. The enumeration is the part an implementer copies.)* 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 | | `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` | | `Service` | Each practice page | `serviceType`, `provider` → Person, `areaServed` |
| `Article` | Each article | `headline`, `description`, `datePublished`, `dateModified`, `author` → Person, `image` | | `Article` | Each article | `headline`, `description`, `datePublished`, `dateModified`, `author` → Person, `image` |
+13 -25
View File
@@ -356,34 +356,22 @@ Then invalidate `/*`.
**Do NOT add a currency sentence to the page while you are here** — his **Do NOT add a currency sentence to the page while you are here** — his
ruling is *"list the memberships; promise nothing about their future ruling is *"list the memberships; promise nothing about their future
state"*, and the struck sentence stays struck. state"*, and the struck sentence stays struck.
**Do NOT add `memberOf` to the Person JSON-LD** unless Pouya has said to. **`memberOf` IS EMITTED on `/about/`** — Q53 answered 2026-08-28 and the
It is withheld deliberately and on narrower grounds than the visible page: withholding is dropped, so the graph asserts the same four memberships the
the reason is recorded in `src/data/schema.ts` and **it is an open page shows. **This item therefore covers both**: re-confirming before
judgement, not a settled one — `AGENTS.md` Q53.** Do not restate the cutover means `src/data/schema.ts` as well as the visible list, and they
reasoning here; a third copy is how the first two went stale. must not be allowed to diverge.
**§4 records yearly renewal for the OBA sections and the CTF only** — it **§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 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. this line asserted "all renew yearly", which §4 does not support.
- [ ] **`AGENTS.md` Q51 answered before cutover** — does listing the **OBA - [ ] **The OBA sections stay listed; the LSO stays out** — a check that nobody
sections** on `/about/` carry the licensure implication that excludes the has tidied the two into one list, not an open question. `AGENTS.md` **Q51
LSO? §4 excludes the Law Society precisely because *"listing the Law Society answered 2026-08-28**: the Law Society is the **regulator**, so membership
among memberships implies licensure"*, and Forbidden bars *any phrasing that *is* licensure; the OBA is a **voluntary association**, which admits
**implies** entitlement to practise law*. The OBA sections **went live on members it does not license. Structural, and independent of eligibility
`/about/` on 2026-08-28** and Q51 was raised the same day, **after** Pouya's details — which is what made the question unanswerable inside this repo
Q44 ruling authorised the group — so the ruling did not consider it. before the ruling. **R1 is still live**: same page, same subject, different
`adversarial-reviewer` rates it moderate-low confidence as a defect and question
**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 `TODO(pouya)` remains in any shipped page
- [ ] No matter counts, rates, dollar figures, or testimonials anywhere - [ ] No matter counts, rates, dollar figures, or testimonials anywhere
- [ ] Q.Arb described as **commenced August 2026** everywhere it appears — §4's - [ ] Q.Arb described as **commenced August 2026** everywhere it appears — §4's
+8 -10
View File
@@ -133,16 +133,14 @@ offer tribunal-secretary work on the site.
Early neutral evaluation, dispute-system design, and pre-dispute technical Early neutral evaluation, dispute-system design, and pre-dispute technical
advisory: **$500 / hour**. advisory: **$500 / hour**.
> 🚫 **A RATE IS NOT A PUBLICATION LICENCE, AND THESE THREE ARE NOT PUBLISHABLE > **PUBLISHABLE — Q46(a) closed 2026-08-28.** All three §4 Offerings rows
> YET.** §4's ENE row says the pricing here *"is a fee-page question, not a > read PUBLISHABLE on Pouya's second ruling, so the line item may go on
> publication licence"*, and all three Offerings rows read **NOT YET > `/fees/`. **Read the §4 ENE row first:** gate 1 is closed as **`[Pouya's
> PUBLISHABLE** — gate 1 (*is the activity gated?*) has no source. **Q46(a)** > stated basis 2026-08-28]`**, not `[verified]` — there is still no source in
> names `docs/07-fees.md` pricing directly as something it blocks. > `docs/reference/` — and the framing constraints in `docs/01` §`/practice/`
> > travel with the offering onto this page. In particular, **ENE is priced as an
> So: the rate is recorded and settled; **the line item does not go on `/fees/` > assessment delivered to both parties**, and nothing on `/fees/` may read as a
> until Q46(a) closes.** This note did not exist until 2026-08-28, which meant > rate for advising one of them.
> 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 **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 priced** — `AGENTS.md` Q42, Pouya 2026-08-27, correcting his own entry in
@@ -0,0 +1,559 @@
# Deploy credential — verification output
**What this is.** The tool output behind `AGENTS.md` §7's *Deploy credential —
PROVISIONED* row and the two risk downgrades in `AGENTS.md` §10. It exists because the row
was written on evidence that lived only in a terminal, which is the
**Q24 / Q32 shape** R14 exists for: a claim whose supporting artefact is
unreachable is unverifiable by construction, not merely unverified.
`AGENTS.md` **Q52**, ruled 2026-08-28: *"YES — commit the simulate results, the
inline policy, and the `NoSuchBucketPolicy` response, access key ID redacted."*
## Provenance
| | |
|---|---|
| Subject | IAM user `adr-sml-deploy`, AWS account `327082975128` |
| Retrieved | **2026-08-28**, re-run from the repository root |
| Calling identity | `arn:aws:iam::327082975128:user/pouya` — the broadly-permissioned personal user, **at an interactive keyboard**. `AGENTS.md` §7 and §10: acceptable interactively, **never** as a CI credential |
| Calls | 18 — all **read-only**. No `create`, `put`, `attach`, `delete`, or `update` |
| Redaction | The access key ID is replaced with `AKIA…REDACTED` throughout. Nothing else is redacted; `UserId` (`AIDA…`) is retained because it is the durable principal identifier that appears in CloudTrail and grants nothing. The **secret** access key was never requested and cannot be retrieved from the API at all |
| Method | `aws-cli/2.34.53`. Every command's exit status was read, and **no `2>/dev/null` anywhere** — see the `NoSuchBucketPolicy` section, where the error *is* the result |
**Re-run it.** Every command below is copy-pasteable. Nothing here is
transcribed from a session; this file was generated from the captured output.
---
## 1. The user
```console
$ aws iam get-user --user-name adr-sml-deploy
{
"User": {
"Path": "/",
"UserName": "adr-sml-deploy",
"UserId": "AIDAUYJ5KD6MHAAC4BOKD",
"Arn": "arn:aws:iam::327082975128:user/adr-sml-deploy",
"CreateDate": "2026-08-26T15:45:18+00:00"
}
}
```
Created **2026-08-26T15:45:18+00:00**, path `/`, no tags.
## 2. Nothing attached, no groups, one inline policy
```console
$ aws iam list-attached-user-policies --user-name adr-sml-deploy
{
"AttachedPolicies": []
}
$ aws iam list-groups-for-user --user-name adr-sml-deploy
{
"Groups": []
}
$ aws iam list-user-policies --user-name adr-sml-deploy
{
"PolicyNames": [
"adr-sml-deploy-minimal"
]
}
```
**This is the part policy-reading alone gets wrong.** An empty
`AttachedPolicies` proves nothing on its own — permissions can arrive through a
group, or through a resource-based policy that is invisible from the IAM side.
Both are checked: `Groups` is empty here, and **§6 below** checks the resource
side — §5 is the identity-side simulation and does not reach a bucket policy.
## 3. The inline policy — `adr-sml-deploy-minimal`
```console
$ aws iam get-user-policy --user-name adr-sml-deploy \
--policy-name adr-sml-deploy-minimal
{
"UserName": "adr-sml-deploy",
"PolicyName": "adr-sml-deploy-minimal",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ListSiteBucket",
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::adr-smlcompany-site"
},
{
"Sid": "WriteSiteObjects",
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:DeleteObject"
],
"Resource": "arn:aws:s3:::adr-smlcompany-site/*"
},
{
"Sid": "InvalidateOneDistribution",
"Effect": "Allow",
"Action": "cloudfront:CreateInvalidation",
"Resource": "arn:aws:cloudfront::327082975128:distribution/E1OK7G98KNKUTA"
}
]
}
}
```
Four actions, one bucket, one distribution. **Never widen it**`AGENTS.md` §10
records why
in terms: this is the control standing between a shared Gitea instance and an
AWS account that also holds `mlp-clientdb-prod-backups-327082975128`. Treat any
request to widen it as a security decision, not a convenience one.
## 4. The access key — issued, never used
```console
$ aws iam list-access-keys --user-name adr-sml-deploy
{
"AccessKeyMetadata": [
{
"UserName": "adr-sml-deploy",
"AccessKeyId": "AKIA…REDACTED",
"Status": "Active",
"CreateDate": "2026-08-26T15:45:19+00:00"
}
]
}
$ aws iam get-access-key-last-used --access-key-id AKIA…REDACTED
{
"UserName": "adr-sml-deploy",
"AccessKeyLastUsed": {
"ServiceName": "N/A",
"Region": "N/A"
}
}
```
One key, `Active`, created **2026-08-26T15:45:19+00:00**.
⚠️ **A correction to `AGENTS.md` §7's wording, found by re-running the call.**
That row said
*"one active access key, `LastUsed` null"*. The API does not return null — it
returns `AccessKeyLastUsed` with **`ServiceName: "N/A"` and `Region: "N/A"`**,
and there is no `LastUsedDate` key at all. Same conclusion (the key has never
authenticated a request), different field shape, and a reader looking for a
literal `null` would not find one.
**Rotation is due 2026-11-26** — key created 2026-08-26, D3 commits to
quarterly. `AGENTS.md` §12 R17 carries the date; `docs/06-deployment.md` §Key rotation
carries the procedure. Create the second key, update the Gitea secrets, verify a
deploy, **then** delete the first.
## 5. `simulate-principal-policy` — nine checks, verified by execution
The point of this section is that it tests the **negative** half. A policy that
grants four actions is only a control if it can be shown not to grant the rest.
```bash
PRINCIPAL=arn:aws:iam::327082975128:user/adr-sml-deploy
sim() { aws iam simulate-principal-policy \
--policy-source-arn "$PRINCIPAL" --action-names "$1" --resource-arns "$2" ; }
```
| # | Action | Resource | `EvalDecision` |
|---|---|---|---|
| 1 | `s3:PutObject` | `arn:aws:s3:::adr-smlcompany-site/index.html` | **allowed** |
| 2 | `s3:DeleteObject` | `arn:aws:s3:::adr-smlcompany-site/old.html` | **allowed** |
| 3 | `s3:ListBucket` | `arn:aws:s3:::adr-smlcompany-site` | **allowed** |
| 4 | `cloudfront:CreateInvalidation` | `arn:aws:cloudfront::327082975128:distribution/E1OK7G98KNKUTA` | **allowed** |
| 5 | `s3:ListBucket` | `arn:aws:s3:::mlp-clientdb-prod-backups-327082975128` | **implicitDeny** |
| 6 | `s3:GetObject` | `arn:aws:s3:::mlp-clientdb-prod-backups-327082975128/anything` | **implicitDeny** |
| 7 | `s3:DeleteBucket` | `arn:aws:s3:::adr-smlcompany-site` | **implicitDeny** |
| 8 | `s3:PutObject` | `arn:aws:s3:::meshkinilaw.ca/anything` | **implicitDeny** |
| 9 | `iam:CreateUser` | `*` | **implicitDeny** |
Four `allowed`, five `implicitDeny`. `implicitDeny` rather than `explicitDeny`
is the correct and expected shape: the policy contains no `Deny` statement, so
everything outside its three `Allow` statements falls through to IAM's
default-deny. An `explicitDeny` here would mean a *different* policy was also in
play.
Raw output for each check, including the full `MatchedStatements` and
`MissingContextValues`, follows in **§7 of this file**. *(Bare `§n` here means a
section of this document; references to the working file are written
`AGENTS.md` §n.)*
## 6. The resource side — `NoSuchBucketPolicy`, and why the contrast call matters
IAM simulation covers identity-based policy. It does **not** cover a
resource-based grant on the backup bucket, which would be invisible from the
principal's side. So:
```console
$ aws s3api get-bucket-policy --bucket mlp-clientdb-prod-backups-327082975128
# exit status: 254
# stdout: 0 bytes
# stderr:
# aws: [ERROR]: An error occurred (NoSuchBucketPolicy) when calling the GetBucketPolicy operation: The bucket policy does not exist
```
**An error is the result here, and that is only legible because stderr was not
suppressed.** `CLAUDE.md`'s convention, from Pouya's own 2026-08-28 correction:
`2>/dev/null` converts *"it failed"* into *"it found nothing"*, and those are
opposite results. The exit status is **254** and stdout is **empty** — read the
status, not just stdout.
**And an empty result needs a working instrument.** The same command against the
site bucket, to prove the call itself resolves a policy when one exists:
```console
$ aws s3api get-bucket-policy --bucket adr-smlcompany-site
{
"Policy": "{\"Version\":\"2008-10-17\",\"Id\":\"PolicyForCloudFrontPrivateContent\",\"Statement\":[{\"Sid\":\"AllowCloudFrontServicePrincipal\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"cloudfront.amazonaws.com\"},\"Action\":\"s3:GetObject\",\"Resource\":\"arn:aws:s3:::adr-smlcompany-site/*\",\"Condition\":{\"StringEquals\":{\"AWS:SourceArn\":\"arn:aws:cloudfront::327082975128:distribution/E1OK7G98KNKUTA\"}}}]}"
}
```
Exit **0**, a real policy returned — the CloudFront OAC grant, scoped to
distribution `E1OK7G98KNKUTA`. So `NoSuchBucketPolicy` on the backup bucket is a
**genuine absence**, not a command that failed to run. That contrast is the
whole reason this call is in the file: without it, an empty result from a broken
command looks exactly like an empty result from a bucket with no policy.
*(This contrast call was **not** part of the original Q22 verification. It was
added on re-run, and it closes the gap that made the original evidence weaker
than it read.)*
## 7. Raw `simulate-principal-policy` responses
### Check 1
```json
{
"EvaluationResults": [
{
"EvalActionName": "s3:PutObject",
"EvalResourceName": "arn:aws:s3:::adr-smlcompany-site/index.html",
"EvalDecision": "allowed",
"MatchedStatements": [
{
"SourcePolicyId": "user_adr-sml-deploy_adr-sml-deploy-minimal",
"SourcePolicyType": "IAM Policy",
"StartPosition": {
"Line": 6,
"Column": 55
},
"EndPosition": {
"Line": 9,
"Column": 57
}
}
],
"MissingContextValues": [],
"EvalDecisionDetails": {},
"ResourceSpecificResults": [
{
"EvalResourceName": "arn:aws:s3:::adr-smlcompany-site/index.html",
"EvalResourceDecision": "allowed",
"MatchedStatements": [
{
"SourcePolicyId": "user_adr-sml-deploy_adr-sml-deploy-minimal",
"SourcePolicyType": "IAM Policy",
"StartPosition": {
"Line": 6,
"Column": 55
},
"EndPosition": {
"Line": 9,
"Column": 57
}
}
]
}
]
}
]
}
```
### Check 2
```json
{
"EvaluationResults": [
{
"EvalActionName": "s3:DeleteObject",
"EvalResourceName": "arn:aws:s3:::adr-smlcompany-site/old.html",
"EvalDecision": "allowed",
"MatchedStatements": [
{
"SourcePolicyId": "user_adr-sml-deploy_adr-sml-deploy-minimal",
"SourcePolicyType": "IAM Policy",
"StartPosition": {
"Line": 6,
"Column": 55
},
"EndPosition": {
"Line": 9,
"Column": 57
}
}
],
"MissingContextValues": [],
"EvalDecisionDetails": {},
"ResourceSpecificResults": [
{
"EvalResourceName": "arn:aws:s3:::adr-smlcompany-site/old.html",
"EvalResourceDecision": "allowed",
"MatchedStatements": [
{
"SourcePolicyId": "user_adr-sml-deploy_adr-sml-deploy-minimal",
"SourcePolicyType": "IAM Policy",
"StartPosition": {
"Line": 6,
"Column": 55
},
"EndPosition": {
"Line": 9,
"Column": 57
}
}
]
}
]
}
]
}
```
### Check 3
```json
{
"EvaluationResults": [
{
"EvalActionName": "s3:ListBucket",
"EvalResourceName": "arn:aws:s3:::adr-smlcompany-site",
"EvalDecision": "allowed",
"MatchedStatements": [
{
"SourcePolicyId": "user_adr-sml-deploy_adr-sml-deploy-minimal",
"SourcePolicyType": "IAM Policy",
"StartPosition": {
"Line": 3,
"Column": 17
},
"EndPosition": {
"Line": 6,
"Column": 55
}
}
],
"MissingContextValues": [],
"EvalDecisionDetails": {},
"ResourceSpecificResults": [
{
"EvalResourceName": "arn:aws:s3:::adr-smlcompany-site",
"EvalResourceDecision": "allowed",
"MatchedStatements": [
{
"SourcePolicyId": "user_adr-sml-deploy_adr-sml-deploy-minimal",
"SourcePolicyType": "IAM Policy",
"StartPosition": {
"Line": 3,
"Column": 17
},
"EndPosition": {
"Line": 6,
"Column": 55
}
}
]
}
]
}
]
}
```
### Check 4
```json
{
"EvaluationResults": [
{
"EvalActionName": "cloudfront:CreateInvalidation",
"EvalResourceName": "arn:aws:cloudfront::327082975128:distribution/E1OK7G98KNKUTA",
"EvalDecision": "allowed",
"MatchedStatements": [
{
"SourcePolicyId": "user_adr-sml-deploy_adr-sml-deploy-minimal",
"SourcePolicyType": "IAM Policy",
"StartPosition": {
"Line": 9,
"Column": 57
},
"EndPosition": {
"Line": 12,
"Column": 83
}
}
],
"MissingContextValues": [],
"EvalDecisionDetails": {},
"ResourceSpecificResults": [
{
"EvalResourceName": "arn:aws:cloudfront::327082975128:distribution/E1OK7G98KNKUTA",
"EvalResourceDecision": "allowed",
"MatchedStatements": [
{
"SourcePolicyId": "user_adr-sml-deploy_adr-sml-deploy-minimal",
"SourcePolicyType": "IAM Policy",
"StartPosition": {
"Line": 9,
"Column": 57
},
"EndPosition": {
"Line": 12,
"Column": 83
}
}
]
}
]
}
]
}
```
### Check 5
```json
{
"EvaluationResults": [
{
"EvalActionName": "s3:ListBucket",
"EvalResourceName": "arn:aws:s3:::mlp-clientdb-prod-backups-327082975128",
"EvalDecision": "implicitDeny",
"MatchedStatements": [],
"MissingContextValues": [],
"EvalDecisionDetails": {},
"ResourceSpecificResults": [
{
"EvalResourceName": "arn:aws:s3:::mlp-clientdb-prod-backups-327082975128",
"EvalResourceDecision": "implicitDeny"
}
]
}
]
}
```
### Check 6
```json
{
"EvaluationResults": [
{
"EvalActionName": "s3:GetObject",
"EvalResourceName": "arn:aws:s3:::mlp-clientdb-prod-backups-327082975128/anything",
"EvalDecision": "implicitDeny",
"MatchedStatements": [],
"MissingContextValues": [],
"EvalDecisionDetails": {},
"ResourceSpecificResults": [
{
"EvalResourceName": "arn:aws:s3:::mlp-clientdb-prod-backups-327082975128/anything",
"EvalResourceDecision": "implicitDeny"
}
]
}
]
}
```
### Check 7
```json
{
"EvaluationResults": [
{
"EvalActionName": "s3:DeleteBucket",
"EvalResourceName": "arn:aws:s3:::adr-smlcompany-site",
"EvalDecision": "implicitDeny",
"MatchedStatements": [],
"MissingContextValues": [],
"EvalDecisionDetails": {},
"ResourceSpecificResults": [
{
"EvalResourceName": "arn:aws:s3:::adr-smlcompany-site",
"EvalResourceDecision": "implicitDeny"
}
]
}
]
}
```
### Check 8
```json
{
"EvaluationResults": [
{
"EvalActionName": "s3:PutObject",
"EvalResourceName": "arn:aws:s3:::meshkinilaw.ca/anything",
"EvalDecision": "implicitDeny",
"MatchedStatements": [],
"MissingContextValues": [],
"EvalDecisionDetails": {},
"ResourceSpecificResults": [
{
"EvalResourceName": "arn:aws:s3:::meshkinilaw.ca/anything",
"EvalResourceDecision": "implicitDeny"
}
]
}
]
}
```
### Check 9
```json
{
"EvaluationResults": [
{
"EvalActionName": "iam:CreateUser",
"EvalResourceName": "*",
"EvalDecision": "implicitDeny",
"MatchedStatements": [],
"MissingContextValues": []
}
]
}
```
---
## What this does and does not establish
**Establishes.** The user exists with the creation date `AGENTS.md` §7 records; it holds one
inline policy and nothing else; the policy grants four actions on one bucket and
one distribution; the four intended actions are `allowed`; five representative
out-of-scope actions — including two against the client-database backup bucket —
are denied; the backup bucket carries no resource-based policy that could grant
around IAM; and one key exists that has never authenticated a request.
**Does not establish.** That the key works (it has never been used, and testing
it would mean putting a real object in the bucket). That Gitea holds it —
`AGENTS.md` §7 records **`GITEA ACTIONS SECRETS: UNSET`**, and Q23 is open on whether a runner
exists at all. That the policy is sufficient for a deploy in practice: the
`s3:AbortMultipartUpload` omission is covered by asset sizes rather than by a
lifecycle rule, and `docs/06-deployment.md` records that with a revisit trigger.
**Not in scope of this file, and deliberately so.** The secret access key. It
must never reach the repository — D3, and `AGENTS.md` §10 on the jointly administered Gitea
instance, where an instance administrator can generally reach repository secrets
or register a runner that receives them.
+90 -80
View File
@@ -16,31 +16,28 @@
* 1. `LegalService` — NEVER. docs/04: schema.org defines it as a business * 1. `LegalService` — NEVER. docs/04: schema.org defines it as a business
* providing legal advice and *representation*, which asserts in * providing legal advice and *representation*, which asserts in
* machine-readable form exactly what D13 bars. `ProfessionalService`. * machine-readable form exactly what D13 bars. `ProfessionalService`.
* 2. `worksFor` — **STILL OMITTED, and the reason has changed.** The original * 2. `worksFor` — **OMITTED, and Q49(b) declined it deliberately on
* ground was "either names the boutique (D16) or misstates the employer". * 2026-08-28.** Two grounds, either sufficient. §4 rows "Operator of SML
* Q47 (2026-08-28) answers the **D16 half**: `jobTitle` now describes this * Company Ltd **alongside** the practice"; "the entity the practice
* practice, so naming SML Company Ltd would not name the boutique. It was * **operates through**" is a different structural relation with no row.
* set on that basis for one pass and `adversarial-reviewer` found why that * And `ProfessionalService.provider` is this Person, so `provider →
* is not sufficient — **the second half was never addressed:** * Person → worksFor → SML` asserts **transitively** a same-entity claim
* `ProfessionalService.provider` is this Person, so `provider → Person → * that `src/pages/about.astro` deliberately removed from visible prose as
* worksFor → SML` asserts transitively a same-entity claim **no §4 row * *"a corporate-structure claim"* — scoping the value to a bare name does
* makes** — and one `src/pages/about.astro` DELETED from visible prose as * not reach that. See `PRACTICE_JOB_TITLE` in `site.ts`.
* *"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 * 3. `priceRange` — omitted until `/fees/` exists (build step 9). docs/04
* gates it on that page being real. * gates it on that page being real.
* *
* AND Q.Arb IS NOT IN `hasCredential`. It commenced August 2026 and is not * 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. * held. Q.Med is. That asymmetry is the whole point of the property.
*/ */
import { CONTACT, CREDENTIALS, PRACTICE_JOB_TITLE, SITE } from './site'; import {
CONTACT,
CREDENTIALS,
MEMBERSHIP_ORGS,
PRACTICE_JOB_TITLE,
SITE,
} from './site';
/** Stable node ids, so pages cross-reference rather than duplicate. */ /** Stable node ids, so pages cross-reference rather than duplicate. */
export const PERSON_ID = `${SITE.url}/about/#person`; export const PERSON_ID = `${SITE.url}/about/#person`;
@@ -73,19 +70,19 @@ export const SERVICE_ID = `${SITE.url}/#practice`;
* implication as hard as assertion, and a crawler summary is a place where an * implication as hard as assertion, and a crawler summary is a place where an
* implication travels unedited. * implication travels unedited.
*/ */
export function personNode(imageUrl?: string) { export function personNode(
imageUrl?: string,
opts: { memberships?: boolean } = {},
) {
return { return {
'@type': 'Person', '@type': 'Person',
'@id': PERSON_ID, '@id': PERSON_ID,
name: SITE.name, name: SITE.name,
url: `${SITE.url}/about/`, url: `${SITE.url}/about/`,
/* Q47: PRACTICE_JOB_TITLE, not ROLE.title — the boutique role stays in /* PRACTICE_JOB_TITLE, not ROLE.title (Q47), and §4 now rows the value:
visible copy and out of this graph, which is what the ruling was for. "Practised role — Mediator" [verified 2026-08-28 — Pouya, Q49]. Do not
The VALUE is the narrowest form §4 rows; it shipped for one pass as widen it to include arbitration — see the constant in site.ts. No
"Mediator and Commercial Arbitrator" and both review agents struck it as `worksFor` beside it: Q49(b) declined the row. */
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, jobTitle: PRACTICE_JOB_TITLE,
description: description:
'Mediator in Toronto, accepting commercial arbitration appointments. ' + 'Mediator in Toronto, accepting commercial arbitration appointments. ' +
@@ -106,6 +103,36 @@ export function personNode(imageUrl?: string) {
}, },
sameAs: [CONTACT.linkedin], sameAs: [CONTACT.linkedin],
email: `mailto:${CONTACT.email}`, email: `mailto:${CONTACT.email}`,
/* `memberOf` — OPT-IN, AND ONLY `/about/` OPTS IN. Q53, ruled by Pouya
2026-08-28: *"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 reason he gave is page-specific**, so the
field is too: /about/ shows the list, `/` does not.
⚠️ DO NOT DELETE THE `opts` PARAMETER AS REDUNDANT. It looks redundant —
both pages serve the same `@id`, so a consumer that fetches both merges
them and gets `memberOf` either way. It was deleted on exactly that
reasoning and had to be put back: the argument is about what a *consumer*
can derive, and the scoping is about what a *page* asserts on its own.
Six records in this repository state the `/about/` scoping; the deletion
made all six false at once, silently.
THE NAMES COME FROM `MEMBERSHIP_ORGS`, NOT FROM THE DISPLAY LIST, and the
two differ on three of four lines — see that constant in site.ts, which
carries the reason and the D13 exclusions that govern both. Only their
LENGTH is asserted at compile time. **Content parity is manual.**
R10 fires on an event, not a date: re-confirm before any cutover or major
republish, and re-stamp §4. That covers this field as well as the visible
list. */
...(opts.memberships
? {
memberOf: MEMBERSHIP_ORGS.map((name) => ({
'@type': 'Organization',
name,
})),
}
: {}),
...(imageUrl ? { image: imageUrl } : {}), ...(imageUrl ? { image: imageUrl } : {}),
}; };
} }
@@ -113,6 +140,36 @@ export function personNode(imageUrl?: string) {
/** /**
* `ProfessionalService` for the home page, with the Person as `provider`. * `ProfessionalService` for the home page, with the Person as `provider`.
* *
* THE MASTHEAD IS TWO FIELDS HERE, NOT ONE STRING — Q50, ruled by Pouya
* 2026-08-28: *"`ProfessionalService.name` takes the ratified masthead string.
* Q33 reaches it; one claim should not have two forms."*
*
* The masthead is not one string, and schema.org has a field for each half, so
* `name` + `slogan` is the mapping rather than a concatenation. Both read the
* constants, which is what kills the variant.
*
* ⚠️ AND ON `/` — THE ONLY PAGE THIS NODE SHIPS ON — THE MASTHEAD DOES NOT
* RENDER THE TAGLINE AT ALL. `SiteHeader.astro` gates it on `!isHome`,
* deliberately, so the header does not repeat the hero. `SITE.tagline` is
* visible on `/` as the **hero eyebrow** instead. That is the page-visible
* counterpart `slogan` mirrors; do not justify this mapping by the masthead.
*
* ⚠️ DO NOT PUT THE TAGLINE BACK INTO `name`. Two independent reasons.
* (1) On a `LocalBusiness`-family type `name` means the business's name; a name
* plus a service list plus a city is the name-stuffing pattern search engines
* discard a rich result for, and `areaServed` already carries Toronto and
* Ontario. (2) It put an **unscoped "Arbitration"** into the node's most
* prominent field — Q39's struck universal reappearing in machine-readable
* form.
*
* **Reason (2) is mitigated, not discharged**, and that is stated rather than
* glossed: the word is still in `slogan`. What makes it acceptable there is
* that the identical unscoped string already ships in `<title>`, `og:title`,
* `twitter:title` and the hero eyebrow, all ratified under Q33 — so excluding
* it from one name-like field alone would be incoherent. `serviceType` stays
* scoped because it **enumerates services**; a slogan and a title are names.
* §9 Q50 records this as a deviation awaiting Pouya's line.
*
* `serviceType` lists what §4 Offerings actually records as offered now — * `serviceType` lists what §4 Offerings actually records as offered now —
* mediation, arbitration, med-arb. **Arbitration is scoped to commercial** * mediation, arbitration, med-arb. **Arbitration is scoped to commercial**
* (Q39, 2026-08-27): family arbitration in Ontario carries prescribed training * (Q39, 2026-08-27): family arbitration in Ontario carries prescribed training
@@ -128,7 +185,8 @@ export function professionalServiceNode(imageUrl?: string) {
return { return {
'@type': 'ProfessionalService', '@type': 'ProfessionalService',
'@id': SERVICE_ID, '@id': SERVICE_ID,
name: `${SITE.name} — Mediation & Arbitration`, name: SITE.name,
slogan: SITE.tagline,
url: `${SITE.url}/`, url: `${SITE.url}/`,
description: description:
'Commercial mediation and arbitration for construction, technology, ' + 'Commercial mediation and arbitration for construction, technology, ' +
@@ -182,61 +240,13 @@ export function homeGraph(imageUrl?: string) {
* no visible breadcrumb, and the header nav marks it as current — so * no visible breadcrumb, and the header nav marks it as current — so
* emitting one would assert a navigation structure the page does not show. * emitting one would assert a navigation structure the page does not show.
* Breadcrumbs begin at the two-level pages: `/practice/<area>/`, `/insights/<slug>/`. * Breadcrumbs begin at the two-level pages: `/practice/<area>/`, `/insights/<slug>/`.
* 3. `memberOf` — **STILL WITHHELD, AND NOW ON NARROWER GROUNDS THAN THE * 3. `memberOf` — **EMITTED HERE, and only here.** Q53, 2026-08-28. It is
* PAGE.** Q44 closed 2026-08-28 and `/about/` **does** publish all four * opted into by this function and by no other; `personNode` carries the
* visibly, so the earlier reasoning ("this field is not a stricter standard * constraint and the reason.
* 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:
*
* **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.
*
* **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) { export function aboutGraph(imageUrl?: string) {
return { return {
'@context': 'https://schema.org', '@context': 'https://schema.org',
'@graph': [personNode(imageUrl)], '@graph': [personNode(imageUrl, { memberships: true })],
}; };
} }
+82 -102
View File
@@ -127,6 +127,38 @@ export const CREDENTIALS = {
*/ */
export const BOUTIQUE = 'a Toronto litigation and ADR boutique' as const; export const BOUTIQUE = 'a Toronto litigation and ADR boutique' as const;
/**
* The GRAPH form of the memberships — `Person.memberOf` in `src/data/schema.ts`.
*
* ⚠️ SEPARATE FROM `CREDENTIALS.memberships` ON PURPOSE, AND THEY DIFFER ON
* THREE OF FOUR LINES: the display list carries the acronyms (`ADR Institute of
* Canada (ADRIC)`) and the OBA's three sections; this list names bare
* organisations. Only `Canadian Tax Foundation` is identical.
*
* **Why bare names:** `memberOf` points at an *organisation*, and nothing is
* named "Ontario Bar Association — Construction & Infrastructure, ADR, and
* Civil Litigation sections". A triple naming that cannot reconcile against the
* real entity gives up most of what the field buys. This is a **narrowing** of
* §4's row — §4 names the OBA as the body and then qualifies the sections — and
* not an inference beyond it. Do not read it the other way and "restore" the
* qualifiers into a name.
*
* ⚠️ THE SAME TWO EXCLUSIONS GOVERN THIS ARRAY, repeated here because this is
* where an addition would land: **NOT OCNI** (§4: not current, do not publish)
* and **NOT the Law Society**. Q51 is the distinction — the Law Society is the
* **regulator**, so membership is licensure, which D13 bars; the OBA is a
* **voluntary association**, which admits members it does not license.
*
* BOTH ARRAYS ARE THE SAME §4 ROW SEEN TWICE, so their lengths are asserted at
* compile time — see `_MembershipParity` below. **Their contents are not.**
*/
export const MEMBERSHIP_ORGS = [
'ADR Institute of Canada',
'ADR Institute of Ontario',
'Ontario Bar Association',
'Canadian Tax Foundation',
] as const;
/** /**
* The boutique role and the litigation line — the two highest-risk strings on * The boutique role and the litigation line — the two highest-risk strings on
* the site, so they live here rather than being typed into a page. * the site, so they live here rather than being typed into a page.
@@ -138,20 +170,14 @@ export const BOUTIQUE = 'a Toronto litigation and ADR boutique' as const;
*/ */
export const ROLE = { export const ROLE = {
/** /**
* §4 verbatim, and it is the VISIBLE role only. * §4 verbatim, and it is the VISIBLE role only. Rendered as
* "I am {ROLE.title} at {ROLE.at}", always paired with BOUTIQUE (D16).
* *
* NO LONGER THE JSON-LD `jobTitle` — Q47, ruled 2026-08-28. This string was * NEVER the JSON-LD `jobTitle` — that takes PRACTICE_JOB_TITLE below (Q47).
* both the visible role line and the Person node's `jobTitle`, which put * §4's row is one fact with two halves and visible copy always pairs them;
* "Director of Firm Operations" on a node whose `url` is this ADR practice's * a graph field carrying only "Director of Firm Operations", on a node whose
* `/about/` — so a consumer could attach the boutique title to this entity. * `url` is this practice's `/about/`, lets a consumer attach the boutique
* Pouya's ruling splits them: the graph carries PRACTICE_JOB_TITLE below, * title to this entity.
* 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] title: 'Director of Firm Operations', // [verified 2026-08-25 — strategy brief §I]
/** Always rendered with BOUTIQUE, never with a firm name (D16). */ /** Always rendered with BOUTIQUE, never with a firm name (D16). */
@@ -179,102 +205,37 @@ export const ROLE = {
} as const; } as const;
/** /**
* The Person node's `jobTitle` — Q47, ruled by Pouya 2026-08-28. * The Person node's `jobTitle`. §4 Verified: **Practised role — "Mediator"**
* `[verified 2026-08-28 — Pouya, Q49]`, supported by the Q.Med row and by
* "Has completed multiple sole mediations".
* *
* NOT `ROLE.title`, and that separation IS the ruling. §4's row is one fact with * NOT `ROLE.title`, and the separation is Q47's ruling: this field describes
* two halves — *"Director of Firm Operations, Toronto litigation and ADR * *this practice*, the boutique role stays in visible copy, and D16 keeps the
* boutique"* — and visible copy always pairs them. The JSON-LD emitted only the * boutique unnamed either way.
* 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 * ⚠️ DO NOT WIDEN IT TO INCLUDE ARBITRATION. "Arbitrator" as a practised role
* describes this practice, not the boutique role, which D16 keeps unnamed"* — * has **no §4 row** — the register verifies completed sole mediations, and for
* and that half holds: this constant names no boutique. * arbitration only that appointments are *accepted*. `jobTitle` is the most
* * role-asserting field in the vocabulary and consumers render it beside `name`,
* **THE `worksFor` HALF OF THE RULING IS NOT IMPLEMENTED — Q49(b).** This * so "Mediator and Commercial Arbitrator" there invites the reader to supply a
* paragraph said *"`worksFor` becomes SML Company Ltd — verified, federally * track record for both halves. The arbitration **offering** is carried by
* incorporated, and the entity the practice operates through. Both are set"*. * `description` and `serviceType`, which is where an offering belongs.
* 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; export const PRACTICE_JOB_TITLE = 'Mediator' as const;
/* `PRACTICE_ENTITY` LIVED HERE FOR ONE PASS AND IS DELETED WITH `worksFor`. /* NO `PRACTICE_ENTITY`, AND NO `Person.worksFor` — Q49(b), declined 2026-08-28.
* *
* It existed only to populate `Person.worksFor`, which is withheld pending a §4 * §4 rows "Operator of SML Company Ltd **alongside** the practice". "The entity
* row (Q49). `adversarial-reviewer` found the defect that decided it, and it is * the practice **operates through**" is a different structural relation and has
* one the "name only, nothing else" scoping did **not** address: the * no row. Two further reasons it must not come back on a tidy-up:
* 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: * - `ProfessionalService.provider` IS this Person, so
* - §4's row says "Operator of SML Company Ltd **alongside** the practice". * `provider → Person → worksFor SML` asserts **transitively** that the
* Q47's ruling says "the entity the practice **operates through**". Those are * practice and the company are the same entity the claim `about.astro`
* different structural relations and the second has no §4 row. * deliberately removed from visible prose as "a corporate-structure claim".
* - `/about/` already **removed** a sentence of this exact class from visible * Scoping the value to a bare name does not reach this.
* copy — see about.astro: *"the company through which the engineering work is * - `SITE.entity` already holds the string for the footer. A second constant
* done" — a corporate-structure claim*. Publishing it machine-readably while * for the same name is the drift this file keeps paying for.
* 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.
*/ */
/** /**
@@ -597,6 +558,25 @@ type _SlugsWithoutAnArea = Exclude<
>; >;
export type _SlugCoverage = _AssertNever<_SlugsWithoutAnArea>; export type _SlugCoverage = _AssertNever<_SlugsWithoutAnArea>;
/**
* The two membership arrays must stay the same LENGTH — contents are not
* checked and cannot be. They are two views of ONE §4 row, and the failure mode
* is adding a membership to the page and not to the graph, which is otherwise
* silent.
*
* ⚠️ IT FAILS `npm run check`, NOT `npm run build` — measured. Both the deploy
* workflow and `scripts/deploy-local.sh` run `check` first, so the deploy path
* is covered; a bare `astro build` is not. And it depends on both arrays keeping
* `as const`: without it `length` widens to `number`, `number extends number` is
* true, and this assertion passes forever while checking nothing.
*/
type _AssertTrue<T extends true> = T;
export type _MembershipParity = _AssertTrue<
(typeof CREDENTIALS.memberships)['length'] extends (typeof MEMBERSHIP_ORGS)['length']
? true
: false
>;
/** /**
* The five process steps. **HERE, NOT IN THE PAGE**, for the reason written * The five process steps. **HERE, NOT IN THE PAGE**, for the reason written
* against PRACTICE_AREAS above and applied by `adversarial-reviewer` 2026-08-27: * against PRACTICE_AREAS above and applied by `adversarial-reviewer` 2026-08-27:
+6 -2
View File
@@ -315,8 +315,12 @@ const ARC = [
* group two entries above. An unused abbreviation is noise, so it is omitted; * group two entries above. An unused abbreviation is noise, so it is omitted;
* one word to reverse if he wants it. * one word to reverse if he wants it.
* *
* `memberOf` IS STILL WITHHELD FROM THE JSON-LD — see `src/data/schema.ts`. * `memberOf` IS EMITTED FROM THIS PAGE'S JSON-LD (Q53), AND FROM A DIFFERENT
* That is a narrower decision than this one and it is explained there. * ARRAY. `src/data/schema.ts` builds it from `MEMBERSHIP_ORGS`, not from the
* `CREDENTIALS.memberships` this group renders: the graph names the bodies, the
* page also names the OBA's three sections. **Only their length is enforced, by
* a compile-time assertion — content parity is manual.** So editing this list
* means editing that one. They are the same §4 row seen twice.
*/ */
const CREDENTIAL_GROUPS = [ const CREDENTIAL_GROUPS = [
{ title: 'Designations', items: CREDENTIALS.designations }, { title: 'Designations', items: CREDENTIALS.designations },
+1 -1
View File
@@ -85,7 +85,7 @@ const graph = homeGraph(new URL(ldImage.src, Astro.site).href);
--- ---
<BaseLayout <BaseLayout
title={`${SITE.name} · Mediation & Arbitration · Toronto`} title={`${SITE.name} · ${SITE.tagline}`}
description="Commercial mediation and arbitration in Toronto. Construction, technology, energy, insurance and shareholder disputes, read as contracts and as engineering." description="Commercial mediation and arbitration in Toronto. Construction, technology, energy, insurance and shareholder disputes, read as contracts and as engineering."
imageAlt={PORTRAIT.alt} imageAlt={PORTRAIT.alt}
jsonLd={graph} jsonLd={graph}