feat: build step 3 — /about/, minus its memberships; close Q40–Q43
Build and deploy / build-and-deploy (push) Failing after 6s

Applies Pouya's rulings on Q42, Q41(a)(b)(c), Q43 and Q40, then builds
`/about/` — six of docs/01's seven items.

`/about/` ships WITHOUT a memberships group. R10 is a prohibition on
shipping a page that lists memberships before they are re-confirmed; the
re-confirmation is a fact only Pouya holds and was not obtained. The
first version published all four and disclosed the gap in five places
instead; both review agents rejected that. Q44 carries the question.

Rulings:
- Q42 — ENE, dispute-system design and pre-dispute technical advisory
  rowed; settlement counsel struck as a partisan role. The strike
  exposed a hole in the offering test, which now states the prior
  question it was missing.
- Q41(a) — Q37 reaches prose, and prose is held to a higher bar. The
  sentence is now one constant, ASYMMETRY_LINE, because two hand-typed
  copies had already diverged inside one session.
- Q41(b) — not restored; the implication turned out to be in three
  places, two of which survived the sweep that closed it.
- Q41(c) — verified against the LAT's own Rules and extracted into
  docs/reference/lat-case-conference.md. Rule 2.4 makes "Pre-Hearing
  Conference" the Tribunal's own term for a case conference; the Rules
  contain zero occurrences of `mediat` in 66,593 characters.
- Q43 — the timings are service commitments; PROCESS_FRAMING renders
  adjacent to them, not in a lede above.
- Q40 — bundled to step 7 as R15, blocking cutover.

Four review passes, 43 findings, nine of them defects in their own
predecessors' fixes. The worst was mine: the false universal Q39 struck
reached a public page. Also fixed a portrait ladder that upscaled 1.93x
at 1024/DPR2 on BOTH pages — the shipped home page included — because
its 960 ceiling was derived from the layout range where the image is
narrowest.

Verified: check/lint/build/audit clean; 0 upscaling across 11 device
profiles; 0 overflow and 0 over-wide elements at 13 widths; 0 contrast
failures across 127 and 88 painted pairs; 0 print failures against white
paper; reveal 0 hidden under reduced-motion and print; zero JavaScript.
Lighthouse NOT RUN — tool unavailable until step 7 (R11). HTML validator
NOT RUN.

Opens Q44 (memberships), Q45 (PDF bio), Q46 (offering-test gating; the
glossary standard), Q47 (jobTitle without worksFor). Adds R15.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0148NztQskLKKApP5SzAA78e
This commit is contained in:
Pouya Lajevardi
2026-08-28 12:10:41 -04:00
co-authored by Claude Opus 5
parent 165d259f5c
commit c576b9a85f
17 changed files with 2603 additions and 147 deletions
+11 -2
View File
@@ -66,8 +66,17 @@ goes stale where nobody re-reads it.
**OCNI is not current** — flag it. **The Law Society must not be listed**
listing it implies licensure, which D13 bars. Flag any addition of either,
however well-intentioned. Memberships renew yearly (§12 R10), so a §4 row can be
verified and still be out of date; check the stamp, not just the presence.
however well-intentioned.
**The OBA sections and the Canadian Tax Foundation renew yearly (§12 R10)** — and
read that scope, because this sentence carried the widened form *"Memberships
renew yearly"* until 2026-08-28. §4 records the period for **those four lines
only**; it says nothing about ADRIC's or ADRIO's. **You found this yourself**, in
your own brief, on the pass where you found the same widening in three source
files — the third stale claim located inside this file, which is why the
instruction below is the one that matters: a §4 row can be verified and still be
out of date, so **read the §4 row at audit time and check the stamp**, never this
gloss.
**Testimonials, endorsements, third-party quotes.** None exist. Any is a
fabrication.
+466 -8
View File
@@ -290,8 +290,12 @@ appointments now**, and that — his acceptance — is what the rows below recor
> everything by saying nothing.
**Scope: an offering is a PROCESS the practice conducts** — mediation,
arbitration, med-arb, early neutral evaluation, settlement counsel,
dispute-system design, pre-dispute technical advisory. Each needs its own row.
arbitration, med-arb, early neutral evaluation, dispute-system design,
pre-dispute technical advisory. Each needs its own row.
*`settlement counsel` was in this enumeration until 2026-08-27 and is removed
from it, not merely left unrowed: it is **not a process this practice conducts**
at all. See the struck row in the Offerings table — Q42.*
**A subject-matter area is NOT an offering.** *Construction*, *technology*,
*energy*, *insurance*, *shareholder*, *cross-cultural* are the contexts in which
@@ -341,6 +345,10 @@ never be read as one:
| **Arbitration — co-arbitration** | `[verified 2026-08-26 — Pouya, Q33/Q36]`. Offered **now**. This closes Q36, which had flagged the claim as asserted in three specs and resting on no §4 row — the row is here |
| **Med-Arb** — mediation-arbitration | `[verified 2026-08-27 — Pouya, Q35]`. Offered **now**. Both halves are live: Q.Med is held, and arbitration appointments are accepted (rows above). Ungated by the same reasoning as arbitration. This closes the "Still unanswered" note that used to sit below this table, and it is why `/med-arb/` may stay in the footer sitemap |
| ~~**Family arbitration** under the *Family Law Act*~~ | **NOT OFFERED — a scope exclusion, not a gating problem** `[verified 2026-08-27 — Pouya, Q39]`. Pouya has confirmed he does not do family arbitration. It is therefore out of scope by his choice, and the prescribed-training question never arises for this practice. Recorded because the register reasoned from a false universal for one day and must not do so again — see the box above and `docs/reference/ontario-family-arbitration-training.md`. **`Shareholder & Family Business` does not touch this:** it means commercial disputes among family shareholders — shareholder and partnership disputes, co-founder breakdowns, business succession — and its page must say plainly that family law matters are not accepted |
| **Early neutral evaluation (ENE)** | ⚠️ **COMPETENCE ANSWERED; GATING NOT ANSWERED — NOT YET PUBLISHABLE.** Question 2: *"A neutral assessment of merits sits inside a Q.Med's competence"* `[Pouya's stated basis 2026-08-27, Q42]`. Question 1 — **is the activity gated?** — is `[unestablished]`. An earlier version of this row read *"Ungated on the same footing as mediation — no designation is required to give a non-binding evaluation"* under a `[verified — Pouya]` stamp. That is **a proposition of Ontario law inside a stamp §4 says cannot carry one**, and it was the register doing exactly what the box above warns against, one paragraph after warning against it. Struck by `claims-auditor` on two consecutive passes. **ENE is also the offering nearest the gated side of the boundary** — a neutral assessment of the *merits*, delivered to parties — so it is the one that most needs a source rather than an assertion. Q46. Priced hourly in `docs/07-fees.md`, which is a fee-page question, not a publication licence |
| **Dispute-system design** | ⚠️ **COMPETENCE ANSWERED; GATING NOT ANSWERED — NOT YET PUBLISHABLE.** Question 2: *"Consulting, no appointment, no neutrality question"* `[Pouya's stated basis 2026-08-27, Q42]`. **That sentence answers neutrality, not gating**, and an earlier version of this row presented it as though it answered both. Question 1 is `[unestablished]` and is not his to answer. Q46 |
| **Pre-dispute technical advisory** | ⚠️ **COMPETENCE ANSWERED; GATING NOT ANSWERED — NOT YET PUBLISHABLE.** Question 2, in three words: *"It is the moat"* `[Pouya's stated basis 2026-08-27, Q42]`. Question 1 is `[unestablished]`. Q46. **Caution that belongs with the row regardless:** advisory work for one organisation is the one item in this table that can create a conflict against a later appointment in the same matter. That is practice management rather than a publication gate — but no copy may imply it is free of that tension |
| ~~**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 |
**How the arbitration page must read** (`docs/01` §`/arbitration/`, step 4):
@@ -378,6 +386,57 @@ above.
> most explicitly (*"Write it as a genuine position, not a claim of existing
> volume"*).
### The offering test, applied — the Q42 worked example (2026-08-27)
**Kept because it is the only place in this file where the test is run on four
candidates at once and one of them fails.** Pouya's instruction was literally
*"apply the offering test"*, and the outcome was 31.
| Candidate | Q1 — is the activity gated? *(the register's, with a source)* | Q2 — competence? *(his)* | Outcome |
|---|---|---|---|
| Early neutral evaluation | **`[unestablished]`** — no source. Q46 | *"sits inside a Q.Med's competence"* | **Not publishable yet** |
| Dispute-system design | **`[unestablished]`** — no source. Q46 | *"Consulting, no appointment, no neutrality question"* | **Not publishable yet** |
| Pre-dispute technical advisory | **`[unestablished]`** — no source. Q46 | *"It is the moat"* | **Not publishable yet** |
| Settlement counsel | **Never reached** | — | **STRUCK** |
**THE Q1 COLUMN WAS FILLED IN WITH HIS ANSWERS AND HAS BEEN EMPTIED.** The first
version of this table read *"No. A non-binding neutral assessment is not a
restricted activity"* and *"No. Consulting, no appointment, no neutrality
question"* — the second of which does not even address gating. §4 is explicit:
*"**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 jurisdiction was named for any of the three. `claims-auditor` caught this
substitution on 2026-08-26 in one place and again on 2026-08-28 in this table —
**the same defect, in the paragraph added to explain the defect.**
**The reason settlement counsel fails is the finding.** It did not fail question
1 and it did not fail question 2. It failed a prior question the test does not
ask: **is this a neutral's role at all?** Settlement counsel acts *for* a party.
Run mechanically, the two-question test would have passed it — negotiation on a
party's behalf is not obviously gated, and Pouya is competent to negotiate — and
it would have put a partisan role on a site whose central claim is neutrality.
So the prior question is: **is this a role in which the practice is partisan
between the parties to a dispute?** If it is, the answer is no before the test
starts.
**THAT IS THE RULE, AND IT IS STATED THIS WAY BECAUSE THE FIRST VERSION HAD AN
UNGATED EXCEPTION IN IT.** It read *"the offering test presumes the role is a
neutral's… The one exception in this table is the pre-dispute technical advisory
row, which is also not a neutral role."* `claims-auditor`: a rule and its ad-hoc
exception in the same paragraph, in the section written to prevent *"a category
that authorises everything by saying nothing"* — and the exception was
self-contradictory, because the *dispute-system design* row two lines above also
describes a non-neutral role (*"Consulting, no appointment, no neutrality
question"*). One of the two statements had to be wrong.
Restated as above, there is no exception: dispute-system design and pre-dispute
technical advisory both pass, because neither involves a party to be partisan
between — one advises an organisation about its future disputes, the other
precedes any dispute. Settlement counsel fails, because acting *for* a party in
a negotiation is partisanship between parties by definition. **The distinction is
the party, not the label.**
**Applied, 2026-08-27 — Q35 CLOSED.** `Energy, Grid & Regulatory`,
`Shareholder & Family Business`, and the other four labels **pass condition 1**
on Pouya's answer; condition 2 is each page's job at build step 5. `Med-Arb`
@@ -562,10 +621,14 @@ Nothing below can be invented. Each needs an answer from Pouya.
| **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-orig~~ | **Does the arbitration offering extend to FAMILY arbitration, and is that activity gated?** Raised by `claims-auditor` 2026-08-26 as a counter-example from inside this repo, and it is a good one. §4 Offerings rests on the proposition that arbitral appointment in Ontario is not gated behind a designation. The site ships a **`Shareholder & Family Business`** practice area — and **family** arbitration in Ontario is understood to be one of the places where arbitrator qualification *is* prescribed by statute and regulation. If so, the offering test's own boundary applies: where an activity is gated, the question is **permission**, and permission is not established. **This record does not resolve it** — Claude Code will not assert a proposition of Ontario law, and neither may a self-report. What is needed: (a) does the practice-area page contemplate family-law arbitration at all, or only shareholder, partnership and family-*business* disputes, which is a different thing; and (b) if it does, the gating question needs a checkable source in the repo, per R14. **Interim:** §4's arbitration rows are scoped to **commercial** arbitration and the universal has been removed from the reasoning. Nothing ships that turns on it | The `Shareholder & Family Business` page (step 5); `/arbitration/` (step 4) |
| **Q40** | **All nineteen pages will share ONE Open Graph image, and it is a portrait crop.** `docs/04-seo-spec.md` specifies OG images *"generated at build with `satori` or `astro-og-canvas`... One template: display headline on cream, infinity mark, designation line. Never a screenshot."* What ships is `src/assets/og-portrait.jpg`, the 1200×630 crop Pouya supplied under Q6 — not a screenshot, so the prohibition is not breached, but not the generated template either. The consequence is specific: `docs/04` requires a **unique** title and description per page and every link preview will nonetheless look identical, which is the surface a general counsel actually sees when a colleague pastes the URL into Teams or Slack. **Two decisions, neither an implementer's:** whether to build the generator at all (it adds a dependency and an `npm audit` surface, against R11), and what the card looks like (brand). **Interim:** the portrait crop ships on `/` and is fine on its own terms. Raised by Claude Code, 2026-08-27 | Nothing today. Sharpest once several pages exist — steps 35 |
| **Q41** | **Three copy questions the step-2 claims audit escalated rather than let an implementer settle.** All three were changed to a defensible interim form so `/` could ship; each interim is marked in the source with this question number. **(a) Does Q37's reasoning extend to PROSE, or is it scoped to the credential label?** The approach section opened *"Law and engineering are not blended here"* — the exact parallel Pouya struck one day earlier, relocated from the label into body copy and strengthened by attributing both halves to him personally. `docs/01` §`/` item 3 and `docs/03` §Home both specify the section as *"law and engineering converging on the same dispute"*, so the framing is his; only the construction carrying the implication was changed (to *"what the documents say, and what the engineering says"*). Extend Q37, or scope it to the label and say so. **(b) May the comparative be restored?** *"facts most neutrals take on faith"* is `docs/03`'s core positioning statement and is therefore approved copy — but it is an assertion about a population of third parties, `docs/03`'s own checklist requires *"any comparative claim is factual and verifiable"*, and §4 has no row for it. Interim: *"the documents rather than the pleadings"*, which says the same thing about the work without saying anything about other neutrals. **(c) What does `LAT pre-hearing mediation` mean as an offering?** `docs/01` §`/practice/insurance/` lists that phrase as a **search intent**; as a service blurb it reads as conducting mediation inside the LAT's own statutory process, which is not what a privately retained neutral is appointed to do. Interim: *"private mediation of matters before the LAT"*. Confirm the intent before the page ships. Raised by `claims-auditor`, 2026-08-27 | (a) and (b): `/` is live with the interim wording — his ratification or reversal. (c): `/practice/insurance/` at step 5 |
| **Q42** | **The four "also offered" processes have no §4 Offerings row, and `/practice/` is specified to offer them.** `docs/01` §`/practice/` calls that page *"the natural home for the 'also offered' strip: early neutral evaluation, settlement counsel, dispute-system design, and pre-dispute technical advisory"*, and `FEES.hourly` in `src/data/site.ts` prices them at $500/h. **None has a row**, and §4 is explicit: *"An offering may not be published until it has a row in 'Offered now'... or it is a category that authorises everything by saying nothing."* Found on `/` first: the practice-areas link read *"All six areas, and what else is offered"*, which asserted offerings beyond the six — the Med-Arb-in-the-footer defect in a new place. **Reworded to "All six practice areas" and nothing is claimed today.** Each of the four is a **process**, so each needs its own row and its own competence answer; they are ungated the same way mediation and arbitration are, so this is a competence call and his alone. Raised by `claims-auditor`, 2026-08-27 | The `/practice/` index and its "also offered" strip (step 5); `/fees/` prices them (step 9) |
| **Q43** | **The five process timings are published commitments with no §4 row.** `Day 0 · Days 17 · Days 721 · Days 2130 · Day 30 onward` come from `docs/01` §`/process/` and are now on a public page. They are **not** a forbidden statistic — no matter count, no settlement rate, no median time to award — but they are checkable, specific, and about how the practice runs, which is precisely the class §4 exists to gate. `docs/03` §Process requires *"five steps with real timing"* and warns against evasions, so softening them to "typical" is barred and inventing them was never on. **Interim:** the numbers are published exactly as `docs/01` specifies, and the editorial claim *"with real timing"* — which asserted a quality about them rather than stating them — is gone from `/`. What is wanted is either an Offerings-style row confirming them for publication, or his explicit sign-off. Raised by `claims-auditor`, 2026-08-27 | `/process/` (step 6) states them in full; `/` states them now |
| ~~Q40~~ | **RULED 2026-08-27 — and deliberately BUNDLED rather than shipped as a second interim.** Two kinds of card, not one. Pouya: *"A portrait is the **right** OG image for `/` and `/about/` — a face is the strongest social preview for a personal brand. It is the **wrong** one for nineteen pages, where a typed card carrying the page title would do the work. But do not build the generator now and do not leave 'portrait everywhere' as an untracked interim. **Ship it at step 7 alongside Insights, which needs per-article cards anyway — one build, one dependency, one review.**"* So the portrait is the **decided** card for `/` and `/about/`, not a placeholder; the generated typed card covers every other page and every article, built once at step 7 against a freshly checked pin (R11). Until then all pages share the portrait, and that interim **blocks cutover, not build step 3** — recorded on the cutover checklist in `docs/06` and tracked as **R15** with its removal trigger, on his instruction: *"Record the trigger so it cannot quietly become permanent."* `docs/04` amended. | Nothing until step 7. Then the generator, and cutover |
| ~~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) | — |
| ~~Q43~~ | **ANSWERED 2026-08-27 — and the ruling reversed the reasoning that had blocked it.** The interim shipped the five timings as bare numbers because `docs/03` §Process required them *"real"* rather than illustrative, which was read as **barring** the word "typical". Pouya: the timings are **service commitments, the same class as Q27's response time***"not facts about Pouya, so they need framing, not a Verified row. Present them as the TYPICAL shape of an engagement, explicitly not a guarantee: mediation timing depends on party and counsel availability, which he does not control. **Published as typical, they are honest and useful; published as commitments, the first matter that slips makes the page false.**"* So no §4 row, and **the numbers are unchanged** — softening them was never the fix. What ships is `PROCESS_FRAMING` in `src/data/site.ts`: *"This is the typical shape of an engagement, not a commitment. Timing depends on party and counsel availability, which I do not control."* **Not optional, and placed adjacent to the numbers rather than in a section lede above them** — a reader who scans the strip and skips the lede has read a commitment. `docs/03` §Process amended to record the override; `docs/01` §`/process/` requires the same rendering at step 6 | — |
| **Q44** | **R10 discharge — are all four memberships current TODAY, and in which month does each renew?** §4 verifies **ADRIC**, **ADRIO**, the three **OBA** sections (Construction & Infrastructure, ADR, Civil Litigation) and the **Canadian Tax Foundation** `[verified 2026-08-26 — Pouya]`, *for now*. **Only Claude Code can raise this; only Pouya can close it** — a two-day-old stamp is not a renewal receipt. **What §4 actually says about renewal, because an earlier version of this row said more:** the **OBA sections and the CTF** renew yearly. §4 records **nothing** about ADRIC's or ADRIO's renewal period, and this row asserted *"All renew yearly"* — a widened fact that had already propagated to `schema.ts`, `docs/06` and `/about/`'s own comment. Fixed in all four. **`/about/` DOES NOT PUBLISH THE MEMBERSHIPS.** An earlier version of this row said it did, and so did §12 R10, `docs/06` and `schema.ts` — four documents recording a page state that had been reversed and not swept, on the one credential class that has already lapsed once (OCNI). R10 is written as a **prohibition**, not a disclosure duty, so the group is withheld and `CREDENTIAL_GROUPS` carries a `TODO(pouya)` with this question. Designations, Education and Certifications ship. **Blocks the memberships block, not step 3.** Four yes/no answers and four renewal months closes it — and the months are what stop this recurring, because they turn R10 from a reminder into a date. Raised by Claude Code 2026-08-28; scope corrected the same day by `claims-auditor` | The Memberships group on `/about/`; `memberOf` in the Person JSON-LD; cutover |
| **Q45** | **The one-page PDF bio — generated, authored, or dropped?** `docs/01` §`/about/` item 7 lists it (brief §VIII: an asset for circulation with appointment proposals) and **it does not exist**; `/about/` therefore ships without a link to it, because a link to a missing file on the page an appointing body reads is worse than the absence. **Why it is a question and not a task:** it is a **credential document**, so every line traces to §4 exactly as a web page does — and it is circulated **detached from the site**, where no reviewer ever sees it again and no build can re-check it. That is the one artefact class this project's whole review apparatus cannot reach. Two decisions are his: (a) generated at build (a dependency and an `npm audit` surface, against R11) or authored once as a designed artefact; (b) whether it carries anything the site does not — a matter list, a fee summary, referees — each of which is a §4 question of its own. Raised by Claude Code, 2026-08-28 | Nothing on the site. It is a circulation asset, wanted before the first appointment proposal |
| **Q46** | **Two questions the offering test cannot close by itself, and one about the glossary.** **(a) Is early neutral evaluation gated in Ontario, and are dispute-system design and pre-dispute technical advisory?** Pouya answered question 2 (competence) for all three on 2026-08-27 and those answers stand. **Question 1 is the register's and it is `[unestablished]`** — §4: *"It needs a source that a reviewer can check, and it is answered per activity and per jurisdiction, never as a class."* No source exists in `docs/reference/` for any of the three (R14). It matters most for **ENE**, which is the offering nearest §4's NOT-NEGOTIABLE boundary: a neutral assessment of the **merits**, delivered to parties, sits closest to *"providing legal services"*, where the binding question is permission and the answer is not established. **Consequence today: none on the site** — the three appear only in comments — but the rows authorise `/practice/`'s "also offered" strip at step 5 and `docs/07-fees.md` prices them, so it blocks step 5, not step 3. Twice-flagged: `claims-auditor` found the register answering its own question 1 with the subject's words on 2026-08-26 and again on 2026-08-28, the second time inside the paragraph added to explain the first. **(b) May §11 Glossary be published as the source for DEFINITIONAL expansions** — what `Q.Med`, `Q.Arb`, `C.Med-Arb`, `POA`, `SABS`, `ADRIC` and `ADRIO` stand for? This is not a claim about Pouya; "he holds it" is the claim and that has a row. `/about/` currently publishes all four classes on this basis, and the alternative is to strip *"Provincial Offences Act"*, *"the ADR Institute of Canada and the ADR Institute of Ontario"* and `recognizedBy` from the JSON-LD as well — which serves no reader and reduces no risk. Sourcing them externally was tried and failed: `adric.ca/designations/` redirects to `/designations-cee/` and serves **zero** occurrences of `Q.Med`, `Qualified Mediator` or `Chartered Mediator` in 114,985 bytes. **This is the one place this session went against a review finding**, on a later finding that the standard was being applied inconsistently. Raised by Claude Code 2026-08-28 | (a) `/practice/` and its strip (step 5), `/fees/` (step 9). (b) `/about/`'s arc and the Person JSON-LD, live now |
| **Q47** | **`Person.jobTitle` is published without `worksFor`, and the two halves of one §4 row are separated in machine-readable form.** §4's row is *"Director of Firm Operations, **Toronto litigation and ADR boutique**"* — one row, one fact, two halves. Visible copy always pairs them (`/about/`: *"Director of Firm Operations at a Toronto litigation and ADR boutique"*). The JSON-LD emits `jobTitle: 'Director of Firm Operations'` with **`worksFor` deliberately omitted**, on a `Person` node whose `url` is this ADR practice's `/about/` — so a consumer may attach the title to **this** entity, which is not what the row says. **This is a structural bind, not an oversight:** `docs/04` instructs the omission and D16 bars naming the employer, so there is no value `worksFor` may take. The options are (i) drop `jobTitle` from the graph and let the visible copy carry the role, (ii) keep it and accept the implication, or (iii) get a §4 row for the half-claim. Flagged twice by `claims-auditor`, which declined to choose. Raised by Claude Code 2026-08-28 | Nothing visible. The Person node on `/` and `/about/`, live now |
| **Q38** | **A true vector master for the infinity mark.** The mark is a shaded ribbon — variable-width band, maroon flowing into champagne, twisting in three dimensions and passing over itself at the crossing. That is gradient-mesh artwork, and there is no honest way to express it as the flat vector paths `docs/02` assumes. An SVG **is** held — `src/assets/brand/sml-logo-source.svg` — and **it renders faithfully**: rasterised at 8333 px it reproduces the master exactly, at the same 1.566:1 `[verified 2026-08-26 — rendered and measured]`. *The characterisation has now moved twice and Pouya has settled it.* This row first called the file **"a raster in a vector wrapper"**; a later draft withdrew that as unfair. **The withdrawal went too far, and Pouya's ruling of 2026-08-27 restores the substance:** *"It renders faithfully because it IS the raster. Your first characterisation was accurate and the walk-back went too far."* Both things are true at once and the row must hold both — the file is a faithful rendering **and** it is faithful because seven base64 PNGs are carried inside it, which is why fidelity was never the question. **The Canva SVG does not close this question.** Pouya: *"Keep it committed, keep the AVIF render path. R13 stays open for a true vector master."* What rules it out is **payload and composition**: 257,278 bytes against **3,063 B** for the AVIF a Retina browser takes in the header — **84×** — plus **seven embedded base64 PNGs** and a 1,225-stop gradient mesh, so inlining it would breach `CLAUDE.md`'s rule against base64-inlining images. *Restated 2026-08-27, because the single number stopped covering the case:* build step 2 added a **232 px** call site (the home page's approach section, rendering at 225.5 px) beside the existing 64 px one, and at that size a DPR-2 device takes **14,555 B** and DPR-3 **22,639 B** — a ratio of ~11×, not 84×. `adversarial-reviewer` caught the three copies of the old figure going stale together, which is the SES-DKIM duplication in a new place. Both ladders are in `docs/reference/brand-assets.md`; **quote the size with the call site, never on its own.** Also worth knowing before someone reads it as a regression: the PNG fallback at 232 px runs **38,094 / 91,618 / 150,215 B**. Nothing that negotiates content types takes it — a DPR-3 device with neither AVIF nor WebP does not exist in practice — and the AVIF above is what real clients fetch. Accepted deliberately rather than capped, because capping it would blunt the mark on the high-DPI desktops that are the only place the 696 px variant is used at all. What is wanted is a master that is faithful **and** light. **Pouya is commissioning a proper vector master.** Until it lands, `InfinityMark.astro` renders an optimised raster and that is a **documented, temporary exception to `docs/02`'s inline-SVG rule** (R13 keeps it from becoming permanent). When the master arrives: replace the component's `<Picture>` with inline SVG, regenerate the favicons from it, and delete the exception from `docs/02` and this row. Raised by Claude Code 2026-08-26; scoped by Pouya the same day | Nothing — the mark renders correctly. This is fidelity and payload, not function |
| ~~Q32~~ | **ANSWERED 2026-08-26 — and the answer was that the reconstruction was WRONG.** Pouya rendered the committed path against the master (`SML Company Just Logo Transparent.png`, 3000×3000) and rejected it on three counts. Two reproduce from the path alone: **(a) TANGENT, NOT CROSSING** — all four cubic branches meet the origin at exactly 90°, so the loops are mutually tangent on a vertical line and at stroke-width 28 render as *two kissing circles*, the one thing an infinity mark must not be `[verified 2026-08-26 — tangent vectors computed per segment, independently reproduced]`. Both lobes are strictly confined to their own half-plane (x is monotone on every segment), so the signed crossing number is **0** — they cannot cross anywhere, not merely at the node. Worse at the size actually shipped: the two strokes stay fused into one mass wherever the centreline separation `y²/192` is under 28, i.e. across **61% of the mark's height** — at 2rem that is a 16.8px blob out of a 27.4px-tall mark. No stroke-width, viewBox or scale change can produce a crossing from this centreline; **(b) WRONG PROPORTION** — the master's ink bounding box is **2668 × 1704 = 1.5657:1** `[verified 2026-08-26 — measured]`, and **(c)** the master is a shaded ribbon where the trace was two flat uniform strokes. ***1.23:1 — RECONCILED, and it was a real measurement, not a slip.*** It is the bounding box of the path's **coordinates** rather than of the **curve**. The control points sit at y = ±160 while the curve only reaches ±120 — the standard 3/4 pull-in of a cubic — so a coordinate-hull box is 400 × 320 = 1.2500, and with stroke-width 28 applied on all four sides it is **428 × 348 = 1.2299**. Pouya's figure to four significant figures, from one method applied consistently `[verified 2026-08-26 — derived]`. **It is a trap rather than a slip:** because x is monotone on every segment, the control points give the *correct* width (±200) and a 33% inflated height, so the obvious sanity check — "does the width look right?" — passes. Any tool that reads a bbox from parsed coordinates lands here; `getBBox()` would have returned 400 × 240. **And the direction is inverted from how it read:** measured from the curve, the traced path is 6.4% *wider and flatter* than the master, not squatter. **Consequence worth keeping:** the declared viewBox 440:280 = 1.5714 is within **0.35%** of the master's 1.566, so re-tuning the layout to the true ratio was ~0.18px of work at the shipped 2rem — and **re-tuning to 1.23 would have actively broken it** — at any given width 1.2299 allocates 1.5657/1.2299 = **27% more height** than the mark occupies, so the header would have been rebuilt around a box a quarter too tall. The ratio was never sufficient grounds on its own; **(a) tangency is, and it is exact.** **The traced path is deleted, not kept as a fallback**, on Pouya's instruction: *a wrong mark that renders is worse than a missing one, because it stops looking wrong.* Now closed by Q38 for the vector master | — |
| ~~Q32-orig~~ | *(superseded — the original wording of this question is preserved in entry (v))* | `src/components/InfinityMark.astro` is built from geometry lifted verbatim from the deployed site's own loading-thumbnail SVG — the element it labels `smlMark`, fetched from `https://adr.smlcompany.ca/` on 2026-08-26. Path, both stroke widths (28 / 6) and the 0.7 inner opacity are the source's; the only change is folding a `translate(60 0)` into the coordinates. So it is SML's own artwork rather than a redrawing — but a loading placeholder is not necessarily the canonical file, and D7 says the mark carries over *unchanged*. If a master SVG or AI/EPS exists, supply it and the component gets replaced. Raised by Claude Code, 2026-08-26 | Nothing — the mark renders. This is about fidelity, not a blocker |
@@ -618,18 +681,19 @@ never being raised again.
| # | Reminder | Raised | Why it must keep coming back |
|---|---|---|---|
| R1 | **Licensure — RAISED 2026-08-27 and acknowledged by Pouya; still open, and the stakes are higher than when it was written.** His words: *"The interim licensure framing is now carried by shipped pages rather than specs, which raises the stakes. Keep surfacing it."* So it is surfaced, and it will be surfaced again next session. **The opening sentence below is now false and is kept only because §12 rows are not rewritten silently:** `src/pages/` exists, `/` ships at build step 2, and the framing is on a public page rather than in a document. Original text follows. **Licensure.** No site exists yet — `src/pages/` does not exist. **As specified**, the copy will assert the JD only and describe the boutique role as *active litigation exposure*, never *practice*. Pouya flagged that as an interim position and asked to be reminded to change it. §4 now records licence status as `[unestablished]`, which is the honest state, not a resolution | 2026-08-26 | If he is licensed and in good standing, it is the first credential appointing bodies and opposing counsel look for, and its absence from a detailed credentials page is conspicuous. If licensure is in progress, the copy should be rewritten the moment it completes. Either way this is a **temporary** framing that will otherwise ossify |
| R1 | **RAISED AGAIN 2026-08-28, and `/about/` is why the stakes moved a second time.** `/about/` is *"the page an appointing body or opposing counsel reads before agreeing to an appointment"* (`docs/01`), it is the site's credential spine, and it now carries the full designation list, the education line, the certifications, the memberships and the boutique role — with **no licence status stated either way**. On `/` that reads as brevity. On a dedicated credentials page a sophisticated reader notices the omission, and D13's framing is doing more work than it was designed for. Q41(a)'s ruling is now load-bearing on the same page: the copy says the legal half is *"training I hold"*, which is honest and is also the closest the site comes to addressing the question. **Nothing here is a request to change D13 — it is the surfacing R1 exists to compel.** Previous text follows. **Licensure — RAISED 2026-08-27 and acknowledged by Pouya; still open, and the stakes are higher than when it was written.** His words: *"The interim licensure framing is now carried by shipped pages rather than specs, which raises the stakes. Keep surfacing it."* So it is surfaced, and it will be surfaced again next session. **The opening sentence below is now false and is kept only because §12 rows are not rewritten silently:** `src/pages/` exists, `/` ships at build step 2, and the framing is on a public page rather than in a document. Original text follows. **Licensure.** No site exists yet — `src/pages/` does not exist. **As specified**, the copy will assert the JD only and describe the boutique role as *active litigation exposure*, never *practice*. Pouya flagged that as an interim position and asked to be reminded to change it. §4 now records licence status as `[unestablished]`, which is the honest state, not a resolution | 2026-08-26 | If he is licensed and in good standing, it is the first credential appointing bodies and opposing counsel look for, and its absence from a detailed credentials page is conspicuous. If licensure is in progress, the copy should be rewritten the moment it completes. Either way this is a **temporary** framing that will otherwise ossify |
| R2 | **Matter counts stay off the site until they are independently credible.** Revisit once there is a number a sophisticated GC would find persuasive on its own | 2026-08-26 | §4 forbids them now. That rule has an expiry date nobody has set |
| R3 | **The month 1218 practice-area review — now two candidates, not one.** *(a)* **Indigenous engagement**, deliberately omitted at launch (§6). *(b)* **Tax-adjacent disputes**, added 2026-08-26 on the Canadian Tax Foundation membership: it is the one credential none of the six areas touch, and valuation, earn-out, indemnity and shareholder disputes that turn on a tax position are ADR territory. Reasoning for both is in `docs/01-architecture.md`. One review, two candidates | 2026-08-26 | The brief rates the Indigenous niche the most valuable single one, and omission there is a timing call rather than a permanent one. The tax case is the same shape and fails for the same reason today: a practice page is a claim of present capability, and a membership is a credential, not a caseload. Both stop being true at some point, and nothing will tell you when |
| R4 | **Insights cadence.** D9 commits to monthly. A blog that stops is worse than one that never started | 2026-08-26 | The section's whole value is compounding |
| R5 | **Fee review at 12 months.** Published rates are sticky; the right moment to move them is deliberate, not reactive | 2026-08-26 | D14 is priced for where the practice is going, not where it is |
| R6 | **Booking tool.** Parked by Pouya on 2026-08-26; `/contact/` ships with the intake form and a reserved slot for an embed | 2026-08-26 | He asked to be reminded. D10 committed to booking because it removes the back-and-forth that loses appointments — the form alone is a partial answer |
| R9 | **The SES alarms notify nobody until the `ses-alerts` email subscription is confirmed.** `SES-BounceRate-High` and `SES-ComplaintRate-High` are configured and live; the SNS email subscription to `info@smlcompany.ca` is **pending confirmation**, and an unconfirmed subscription drops every message | 2026-08-26 | A monitoring control that exists but does not deliver is worse than none, because it reads as covered. At this volume five bounces can cross the ~5% suspension threshold. Tracked in §7 and on the cutover checklist, but a one-click task nobody owns is exactly what §12 is for |
| R10 | **Annually-renewing memberships.** §4 verifies the **OBA sections** (Construction & Infrastructure, ADR, Civil Litigation) and the **Canadian Tax Foundation** as of 2026-08-26 — *for now*. Both renew yearly. *Widened 2026-08-26 when CTF was added; it was OBA-only before* | 2026-08-26 | A credential that lapses quietly is the failure mode §4 exists to prevent, and OCNI already did exactly this (§4 records it as "not current, do not publish"). Re-confirm at each renewal, and before any page listing memberships ships — `/about/` at build step 3 is the first one that will |
| R10 | **RAISED 2026-08-28 AND NOT DISCHARGED — AND THE PROHIBITION HELD.** Pouya's instruction for this session was *"R10 first: re-confirm the memberships, which now includes CTF"*. The re-confirmation is a fact only he holds, so it is now **Q44**, and `/about/` ships **without a memberships group** — this row is written as a prohibition on shipping such a page, and documenting a prohibition is not discharging it. *An earlier version of this row said `/about/` had shipped with all four; that was true for part of one session and was reversed on review. Three other documents recorded the same reversed state and have been corrected.* Four yes/no answers and four **renewal months** close it; the months are the part that matters, because they turn this row from a reminder into a date. Original text follows. **Annually-renewing memberships.** §4 verifies the **OBA sections** (Construction & Infrastructure, ADR, Civil Litigation) and the **Canadian Tax Foundation** as of 2026-08-26 — *for now*. Both renew yearly. *Widened 2026-08-26 when CTF was added; it was OBA-only before* | 2026-08-26 | A credential that lapses quietly is the failure mode §4 exists to prevent, and OCNI already did exactly this (§4 records it as "not current, do not publish"). Re-confirm at each renewal, and before any page listing memberships ships — `/about/` at build step 3 is the first one that will |
| R11 | **Re-check dependency currency at every phase boundary in the build order** (`docs/01-architecture.md` §Build order, 11 steps). Run `npm view <pkg> version` across **every** pin in `package.json` and compare; do not wait for something to break. Verified does not mean latest — record the reason for any deliberate hold in §7. **Carries one specific re-add trigger: at step 7, put `@lhci/cli` back.** Check for a patched release — do not assume `0.15.1` is still the ceiling just because it was on 2026-08-26 — pin it against `npm view` that day, write a `lighthouserc` with the budgets from `docs/04-seo-spec.md`, and delete the UNAVAILABLE notices this repo now carries in six places (§7 lists them). If the advisories are still unfixed, that is a decision to take deliberately, not a reason to leave the gap unstated | 2026-08-26 | `astro: "^5.0.0"` was recalled rather than checked and was two majors stale the day it was written, which meant a framework carrying high-severity XSS advisories. Between phases is cheap; after a phase of pages is written is not. The build order has ten more boundaries |
| R12 | **`compressHTML: true` is a deliberate deviation from the Astro 7 default (`'jsx'`).** Measured 2026-08-26: in an `.astro` template an inline pair split across two lines renders as `<em>a</em><strong>b</strong>` under the default — the space is silently deleted. MDX prose is unaffected | 2026-08-26 | It is a deviation, and undocumented deviations become folklore. Revisit **with a measurement**, not a preference — and re-measure after any Astro major, since the behaviour could change again |
| R13 | **The infinity mark ships as a RASTER, and that is temporary. RAISED 2026-08-27; Pouya ruled the committed SVG does NOT close it***"Keep it committed, keep the AVIF render path. Your own measurement is the reason: 257 KB wrapping seven embedded base64 PNGs. It renders faithfully because it IS the raster."* So the exception stands and the reminder stays live. `InfinityMark.astro` renders an optimised AVIF/WebP from `src/assets/brand/sml-infinity-mark.png` — a deliberate, documented exception to `docs/02`'s "inline SVG, never a PNG", because the mark is gradient-mesh artwork and no true vector master exists yet (Q38). **Removal trigger: the commissioned vector master lands.** Then replace the `<Picture>` with inline SVG, regenerate `favicon.ico` and `apple-touch-icon.png` from it, and delete the exception from `docs/02`, from the component, and from Q38 | 2026-08-26 | Pouya flagged this himself when he made the ruling: *an interim raster is exactly the kind of temporary measure that becomes permanent by never being raised.* It costs ~8 KB and works, which is precisely why nobody will notice it again. There is no build error to prompt anyone — only this row |
| R14 | **Anything a spec makes a claim about must be reachable from the repository.** If the artefact lives only in Drive, in a console, or on someone's disk, no reviewer can check the claim and the claim is unverifiable by construction — see the rule now in `CLAUDE.md` | 2026-08-26 | **This has now cost twice.** Q24 was `AWS-Hosting-Guide.md`, the only record of how the infrastructure was hand-built, living outside the repo. Q32 was the infinity mark: Claude Code traced it from the old site's *loading placeholder*, wrote a scrupulous provenance comment recording exactly that doubt — and **two adversarial review passes still could not catch it**, because the artwork they would have had to compare against was not in the repo. The doubt was correctly stated and structurally uncheckable. That is the failure mode: not a missing warning, a missing artefact |
| R15 | **Every page shares ONE Open Graph image — the portrait — and that is an interim for seventeen of the nineteen. RULED, DEFERRED, AND TRACKED HERE ON POUYA'S INSTRUCTION:** *"Record the trigger so it cannot quietly become permanent."* Q40, 2026-08-27. The portrait is the **decided** card for `/` and `/about/` — a face is the strongest social preview for a personal brand. It is the wrong card for the other seventeen, where a typed card carrying the page title does the work. **Removal trigger: build step 7**, where Insights needs per-article cards anyway — one generator (`satori` or `astro-og-canvas`, pinned against `npm view` that day per R11), one dependency, one review. Then delete the interim note from `docs/04` and the cutover line from `docs/06`. **Blocks cutover; does not block steps 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 |
| ~~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 | — |
@@ -637,6 +701,400 @@ never being raised again.
# Change Log
## 2026-08-28 (x) — Build step 3: `/about/` ships without its memberships. Q40Q43 close; four review passes found nine defects in their own predecessors' fixes
**Task, in Pouya's words:** rulings on **Q42**, **Q41(a)(b)(c)**, **Q43** and
**Q40**, then *"step 3, `/about/` — and R10 first: re-confirm the memberships,
which now includes CTF."*
**Headline, because it is the one thing to read if nothing else:** `/about/`
ships **without a memberships group**. R10 is written as a prohibition on
shipping a page that lists memberships before they are re-confirmed; the
re-confirmation is a fact only Pouya holds; it was not obtained. The first
version of the page published all four and *disclosed* the gap in five places
instead — both review agents rejected that, and they were right. **Q44** carries
the exact question.
---
### Standing reminders surfaced (§12)
- **R1 — licensure. Raised again, and `/about/` is why the stakes moved.** It is
the site's credential spine, it now carries designations, education,
certifications and the boutique role, and it states no licence status either
way. On `/` that reads as brevity; on a dedicated credentials page a
sophisticated reader notices. Q41(a)'s ruling is now load-bearing on the same
page — the copy says the legal half is *"training I hold"*, which is the closest
the site comes to addressing the question. **Nothing here asks to change D13.**
- **R10 — raised and NOT discharged.** See the headline. Now Q44.
- **R13 — the mark is still a raster.** Unchanged; no vector master has landed.
- **R11 — phase-boundary currency check RUN, not recalled.** Every pin in
`package.json` against `npm view`: 13 of 14 exact. The one hold is
`typescript ^6.0.3` against `7.0.2`, and the reason was re-verified rather than
carried forward — `@astrojs/check` peers `^5.0.0 || ^6.0.0` and
`typescript-eslint` peers `>=4.8.4 <6.1.0`. Both bar 7. `npm audit`: **0
vulnerabilities.** `[verified 2026-08-28]`
- **R15 — NEW.** The single portrait OG image across nineteen pages, per Pouya's
Q40 ruling, with build step 7 as the removal trigger.
### Rulings applied
**Q42 — three offerings rowed, settlement counsel struck.** ENE, dispute-system
design and pre-dispute technical advisory gained rows; `settlement counsel` was
struck as Pouya's own error in `docs/01`, on the ground he named first —
*"it undercuts the brand's central claim"* — with the D13 half as aggravation
rather than reason. Swept by command; output below.
**And the strike exposed a hole in the offering test.** Settlement counsel fails
neither question 1 nor question 2; run mechanically the test would have **passed**
it. It fails a prior question the test does not ask. §4 now states that prior
question — *is this a role in which the practice is partisan between the parties
to a dispute?* — with the Q42 worked example kept as the 31 table.
**Q41(a) — Q37 reaches prose, and prose is held to a HIGHER bar.** Deleting the
parallel was half the fix; a reader supplies the missing symmetry from silence.
The sentence that names which half is which is now **one constant**,
`ASYMMETRY_LINE`, because it had been typed into two pages and the two copies had
**already diverged inside the same session** — a comma on one, full stops on the
other.
**Q41(b) — not restored, and the comparative turned out to be in three places,
not one.** Pouya's replacement wording is used verbatim in `docs/03`'s core
positioning statement. Then the second audit found the implication had been
*relocated, not removed*: a new instance written into the `/about/` biography,
plus **two pre-existing instances on `/` that had survived the sweep that closed
Q41(b) the day before** — *"usually arrives as a separate expert report"* and
*"not something a party has to commission and wait for"*. All three gone.
**Q41(c) — verified against the Tribunal's own materials, and the interim was
ambiguous in the one word that mattered.** New extract:
`docs/reference/lat-case-conference.md`. Rule 2.4 makes *"Pre-Hearing
Conference"* the LAT's own term for a **case conference**; Rule 14.3 puts a
**Member** in the chair and disqualifies them from the hearing panel; Rule 14.6
makes attendance mandatory; the Rules contain **zero** occurrences of `mediat` or
`arbitrat` in 66,593 characters. The affirmative basis is the Tribunal's own AABS
page: *"you may want to consider negotiation or mediation services… including
before filing at the LAT-AABS, and continuing… after a claim has been filed."*
**Q43 — the timings are service commitments; framing, not a row.** Numbers
unchanged. `PROCESS_FRAMING` renders adjacent to the strip, not in a lede above
it, because a reader who scans the strip and skips the lede has read a
commitment. `docs/03` §Process amended to record that its *"real timing"*
requirement had been over-read as barring the word "typical".
**Q40 — bundled to step 7, not shipped as a second interim.** Portrait is the
*decided* card for `/` and `/about/`; the generated typed card covers the rest,
built once with Insights. Tracked as **R15**, blocking cutover, not step 3.
### `/about/` — what shipped
Six of `docs/01`'s seven items. Item 6 (Speaking) omitted on the spec's own
instruction. Item 7's PDF **not** shipped — **Q45**. Item 3 ships Designations,
Education and Certifications; **Memberships withheld** — Q44. Sections ordered
4-before-3 deliberately: the arc is the part a reader has a question about.
### Four review passes, and what they cost
Two agents, twice. **28 findings, then 15 more.** Nine of the second round's
findings were defects in the first round's fixes — which is the measurement
`/build` Phase 4 exists on.
**Three that must never have shipped, all mine:**
1. **The false universal Q39 struck, on a public page.** The arc's Q.Arb body
read *"arbitral appointments are not gated behind it, which is why I accept
them now"* — unscoped, first person, publishing a proposition of Ontario law
§4 holds only in scoped form and deliberately does **not** stamp. Q39 swept
three instances on 2026-08-27; this was the **fourth** and the first outside a
comment. Found independently by both agents.
2. **A public warranty of currency over an undischarged R10** — *"Memberships are
renewed annually and are listed as current."* Also **widened §4**, which
records yearly renewal for the OBA sections and the CTF only and says nothing
about ADRIC or ADRIO. The widened form had propagated to four files.
3. **A licensure denial** — *"Nothing above asserts a licence to practise law, in
either direction"* — on the page §4 marks `[unestablished]`, where the rule is
*do not assert it, do not deny it*. No spec asked for it.
**And the same sentence was wrong in both directions, which is the finding worth
keeping.** Audit 1 flagged *"I do not give legal advice"* — "do not" describes an
election, and an election implies the entitlement. So it became *"I cannot give
legal advice"*. Audit 2 flagged that — "cannot" is a **denial**. Both readings
are correct and they point in opposite directions, because **both sentences make
a claim about capacity**. The third version does not: it states the role and its
consequence for the reader.
**Defects in my own fixes, all found by measuring the fix rather than reading it:**
- `:where(.prose) > p + p` is **additive with a flex `gap`**`/`'s approach
paragraphs went 24px → **48px**. My comment said *"Verified: with `:where()`
the flex container's gap governs and this contributes nothing."* False, and
measured false minutes after being written: `:where()` lowers specificity,
which only matters when two rules set the **same property**.
- The 1440w portrait rung removed a 1.07× upscale and imposed **+27,273 B** on
DPR-3 phones (48,799 vs 21,526). Added 1080; that sample is now 27,594 B and
exact.
- Gating the italic preload behind a new prop and **never setting it on `/`**,
which uses the face in a 96px headline.
- `Pill`'s type fix, twice: `interface Props {}` is rejected by eslint and means
"any non-nullish value" anyway; `Record<string, never>` passes eslint and
rejects `class` **and also rejects `children`**, breaking two real call sites
while the probe page went green on exactly what it tested.
- `.designation-part { white-space: nowrap }` fixed an orphaned separator and
took `/about/` to **108px of overflow at 320px** at a 200% default font size.
- The print override, scoped by class, **missed two elements** and then a third:
`.approach-metaphor`, `.btn-gold`, and — after the token rewrite — the hero
`.btn-primary` at **1.07:1** against white paper, which sits on cream inside no
inverse section at all.
**The portrait defect was the expensive one, and it was on the shipped home page
too.** Below 66rem the hero is one column, so the portrait is the **full content
width** — 592 to 928 CSS px — while `sizes` declared 5260vw and the ladder
stopped at 960w. Measured **1.40× upscale at 768/DPR2 and 1.93× at 1024/DPR2**,
identical on both pages, surviving a cleared cache. `/`'s own comment derived the
960 ceiling from the ≥66rem layout: **the range where the image is widest was
never in the arithmetic.**
**Declined, with reasons:**
- *"I will tell you whether I am the right neutral for it"* flagged as an unrowed
service commitment. It is a statement about a conversation, not a metric a
slipped date could falsify, and it ships identically on `/`.
- Empty-collection guards on `CREDENTIAL_GROUPS` and `litigationAreas`. Both are
`as const` tuples; neither is reachable without a source edit.
- `Person.hasCredential` currency (Q.Med as `Held`, present tense, on a
`[verified 2026-08-25]` row under a *"currency is not confirmed"* preamble).
The row exists, so it traces. Noted for Pouya rather than resolved.
- The `ContactBand` CTA invites matter details on pages carrying no no-retainer
notice. `docs/03` scopes `NO_RETAINER_NOTICE` to `/contact/`, which is where the
CTA goes. Worth a ruling before the band reaches nineteen pages.
**Reversed a review finding once, deliberately** — the designation-name
expansions. Audit 1 struck them as §11-Glossary-only; audit 2 then found the page
also publishes *"Provincial Offences Act"*, *"the ADR Institute of Canada and the
ADR Institute of Ontario"* and `recognizedBy`, all on the same footing —
*"one standard or the other."* Standard chosen: **§11 is the source for
definitional expansions; §4 remains the only source for claims about Pouya.**
Sourcing externally was tried and failed — `adric.ca/designations/` redirects and
serves **zero** occurrences of `Q.Med`, `Qualified Mediator` or `Chartered
Mediator` in 114,985 bytes. **Q46(b)** asks Pouya to ratify the standard; if he
declines, all four classes come out together.
### The third review round, and a process defect of my own
The code re-review returned **8 more findings**, and it opened with a criticism
of how I ran the loop that is correct and is recorded here rather than softened:
**I edited the tree while it was measuring.** It anchored to SHA-256, re-verified,
and reported that four of the defects it had measured *"were repaired under me
mid-review"* — so its certification covers a snapshot, not the tree, and the
repairs it watched me make **were reviewed by nobody**. `/build` Phase 4 says to
re-review material fixes; it does not say to hold the tree still while a review
is in flight, and it should. Next session: snapshot, review, then fix.
The four it watched being repaired were all real and all measured: the lost
italic preload on `/`, the 24→48px prose regression, three elements the print
block missed (rasterised from `printToPDF` at 100 dpi: 2.49:1 and 3.96:1 against
white), and dead page-scoped CSS whose compiled selectors carried the old page
cids while the rendered elements carried `ContactBand`'s.
**Two of the eight were defects in fixes from this same session:**
- **`/` kept `fetchpriority="high"` while `/about/` withheld it on the identical
measurement.** Portrait visible px: **0 at 320, 0 at 360, 0 at 390**, with LCP
measured as `P.hero-lede` — so the attribute promoted 2749 KB of image the
reader cannot see above the face that paints the actual LCP element, on the
axis the ≥95 budget is measured on. Removed. `loading="eager"` stays; the
portrait is the LCP element from 768px up.
- **The 1080 rung I added closed the 390px gap and missed the two largest current
iPhones.** 428@3 and 430@3 need 1140/1146 and took **1440 — 48,799 B**, against
27,594 for the device the rung was tuned for: **+21,205 B, 13% of page weight.**
A 1200 rung closes it at 1.05x. Third iteration of this ladder.
**And one of my stated reasons was simply wrong about ARIA.** I removed
`role="list"` from the arc `<ol>` on the ground that it *"re-announces an ordered
list as an unordered one"*. It does not — **both `<ul>` and `<ol>` map to the
`list` role**, so on an `<ol>` it is a no-op for ordering. What it is for is the
WebKit heuristic that strips list semantics from a list with
`list-style-type: none`, which `.arc` sets. Restored, and `.arc`'s hand-written
`padding: 0; list-style: none` deleted because `global.css`'s `ol[role='list']`
reset already supplies both. **Not verified: whether WebKit's heuristic covers
`<ol>`.** No Safari instrument here, so the role stays on the precautionary side.
Also fixed: `ContactBand` shipped `eyebrow?`, `cta?` and a named `heading` slot
with **zero call sites overriding any of them** — the pattern this repo has
already deleted twice, in `Eyebrow` and `SectionHeading`, with the reasons written
into the source. All three gone; the empty `Props` guard stays, because that is
what makes `<ContactBand class="x" />` a build error. `.section-head` moved to
`global.css` (byte-identical in two pages, seventeen to come). `sizes` corrected
in the 66rem80rem band, where `42vw`/`38vw` described neither track — measured
36.0% and 32.5% — costing up to **1.45x** over-fetch at 1200/DPR 1.
Two residual over-fetches left deliberately and recorded in the source: 320@2 at
1.18x (no rung between 480 and 640, and 480 would be an upscale) and 1056@2 at
1.26x, where 380.2 x 2 = 760.4 misses the 760 rung **by four tenths of a pixel**.
Declaring 35vw to duck under it would make `sizes` less truthful across the band
for a 0.05% upscale. The declaration stays honest.
`docs/02`'s reflow table is corrected (65 → **63** px, re-measured) and now
carries an `/about/` row — the first page measured *against* that table rather
than establishing it. It records that `.designation-part { white-space: nowrap }`
was itself introduced as a fix, for an orphaned separator, and created a
**108px** reflow regression at 320px.
### Register defects the audits found in §4 itself
`claims-auditor` caught the register answering **its own question 1 with the
subject's words** — twice, the second time inside the paragraph added to explain
the first. The three new Offerings rows carried gating conclusions
(*"no designation is required to give a non-binding evaluation"*) under a
`[verified — Pouya]` stamp, which §4's own box says cannot carry a proposition of
law. Q1 is now `[unestablished]` on all three, the worked example's Q1 column is
emptied, and **Q46(a)** carries it. Nothing publishes on it today; it blocks
`/practice/` at step 5.
Also: **four documents recorded that `/about/` publishes memberships** after the
page had been changed not to — §9 Q44, §12 R10, `docs/06` and `schema.ts`. And
the widened *"all renew yearly"* survived in three of them plus
**`.claude/agents/claims-auditor.md` itself**, which the auditor found in its own
brief. Third stale claim located inside that file.
### Verified — measured, not asserted
```
npm run check 0 errors / 0 warnings / 0 hints
npm run lint eslint clean; prettier clean
npm run build 2 pages, no errors
npm audit 0 vulnerabilities
grep -rE 'animation:[^;}]*(scroll\(\)|view\(\))' dist --include='*.css' → no match
```
- **Portrait ladder: 0 upscaling** — across 24 synthetic samples and then across
**11 real device profiles** on both pages (was 1.40× / 1.93×). Worst oversize
1.26×, at one viewport, recorded in the source with the reason.
- **`.section-head`: 48 px on all seven wrappers** after the rule moved to
`global.css` — re-measured, because moving a rule that exists to work around
the parent/child scope trap is exactly where that trap recurs.
- **Overflow 0 and 0 over-wide elements** at 13 widths on both pages — elements
measured, not only the document.
- **Contrast: 0 failures** of 127/127/128 painted pairs on `/` and 86/86/88 on
`/about/`, at 390/768/1280.
- **Print, against white paper: 0 failures** of 89 and 48 visible text elements
under print-media emulation (was 1.07:1 on the arc, the contact band and both
CTAs).
- **200% default font size: `/about/` 63 / 23 / 0** px overflow at 320/360/390,
against `/`'s 63 / 23 / 3. The 320/360 residual is the header `A.brand`, which
`docs/02` already accepts.
- **Reveal: 0 of 10 and 0 of 4 hidden** under `prefers-reduced-motion: reduce`
and under print.
- One `<h1>`; outline `h1 → h2 → h3` with no skips; 30 tabbable elements of 37 in
the DOM (the 7 are closed `<details>` contents, correctly untabbable and
correctly ringed when open).
- **Bio: 409 words by my count, 411 by `adversarial-reviewer`'s** (spec 400600).
The two differ on whether a standalone em-dash is a token; both are inside the
range and neither is presented as the number. It was **385** at first review,
which is the point of measuring it — the source comment then claimed the count
had been verified against *"the verify step of this session's Change Log
entry"*, a document that did not yet exist.
- **Zero `<script>`** other than `application/ld+json`; no `.js` in `dist`.
- **Lighthouse: NOT RUN — tool unavailable** (R11, step 7).
- **HTML validator: NOT RUN.** The duplicate-`1x` srcset conformance error
recorded at step 2 stands; no "validator clean" claim is made.
### Sweeps — the command, then the output
```
$ grep -rni "settlement counsel" . --include='*.md' --include='*.ts' --include='*.astro'
AGENTS.md:293 (§4 scope enumeration — REMOVED from the list, pointer added)
AGENTS.md:567 (§9 Q42 — now ANSWERED, records the strike)
AGENTS.md:3298 (Change Log entry (d) — history, not edited)
docs/07-fees.md:128 → three services, not four
docs/01-architecture.md:235 → struck from the strip, with Pouya's reasoning
src/data/site.ts:236 → FEES.hourly comment
src/pages/index.astro:423 → areas-more comment
```
Every live instance struck or converted to an explicit prohibition. A
**whitespace- and blockquote-insensitive** sweep was needed to find them all: a
plain `grep` for `take on faith` returned four hits and **missed `docs/03`
entirely**, because the phrase wrapped across a newline behind a `>` marker — the
positioning statement, i.e. the one that mattered.
```
$ (normalised sweep for "all renew yearly" / "/about/ publishes")
→ every remaining match is a QUOTATION INSIDE A CORRECTION, read individually.
$ (rendered-text-only forbidden sweep, printed with context)
→ 4 matches, all read: "a licence question" (software licence, x2),
"I do not act for a party" (the protective negation), "their own legal advice"
(advising the reader to get advice). The `aLSO` / `pLEADINGs` family.
$ grep -rn "law degree on one side" --include='*.astro' --include='*.ts' --include='*.md' .
docs/03-content-spec.md (spec quotation, canonical form)
src/data/site.ts (the constant)
→ one authoring location.
```
### Instrument errors caught before acting — six this session
`CLAUDE.md`'s rule earned its place again. None of these reached a report:
1. A `<title>` probe using a regex that **cannot match a `<title>` element**
reported "MISSING" on both pages.
2. A link checker counting `?v=1` query strings as missing files.
3. `/` at 390/DPR1 reading as **2.81× oversized** — an HTTP-cache artefact.
Cleared: 0.90, correct.
4. "**7 focusables with no focus ring**" — closed `<details>` contents, correctly
untabbable, correctly ringed when open.
5. A `<picture>` regex that grabbed the **header's infinity mark** instead of the
portrait, reporting the AVIF ladder as 0 bytes.
6. `/about/`'s print button reading as gold **because print media was emulated
after navigation on one page and before it on the other.**
And one non-error worth recording: `adric.ca/designations/` really does serve
zero designation names — but only checking the **raw bytes** established that,
because 4,840 characters extracted from 114,985 is the signature of a
JS-rendered shell, not of an absence.
### Corrections to comments that asserted the opposite of the measurement
Recorded because the confident ones were the false ones:
- *"The `<picture>` WRAPPER carries no cid, so it needs `:global()`"* — false.
The emitted markup is `<picture data-astro-cid-ta2fbyqs="true">`, and
InfinityMark's **bare** `picture` selector compiles to
`picture[data-astro-cid-usztftas]` and works. `:global()` dropped on both pages.
- *"The LCP element on this page is the `<h1>` — two words of 96px serif"*
false twice. LCP at 1280 is `IMG.portrait-img` (229,679 vs the h1's 51,484), and
`--text-5xl` computes to **76px**, not 96.
- *"above the fold at every width"* — false. The portrait is **entirely** below
the fold at 320 and 360, the two widths `docs/02` names.
- *"`--text-meta` on cream measures 3.07:1"* — false, in two files. It is
**5.47:1**; 3.07 is the ratio on **ink**, which is what `tokens.css` says.
- *"the components have had their `class` props deleted so passing one is a build
error"* — false for `Pill`, which had **no `Props` interface at all**, so its
call sites were unchecked. `CLAUDE.md` names `Pill` as the next place the
parent-scope defect will happen; the guard documented as protecting it was
absent on exactly it.
- A comment citing *"the word-count assertion in the verify step of this session's
Change Log entry"* — **which did not exist yet.** The same shape §9's Q39 row
already records as a fair catch.
### Files
New: `src/pages/about.astro`, `src/components/ContactBand.astro`,
`docs/reference/lat-case-conference.md`. Changed: `AGENTS.md` (§4, §9, §12),
`CLAUDE.md`-adjacent agent brief, `docs/01`, `docs/03`, `docs/04`, `docs/06`,
`docs/07`, `src/data/{site,schema}.ts`, `src/layouts/BaseLayout.astro`,
`src/components/Pill.astro`, `src/styles/global.css`, `src/pages/index.astro`.
### Open for Pouya
**Q44** memberships (blocks the group + `memberOf` + cutover) · **Q45** the PDF
bio · **Q46** (a) ENE / DSD / advisory gating, (b) §11 as a source for
definitional expansions · **Q47** `jobTitle` without `worksFor` · plus
**Q23**, **Q34**, **Q38**. Live reminders: **R1**, **R10**, **R13**, **R15**.
**Next:** step 4 — `/mediation/`, `/arbitration/`, `/med-arb/`. `/arbitration/`
is where §4's paired-disclosure condition is hardest: it offers all three forms
and must state the Q.Arb stage plainly, *"and neither half may be dropped."*
## 2026-08-27 (w) — Build step 2: `/` ships. Q35, Q37 and Q39 close, and Q39's answer was that this register had been reasoning from a falsehood
**Pouya ruled on all five parked items in one message.** Four are implemented
+68 -3
View File
@@ -134,7 +134,10 @@ four audiences to its surface.
2. **Credential row.** Three slots: `Q.Med` · `JD + ML` · `EN · FA`. Never
matter counts — `AGENTS.md` §4.
3. **The approach.** The "two directions at once" argument — law and engineering
converging on the same dispute. Infinity mark as the visual anchor.
converging on the same dispute. ⚠️ **The noun pair "law and engineering" is
the construction Q37 struck and Q41(a) extended to prose. The argument
stands; do not lift the phrase into copy** — it reached `/` once already.
State the asymmetry instead: `docs/03` §The credential row. Infinity mark as the visual anchor.
4. **Two practices.** Mediation and Arbitration cards → `/mediation/`, `/arbitration/`.
Med-Arb named here as the long-term arc, linking to `/med-arb/`.
5. **Practice areas.** Six-card grid → `/practice/*`. This is the most important
@@ -173,6 +176,17 @@ to an appointment. This page carries the verifiable record.
7. `Person` JSON-LD. Downloadable one-page PDF bio — brief §VIII lists this as
an asset for circulation with appointment proposals.
> **The PDF bio does NOT ship with build step 3, and the omission is stated
> rather than silent** — `AGENTS.md` Q45, opened 2026-08-28. No such file exists
> in the repo, and a link to one that does not exist is a broken link on the
> page an appointing body reads. It is also not a formatting job: a one-page bio
> is a **credential document** whose every line has to trace to §4 exactly as a
> web page does, and it will be circulated detached from the site, where no
> reviewer sees it again. Two decisions are Pouya's — whether it is generated at
> build (a dependency, against R11) or authored once as a designed artefact, and
> whether it carries anything the site does not. Everything else on this page
> ships.
### `/mediation/`
**Job:** convert counsel who have already decided on mediation and are choosing a
@@ -232,8 +246,23 @@ long-term narrative.
### `/practice/` — index
Six cards, one paragraph each, linking onward. Also the natural home for the
"also offered" strip: early neutral evaluation, settlement counsel, dispute-
system design, and pre-dispute technical advisory.
"also offered" strip: **early neutral evaluation, dispute-system design, and
pre-dispute technical advisory** — three, and each now has an `AGENTS.md` §4
Offerings row, which is what the strip needs before it may ship.
> **`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:
>
> > "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 which objection comes first. This is not primarily a compliance problem —
> it is a **positioning** problem, and it would have been wrong on a site with
> no licensure question at all. The compliance half is the aggravation, not the
> reason. Never priced, never offered, never listed: it is a struck row in §4
> Offerings so that a later reader finds the decision rather than the gap.
### `/practice/construction/`
@@ -275,6 +304,35 @@ a claim of existing volume.**
**Search intent:** `SABS mediation`, `LAT pre-hearing mediation`,
`accident benefits mediator Ontario`, `MIG dispute`.
> ⚠️ **`LAT pre-hearing mediation` IS A SEARCH INTENT AND NOTHING ELSE. It must
> never be published as an offering** — `AGENTS.md` Q41(c), closed 2026-08-27,
> verified 2026-08-28 against the Tribunal's own materials and extracted into
> **`docs/reference/lat-case-conference.md`**. It reached `src/data/site.ts` as a
> service blurb once already; this note exists because a search-intent list is
> where that lift starts.
>
> What the verification found, in one line each:
>
> - **LAT Rule 2.4:** *"'Case Conference' has the same meaning as 'Pre-Hearing
> Conference' as defined in the SPPA."* **"Pre-hearing" is the Tribunal's own
> label**, and what it labels is a case conference.
> - **Rule 14.3:** a **Member** presides and is then disqualified from the
> hearing panel; **Rule 14.6:** parties must attend. The neutral is the
> Tribunal's. A privately retained one is not appointed to it and cannot be.
> - The LAT Rules contain **zero** occurrences of `mediat` or `arbitrat` —
> 0 in 66,593 characters. The concept is not in them.
> - The LAT-AABS page itself, though, says: *"Before you apply to the LAT-AABS,
> you may want to consider negotiation or mediation services… including before
> filing at the LAT-AABS, and continuing… after a claim has been filed."*
> **That is the affirmative basis for the offering, in the Tribunal's words.**
>
> **The page must state that the mediation offered is PRIVATE, retained by the
> parties, and is not the Tribunal's case conference.** Published blurb:
> *"Accident benefits and SABS entitlement, MIG disputes, and private mediation
> alongside a LAT application, before filing or after."* If Pouya holds a roster
> position that makes more than that true, it is a §4 addition — absent a row,
> it is not.
Highest realistic near-term volume — it flows directly from the existing
personal-injury and SABS work, and brief §IV.7 notes the segment is
underserved by senior mediators. Unglamorous and worth doing well.
@@ -319,6 +377,13 @@ and framing (17) · pre-session exchange (721) · the session (2130) ·
conclusion (30+). Also: conflicts checking, confidentiality, and what happens if
a matter does not settle.
**The timings are published as the TYPICAL shape of an engagement, explicitly
not a guarantee** — `AGENTS.md` Q43, Pouya 2026-08-27. Render `PROCESS_FRAMING`
(`src/data/site.ts`) **adjacent to the steps**, on this page and on `/`. The
numbers above are unchanged; what is required is that they never appear
unframed. *"Published as typical, they are honest and useful; published as
commitments, the first matter that slips makes the page false."*
### `/fees/`
**Unblocked — `AGENTS.md` Q4/Q14 answered (D14). Build from the confirmed card
+28 -1
View File
@@ -231,7 +231,34 @@ Not a polish pass. A build requirement.
|---|---|---|
| as first built | 234 px | 304 px |
| `minmax(min(Nrem, 100%), 1fr)` on three grids | 83 px | 153 px |
| `.credentials` made explicit `repeat(2, minmax(0, 1fr))`; `.feature` padding clamped and `overflow-wrap: anywhere` on its title; `.contact-action` `flex: 0 1 auto` + `min-inline-size: 0` | **3 px** | **65 px** |
| `.credentials` made explicit `repeat(2, minmax(0, 1fr))`; `.feature` padding clamped and `overflow-wrap: anywhere` on its title; `.contact-action` `flex: 0 1 auto` + `min-inline-size: 0` | **3 px** | **63 px** |
**`65 px` corrected to `63 px` on 2026-08-28**, re-measured independently on
the same page and setting. Two pixels, and it is recorded because a table that
reads as the site-wide record has to be re-measurable rather than remembered.
**`/about/` added 2026-08-28** — step 3, and the first page to be measured
against this table rather than establishing it:
| Page and fix | 390 px | 360 px | 320 px |
|---|---|---|---|
| `/about/` as first built | 38 px | 68 px | 108 px |
| `.designation-part` `white-space: nowrap` removed (the separator is held by an NBSP instead) and `overflow-wrap: anywhere` on `.hero-h` | **0 px** | **23 px** | **63 px** |
Two findings from that page specifically. The `nowrap` was **introduced as a
fix** for an orphaned `·` at the end of a wrapped line, and it made the whole
designation item unbreakable — a fix that created a reflow regression, caught
only because this table existed to regress against. And **the type scale is
rem-based**, so an `<h1>` at `--text-5xl` computes to 88 px at root 32 and a
single unbreakable 9-character name ("Lajevardi") exceeds the 224 px content
box at 320 px; `overflow-wrap: anywhere` is the only remedy that reduces
min-content size. `/about/` now measures equal to or better than `/` at all
three widths, and its 320/360 residual is the same header decision.
Command, so the numbers are re-runnable rather than quoted: headless Chrome
over the built `dist`, `document.documentElement.style.fontSize = '32px'`, then
`documentElement.scrollWidth - documentElement.clientWidth`, plus an
enumeration of every element wider than `clientWidth` to name the offender.
Two things worth keeping. **`overflow-wrap: break-word` permits a break at
layout time but does not reduce min-content size** — `anywhere` does, and that
+81 -3
View File
@@ -85,13 +85,32 @@ Reused, adapted, across the hero, the About page, and the PDF bio:
> The dispute resolution practice of Pouya Lajevardi — a credentialed neutral
> who is also close to live litigation and a practising machine-learning and
> infrastructure engineer. Built for commercial, construction, energy,
> technology, and cross-cultural disputes that turn on facts most neutrals take
> on faith: the contract, the code, the engineering documents, and the
> regulatory overlay around them.
> technology, and cross-cultural disputes that turn on the contract, the code,
> the engineering documents, and the regulatory overlay around them.
Every version of this must survive the §4 check. It does: each element is
verified.
**AMENDED 2026-08-27 — `AGENTS.md` Q41(b). The statement read *"disputes that
turn on facts most neutrals take on faith: the contract…"* and the comparative
is struck.** It was not restored, and Pouya gave two reasons, the second of
which is the one to remember:
> "That is an unverifiable empirical claim about other practitioners, and
> comparative claims must be factual and verifiable. **It is also weaker copy:
> assert his capability, not the field's incapability.** Rewrite to claim only
> about himself — 'built for disputes that turn on the contract, the code, and
> the engineering documents'. Same force, nothing to defend."
So the compliance objection and the editorial objection point the same way.
The checklist item below — *"any comparative claim is factual and verifiable"*
had been overridden in practice by the fact that this paragraph was **approved
copy**, which is how an unverifiable claim ends up inside the document that
forbids it. The approved copy is what changed.
**This is now the ONLY sanctioned form of the statement.** Any earlier draft
carrying the comparative is superseded, wherever it is quoted.
## Approved headline options
From the content brief; all three sit honestly with the practice.
@@ -124,6 +143,37 @@ invited the reader to supply the symmetry, and for "Law" the missing half is a
licence — which D13 bars by implication as hard as by assertion. The replacement
is longer and deliberately lopsided. Do not tidy it back into a parallel.
**AND THE RULE IS NOT SCOPED TO THIS LABEL — `AGENTS.md` Q41(a), Pouya
2026-08-27.** Q37 was asked about a credential label; the reasoning applies to
every surface, prose included:
> "Yes, Q37's reasoning reaches prose. 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.**"
Read the second half carefully, because it sets a **higher** bar for prose, not
a looser one. Deleting the parallel is only half the job — a reader can still
supply the missing symmetry from silence. Prose has room to say which half is
which, so it must. Naming the legal half as **training** is what makes the licence
implication impossible rather than merely absent.
**THE SENTENCE IS A CONSTANT, NOT COPY TO BE RETYPED**`ASYMMETRY_LINE` in
`src/data/site.ts`:
> "The two halves are not the same kind of thing, and the asymmetry is the honest
> part. A law degree on one side. A working engineering practice on the other.
> One is training I hold. The other is work I still do."
It lives beside `ROLE` for the reason that file gives: *"these are the two where
the wording IS the compliance."* This paragraph previously quoted it inline and
cited it as living at "`/`, §The approach" — and by then it had been typed into
`/about/` too, so there were **three copies and two of them had already
diverged**: a comma here and on `/`, full stops on `/about/`, all inside the
session that wrote them. Consume the constant on any page that needs the
sentence. Do not retype it, do not paraphrase it, and do not quote a variant of
it in a spec.
Fourth slot where the layout has one: **Q.Arb — commenced August 2026.** Use
that wording, not "in progress": §4 pins it, and the weaker form drifts toward
"nearly complete", which §4 Forbidden bars outright.
@@ -151,6 +201,14 @@ Hero headline from the approved list. Positioning paragraph above. CTAs:
dispute — and keeps the infinity metaphor: *disputes are loops; the work is
redrawing the loop into a line.* First person: "my mark", not "our mark".
> ⚠️ **"law and engineering" IS THE STRUCK CONSTRUCTION. Do not lift this
> sentence into copy.** The *argument* it names is Pouya's and stands; the noun
> pair carrying it is what Q37 struck and Q41(a) extended to prose. It reached
> the page once already, as *"Law and engineering are not blended here"* — the
> struck parallel relocated from the credential label into body copy, one day
> after it was struck, and strengthened by attributing both halves to him
> personally. A spec phrase describing an argument is not approved copy.
### About
400600 words of narrative, then structured credentials. Tell the three tracks
as one arc, not three lists: a JD and active litigation exposure; a parallel
@@ -187,6 +245,26 @@ neither.
Five steps with real timing. Say what happens if the matter does not settle —
counsel want to know the downside shape before they commit a client's day.
**AMENDED 2026-08-27 — `AGENTS.md` Q43, and it overrides this section's previous
reading.** "Real timing" was being read as *barring* the word "typical", which
is why the step-2 build shipped the five timings as bare numbers and escalated
the question instead of framing them. Pouya ruled the other way:
> "The five process timings are **service commitments, 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: the **numbers do not change** — softening them was never the fix and
inventing them was never on. What "real timing" bars is a *vague* timing
("promptly", "in a matter of weeks"), not an honest statement of what the
numbers are. The framing is `PROCESS_FRAMING` in `src/data/site.ts` and it is
**not optional**: every page that renders the steps renders it, 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.
### Fees
**Unblocked — Q4/Q14 answered, D14.** Build from the confirmed card in
`docs/07-fees.md`. Plain table, no "starting from"
+28 -3
View File
@@ -66,9 +66,34 @@ twitter:card summary_large_image
robots index,follow — except /legal/* which is noindex,follow
```
**OG images:** 1200 × 630. Generate at build with `satori` or `astro-og-canvas`
using the site's own type and palette. One template: display headline on cream,
infinity mark, designation line. Never a screenshot.
**OG images:** 1200 × 630. Never a screenshot.
**RULED 2026-08-27 (`AGENTS.md` Q40, R15) — TWO kinds of card, not one, and the
generator is deferred to build step 7.** This spec said "one template" for all
nineteen pages. Pouya split it:
> "A portrait is the **right** OG image for `/` and `/about/` — a face is the
> strongest social preview for a personal brand. It is the **wrong** one for
> nineteen pages, where a typed card carrying the page title would do the work.
>
> But do not build the generator now and do not leave 'portrait everywhere' as
> an untracked interim. **Ship it at step 7 alongside Insights, which needs
> per-article cards anyway — one build, one dependency, one review.**"
So:
| Pages | Card |
|---|---|
| `/` and `/about/` | The **portrait** crop, `src/assets/og-portrait.jpg`. Not an interim — the decided answer |
| Every other page | Generated at build with `satori` or `astro-og-canvas`, using the site's own type and palette: display headline on cream, infinity mark, designation line |
| Each article | Per-article card from the same generator — the reason the two jobs are one build |
**Until step 7 every page shares the portrait, and that is a RECORDED interim
that blocks cutover, not build step 3.** It is tracked as **R15** in
`AGENTS.md` §12 with its removal trigger, because a link preview nobody on the
team ever sees is exactly the kind of interim that becomes permanent by
never being raised. The dependency choice is made against R11 on the day, not
recalled from this paragraph.
## Structured data
+18
View File
@@ -329,6 +329,18 @@ Then invalidate `/*`.
**Content and compliance**
- [ ] Every claim traced to `AGENTS.md` §4 Verified
- [ ] **Memberships re-confirmed with Pouya, then published**`AGENTS.md` §12
**R10** and **Q44**. ADRIC, ADRIO, the three OBA sections and the Canadian
Tax Foundation are `[verified 2026-08-26]`. **§4 records yearly renewal for
the OBA sections and the CTF only** — it says nothing about ADRIC's or
ADRIO's period, and an earlier version of this line asserted "all renew
yearly", which §4 does not support. **`/about/` currently publishes NO
memberships group**: R10 is a prohibition and the re-confirmation was not
obtained, so the group is withheld behind a `TODO(pouya)`. OCNI already
lapsed quietly and §4 records it as "not current, do not publish" — that is
the failure mode, and a stamp is not a renewal receipt. Re-confirm,
re-stamp §4 and `CREDENTIALS.memberships`, restore the group to
`CREDENTIAL_GROUPS`, and add `memberOf` to the Person JSON-LD
- [ ] No `TODO(pouya)` remains in any shipped page
- [ ] No matter counts, rates, dollar figures, or testimonials anywhere
- [ ] Q.Arb described as **commenced August 2026** everywhere it appears — §4's
@@ -346,6 +358,12 @@ Then invalidate `/*`.
- [ ] All internal links resolve; no orphan pages
- [ ] Sitemap generated and correct; `robots.txt` served, not 403
- [ ] Rich Results Test passes; OG previews render in LinkedIn and Slack
- [ ] **OG cards are per-page, not one portrait on all nineteen**`AGENTS.md`
Q40 / **R15**. The portrait is the decided card for `/` and `/about/`; every
other page needs the generated typed card, built at step 7 with Insights.
**This blocks cutover.** A link preview is the surface a general counsel
actually sees when a colleague pastes the URL into Teams, and the interim
makes nineteen unique titles look identical
- [ ] 404 returns a 404 status
- [ ] Security headers present (`securityheaders.com` A or better)
- [ ] **SES identities verified for sending** — confirmed 2026-08-26, re-check at cutover: `aws sesv2 get-email-identity --email-identity smlcompany.ca` and confirm `VerifiedForSendingStatus: true`
+15 -2
View File
@@ -125,8 +125,21 @@ offer tribunal-secretary work on the site.
### Other services — hourly
Early neutral evaluation, settlement counsel, dispute-system design, and
pre-dispute technical advisory: **$500 / hour**.
Early neutral evaluation, dispute-system design, and pre-dispute technical
advisory: **$500 / hour**.
**THREE services, not four. `settlement counsel` is struck and must not be
priced** — `AGENTS.md` Q42, Pouya 2026-08-27, correcting his own entry in
`docs/01`:
> "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."
A struck row exists in §4 Offerings so the decision is findable. Same treatment
as the tribunal-secretary rate above, and for a related reason: a rate on a fee
page is an offer.
### Cancellation — adopted as recommended
+180
View File
@@ -0,0 +1,180 @@
# Reference — how the Licence Appeal Tribunal actually runs its pre-hearing step
**Why this file exists.** `AGENTS.md` Q41(c) asked what `LAT pre-hearing
mediation` means as an offering. Pouya's ruling of 2026-08-27: *"'LAT pre-hearing
mediation' is imprecise and must not imply appointment by the tribunal. Verify
against LAT's own materials how its case-conference process is conducted and who
conducts it."* This is that verification, committed rather than cited, under
`CLAUDE.md`'s rule that anything a spec makes a claim about must be reachable
from the repository (R14).
---
## Provenance — read this before quoting anything below
| | |
|---|---|
| Source 1 | `https://tribunalsontario.ca/documents/lat/LAT-Rules.html`*Licence Appeal Tribunal, Animal Care Review Board and Fire Safety Commission Rules of Practice and Procedure*, effective July 21, 2023 |
| Source 2 | `https://tribunalsontario.ca/lat-aabs/application-and-hearing-process/` — LATAABS, *Application and hearing process* |
| Retrieved | **2026-08-28** |
| Method | `curl -sS -o <file> '<url>'` — HTTP **200** both; **88,429 B** (rules) and **107,996 B** (AABS page) |
| Text extraction | script/style stripped, tags stripped, entities unescaped, whitespace collapsed → **66,593** and **33,696** characters |
> ⚠️ **NO HASHES, AND THE REASON IS THE POINT.** This table carried `sha256`
> prefixes `07d9c077e41cc8bd` and `08eff9a73b683cc5`. They are removed because
> **they cannot be reproduced, and a stamp that cannot be re-checked is worse
> than no stamp** — a future reader who re-fetches and gets a different digest
> would conclude the source had changed when it had not.
>
> Found by `adversarial-reviewer`, which re-fetched both URLs and got two
> different digests, then two more on two further fetches. Cause isolated by
> diffing consecutive responses: `LAT-Rules.html` carries a per-request
> bot-detection nonce (`__uzdbm_1`, `__uzdbm_2`), and the AABS page carries
> rotating WordPress `?ver=` cache-busters. **The sha256 of these URLs is not a
> stable quantity.**
>
> What *does* reproduce, and was independently reproduced: **both byte counts
> exactly**, **all ten verbatim quotes** with their rule numbers and headings, and
> **all four term counts**. So the substance of this file is verified twice over;
> only the hashes were spurious. Same family as the `1.23:1` bounding box and the
> `timeout 60 ls` in `CLAUDE.md` — a number that looks like verification, from a
> probe nobody validated.
**Instrument check, because `CLAUDE.md` requires one.** The word counts below were
taken from the **raw fetched bytes**, not from a `WebFetch` answer. `WebFetch`
answers through a summarising model, so a "quote" it returns may be a paraphrase
— and the first pass here did return a plausible-looking Rule 14.4 quote
(*"The case conference is an important opportunity to discuss settlement"*) that
turned out to be **correct**, and a Rule 14.6 gloss that was **not** how the rule
reads. Both were then checked against the literal text. Quotes in this file are
literal; where the two disagreed the literal text won.
A second instrument note: the rules document repeats every heading in a table of
contents before the body, so a naive "find the heading" extraction returns the
**TOC** and reports the rules as empty. The bodies are present, ~35 KB further in.
---
## Finding 1 — the LAT's settlement step is a *case conference*, and a Tribunal Member conducts it
**Rule 2.4, verbatim:**
> "Case Conference" has the same meaning as "Pre-Hearing Conference" as defined
> in the SPPA.
So **"pre-hearing" is the LAT's own term, and what it names is a case
conference** — not a mediation.
**Rule 14.2 — Scope of case conference subject matter, verbatim opening:**
> The Tribunal may on its own initiative, or in response to a party's written
> request, direct the parties to participate in a case conference to consider:
> The settlement of any or all of the issues; […]
**Rule 14.3 — Member not to participate on a hearing panel, verbatim:**
> A Member who presides at or otherwise takes part in a case conference shall not
> participate as a Member of a panel at a subsequent hearing of the appeal except
> with the consent of the parties.
**Rule 14.4 — Settlement discussions, verbatim:**
> The case conference is an important opportunity to discuss settlement of the
> issues without the need for a hearing. The parties are expected to come to the
> case conference prepared to discuss settlement.
>
> All settlement discussions in a case conference and the documents put forward
> solely for the purpose of settlement are confidential. Settlement discussions
> are held on a "without prejudice" basis. Settlement discussions shall not be
> communicated to the Member that participates in the hearing or otherwise be
> relied on in a hearing before the Tribunal for any purpose unless the parties
> consent.
**Rule 14.6 — Party attendance, verbatim first sentence:**
> A party as defined under Rule 2.16 must attend their case conference.
**Rule 12 — Format, verbatim:**
> In accordance with applicable provisions of the SPPA, the Tribunal may hold a
> hearing or case conference in any of the following formats, as it considers
> appropriate: In-person; Electronic; Written; or Any combination of the above.
The public LATAABS page adds, of the same step: *"A case conference is led by an
adjudicator whose role is to guide and support the parties in working to resolve
the dispute."*
**Consequence:** the neutral in the LAT's pre-hearing step is a **Member /
adjudicator of the Tribunal**. It is directed by the Tribunal, attendance is
mandatory, and the Member is disqualified from the subsequent hearing panel. A
privately retained neutral is not appointed to it and cannot be.
## Finding 2 — the LAT Rules never use the words "mediation", "mediator" or "arbitration"
Counted on the literal extracted text, case-sensitively for both cases:
```
lat-rules.html 66,593 chars 'mediat' 0 'Mediat' 0 'arbitrat' 0 'Arbitrat' 0
lat-aabs.html 33,696 chars 'mediat' 1 'Mediat' 0 'arbitrat' 0 'Arbitrat' 0
```
**Zero** in the Rules. There is no rule providing for the Tribunal to appoint an
external mediator, and no rule about a party retaining a private neutral —
because the Rules do not contemplate the concept at all.
## Finding 3 — the single match, read rather than counted
`CLAUDE.md`: *a grep that matches is not a finding until you read what it
matched.* The one `mediat` on the AABS page, printed with its heading, is this —
and it is the affirmative basis for the offering rather than a problem for it:
> **4. Consider other ways to resolve your dispute**
>
> Before you apply to the LATAABS, you may want to consider negotiation or
> mediation services. Parties are encouraged to attempt to negotiate the claim
> at all times, including before filing at the LATAABS, and continuing
> negotiation discussions after a claim has been filed.
The Tribunal itself points parties at private mediation, **before filing and
continuing after filing.** That is exactly the space a privately retained
mediator occupies, and it is the Tribunal's own words for it.
---
## What this establishes, and what it does not
**Establishes:**
1. The LAT's pre-hearing settlement step is a **case conference conducted by a
Tribunal Member**. `LAT pre-hearing mediation` therefore describes a thing
that does not exist, and the half a reader would recognise — *pre-hearing*
is the Tribunal's own label for a step nobody outside the Tribunal conducts.
2. Private mediation of accident-benefits and SABS disputes is **compatible with
a LAT application, before filing or after**, and the Tribunal says so.
**Does not establish:**
- Anything about whether Pouya holds a roster position with the LAT or Tribunals
Ontario. Nothing here bears on that. §4 has no such row, so the site claims
none — per Pouya's ruling: *"If Pouya holds a roster position that makes more
than that true, it is a §4 addition — absent a row, it isn't."*
- Anything about *commercial* arbitration gating. Same caution as
`ontario-family-arbitration-training.md`: a source about one process is not
authority about another. These documents do not mention arbitration at all.
## The wording that follows from it
**Never publish** `LAT pre-hearing mediation`, or any phrasing in which a LAT
proceeding appears to appoint or host the mediator.
**Published instead**`src/data/site.ts`, `PRACTICE_AREAS``insurance`:
> Accident benefits and SABS entitlement, MIG disputes, and private mediation
> alongside a LAT application, before filing or after.
`docs/01` keeps `LAT pre-hearing mediation` as a **search intent** — people do
type it — with a note that it must never be lifted into copy. That lift is
exactly what happened once already.
`/practice/insurance/` at build step 5 must state that the mediation offered is
**private**, retained by the parties, and **not the Tribunal's case conference**.
+97
View File
@@ -0,0 +1,97 @@
---
/**
* The conversion band — maroon ground, one heading, one CTA. `docs/01` puts it
* at the foot of `/` (item 8) and it belongs at the foot of every page that
* wants an appointment enquiry.
*
* EXTRACTED 2026-08-28 ON `adversarial-reviewer`'S FINDING, and the finding was
* not "this is duplicated" but "this is duplicated AND HAS ALREADY DRIFTED."
* `/` and `/about/` carried identical markup and ~20 identical lines of CSS,
* except `.contact-body` — `52ch` on `/`, `46ch` plus a `line-height` on
* `/about/`. Two call sites, one already divergent, seventeen pages to come.
*
* NO PROPS AND NO SLOTS AT ALL, AND THAT IS A CORRECTION MADE ON REVIEW.
* This shipped with `eyebrow?`, `cta?` and a named `heading` slot, all
* defaulted, and **not one of the two call sites overrode any of them** — the
* exact pattern this repo has already deleted twice with the reasons written
* into the source: `Eyebrow.astro` (*"`tag?: 'p' | 'span'` had zero call sites,
* so its `<span>` branch was unreachable code"*) and `SectionHeading` (*"two
* mechanisms for one job… One way in."*). The header even argued against
* `title`/`body` props and then added `eyebrow`/`cta`. Strings are inlined; add
* a prop when a second call site actually needs one.
*
* The empty `Props` guard stays, though, and it is not decoration: without it
* an Astro component's props widen to `any` and `<ContactBand class="x" />`
* compiles clean while matching nothing — the parent-scope defect `CLAUDE.md`
* records four times, and the one `Pill` was caught by. Verified by probe.
*
* THE `<h2>` IS FIXED AT LEVEL 2 rather than taken as a prop. Every page that
* uses this band has an `<h1>` of its own and top-level sections at `<h2>`, so a
* configurable level here is a way to skip a heading level by accident. If a
* page ever needs otherwise, that is a spec question, not a prop.
*
* `CONTACT.responseTime` is rendered from the constant, never typed: §4 records
* it as **a public commitment** that *"must read identically on `/contact/`, in
* the inquirer confirmation email, and in any bio."*
*/
import Button from './Button.astro';
import Eyebrow from './Eyebrow.astro';
import { CONTACT } from '../data/site';
interface Props {
children?: unknown;
}
const _props: Props = Astro.props;
void _props;
---
{
/* NO BOOKING LINK, and that is not an omission: booking is parked
(AGENTS.md R6) and `CONTACT.bookingUrl` is null, so `/contact/` ships the
intake form with a reserved slot for an embed. Stated rather than silently
dropped, on every page that renders this band. */
}
<section class="section section-accent contact-band">
<div class="wrap contact-inner">
<div class="contact-copy">
<Eyebrow dot>Next step</Eyebrow>
<h2 class="display contact-h">Start with a call.</h2>
<p class="contact-body">
Tell me the shape of the matter and who is involved, and I will tell you
whether I am the right neutral for it. {CONTACT.responseTime}
</p>
</div>
<div class="contact-action">
<Button href="/contact/" variant="gold"
>Request a consultation &rarr;</Button
>
</div>
</div>
</section>
<style>
.contact-inner {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: var(--space-6);
}
.contact-h {
margin-block: var(--space-4) var(--space-4);
font-size: var(--text-4xl);
}
.contact-body {
/* 52ch, which is `/`'s value. The two call sites had drifted to 52ch and
46ch; 52 is the one that shipped first and was reviewed. */
max-inline-size: 52ch;
line-height: var(--leading-body);
}
.contact-action {
/* `0 1 auto` + `min-inline-size: 0`, NOT `flex: none`. `none` is `0 0 auto`,
which refuses to shrink below max-content and pushed the band into
overflow at 320px. This lets the button wrap instead. Measured on `/`. */
flex: 0 1 auto;
min-inline-size: 0;
}
</style>
+64 -5
View File
@@ -15,11 +15,53 @@
* :global(), no wrapper div, and no rule that silently does nothing.
*/
/**
* No props. A `class?: string` was declared and never passed, and a parent
* cannot reach this root regardless — see SectionHeading for the measurement
* and CLAUDE.md for the rule. The custom-property hooks below are how an
* ancestor influences it.
* NO PROPS — AND THE EMPTY `Props` INTERFACE IS LOAD-BEARING, NOT DECORATION.
*
* A `class?: string` was declared here once, was never passed, and a parent
* cannot reach this root regardless — see SectionHeading for the measurement and
* CLAUDE.md for the rule. It was deleted, and the deletion was written up as
* "passing one is now a build error". **It was not.** With frontmatter
* containing only comments, an Astro component's props widen to `any`, so
* `<Pill class="chip">` compiled with **zero** errors, matched nothing, and let
* the flex or grid child absorb the difference — silently.
*
* Measured by probe page, `<Eyebrow class>`, `<Pill class>`,
* `<SectionHeading class>`, `<Button bogus>`: `astro check` reported **3 errors
* — Eyebrow, SectionHeading, Button. Nothing for Pill.** Adding the three lines
* below takes the same probe to **4 errors, 0 hints** (and no `ts(6196)`,
* because the interface is referenced by the destructure below).
*
* CLAUDE.md names `Pill` as the next place the parent-scope defect will happen.
* The guard that was documented as protecting it was absent on exactly it.
*
* The custom-property hooks in the style block are how an ancestor influences
* this component: custom properties inherit, which is the one mechanism that
* legitimately crosses the boundary.
*/
/**
* `children` DECLARED, NOTHING ELSE. Getting to this line took two wrong turns
* and both are worth recording, because each looked correct:
*
* - `interface Props {}` — rejected by eslint
* (`@typescript-eslint/no-empty-object-type`), and it would have been the
* wrong tool anyway: `{}` in TypeScript means "any non-nullish value", not
* "no properties".
* - `Record<string, never>` — passes eslint and does reject `class`, but it
* also rejects `children`, so it broke the two REAL call sites
* (`PracticeCard.astro:34` and `/about/`'s arc) while the probe page went
* green on the thing it was testing. A fix that satisfies its own test and
* breaks production is exactly what `/build` Phase 4 warns about.
*
* Slot content arrives as `children`, so `children` is the one permitted
* property and every other prop is an error. Verified by probe: all six
* components now reject `class`, and `<Pill>text</Pill>` compiles. Deleting
* this re-disables checking at every call site.
*/
interface Props {
children?: unknown;
}
const _props: Props = Astro.props;
void _props;
---
<span class="pill"><slot /></span>
@@ -39,6 +81,23 @@
line-height: 1.4;
text-transform: uppercase;
color: var(--pill-fg, var(--text-meta));
white-space: nowrap;
/* `nowrap` UNTIL 2026-08-28, AND IT WAS FINE UNTIL A PILL HAD FOUR WORDS.
`/`'s six pills are one or two words (longest "Cross-cultural").
`/about/` ships `Commenced August 2026`, and at a 200% DEFAULT FONT SIZE
(root 32px — a real browser setting, not page zoom) that pill measured
382.6px wide with its right edge at 430.6 in a 390px viewport:
**41px of document overflow at 390, 111px at 320.** Injecting
`white-space: normal` took 390 to **0** and 320 to **63**, 63 being the
header residual docs/02 already accepts. WCAG 1.4.10 Reflow.
`normal` costs nothing at default size — a pill only wraps when it cannot
fit, which is exactly when wrapping is the right answer.
WHAT IT LOOKS LIKE AT THE EXTREME, recorded so it is not later read as a
new bug: at 320px with root at 32px, `Commenced August 2026` renders
**224 x 119px** inside `border-radius: 999px` — a three-line stadium. It
is ungainly and it is legible, in-viewport, and the alternative was
111px of document overflow. */
white-space: normal;
}
</style>
+44
View File
@@ -139,3 +139,47 @@ export function homeGraph(imageUrl?: string) {
'@graph': [professionalServiceNode(imageUrl), personNode(imageUrl)],
};
}
/**
* `/about/`'s graph — build step 3. This is where PERSON_ID actually resolves:
* every other page references `/about/#person`, and until now nothing served it
* from that URL.
*
* ONE NODE, AND THREE ADDITIONS WERE CONSIDERED AND DECLINED. Each is a
* decision rather than an omission, recorded so the next reader does not
* "complete" it:
*
* 1. `ProfilePage` as a wrapper, with `mainEntity` → Person. Accurate, and
* Google documents it. Declined: docs/04's structured-data table lists
* `Person` for this page and does not list `ProfilePage`, and a type not in
* the spec is a deviation that needs a reason. The marginal gain is not
* one. Revisit in docs/04, not here.
* 2. `BreadcrumbList`. docs/04 requires it on "all nested pages" and says it
* must MATCH VISIBLE BREADCRUMBS. `/about/` is one hop from the root, has
* no visible breadcrumb, and the header nav marks it as current — so
* emitting one would assert a navigation structure the page does not show.
* Breadcrumbs begin at the two-level pages: `/practice/<area>/`, `/insights/<slug>/`.
* 3. `memberOf` for the four memberships. Declined on R10 / **Q44** — and
* the visible page reached the same answer one round later, which is worth
* recording: `/about/` now publishes **no memberships group at all**,
* because R10 is a prohibition on shipping such a page and the
* re-confirmation was not obtained. So this field is not a stricter
* standard than the page; it is the same one.
*
* Two earlier versions of this comment were wrong on the facts. They said
* "the page publishes them visibly" (it does not, as of 2026-08-28) and
* "all four renew yearly" — §4 records yearly renewal for **the OBA
* sections and the CTF only** and says nothing about ADRIC or ADRIO. The
* widened form had propagated to four files.
*
* The reason a machine-readable membership claim is worse than a visible
* one stands regardless: a list on a page is corrected by editing the page,
* while a scraped claim is cached and re-served by systems that never
* re-read it. OCNI lapsed quietly once already. Add this when Q44 closes.
*/
export function aboutGraph(imageUrl?: string) {
return {
'@context': 'https://schema.org',
'@graph': [personNode(imageUrl)],
};
}
+124 -19
View File
@@ -56,12 +56,31 @@ export const CREDENTIALS = {
'Stitt Feld Handy — negotiation and ADR workshop series',
],
languages: ['English', 'Farsi'],
/** [verified 2026-08-26 — Pouya, AGENTS.md Q28 and the CTF addition of the
* same date] — and FOR NOW. Both the OBA sections and the Canadian Tax
* Foundation renew yearly, so every line below is a fact with a shelf life
* (AGENTS.md R10). Re-confirm at renewal, and before any page that lists
* memberships ships. NOT OCNI (lapsed) and NOT the Law Society — listing the
* LSO implies licensure, which D13 bars. Do not add either. */
/**
* [verified 2026-08-26 — Pouya, AGENTS.md Q28 and the CTF addition of the same
* date] — and FOR NOW.
*
* WHAT §4 ACTUALLY SAYS ABOUT RENEWAL, because a widened version of it reached
* a public page. §4: *"Both the OBA sections and the CTF renew yearly."* It
* says **nothing** about ADRIC's or ADRIO's renewal period. An earlier form of
* this comment read "Both the OBA sections and the Canadian Tax Foundation
* renew yearly, so every line below is a fact with a shelf life", which is two
* claims joined by a "so" that does not follow — and the widened form
* ("all four renew annually") then propagated into `schema.ts`, into
* `/about/`, and into §9 Q44. Exactly the SES-DKIM duplication shape: the copy
* that goes stale is the one nobody re-reads, and this copy became public copy.
*
* **NOT PUBLISHED AS OF 2026-08-28 — R10 / Q44.** R10 requires a
* re-confirmation *"before any page listing memberships ships"*, `/about/` is
* that page, and the re-confirmation is a fact only Pouya holds. It was not
* obtained, so `/about/` ships its Credentials section WITHOUT a memberships
* group and carries a `TODO(pouya)`. Do not render this array on a public page
* until Q44 closes.
*
* NOT OCNI (lapsed — §4: "not current, do not publish") and NOT the Law
* Society: listing the LSO implies licensure, which D13 bars. Do not add
* either.
*/
memberships: [
'ADR Institute of Canada (ADRIC)',
'ADR Institute of Ontario (ADRIO)',
@@ -114,6 +133,33 @@ export const ROLE = {
],
} as const;
/**
* THE Q41(a) SENTENCE. It lives here for the reason `ROLE` above lives here:
* *"these are the two where the wording IS the compliance."*
*
* It was hand-typed into `/` and then into `/about/`, and **the two copies had
* already diverged** — `/` used a comma ("one side, a working engineering
* practice on the other"), `/about/` used full stops — within the same session
* that wrote both. This is the sentence Q41(a) makes responsible for making the
* licence implication *"impossible rather than merely absent"*, so a silent
* divergence in it is the highest-consequence drift on the site.
*
* Pouya's ruling, 2026-08-27, kept because it is the finding rather than the fix:
*
* "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 is only half of it — a reader supplies the missing
* symmetry from silence, and for the legal half the missing half is a licence.
* Naming that half **training** is what forecloses it. Do not tidy this into a
* parallel, do not shorten it to fit a layout, and do not retype it into a page.
*/
export const ASYMMETRY_LINE =
'The two halves are not the same kind of thing, and the asymmetry is the ' +
'honest part. A law degree on one side. A working engineering practice on ' +
'the other. One is training I hold. The other is work I still do.';
/** The three credential slots. Never matter counts — AGENTS.md §4. */
export const CREDENTIAL_ROW = [
{ value: 'Q.Med', label: 'ADRIC / ADRIO designation' },
@@ -233,7 +279,15 @@ export const FEES = {
documentsOnlyComplex: 9500, // flat
// No tribunal-secretary rate — removed by Pouya 2026-08-26.
},
// ENE, settlement counsel, dispute-system design, pre-dispute technical advisory
/**
* THREE services at this rate, not four. Q42 CLOSED 2026-08-27 by Pouya:
* early neutral evaluation, dispute-system design, and pre-dispute technical
* advisory each gained a §4 Offerings row; **settlement counsel was REMOVED**
* — his words: *"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."* Do not restore
* it, and do not price it.
*/
hourly: 500, // [verified 2026-08-26]
cancellation: [
{ window: 'More than 30 days before', fee: 'No fee. Disbursements only.' },
@@ -313,19 +367,38 @@ export const PRACTICE_AREAS = [
name: 'Insurance, SABS & LAT',
chip: 'Insurance',
/**
* "LAT pre-hearing mediation" was flagged by `claims-auditor` 2026-08-27:
* `docs/01` §`/practice/insurance/` lists that phrase as a SEARCH INTENT,
* not as an offering, and as a service blurb it reads as conducting
* mediation inside the LAT's own statutory process — which is not what a
* privately retained neutral is appointed to do.
* Q41(c) CLOSED 2026-08-27 — and the verification changed the wording again.
*
* Reworded to the offering that is actually rowed in §4 (mediation) applied
* to the subject matter that is actually verified (insurance / SABS).
* Q41 asks Pouya to confirm the intent before the page ships at step 5.
* `LAT pre-hearing mediation` (a SEARCH INTENT in `docs/01`, never an
* offering) must never be published. Pouya's ruling: *"imprecise and must
* not imply appointment by the tribunal. Verify against LAT's own materials
* how its case-conference process is conducted and who conducts it."*
*
* Verified 2026-08-28 against the LAT Rules and the LAT-AABS process page,
* both extracted into `docs/reference/lat-case-conference.md`:
*
* - Rule 2.4: *"'Case Conference' has the same meaning as 'Pre-Hearing
* Conference' as defined in the SPPA."* **"Pre-hearing" is the
* Tribunal's own label**, and what it names is a case conference.
* - Rule 14.3: a **Member** presides, and is then disqualified from the
* hearing panel. Rule 14.6: parties must attend. The neutral is the
* Tribunal's, and a privately retained one cannot be appointed to it.
* - The Rules contain **zero** occurrences of `mediat` or `arbitrat`
* (0 in 66,593 characters). The concept is not in them.
*
* The interim read "private mediation of matters before the LAT", which is
* ambiguous in the one word that matters: `before` reads as *pending at* as
* easily as *prior to*. Replaced with the temporal frame the Tribunal's own
* page endorses — *"you may want to consider negotiation or mediation
* services... before filing at the LAT-AABS, and continuing... after a
* claim has been filed."*
*
* `/practice/insurance/` at step 5 must say the mediation is PRIVATE and is
* not the Tribunal's case conference.
*/
blurb:
'Accident benefits and SABS entitlement, MIG disputes, and private ' +
'mediation of matters before the LAT.',
'mediation alongside a LAT application, before filing or after.',
},
{
slug: 'shareholder',
@@ -392,9 +465,25 @@ export type _SlugCoverage = _AssertNever<_SlugsWithoutAnArea>;
*
* TIMINGS ARE `docs/01` §`/process/`'s, verbatim: "confidential intake (day 0) ·
* engagement and framing (17) · pre-session exchange (721) · the session
* (2130) · binding conclusion (30+)". `docs/03` §Process requires them REAL
* rather than illustrative, so they are not softened to "typically" — and they
* are not invented either. **They have no §4 row; that is Q43.**
* (2130) · binding conclusion (30+)".
*
* **Q43 CLOSED 2026-08-27, and the ruling went the other way from this
* comment's previous reasoning.** It read: *"`docs/03` §Process requires them
* REAL rather than illustrative, so they are not softened to 'typically'."*
* Pouya ruled that the five timings are **service commitments, the same class
* as Q27's response time** — not facts about him, so they need framing rather
* than 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."
*
* The NUMBERS ARE UNCHANGED — softening was never the fix, and inventing them
* was never on. What changed is that they now ship with `PROCESS_FRAMING`
* below, which is **not optional**: any page rendering these steps renders it
* too. `docs/03` §Process has been amended to record the override.
*
* Step 5 is labelled from the spec but its body says what actually concludes —
* minutes of settlement in a mediation, an award where the process is arbitral.
@@ -435,6 +524,22 @@ export const PROCESS = [
},
] as const;
/**
* THE FRAMING THAT MAKES THE TIMINGS PUBLISHABLE — Q43, Pouya 2026-08-27.
*
* Not decoration and not a disclaimer bolted on: it is the condition on which
* the five numbers above may appear at all. *"Published as typical, they are
* honest and useful; published as commitments, the first matter that slips
* makes the page false."*
*
* RENDER IT ADJACENT TO THE STEPS, on every page that renders them — `/` now,
* `/process/` at step 6. A reader who sees `Days 2130` and not this sentence
* has read a commitment. First person, per `docs/03` §Voice.
*/
export const PROCESS_FRAMING =
'This is the typical shape of an engagement, not a commitment. Timing ' +
'depends on party and counsel availability, which I do not control.';
/** Seven items is the ceiling before a nav stops being scannable. */
export const PRIMARY_NAV = [
{ href: '/about/', label: 'About' },
+40 -9
View File
@@ -13,17 +13,44 @@ import SiteHeader from '../components/SiteHeader.astro';
import SiteFooter from '../components/SiteFooter.astro';
import { SITE } from '../data/site';
export type Props = SeoProps;
/**
* `preloadSerifItalic` — OPT-IN, AND IT IS A PER-PAGE DECISION SITTING IN A
* SHARED LAYOUT, WHICH IS WHY IT NEEDED A PROP.
*
* The italic face is preloaded because `/`'s `<h1>` contains
* `<em class="it">the room</em>` and a serif-to-fallback swap inside a 96px
* headline moves the whole last line. That reasoning is `/`-specific and the
* preload was unconditional.
*
* Measured on `/about/` (resource timing, cache disabled, 390x844 DPR 2):
* `instrument-serif-latin-400-italic.woff2` fetched as a `link` at **22,428 B**,
* while an enumeration of every element's computed `fontFamily|fontStyle` on
* that page returns `Instrument Serif|normal`, `Geist|normal`,
* `Geist Mono|normal`, `Geist|italic` — **no `Instrument Serif|italic`.** Total
* page transfer is ~162 KB, so it was ~14% of the page, preloaded ahead of the
* faces that actually render.
*
* OPT-IN RATHER THAN OPT-OUT: forgetting to opt in costs one line of reflow on a
* page that has an italic headline; forgetting to opt out costs 22 KB on the
* critical path of a page that does not. Fifteen pages remain, so the default
* is the one whose failure is cosmetic. docs/02 allows one italic phrase per
* headline, so set it wherever a headline uses `.it`.
*/
export type Props = SeoProps & { preloadSerifItalic?: boolean };
// SITE.locale is `en_CA` — Open Graph's underscore form. The lang attribute
// takes the BCP 47 hyphen form. One source, two spellings, no second constant.
const lang = SITE.locale.replace('_', '-');
// Destructured OFF the props before the spread below, so it does not reach
// <SEO>, which would reject it.
const { preloadSerifItalic = false, ...seo } = Astro.props;
---
<!doctype html>
<html lang={lang}>
<head>
<SEO {...Astro.props} />
<SEO {...seo} />
{
/* No SVG favicon. The mark is a shaded ribbon, not flat vector paths, so
@@ -74,13 +101,17 @@ const lang = SITE.locale.replace('_', '-');
type="font/woff2"
crossorigin
/>
<link
rel="preload"
href="/fonts/instrument-serif-latin-400-italic.woff2?v=1"
as="font"
type="font/woff2"
crossorigin
/>
{
preloadSerifItalic && (
<link
rel="preload"
href="/fonts/instrument-serif-latin-400-italic.woff2?v=1"
as="font"
type="font/woff2"
crossorigin
/>
)
}
{
/* No script tag. Not "no framework", not "minimal JS" — none.
+971
View File
@@ -0,0 +1,971 @@
---
/**
* `/about/` — Biography and credentials. Build step 3 (docs/01 §Build order):
* "the credential spine everything else references."
*
* JOB (docs/01 §`/about/`): "be the page an appointing body or opposing counsel
* reads before agreeing to an appointment. This page carries the verifiable
* record."
*
* SECTIONS, against docs/01's seven-item outline:
* 1 Portrait, name, designation line → the hero
* 2 Narrative biography, 400600 words → §Background
* 3 Credentials, structured → §Credentials
* 4 The credentialing arc → §The arc
* 5 Languages and cross-cultural → §Language
* 6 Speaking and publications → OMITTED, per the spec itself
* 7 Person JSON-LD + PDF bio → JSON-LD ships; the PDF does not
*
* ITEM 6 IS OMITTED ON THE SPEC'S OWN INSTRUCTION, not by oversight: "Omit the
* section entirely until there is something in it. An empty 'Speaking' heading
* is worse than no heading." Nothing to list.
*
* ITEM 7'S PDF IS NOT SHIPPED, and the omission is stated rather than silent —
* AGENTS.md Q45. No such file exists, and a link to a missing file on the page
* an appointing body reads is worse than its absence. It is also not a
* formatting job: a one-page bio is a credential document circulated DETACHED
* from the site, where no build and no reviewer ever re-checks it. Two
* decisions there are Pouya's.
*
* THE PARENT/CHILD SCOPE TRAP, because this page uses <SectionHeading> four
* times. A parent CANNOT style a child component's root element — the rule
* compiles against the parent's cid and silently never matches. Every heading
* below is wrapped in a page-owned <div class="section-head">. Not defensive
* boilerplate: it is the fourth-instance defect CLAUDE.md records, and the
* components have had their `class` props deleted so passing one is a build
* error rather than a silent no-op.
*
* R10 / Q44 — THE MEMBERSHIPS GROUP IS NOT ON THIS PAGE. R10 is written as a
* prohibition — re-confirm *before* any page listing memberships ships — and
* `/about/` is the page it names. The re-confirmation is a fact only Pouya holds
* and was not obtained, so the group is withheld and a `TODO(pouya)` sits on
* CREDENTIAL_GROUPS below with the exact question. §4 is NOT re-stamped:
* nothing was re-checked. Q44.
*
* A first version of this page published all four and disclosed the gap instead.
* Both review agents rejected that; the reasoning is on CREDENTIAL_GROUPS.
*/
import { Picture, getImage } from 'astro:assets';
import BaseLayout from '../layouts/BaseLayout.astro';
import ContactBand from '../components/ContactBand.astro';
import Eyebrow from '../components/Eyebrow.astro';
import Pill from '../components/Pill.astro';
import SectionHeading from '../components/SectionHeading.astro';
import portrait from '../assets/pouya-lajevardi.jpg';
import ogDefault from '../assets/og-portrait.jpg';
import { aboutGraph } from '../data/schema';
import {
ASYMMETRY_LINE,
CREDENTIALS,
PORTRAIT,
ROLE,
SITE,
} from '../data/site';
/**
* `image` ON THE Person NODE — docs/04 lists it, and this page is where
* PERSON_ID (`/about/#person`) actually resolves.
*
* AN EARLIER VERSION OF THIS PAGE OMITTED IT and argued at length that it could
* not be supplied: "SEO.astro computes that URL internally and does not expose
* it." That reasoning talked itself into the wrong answer — the URL does not
* have to come from SEO.astro. `/` derives it in six lines with `getImage()`,
* and the same six lines work here. The result was two documents asserting the
* same `@id` with different property sets, which is worse than either choice
* made deliberately.
*
* EXACTLY the transform SEO.astro applies to the same source (jpeg, 1200x630),
* so Astro's asset cache returns the same hashed file rather than emitting a
* second copy for the crawler. JPEG on purpose: link-preview and structured-data
* consumers are not browsers and several still do not decode WebP, let alone
* AVIF.
*
* The withdrawn reasoning follows, because it is a good example of a comment
* arguing for a defect.
*
* NO `getImage()` CALL FOR THE JSON-LD IMAGE, unlike `/`.
*
* `/` generates the 1200x630 jpeg so the Person node can carry an absolute
* `image` URL, and it works because that page renders the ProfessionalService
* node too. Here the Person node is the whole graph, and SEO.astro already emits
* exactly the same transform of exactly the same source as `og:image`. Calling
* `getImage()` again would return the same cached asset — so this is not about
* duplicate files, it is about a second place that has to be kept in step with
* SEO.astro's transform. It is passed the URL by the layout instead.
*
* Except it cannot be: `SEO.astro` computes that URL internally and does not
* expose it. So the node ships WITHOUT `image` on this page and WITH it on `/`,
* which is a real inconsistency in a field docs/04 lists for the Person node.
* Both resolve to the same @id, so a crawler joining the two documents gets the
* image either way — but that is a hope about crawler behaviour, not a fact.
* Recorded rather than papered over; the fix is for SEO.astro to expose the URL
* it already computes, which is a component change and not a page change.
*/
const ldImage = await getImage({
src: ogDefault,
format: 'jpeg',
width: 1200,
height: 630,
});
const graph = aboutGraph(new URL(ldImage.src, Astro.site).href);
/**
* The designation line — docs/01 item 1. Assembled from constants so it cannot
* drift from §4, and ordered held-first.
*
* Q.Arb IS NOT IN IT, deliberately. It is not held (§4: "Describe as newly
* commenced, never as held or nearing completion"), and a designation line is
* precisely a list of things held. The arc section states the stage plainly,
* which is what §4's paired-disclosure condition requires — this page offers
* arbitration, so the stage appears on this page and not only in the footer.
*/
const designationLine = [
'Mediator',
CREDENTIALS.designations[0],
CREDENTIALS.education[0],
];
/**
* The credentialing arc — docs/01 item 4, and docs/03: "the credentialing
* pathway from Q.Med through Q.Arb to C.Med-Arb is stated openly as in
* progress. The brief treats that arc as part of the story rather than
* something to obscure."
*
* `state` is the load-bearing column. "Commenced August 2026" is §4's exact
* wording and the ONLY permitted wording — docs/03: not "in progress", because
* the weaker form drifts toward "nearly complete", which §4 Forbidden bars
* outright.
*/
/*
* FIVE CLAIMS CAME OUT OF THIS BLOCK, and the first was the worst thing in the
* step-3 diff. BOTH review agents found it independently, which is the strongest
* signal this loop produces.
*
* 1. ⚠️ "arbitral appointments are not gated behind it, which is why I accept
* them now" — **the false universal Q39 struck, on a public page.**
* Unscoped ("arbitral", not commercial), asserted as flat fact in the first
* person, and it publishes a proposition of Ontario law that §4 holds only
* in scoped form and deliberately does NOT stamp `[verified]`. Family
* arbitration is an arbitral appointment and it IS gated
* (`docs/reference/ontario-family-arbitration-training.md`). Q39 swept
* three instances of this universal on 2026-08-27; this was the fourth and
* the first outside a comment. §4 requires the STAGE be stated — never the
* register's gating rationale. Deleted rather than rescoped: this page has
* no business carrying the argument at all.
* 2. "on the same institutional pathway" and
* 3. "Three designations on one institutional pathway" (the section lede) —
* §4 attaches ADRIC / ADRIO to **Q.Med only**. Neither the Q.Arb row nor
* the C.Med-Arb row names a body.
* 4. "The senior hybrid designation" — a ranking claim about a third party's
* credential structure, with no row and no source.
* 5. The expansions — "Qualified Mediator", "Qualified Arbitrator",
* "Chartered Mediator-Arbitrator". Flagged as being in §11 Glossary but
* not in §4 Verified.
*
* ⚠️ ITEM 5 WAS REMOVED AND IS NOW RESTORED, AND IT IS THE ONE PLACE THIS
* SESSION WENT AGAINST A REVIEW FINDING. The reason is a SECOND finding, from
* the next audit pass, and it is a consistency point rather than a claim point:
* this page also publishes "Provincial Offences Act", "Statutory Accident
* Benefits Schedule" (as SABS) and "the ADR Institute of Canada and the ADR
* Institute of Ontario" — every one of them a §11 Glossary expansion, on exactly
* the ground the designation names were struck. *"One standard or the other."*
*
* The standard chosen is: **§11 Glossary is the source for DEFINITIONAL
* expansions** — what an abbreviation stands for — while §4 Verified remains the
* only source for claims ABOUT POUYA. Expanding `Q.Med` says nothing about him;
* "he holds it" is the claim, and that has a row. The alternative standard would
* have required stripping POA, SABS and the institute names from the prose and
* `recognizedBy` from the JSON-LD, which makes the page materially worse for a
* reader who does not already know the acronyms, in exchange for no reduction in
* risk. **Q46 asks Pouya to ratify that standard** and it is the only thing
* holding it up; if he declines, all four classes come out together.
*
* Sourcing them externally was tried first and failed: `adric.ca/designations/`
* redirects to `/designations-cee/` and its HTML contains **zero** occurrences
* of "Q.Med", "Qualified Mediator" or "Chartered Mediator" in 114,985 bytes —
* navigation only, body assembled client-side. So R14 cannot be met from the
* obvious URL, which is why this rests on §11 and on Q46 rather than on a
* committed extract.
*/
const ARC = [
{
name: 'Q.Med',
state: 'Held',
/* NOT "the designation I mediate under". That imported a PERMISSION framing
onto what §4 records as a voluntary credential, in a register that says
no designation is required to be appointed as a mediator — the
credential-as-licence slip §4 says produced a wrong answer twice. */
body:
'Qualified Mediator, held through the ADR Institute of Canada and the ' +
'ADR Institute of Ontario. The designation I hold as a mediator today.',
},
{
name: 'Q.Arb',
state: 'Commenced August 2026',
body:
'Qualified Arbitrator. Newly commenced — not held, and not nearing ' +
'completion.',
},
{
name: 'C.Med-Arb',
state: 'The endpoint',
body:
'Chartered Mediator-Arbitrator. The designation this practice is built ' +
'toward.',
},
];
/**
* The structured credentials — docs/01 item 3: "designations, education,
* certifications, memberships. Every line from AGENTS.md §4 Verified."
*
* LANGUAGES ARE NOT A GROUP HERE, and that is a heading decision rather than an
* omission: docs/01 item 5 gives them a section of their own, and having both
* an h3 "Languages" group and an h2 "Language" section would put the same two
* facts in the accessibility tree twice under near-identical names. The section
* wins because it carries the cross-cultural half, which a list cannot.
*
* NOT PRESENT, AND EACH IS A §4 DIRECTIVE RATHER THAN A GAP:
* - The Law Society. Listing it implies licensure, which D13 bars. §4:
* "Excluded deliberately, not by oversight."
* - OCNI. Not current (§4), so it is not published.
* - Any licence status, in either direction. §4 records it `[unestablished]`.
*
* TODO(pouya): Are ADRIC, ADRIO, the three OBA sections (Construction &
* Infrastructure, ADR, Civil Litigation) and the Canadian Tax Foundation all
* current TODAY, and in which month does each renew? — AGENTS.md Q44.
*
* ⚠️ MEMBERSHIPS ARE DELIBERATELY NOT RENDERED, AND THIS IS A REVERSAL.
*
* The first version of this page published all four on §4's 2026-08-26 stamp and
* disclosed the outstanding re-confirmation in a note, in this comment, in
* `schema.ts`, in §9 Q44 and on the cutover checklist. Both review agents
* rejected that, and they are right. §12 **R10** is written as a PROHIBITION —
* *"Re-confirm at each renewal, **and before any page listing memberships
* ships** — `/about/` at build step 3 is the first one that will"* — and
* documenting a prohibition is not discharging it. `CLAUDE.md` gives the
* procedure for a fact you do not have, and it is this one: leave
* `TODO(pouya)`, log the question, let the gap be visible. *"A build that fails
* on an unanswered question is a correct build."*
*
* The alternative was to ship them and call it disclosed. It was taken once and
* is recorded here as the decision it was, not as an oversight — and it came
* with a second defect on top: the note asserted *"Memberships are renewed
* annually and are listed as current"*, which (a) warranted currency the
* register cannot vouch for and (b) widened §4, which records yearly renewal for
* the **OBA sections and the CTF only** and says nothing about ADRIC or ADRIO.
*
* OCNI is the precedent and it is in §4: a membership lapsed, quietly, and the
* register now reads "not current, do not publish". Nothing tells you when.
*
* The other three groups ship. Restoring this one is one array entry, the moment
* Q44 closes — and re-stamp §4 and `CREDENTIALS.memberships` that day.
*/
const CREDENTIAL_GROUPS = [
{ title: 'Designations', items: CREDENTIALS.designations },
{ title: 'Education', items: CREDENTIALS.education },
{ title: 'Certifications', items: CREDENTIALS.certifications },
];
---
<BaseLayout
title="About · Pouya Lajevardi · Mediator, Q.Med · Toronto"
description="Pouya Lajevardi, JD, Q.Med — a Toronto mediator who also practises as a machine-learning and infrastructure engineer. Credentials, background, designations."
ogType="profile"
imageAlt={PORTRAIT.alt}
jsonLd={graph}
>
{/* ---- 1. Hero: portrait, name, designation line --------------------- */}
<section class="hero">
<div class="wrap hero-inner">
<div class="hero-copy">
<Eyebrow dot>About</Eyebrow>
{
/* THE H1 IS THE NAME, not a headline, and that is docs/01 item 1
("Portrait, name, designation line") agreeing with the search intent
it records for this page (`"Pouya Lajevardi"`, `Pouya Lajevardi
mediator`). The masthead carries the name as a brand mark; a bio page
needs it as the document's subject. */
}
<h1 class="display hero-h">{SITE.name}</h1>
{
/* EACH SEPARATOR IS INSIDE THE SPAN IT PRECEDES, not a sibling of it.
As siblings the flex container wrapped between them, leaving an
orphaned "·" at the end of line 1 at 390px. The NON-BREAKING SPACE
after the glyph is what keeps it attached — an earlier version used
`white-space: nowrap` on the whole item instead, which fixed the
orphan and broke reflow at a 200% default font size. */
}
<p class="designation">
{
designationLine.map((part, i) => (
<span class="designation-part">
{i > 0 && (
<span class="sep" aria-hidden="true">
{'·\u00A0'}
</span>
)}
{part}
</span>
))
}
</p>
{
/* THE ROLE LINE, and it is the single highest-risk sentence on this
page. Both strings come from `ROLE` in src/data/site.ts rather than
being typed here, for the reason that file gives: "these are the two
where the wording IS the compliance."
D13: the approved phrasing is "active litigation exposure", NEVER
"practice" in this context. The boutique is never named (D16). The
matter types are §4 verbatim and must not be extended without a row.
EXPLICITLY INTERIM — AGENTS.md R1, surfaced again 2026-08-28
precisely because this page is where the framing now does its
heaviest work. */
}
<p class="hero-lede">
I am {ROLE.title} at {ROLE.at}, with {ROLE.litigationLine} across{' '}
{ROLE.litigationAreas.slice(0, -1).join(', ')} and{' '}
{ROLE.litigationAreas.at(-1)}. I mediate commercial disputes and I
accept arbitration appointments in commercial matters; the Q.Arb
pathway commenced in August 2026. I also work as a machine-learning
and infrastructure engineer.
</p>
</div>
{
/* `widths` + `sizes` rather than `densities`, because the portrait is
fluid and a density ladder would size it from one assumed CSS width.
`width` and `height` are passed ALONGSIDE `widths` — without them Astro
declares the untouched 1600px master as the <img src> fallback, which
is the defect `/`'s comment records at 254,626 bytes.
⚠️ THIS COMMENT PREVIOUSLY MADE FOUR CLAIMS AND THREE WERE MEASURABLY
FALSE. Recorded rather than quietly replaced, because the false ones
were the confident ones.
(a) "Same ladder as `/`'s hero and the same reasoning" — true, and
that was the problem: `/`'s reasoning derived a 960 ceiling from
the TWO-COLUMN layout, which only engages at 66rem. Below 66rem
the hero is one column and the portrait is the full content
width. Measured: 592px at a 640 viewport, 672 at 768, 804 at 900,
928 at 1024 — needing 1184-1856 device px at DPR 2 against a 960
ceiling. **1.40x upscale at 768/DPR2, 1.93x at 1024/DPR2**, on
this page and on `/`. At 768/DPR1 a 760w file exists and is not
chosen, so part of the loss was purely a wrong `sizes` (52vw
declared against an ~88vw slot). Fixed two ways: `.hero-portrait`
is capped at 30rem below 66rem so the widest real slot is 480 CSS
px, which makes 960 exactly right for DPR 2; and a 1440 rung
covers DPR 3, which the ≥66rem range had also been missing
(429px x 3 = 1287 against 960).
AND THE 1440 RUNG OVERSHOT, SO 1080 EXISTS TO CORRECT IT. Adding 1440
for DPR 3 removed a 1.07x upscale at 390/DPR3 and replaced it with a
**48,799 B fetch where the old one was 21,526 B** — +27 KB on a phone,
to fix a 7% softness nobody can see. A browser takes the smallest
candidate at or above what it needs, and with no rung between 960 and
1440 the only choices were "slightly soft" or "+27 KB". 1080 makes
1026 (390 x DPR 3) exact and cheap. This was a defect in the fix for
the defect above, found by measuring the fix rather than the source.
AND 1080 ALONE MISSED THE TWO LARGEST CURRENT PHONES, WHICH
MAKES THIS THE THIRD ITERATION OF THIS LADDER. 1080 was tuned to
390 CSS px x DPR 3 (= 1026), and `sizes` resolves to
`calc(100vw - 3rem)` up to 528px, so every phone wider than 390
overshoots to the next rung: iPhone 14 Plus (428@3, needs 1140)
and 15/16 Pro Max (430@3, needs 1146) both took **1440 —
48,799 B**, against 27,594 for the device the rung was tuned
for. +21,205 B, 13% of page weight. A 1200 rung closes it at
1.05x. Measured after: no rung more than 1.06x oversized on the
phone axis, and still no upscaling anywhere.
(b) "The LCP element on this page is the <h1>" — **false.**
`PerformanceObserver` at 1280x900: LCP element is
`IMG.portrait-img`, size 229,679; the <h1> box is 51,484, 4.5x
smaller. So the portrait IS the LCP element at desktop widths.
(c) "two words of 96px serif" — **false.** `.hero-h` sets
`--text-5xl`, which computes to **76px**. 96px is `--text-6xl`,
which is what `/` uses.
(d) "above the fold at every width" — **false.** Portrait top vs
viewport height: 782 vs 568 at 320, 752 vs 640 at 360 — entirely
below the fold at both, i.e. **0 visible px** at the two widths
`docs/02` names explicitly. 120px visible at 390x844.
SO WHY IS IT STILL `eager` AND NOT `fetchpriority="high"`? Because (b)
and (d) pull in opposite directions and the split is real. Re-measured
AFTER the cap, since the cap changes the element's size and therefore
the LCP candidate (`PerformanceObserver`, cache cleared per sample):
390x844 LCP = P.hero-lede 93,411
768x1024 LCP = IMG.portrait-img 168,161
1280x900 LCP = IMG.portrait-img 229,679
So the portrait is the LCP element from **768px up** — not "~1056px
up", which is what this comment said before the cap was measured — and
at phone widths LCP is the hero lede, a font-dependent text paint the
preloaded Geist already covers. `loading` and `fetchpriority` cannot be
conditioned on viewport. `eager` serves the tablet-and-desktop LCP;
`fetchpriority="high"` is withheld because at 320-360, where the image
is entirely off-screen, it would outrank that text paint. For
reference, `/` differs at 768 (LCP = H1.display, 135,289) because its
headline is a four-line sentence rather than a two-word name. */
}
<div class="hero-portrait">
<Picture
src={portrait}
width={960}
height={960}
widths={[380, 480, 640, 760, 960, 1080, 1200, 1440]}
sizes="(min-width: 80rem) 429px, (min-width: 66rem) 33vw, (min-width: 33rem) 480px, calc(100vw - 3rem)"
formats={['avif', 'webp']}
fallbackFormat="jpeg"
alt={PORTRAIT.alt}
loading="eager"
decoding="sync"
class="portrait-img"
/>
</div>
</div>
</section>
{/* ---- 2. Narrative biography ---------------------------------------- */}
<section class="section bio reveal">
<div class="wrap">
<div class="section-head">
<SectionHeading eyebrow="Background" level={2}>
<span slot="heading">Two directions, one file.</span>
</SectionHeading>
</div>
{
/* 400600 WORDS, docs/03: "Tell the three tracks as one arc, not three
lists." Measured, not estimated — see the word-count assertion in the
verify step of this session's Change Log entry.
Q41(a) IS APPLIED THROUGHOUT AND THIS IS THE FIRST PAGE WRITTEN UNDER
IT. Pouya's ruling, 2026-08-27: the implication test reaches prose, and
prose is held to a HIGHER bar — "state the asymmetry explicitly rather
than relying on a parallel construction to carry it." So the fourth
paragraph names which half is training and which is work, in as many
words. Avoiding the noun pair "law and engineering" is not sufficient
on its own: a reader can supply the missing symmetry from silence, and
for the legal half the missing half is a licence.
EVERY CLAIM TRACES TO §4 Verified: the JD, the boutique role, active
litigation exposure and its four matter types, Q.Med, multiple
completed sole mediations, arbitration appointments (§4 Offerings,
scoped to commercial), the Q.Arb pathway commenced August 2026,
C.Med-Arb as the goal, engineering practice, SML Company Ltd, Farsi,
Iranian-Canadian. Nothing here asserts or implies licensure. */
}
<div class="prose bio-prose">
<p>
I came to dispute resolution from two directions, and I still work in
both.
</p>
<p>
The first is law. I hold a JD from Bond University, and I am{' '}
{ROLE.title} at {ROLE.at}. That role gives me {ROLE.litigationLine} — personal
injury, construction, regulatory matters under the Provincial Offences Act,
and accident benefits under the SABS. What that exposure is actually worth
in a mediation is unglamorous: I have seen how these files get built. Which
productions turn out to be thin. Where expert reports talk past each other
rather than disagree. Which issues resolve once someone puts the documents
in order, and which ones never will.
</p>
<p>
The second is engineering. I work as a machine-learning and
infrastructure engineer. That is current practice, not a former career
and not an interest: I read code, model documentation, deployment
topology, and the operational records that show what a system did
rather than what a specification said it would do.
</p>
{
/* FROM A CONSTANT — ASYMMETRY_LINE in src/data/site.ts. It was typed
here and separately on `/`, and the two copies had already diverged
(full stops here, a comma there) inside the session that wrote both.
Q41(a) makes this the sentence responsible for foreclosing the
licence implication, so it is the worst string on the site to let
drift. */
}
<p>{ASYMMETRY_LINE}</p>
<p>
Mediation is where they meet. I hold the Q.Med designation through the
ADR Institute of Canada and the ADR Institute of Ontario, and I have
completed multiple sole mediations. I accept arbitration appointments
in commercial matters — as sole arbitrator, as a party-appointed
arbitrator, and in co-arbitration. Where a matter turns on a technical
question, I read the technical material myself.
</p>
<p>
My Q.Arb pathway commenced in August 2026, and C.Med-Arb is the
designation I am working toward. I state the stage openly because an
appointing body will establish it anyway, and because a reader can do
more with the fact than with a hedge. I would rather say where I am on
the arc than leave it to be inferred.
</p>
{
/* BOTH ADDITIONS TO THIS SENTENCE CAME BACK OUT. §4 verifies exactly
one relation — *"Operator of SML Company Ltd. alongside the
practice"* — and that is now all it says.
"It is not a law firm and does not hold itself out as one" — a
negative REGULATORY statement with no row, attached to the one
§4 row carrying an express caution against being read together
with the licence row *"into an implication that neither row
makes."* Added to be helpful; it touches exactly what §4 says
not to touch.
"the company through which the engineering work is done" — a
corporate-structure claim. §4 verifies operation alongside the
practice, the jurisdiction of incorporation and the place of
business — not which work runs through which vehicle. */
}
<p>I run SML Company Ltd alongside both.</p>
<p>
I have also completed the Kompass Arbitration Certificate Program and
the Stitt Feld Handy negotiation and ADR workshop sequence. Neither is
a designation, and I name them precisely for that reason: process
training is the easiest thing in this field to assert loosely, so it
is worth stating exactly what it was.
</p>
{
/* THE NEUTRALITY LINE. It is a disclaimer and it earns its place:
docs/03 requires the equivalent on `/for-parties/`, and this is the
page an appointing body reads. It also states the negative of the
implication §4 Forbidden bars — "acts for clients", "represents
parties" — which is a stronger position than merely never asserting
it. Q42's reasoning is the same reasoning: Pouya struck settlement
counsel because a partisan role "undercuts the brand's central
claim". This sentence is that claim, stated.
The family-law exclusion is NOT here. Pouya scoped it to
`/practice/shareholder/` — "One sentence, not a section" — and
widening it to this page is his call, not an implementer's. */
}
{
/* THIS SENTENCE HAS NOW BEEN WRONG IN BOTH DIRECTIONS, WHICH IS WHY
THE THIRD VERSION AVOIDS THE AXIS ALTOGETHER.
"I do not give legal advice" — flagged because "do not" describes
an ELECTION, and an election implies the entitlement to choose.
"I cannot give legal advice" — flagged on the next pass because
"cannot" is a DENIAL of entitlement, and §4 on licence status
is explicit: *"Do not assert it, do not deny it, do not infer
it from anything else here."*
Both readings are correct and they point in opposite directions,
because both sentences make a claim about CAPACITY. So this one does
not: it states the ROLE and its consequence for the reader, which is
the form `docs/03` actually sanctions on `/for-parties/` (*"the
mediator is not your lawyer"* — role, not capacity) and the only one
that asserts nothing and denies nothing. The underlying question is
R1's. */
}
<p>
I act as a neutral. I do not act for a party in a matter I take, and
each party should have their own legal advice.
</p>
</div>
</div>
</section>
{/* ---- 4. The credentialing arc -------------------------------------- */}
{
/* SECTION 4 BEFORE SECTION 3, and the reorder is deliberate. docs/01 lists
credentials (item 3) then the arc (item 4). The arc is the part a reader
is likely to have a question about — it is the thing this practice is
candid about that others are not — and burying it under a scannable list
of things already held reads as a footnote to them. §4's paired-disclosure
condition also wants the stage stated where the offering is made, and the
offering is made in the narrative directly above. The list follows. */
}
<section class="section section-inverse arc-section reveal">
<div class="wrap">
<div class="section-head">
<SectionHeading
eyebrow="The arc"
level={2}
lede="Three designations. Two of them are ahead of me, and saying so is the point."
>
<span slot="heading">Where the credentials sit.</span>
</SectionHeading>
</div>
{
/* `role="list"` RESTORED, AND THE REASON I REMOVED IT WAS WRONG ABOUT
ARIA. The comment here claimed that on an <ol> the role "re-announces
an ordered list as an unordered one". It does not: **both <ul> and <ol>
map to the `list` role**, so `role="list"` on an <ol> is a no-op for
ordering, not a downgrade. What it is actually for is the WebKit
heuristic that strips list semantics from a list with
`list-style-type: none` — and `.arc` sets exactly that.
It also left the two <ol>s on this two-page site DISAGREEING, with
`/`'s `.process-strip` keeping the role. That is the state that gets
copied seventeen times.
Not verified here: whether WebKit's heuristic covers <ol> as well as
<ul>. There is no Safari instrument in this environment, so the role
stays on the precautionary side, which costs nothing. Chrome's AX tree
exposes `.arc` as `list` with three `listitem` children either way. */
}
<ol class="arc" role="list">
{
ARC.map((stage) => (
<li class="arc-item">
<h3 class="arc-name">{stage.name}</h3>
<p class="arc-state">
<Pill>{stage.state}</Pill>
</p>
<p class="arc-body">{stage.body}</p>
</li>
))
}
</ol>
</div>
</section>
{/* ---- 3. Credentials, structured ------------------------------------ */}
<section class="section section-alt creds reveal">
<div class="wrap">
<div class="section-head">
<SectionHeading eyebrow="Credentials" level={2}>
<span slot="heading">The verifiable record.</span>
</SectionHeading>
</div>
<div class="cred-grid">
{
CREDENTIAL_GROUPS.map((group) => (
<div class="cred-group">
<h3 class="cred-title">{group.title}</h3>
<ul class="cred-items" role="list">
{group.items.map((item) => (
<li>{item}</li>
))}
</ul>
</div>
))
}
</div>
{
/* THIS NOTE IS GONE, AND IT CARRIED THREE SEPARATE DEFECTS. It read:
"Memberships are renewed annually and are listed as current. Nothing
above asserts a licence to practise law, in either direction."
(a) "renewed annually" WIDENED §4, which records yearly renewal for
the OBA sections and the CTF only and says nothing about ADRIC
or ADRIO. The widened form had already propagated to four places.
(b) "listed as current" was an affirmative public WARRANTY of
currency stacked on top of an undischarged R10 — the reminder
whose entire purpose is that no such warranty be made without a
re-confirmation. The memberships group is now off the page
(Q44), so the sentence has nothing left to warrant either.
(c) "Nothing above asserts a licence to practise law, in either
direction" READS AS A DENIAL. §4 on licence status: "Do not
assert it, do not deny it, do not infer it from anything else
here." It was also the only sentence on the site that raised
licensure at all, on the page where R1 says the D13 framing is
already doing its heaviest work — and no spec asked for it.
Both review agents flagged (c) independently and escalated it to
Pouya rather than rewriting it. That is the right destination: R1. */
}
</div>
</section>
{/* ---- 5. Language and cross-cultural practice ----------------------- */}
<section class="section language reveal">
<div class="wrap">
<div class="section-head">
<SectionHeading eyebrow="Language" level={2}>
<span slot="heading">English and Farsi, without an interpreter.</span>
</SectionHeading>
</div>
{
/* §4 verifies "Bilingual English and Farsi" and "Iranian-Canadian;
cross-cultural fluency with diaspora business communities".
NO QUANTITY AND NO COMPARATIVE. An earlier draft opened "many of the
disputes I am best placed to take", which carries a count I do not
have and the token "best" — which §4 Forbidden bars as a superlative
and which a forbidden-terms sweep would flag on sight. Rewritten to a
claim about the work: some disputes are not separable from the
relationship, and this is what working in the parties' own language
changes. Nothing about other neutrals — Q41(b). */
}
<div class="prose">
<p>
I mediate in English and in Farsi. I am Iranian-Canadian, and some
commercial disputes are not separable from the relationship between
the parties — family-held companies and diaspora businesses in
particular, where the commercial disagreement and a much longer
history arrive together.
</p>
<p>
Working in the parties' own language, with no interpreter in the room,
changes what gets said and how early it gets said. It removes a layer
between a party and their own account of events.
</p>
</div>
</div>
</section>
{/* ---- Contact band --------------------------------------------------- */}
<ContactBand />
</BaseLayout>
<style>
/* --- 1. Hero -------------------------------------------------------- */
.hero {
padding-block: var(--space-8) var(--space-9);
}
.hero-inner {
display: grid;
gap: var(--space-7);
align-items: center;
}
.hero-copy {
display: flex;
flex-direction: column;
gap: var(--space-5);
}
.hero-h {
/* --text-5xl, not --text-6xl. `/`'s headline is a sentence and needs the
display ceiling; this is a two-word name, and at 96px it sets 15
characters across a line that then has nothing to balance against. */
font-size: var(--text-5xl);
/* `anywhere`, NOT `break-word`. The type scale is rem-based, so at a 200%
DEFAULT FONT SIZE this heading computes to 88px and "Lajevardi" — one
unbreakable 9-character word — is wider than the 224px content box at a
320px viewport. `break-word` permits a break at layout time but does NOT
reduce min-content size, so it would not have helped; `anywhere` does.
It has no effect at any normal size: a word only breaks when it cannot
fit. Breaking a name mid-word is ugly and it is better than a reader at
200% zoom losing the page. WCAG 1.4.4 / 1.4.10. */
overflow-wrap: anywhere;
}
.designation {
display: flex;
flex-wrap: wrap;
/* THE GAP CARRIES THE SEPARATOR'S SPACING, not a margin on .sep. The
separator is aria-hidden, so its box must not be what a sighted reader
depends on for rhythm while a screen-reader user gets nothing — with
`gap` the spacing survives the element being ignored. */
gap: var(--space-1) var(--space-3);
align-items: baseline;
font-family: var(--font-mono);
font-size: var(--text-sm);
letter-spacing: var(--tracking-tight);
color: var(--text-secondary);
}
/* NO `white-space: nowrap` — IT WAS HERE AND IT BROKE REFLOW. Gluing the whole
item together made "Q.Med (ADRIC / ADRIO)" unbreakable, and at a 200%
DEFAULT FONT SIZE that pushed this page to 108px of overflow at 320px
against `/`'s accepted 63. The separator does not need the whole item to be
unbreakable — it only needs to stay attached to the FIRST word, which the
non-breaking space in the markup does. WCAG 1.4.10. */
.designation-part {
display: inline;
}
.designation .sep {
/* NOT `var(--rule)`. Gold `#c9a876` on cream measures **2.10:1** — the one
hard constraint in `docs/02` and `tokens.css`, which say in terms that
gold is never a text colour on cream. An in-browser audit of all 100
text-bearing elements on this page returned exactly two failures and both
were this span. `aria-hidden` does not dispose of it: these separators are
the only thing dividing three credential items, and at 2.10:1 they are
invisible, so the line reads as a run-on. That is a legibility failure
before it is a rule breach. `--text-meta` measures 5.47:1 on cream and
still recedes from the 11.75:1 text beside it. */
color: var(--text-meta);
}
.hero-lede {
max-inline-size: var(--width-prose);
font-size: var(--text-lg);
line-height: var(--leading-relaxed);
color: var(--text-secondary);
}
/* `<Picture>` emits an <img> wrapped in a <picture>, and the <picture> is the
box the grid sizes — the `class` prop lands on the <img>, which is the
defect InfinityMark.astro records for its own flex sizing.
THIS COMMENT CLAIMED "the <picture> WRAPPER carries no cid, so it needs
`:global()`". **That is false.** Read from the built HTML: the emitted markup
is `<picture data-astro-cid-ta2fbyqs="true">` — Astro DOES propagate the
page's scope attribute to both elements for `astro:assets` components (it
does not for ordinary user components, which is the real rule CLAUDE.md
records). Decisive corroboration in the shipped CSS: InfinityMark's BARE
`picture` selector compiles to `picture[data-astro-cid-usztftas]` and
demonstrably works. So `:global()` was unnecessary and merely broader than
intended — it would also have matched a <picture> inside any child
component placed here. Plain selector, correct comment.
4/5 rather than 1/1 — the master is square, and 4/5 is the crop `/` uses.
One portrait treatment across the site rather than two. */
.hero-portrait {
aspect-ratio: 4 / 5;
overflow: hidden;
border-radius: var(--radius-lg);
background: var(--bg-raised);
/* THE CAP IS THE UPSCALE FIX, not a style preference — see the <Picture>
comment. Uncapped, this slot ran to 928 CSS px at a 1024px viewport, which
is 1856 device px at DPR 2 against a 960w ceiling. `margin-inline: auto`
because a 480px box in a 928px column would otherwise sit hard against
the inline start. */
max-inline-size: 30rem;
margin-inline: auto;
}
.hero-portrait picture {
display: block;
block-size: 100%;
}
.portrait-img {
inline-size: 100%;
block-size: 100%;
object-fit: cover;
/* Above centre: the head sits in the upper half of a square crop. */
object-position: 50% 22%;
}
@media (min-width: 66rem) {
.hero-portrait {
/* Released above 66rem: the grid track is already 390-476px, so the cap
is inert — and leaving it in place would silently become the constraint
if the track ever widened. The track governs here, not this number. */
max-inline-size: none;
}
.hero-inner {
/* 1fr / 0.62fr — the portrait is smaller than `/`'s 0.72 because this
hero's copy block is a name plus two short lines and the picture would
otherwise dominate a page whose subject is the text. */
grid-template-columns: 1fr 0.62fr;
gap: var(--space-8);
}
}
/* --- 2. Background --------------------------------------------------- */
/* NO `.section-head` RULE — it moved to `global.css`, where `.prose` lives.
It was byte-identical in both pages, and every one of the seventeen
remaining pages needs it for the same reason (a parent cannot style a child
component's root, so the wrapper must be page-owned). */
/* NO `> p + p` RULE HERE. It was the only paragraph-spacing rule in this
file and it is now redundant: global.css owns `.prose` paragraph spacing as
of 2026-08-28, which is what stopped §Language below from rendering its two
paragraphs as one block. Two rules setting the same property to the same
value is one rule that will eventually disagree. */
.bio-prose {
font-size: var(--text-lg);
line-height: var(--leading-relaxed);
}
/* NO `.bio-prose i` RULE. It styled a statute-name italic that the bio no
longer uses: `Geist` ships NO italic face (every Geist `@font-face` is
`font-style: normal`), so the `<i>` rendered as SYNTHETIC OBLIQUE, and the
serif italic that would have set it properly is no longer preloaded on this
page. "Provincial Offences Act" is set in roman. If a statute name ever
needs italics here, load a face for it first. */
/* --- 4. The arc ------------------------------------------------------ */
.arc {
display: grid;
/* `min(18rem, 100%)` rather than a bare 18rem floor: a bare floor cannot
shrink below itself and overflows at a large default font size. The
credential row on `/` is the measured instance of that mistake. */
grid-template-columns: repeat(auto-fit, minmax(min(18rem, 100%), 1fr));
gap: var(--space-6);
/* NO `padding: 0` OR `list-style: none` HERE — `global.css`'s
`ul[role='list'], ol[role='list']` reset already supplies both, and this
block was re-implementing it by hand. Two rules for one job, and the
hand-written copy is the one that drifts. `margin: 0` also comes from the
global `* { margin: 0 }` reset. */
}
.arc-item {
display: flex;
flex-direction: column;
gap: var(--space-3);
padding-block-start: var(--space-4);
border-block-start: 1px solid var(--line-dark);
}
/* <h3>, not <p>. These are the headings of the three arc items and they set
at --text-2xl serif, so marking them up as paragraphs was the fake-heading
pattern: a screen-reader user got no heading navigation for the one section
on this page a reader is most likely to jump to. `ProcessStep` on `/` uses
<h3> for exactly this shape. Outline stays h1 -> h2 -> h3 with no skips. */
.arc-name {
font-family: var(--font-serif);
font-size: var(--text-2xl);
line-height: var(--leading-tight);
}
.arc-state {
margin: 0;
}
.arc-body {
margin: 0;
font-size: var(--text-base);
line-height: var(--leading-body);
/* NOT --text-secondary. On an inverse ground `--ink-soft` measures ~1.4:1
against `--ink` — the inherited `--text-inverse` (cream, 16.81:1) is what
carries body copy here, so the colour is deliberately left alone rather
than set to a token that is correct only on cream. */
}
/* --- 3. Credentials -------------------------------------------------- */
.cred-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(16rem, 100%), 1fr));
gap: var(--space-7) var(--space-6);
}
/* THESE ARE HEADINGS AND THEY WERE DRESSED AS EYEBROWS. The previous rule set
11px / Geist Mono / 0.18em / uppercase / --text-meta, which is `docs/02`'s
eyebrow specification exactly — and `docs/02` says in terms: "An eyebrow is
not a heading and never carries the <h*>." `Eyebrow.astro` restates it.
The measurable consequence was worse than the rule breach: at 11px these
<h3>s were SMALLER than the 12px eyebrow above them and 5px smaller than
the 16px list items they head, so "MEMBERSHIPS" was the least legible text
on the page an appointing body reads.
Resolved by keeping the <h3> — these genuinely are the headings for their
lists, and the heading navigation is worth more than the styling — and
dropping the eyebrow treatment. The gold rule stays: gold is sanctioned for
dividers, and a 1px border is not text. */
.cred-title {
font-size: var(--text-base);
font-weight: var(--weight-medium);
letter-spacing: var(--tracking-tight);
color: var(--text-secondary);
padding-block-end: var(--space-3);
border-block-end: 1px solid var(--rule);
}
.cred-items {
margin: var(--space-4) 0 0;
padding: 0;
list-style: none;
display: flex;
flex-direction: column;
gap: var(--space-3);
font-size: var(--text-base);
line-height: var(--leading-snug);
}
/* NO `.cred-note` RULE. The note it styled was removed — three defects in one
sentence, recorded in the markup above — and the rule went with it rather
than shipping as dead CSS to every visitor. Noted so the next reader does
not re-add a note to fill a rule that no longer exists. */
/* NO CONTACT-BAND RULES HERE. `.contact-inner`, `.contact-h`, `.contact-body`
and `.contact-action` moved to `ContactBand.astro` with the markup they
style. They were left behind after the extraction — dead CSS shipping to
every visitor, and worse, the **46ch / 52ch divergence the extraction
existed to end was still sitting on disk in both pages**, so the next reader
would have found two different values and no rendered difference. Deleted
2026-08-28. */
</style>
+258 -92
View File
@@ -29,6 +29,7 @@
import { Picture, getImage } from 'astro:assets';
import BaseLayout from '../layouts/BaseLayout.astro';
import Button from '../components/Button.astro';
import ContactBand from '../components/ContactBand.astro';
import CredentialRow from '../components/CredentialRow.astro';
import Eyebrow from '../components/Eyebrow.astro';
import InfinityMark from '../components/InfinityMark.astro';
@@ -39,12 +40,13 @@ import portrait from '../assets/pouya-lajevardi.jpg';
import ogDefault from '../assets/og-portrait.jpg';
import { homeGraph } from '../data/schema';
import {
CONTACT,
ASYMMETRY_LINE,
CREDENTIAL_ROW,
CREDENTIAL_ROW_ARB,
PRACTICE_AREAS,
PORTRAIT,
PROCESS,
PROCESS_FRAMING,
SITE,
} from '../data/site';
@@ -87,6 +89,7 @@ const graph = homeGraph(new URL(ldImage.src, Astro.site).href);
description="Commercial mediation and arbitration in Toronto. Construction, technology, energy, insurance and shareholder disputes, read as contracts and as engineering."
imageAlt={PORTRAIT.alt}
jsonLd={graph}
preloadSerifItalic
>
{/* ---- 1. Hero ------------------------------------------------------- */}
<section class="hero">
@@ -125,21 +128,35 @@ const graph = homeGraph(new URL(ldImage.src, Astro.site).href);
below uses.
(b) "facts most neutrals take on faith" is a COMPARATIVE assertion
about a population of third parties. It comes from `docs/03`'s core
positioning statement, so it is approved copy — but `docs/03`'s own
compliance checklist requires "any comparative claim is factual and
verifiable", and §4 has no row for it. Replaced with a
non-comparative distinction that is checkable and says the same
thing: documents rather than pleadings. Q41 asks Pouya whether the
original may be restored; changing approved copy back is his call,
and shipping an unverifiable comparative in the meantime is not. */
about a population of third parties, and **Q41(b) CLOSED 2026-08-27:
it is not restored, and the reason is not only compliance.** Pouya:
*"That is an unverifiable empirical claim about other practitioners,
and comparative claims must be factual and verifiable. It is also
weaker copy: assert his capability, not the field's incapability."*
It is struck from `docs/03`'s core positioning statement too — the
approved-copy defence is gone, because the approved copy changed.
His replacement wording is used verbatim: *"built for disputes that
turn on the contract, the code, and the engineering documents"*. The
interim ("the documents rather than the pleadings") is also gone; it
said nothing about other neutrals but it still worked by contrast.
ON THE ECHO OF THE HEADLINE, because it is deliberate and one edit
from being reversed if he reads it as a stumble. The `<h1>` ends
"the contract, the code, and the room"; this sentence re-runs the
triad and swaps the third term for "the engineering documents". Two
of three words repeat forty words apart. Read as a rhyme it does the
work of the whole positioning statement in one move; read as an
oversight it looks careless. Judged the first, flagged as the
second. */
}
<p class="hero-lede">
I mediate commercial disputes from Toronto, and I accept arbitration
appointments. I also practise as a machine-learning and infrastructure
engineer, so the matters I take are the ones that turn on the
documents rather than the pleadings: the change order, the model card,
the System Impact Assessment, and the regulatory overlay around them.
I mediate commercial disputes from Toronto, and I accept commercial
arbitration appointments. I also practise as a machine-learning and
infrastructure engineer, so the matters I take are the ones that turn
on the contract, the code, and the engineering documents: the change
order, the model card, the System Impact Assessment, and the
regulatory overlay around them.
</p>
<div class="hero-cta">
@@ -152,9 +169,39 @@ const graph = homeGraph(new URL(ldImage.src, Astro.site).href);
{
/* `widths` + `sizes` rather than `densities`: the portrait is fluid, and
a density ladder would size it from one assumed CSS width. The largest
real render is ~476px (content 1280 - 96 gutter - 64 gap, x 0.425),
so 960 is the 2x ceiling.
a density ladder would size it from one assumed CSS width.
⚠️ THE OLD CEILING ARGUMENT WAS WRONG, AND IT WAS WRONG BY IGNORING
THE RANGE WHERE THIS IMAGE IS WIDEST. It read: "The largest real
render is ~476px (content 1280 - 96 gutter - 64 gap, x 0.425), so 960
is the 2x ceiling." That arithmetic describes the TWO-COLUMN layout,
which only engages at 66rem. Below 66rem the hero is a single column
and the portrait is the full content width. Measured, both pages:
viewport slot DPR-2 needs picked result
640 592 1184 760/960 1.23-1.56x upscale
768 672 1344 960 1.40x
900 804 1608 960 1.68x
1024 928 1856 960 1.93x
At 768/DPR-1 a 760w file EXISTS and is not chosen, so part of the loss
was purely the wrong `sizes` (60vw declared against a ~88vw slot).
Reconfirmed with the HTTP cache cleared — an earlier probe reported a
2.81x OVERSIZED fetch at 390/DPR-1 which was a cache artefact, not a
defect.
TWO FIXES, BOTH REQUIRED. (1) `.hero-portrait` is capped at 30rem in
the single-column range, so the widest real slot is 480 CSS px
everywhere — which makes 960 exactly right for DPR 2 rather than
accidentally short. (2) A 1440 rung, because 480 x 3 = 1440 and the
desktop slot at DPR 3 already needed 1287-1428; the ≥66rem range was
upscaling ~1.34-1.49x at DPR 3 before this and nobody had measured it.
The master is 1600, so 1440 exists.
THE CAP CHANGES HOW THIS PAGE LOOKS between 640px and 1055px — the
portrait was 592-928px wide there and is now 480. That is a visible
design change to a reviewed page, made on payload grounds; raising the
cap is a one-line change but the ladder has to grow with it.
`width` AND `height` ARE PASSED ALONGSIDE `widths`, AND THAT IS NOT
REDUNDANT. With `widths` alone, Astro emits the UNTOUCHED 1600px
@@ -168,24 +215,79 @@ const graph = homeGraph(new URL(ldImage.src, Astro.site).href);
349kB" for every variant either way.
What a browser actually takes is the AVIF: 5.6 / 7.3 / 11.1 / 14.8 /
21.5 kB across the five widths [measured 2026-08-27].
21.5 kB across the first five widths [measured 2026-08-27]; 1080 and
1440 are added 2026-08-28 for DPR 3 (26.6 / 48.8 kB).
eager + fetchpriority=high because this is the LCP candidate on the
page docs/04 budgets hardest. */
AND THE 1440 RUNG OVERSHOT, SO 1080 EXISTS TO CORRECT IT. Adding 1440
for DPR 3 removed a 1.07x upscale at 390/DPR3 and replaced it with a
**48,799 B fetch where the old one was 21,526 B** — +27 KB on a phone,
to fix a 7% softness nobody can see. A browser takes the smallest
candidate at or above what it needs, and with no rung between 960 and
1440 the only choices were "slightly soft" or "+27 KB". 1080 makes
1026 (390 x DPR 3) exact and cheap. This was a defect in the fix for
the defect above, found by measuring the fix rather than the source.
AND 1080 ALONE MISSED THE TWO LARGEST CURRENT PHONES, WHICH
MAKES THIS THE THIRD ITERATION OF THIS LADDER. 1080 was tuned to
390 CSS px x DPR 3 (= 1026), and `sizes` resolves to
`calc(100vw - 3rem)` up to 528px, so every phone wider than 390
overshoots to the next rung: iPhone 14 Plus (428@3, needs 1140)
and 15/16 Pro Max (430@3, needs 1146) both took **1440 —
48,799 B**, against 27,594 for the device the rung was tuned
for. +21,205 B, 13% of page weight. A 1200 rung closes it at
1.05x. Measured after: no rung more than 1.06x oversized on the
phone axis, and still no upscaling anywhere — 0 upscaling across 11
real device profiles on both pages.
TWO RESIDUAL OVER-FETCHES, LEFT DELIBERATELY, so neither reads as an
oversight later. **320@2** needs 544 and takes 640 (1.18x): there is no
rung between 480 and 640, and 480 would be a 1.13x UPSCALE, so the
oversize is the better half of that trade. **1056@2 needs 760.4 and
takes 960 (1.26x, +6.8 KB)** — a knife-edge, and worth stating because
it looks like a `sizes` error and is not: the declared `36vw` is
accurate to the measured 36.0% track, and 380.2 x 2 = 760.4 misses the
760 rung by four tenths of a pixel. Declaring 35vw to duck under it
would make `sizes` less truthful across the whole band in exchange for
a 0.05% upscale at this width. The declaration stays honest and one
viewport over-fetches.
⚠️ `fetchpriority="high"` IS GONE, AND THIS PAGE HAD IT WHILE
`/about/` WITHHELD IT ON THE IDENTICAL MEASUREMENT. The old comment
read "eager + fetchpriority=high because this is the LCP candidate on
the page docs/04 budgets hardest" — true only from 768px up. Measured,
cache cleared per device:
320x568 @2 portrait visible 0px LCP — 11,058 B
360x780 @3 portrait visible 0px LCP — 21,526 B
390x844 @3 portrait visible 0px LCP P.hero-lede 27,594 B
430x932 @3 portrait visible 30px LCP P.hero-lede 48,799 B
1280x900 @1 portrait visible 595px LCP IMG.portrait 7,257 B
So on mobile — the axis the ≥95 budget is actually measured on — it
promoted 27-49 KB of image the reader cannot see above the Geist face
that paints the real LCP element. `/about/` already withheld it for
exactly this reason and this page did the opposite; the inconsistency
is the finding.
`loading="eager"` STAYS: the portrait is the LCP element from 768px up,
and eager costs nothing where it is off-screen. If the desktop LCP ever
needs protecting explicitly, the right instrument is
`<link rel="preload" imagesrcset imagesizes>` in <head>, which honours
`sizes` and therefore self-cancels on phones — not a blanket attribute
that cannot. */
}
<div class="hero-portrait">
<Picture
src={portrait}
width={960}
height={960}
widths={[380, 480, 640, 760, 960]}
sizes="(min-width: 80rem) 476px, (min-width: 66rem) 42vw, (min-width: 40rem) 60vw, 92vw"
widths={[380, 480, 640, 760, 960, 1080, 1200, 1440]}
sizes="(min-width: 80rem) 476px, (min-width: 66rem) 36vw, (min-width: 33rem) 480px, calc(100vw - 3rem)"
formats={['avif', 'webp']}
fallbackFormat="jpeg"
alt={PORTRAIT.alt}
loading="eager"
decoding="sync"
fetchpriority="high"
class="portrait-img"
/>
</div>
@@ -234,26 +336,62 @@ const graph = homeGraph(new URL(ldImage.src, Astro.site).href);
as "the 'two directions at once' argument — law and engineering
converging on the same dispute", so the ARGUMENT is unchanged and
still delivered; only the construction that carried the implication
is gone. Whether Q37's reasoning formally extends to prose is
Pouya's to say — Q41. */
is gone.
**Q41(a) CLOSED 2026-08-27: Q37's reasoning DOES extend to prose,
and prose has to do more than avoid the parallel.** 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."* Avoiding the pair was therefore only half the fix — a reader
can still supply the missing symmetry from silence. So the second
paragraph now names both halves for what they are: training on one
side, current work on the other. "Training I hold" is the opposite
of a licence claim, which is the point of saying it out loud.
`docs/01`'s and `docs/03`'s own phrase "law and engineering" is the
struck construction; both now carry a note not to lift it into copy.
The argument it names is Pouya's and stands. */
}
<div class="prose approach-prose">
<p>
Any dispute I take has two readings: what the documents say, and
what the engineering says. They are not blended here. They run at
the same time.
Any dispute I take gets read twice: once against the documents, and
once as engineering. The two readings are not blended here. They run
at the same time.
</p>
{
/* FROM A CONSTANT, NOT TYPED. It was typed here and then typed
again on `/about/`, and the two copies had ALREADY diverged inside
one session — a comma here, full stops there. Q41(a) makes this
the sentence responsible for foreclosing the licence implication,
so it is the worst string on the site to let drift. See
ASYMMETRY_LINE in src/data/site.ts. */
}
<p>{ASYMMETRY_LINE}</p>
{
/* TWO COMPARATIVES CAME OUT OF THESE PARAGRAPHS ON 2026-08-28, and
both had SURVIVED the sweep that closed Q41(b) the day before:
"The second half of each pair usually arrives as a separate
expert report." — an empirical claim about how disputes are
usually run, i.e. about a population of other matters.
"it is why the technical half is not something a party has to
commission and wait for" — the same claim in counterfactual
form, which is harder to spot and says more.
Pouya's ruling on Q41(b) is the test: *"assert his capability, not
the field's incapability."* Both worked by asserting the field's.
What replaces them says only what he does, which is the stronger
claim anyway — and it is shorter. */
}
<p>
A construction claim is a contract question and a scheduling
question. A software dispute is a licence question and an
architecture question. A grid connection is a regulatory question
and a load question. The second half of each pair usually arrives as
a separate expert report.
and a load question.
</p>
<p>
I do both readings myself. That is the whole of it, and it is why
the technical half is not something a party has to commission and
wait for.
I read both halves of each pair myself. That is the whole of it.
</p>
<p class="approach-metaphor">
My mark is an infinity loop, and it is the argument in one line:
@@ -419,14 +557,21 @@ const graph = homeGraph(new URL(ldImage.src, Astro.site).href);
{
/* THIS SAID "All six areas, and what else is offered", which asserted
offerings beyond the six. The only candidates — early neutral
evaluation, settlement counsel, dispute-system design, pre-dispute
technical advisory (`docs/01` §`/practice/`) — have NO row in §4
"Offered now", and §4 states: "An offering may not be published until
it has a row." `claims-auditor` called this the Med-Arb-in-the-footer
defect in a new place, and it is exactly that. Reworded to what is
rowed; the four candidates need rows before `/practice/` can offer
them at step 5. */
offerings beyond the six, none of which had a §4 row.
**Q42 CLOSED 2026-08-27, and one of the four candidates came out.**
Early neutral evaluation, dispute-system design and pre-dispute
technical advisory now have Offerings rows. **Settlement counsel does
not, and never will** — Pouya struck 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."*
THIS LINE STILL READS "All six practice areas" and that is unchanged
on purpose. The three rowed processes are `/practice/`'s "also
offered" strip at step 5, not a claim `/` makes in a link label — a
six-card grid followed by "and what else is offered" is the
Med-Arb-in-the-footer shape whether or not the rows exist. */
}
<p class="areas-more">
<a href="/practice/">All six practice areas &rarr;</a>
@@ -441,7 +586,7 @@ const graph = homeGraph(new URL(ldImage.src, Astro.site).href);
<SectionHeading
eyebrow="How it runs"
level={2}
lede="Five steps, from the first call to the conclusion. Counsel want the shape of the downside before they commit a client's day."
lede="Five steps, from the first call to the conclusion — including what happens if the matter does not settle."
>
<span slot="heading">From first call to conclusion.</span>
</SectionHeading>
@@ -457,6 +602,17 @@ const graph = homeGraph(new URL(ldImage.src, Astro.site).href);
}
</ol>
{
/* NOT OPTIONAL, AND NOT A DISCLAIMER — Q43, Pouya 2026-08-27. It is the
condition on which the five timings may be published at all: *"Published
as typical, they are honest and useful; published as commitments, the
first matter that slips makes the page false."* It sits directly under
the numbers rather than in the section lede above them, because a
reader who scans the strip and skips the lede has read a commitment.
`/process/` renders the same constant at step 6. */
}
<p class="process-framing">{PROCESS_FRAMING}</p>
<p class="process-more">
<a href="/process/">What happens if the matter does not settle &rarr;</a
>
@@ -468,28 +624,13 @@ const graph = homeGraph(new URL(ldImage.src, Astro.site).href);
{/* ---- 8. Contact band ---------------------------------------------- */}
{
/* docs/01 item 8 is "Intake CTA and booking link". THERE IS NO BOOKING LINK
and that is not an omission: booking is parked (AGENTS.md R6) and
CONTACT.bookingUrl is null, so /contact/ ships the intake form with a
reserved slot for an embed. Stated rather than silently dropped. */
/* A COMPONENT SINCE 2026-08-28. It was ~20 lines of markup plus ~20 of CSS
here and the same again on `/about/`, and the two had already drifted
(`.contact-body` at 52ch here, 46ch there) inside the session that wrote
the second one. Seventeen pages remain. docs/01 item 8's missing booking
link is documented in the component, once. */
}
<section class="section section-accent contact-band">
<div class="wrap contact-inner">
<div>
<Eyebrow dot>Next step</Eyebrow>
<h2 class="display contact-h">Start with a call.</h2>
<p class="contact-body">
Tell me the shape of the matter and who is involved, and I will tell
you whether I am the right neutral for it. {CONTACT.responseTime}
</p>
</div>
<div class="contact-action">
<Button href="/contact/" variant="gold"
>Request a consultation &rarr;</Button
>
</div>
</div>
</section>
<ContactBand />
</BaseLayout>
<style>
@@ -536,6 +677,15 @@ const graph = homeGraph(new URL(ldImage.src, Astro.site).href);
overflow: hidden;
border-radius: var(--radius-lg);
background: var(--bg-raised);
/* THE CAP IS THE FIX FOR THE UPSCALE, not a style preference. Uncapped, the
single-column slot ran to 928 CSS px at a 1024px viewport, which is 1856
device px at DPR 2 against a 960w ceiling — 1.93x. 30rem makes 480 the
widest real slot on any page, so the ladder's 960 covers DPR 2 exactly
and the new 1440 rung covers DPR 3. See the <Picture> comment above.
`margin-inline: auto` because a 480px box in a 928px column would
otherwise sit hard against the inline start. */
max-inline-size: 30rem;
margin-inline: auto;
}
/* The <picture> wrapper is the box that gets sized, NOT the <img> — the exact
defect CLAUDE.md records for <Button> and then for <Picture> inside
@@ -555,6 +705,13 @@ const graph = homeGraph(new URL(ldImage.src, Astro.site).href);
}
@media (min-width: 66rem) {
.hero-portrait {
/* Above 66rem the grid track is already 390-476px, so the cap is inert —
released anyway so the track, not this number, governs the two-column
layout. Keeping it would silently become the constraint if the track
ever widened. */
max-inline-size: none;
}
.hero {
padding-block: var(--space-9);
}
@@ -581,10 +738,17 @@ const graph = homeGraph(new URL(ldImage.src, Astro.site).href);
gap: var(--space-7);
align-items: center;
}
/* NO `display: flex; gap` ANY MORE, AND THAT IS A CORRECTION TO A FIX.
global.css gained `:where(.prose) > p + p { margin-block-start }` on
2026-08-28 because a bare `.prose` block had no paragraph spacing at all.
The new rule's comment asserted "with `:where()` the flex container's gap
governs and this contributes nothing" — **false, and it was measured false
immediately after being written.** `:where()` controls SPECIFICITY, not
whether a declaration applies: nothing here was overriding the margin, so
flex `gap` and the margin both applied and this block's paragraph gaps went
**24px -> 48px**. Spacing now comes from the one global rule, which is the
point of having it. */
.approach-prose {
display: flex;
flex-direction: column;
gap: var(--space-5);
margin-block-start: var(--space-6);
font-size: var(--text-lg);
line-height: var(--leading-relaxed);
@@ -614,9 +778,10 @@ const graph = homeGraph(new URL(ldImage.src, Astro.site).href);
/* --- 4. Two practices ---------------------------------------------- */
.section-head {
margin-block-end: var(--space-7);
}
/* NO `.section-head` RULE — it moved to `global.css`, where `.prose` lives.
It was byte-identical in both pages, and every one of the seventeen
remaining pages needs it for the same reason (a parent cannot style a child
component's root, so the wrapper must be page-owned). */
.pair {
display: grid;
gap: var(--space-5);
@@ -752,29 +917,30 @@ const graph = homeGraph(new URL(ldImage.src, Astro.site).href);
gap: var(--space-5);
margin: 0;
}
/* --space-5 rather than --space-6: this belongs to the strip above it, not to
the link below.
/* --- 8. Contact band ----------------------------------------------- */
THE RATIO IN THIS COMMENT WAS WRONG WHEN FIRST WRITTEN. It said
"--text-meta on cream measures 3.07:1". It does not: `#6e6359` on `#faf7f2`
measures **5.47:1** and passes AA. 3.07:1 is `--muted` on **ink**, which is
exactly what `tokens.css` says and what this comment misread. So the
*reason* given was false even though the *choice* is right —
--text-secondary (10.76-11.75:1) is correct here because this sentence is a
CONDITION on the numbers above it, not metadata about them, and a condition
has to read like body copy. Corrected 2026-08-28 on
`adversarial-reviewer`'s measurement. */
.process-framing {
margin-block-start: var(--space-5);
max-inline-size: var(--width-prose);
font-size: var(--text-sm);
color: var(--text-secondary);
}
.contact-inner {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: var(--space-6);
}
.contact-h {
margin-block: var(--space-4) var(--space-4);
font-size: var(--text-4xl);
}
.contact-body {
max-inline-size: 52ch;
}
.contact-action {
/* `flex: none` is `0 0 auto`, so the button could not shrink below its
max-content width — 425px at a 200% default font size, in a 342px
container. `0 1 auto` plus `min-inline-size: 0` lets it. It still never
shrinks at a normal font size, because there is room. */
flex: 0 1 auto;
min-inline-size: 0;
}
/* NO CONTACT-BAND RULES HERE. `.contact-inner`, `.contact-h`, `.contact-body`
and `.contact-action` moved to `ContactBand.astro` with the markup they
style. They were left behind after the extraction — dead CSS shipping to
every visitor, and worse, the **46ch / 52ch divergence the extraction
existed to end was still sitting on disk in both pages**, so the next reader
would have found two different values and no rendered difference. Deleted
2026-08-28. */
</style>
+110
View File
@@ -283,6 +283,44 @@ a:hover {
.prose p {
max-inline-size: var(--width-prose);
}
/* `.prose` HAD NO PARAGRAPH SPACING, AND NOTHING ANYWHERE SUPPLIED IT.
The reset above sets `* { margin: 0 }`, so a bare `.prose` with two <p>
children rendered them as one block. Measured on `/about/` §Language:
**gap between paragraph 1 and paragraph 2 = 0.0px** — "…history arrive
together." running straight into "Working in the parties' own language…", on
screen and in the printed PDF.
It survived step 2 because BOTH of `/`'s prose blocks supply their own
spacing: `.approach-prose` uses `display:flex; gap`, and `.bio-prose` on
`/about/` has its own `> p + p`. So the only two call sites happened to opt
out of the defect. The rule belongs HERE, where `.prose` lives, or it has to
be remembered on all fifteen remaining pages.
`:where()` KEEPS THE SPECIFICITY AT ZERO so a component's own rule for the
SAME PROPERTY wins without `!important`.
⚠️ IT DOES NOT PROTECT AGAINST A FLEX `gap`, AND THIS COMMENT ONCE CLAIMED IT
DID — "Verified: with `:where()` the flex container's gap governs and this
contributes nothing." That was false and was measured false minutes later:
`:where()` lowers SPECIFICITY, which only matters when two rules set the same
property. A flex `gap` is a different property, so gap and margin both apply
and add. `/`'s `.approach-prose` went **24px -> 48px** on the strength of that
sentence. It has been converted to use this rule instead of a `gap`, and
`.bio-prose`'s duplicate `> p + p` was removed for the same reason. If a
future block needs different spacing, override `margin-block-start` — do not
reach for `gap`. */
:where(.prose) > p + p {
margin-block-start: var(--space-5);
}
/* THE PAGE-OWNED WRAPPER FOR `SectionHeading`, and it lives here because it was
byte-identical in two pages with seventeen to come. It exists only because a
parent cannot style a child component's root (`CLAUDE.md`; measured on
`SectionHeading`), so every page that uses a section heading needs a wrapper
it owns — which means every page needs this rule. Same argument that extracted
`ContactBand`, applied to a rule instead of a component. */
.section-head {
margin-block-end: var(--space-7);
}
.section {
padding-block: var(--section-y);
}
@@ -491,4 +529,76 @@ hr {
.section {
padding-block: var(--space-5);
}
/* THE INVERSE GROUNDS HAD TO BE NEUTRALISED AND WERE NOT — and this block's
own heading says why it matters: the About page is printed by people
evaluating an appointment.
`print-color-adjust` defaults to `economy`, so a UA drops the BACKGROUND
and keeps the text. Chrome's default print dialog has "Background graphics"
unchecked, so `.section-inverse` and `.section-accent` printed cream text
on white paper. Measured with `Page.printToPDF`, `printBackground: false`,
rasterised at 150 dpi: the dominant glyph colour across the whole arc block
was **rgb(166,164,161) — 2.49:1 against white**, and that grey is Chrome's
own legibility fudge. The DECLARED colour is cream at ~1.04:1, which is
what a UA without that fudge renders. With `printBackground: true` the
pages are correct, which is what isolates the cause.
What vanished was the Q.Med / Q.Arb / C.Med-Arb progression on `/about/` —
§4's paired disclosure — plus the contact band. `!important` because the
rules being overridden are class-level and these must win regardless of
which section variant a future page uses. */
/* TOKENS FIRST, THEN CLASSES — and the token half is the part that works.
A class-by-class version of this block shipped first and MISSED TWO
ELEMENTS, both measured under print-media emulation: `.approach-metaphor`
on `/` and `.btn-gold` on both pages stayed at `rgb(226,200,154)` —
gold-l, which is **1.62:1 against white paper** once the ground is dropped.
One is the paragraph carrying the infinity-mark argument; the other is the
call to action. Enumerating class names cannot work here: `--text-inverse-2`
is consumed by page-scoped and component-scoped rules this file has never
heard of, and there will be seventeen more pages of them.
Custom properties INHERIT, and that is the one mechanism that crosses
Astro's component-scope boundary (see `Pill.astro`). Redefining the three
inverse tokens on the section itself therefore reaches every descendant
rule, including ones written after this block. */
.section-inverse,
.section-accent {
background: transparent !important;
color: #000 !important;
--text-inverse: #000;
--text-inverse-2: #000;
--pill-fg: #000;
--pill-border: #000;
--rule: #000;
}
/* The belt-and-braces half. These four set a colour LITERALLY rather than
through a token, so the inheritance above does not reach them. */
.section-inverse .eyebrow,
.section-accent .eyebrow,
.section-inverse .lede,
.section-accent .lede {
color: #000 !important;
}
/* The dot is a background, not text, so it does not follow `color`. */
.section-inverse .eyebrow .dot,
.section-accent .eyebrow .dot {
background: #000 !important;
}
/* EVERY BUTTON, NOT JUST THE ONES ON AN INVERSE GROUND. Two of the three
variants set light text on a coloured background of their own
(`.btn-primary` cream-on-maroon, `.btn-gold` gold-on-ink), and a UA at
`print-color-adjust: economy` drops the background and keeps the text.
Measured against white paper: `.btn-gold` 1.62:1, `.btn-primary` **1.07:1**.
The first version of this rule was scoped to `.section-accent .btn-gold`,
which fixed the contact band and left the HERO CTA on `/` unreadable —
`.btn-primary` sits on cream, inside no inverse section at all, so nothing
in this block reached it. A print sweep of all 89 visible text elements
found it; the class-scoped version had passed its own narrower check. */
.btn {
background: transparent !important;
color: #000 !important;
border-color: #000 !important;
}
}