feat: D19 bounds the review loop; apply nine rulings; close Q46(a) and Q48–Q53
D19 into §3 and swept to all six destinations Pouya named: both agent briefs
(scope + severity filter), /build Phases 2–4 (non-gating questions, scope, stop
signal, two-round cap), /wrap, and CLAUDE.md (comments record decisions, not
history). Sweep verified by command, not recalled.
Rulings applied:
Q46(a) PUBLISHABLE — three §4 Offerings rows flipped; gate 1 records
[Pouya's stated basis], never [verified]. Step 5 unblocked.
Q48 closed, not site-relevant.
Q49 one §4 row, "Mediator"; read as declining Q49(b), so worksFor stays out.
Q50 DEVIATES — ships as name + slogan, not the concatenation. Flagged.
Q51 OBA sections stay; the regulator/voluntary distinction recorded.
Q52 docs/reference/deploy-credential-verification.md — 18 read-only AWS
calls, re-run rather than transcribed, access key ID redacted.
Q53 memberOf emitted on /about/'s Person node.
Two review rounds. The headline finding was this session's own: the Q53 sweep
was asserted and never run, leaving six in-scope records saying memberOf was
withheld — including §12 R10, which is read aloud every session. Round 2 then
found that round 1's simplification had put memberOf on / as well; the per-page
opt-in is restored, because Pouya's ruling turns on /about/'s visible HTML.
Also fixed: MEMBERSHIP_ORGS had orphaned BOUTIQUE's D16 JSDoc; /'s title now
derives from the constants; §7's deploy row stated and retracted three facts.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0148NztQskLKKApP5SzAA78e
This commit is contained in:
co-authored by
Claude Opus 5
parent
77a7b410b2
commit
fd5f610982
+90
-80
@@ -16,31 +16,28 @@
|
||||
* 1. `LegalService` — NEVER. docs/04: schema.org defines it as a business
|
||||
* providing legal advice and *representation*, which asserts in
|
||||
* machine-readable form exactly what D13 bars. `ProfessionalService`.
|
||||
* 2. `worksFor` — **STILL OMITTED, and the reason has changed.** The original
|
||||
* ground was "either names the boutique (D16) or misstates the employer".
|
||||
* Q47 (2026-08-28) answers the **D16 half**: `jobTitle` now describes this
|
||||
* practice, so naming SML Company Ltd would not name the boutique. It was
|
||||
* set on that basis for one pass and `adversarial-reviewer` found why that
|
||||
* is not sufficient — **the second half was never addressed:**
|
||||
* `ProfessionalService.provider` is this Person, so `provider → Person →
|
||||
* worksFor → SML` asserts transitively a same-entity claim **no §4 row
|
||||
* makes** — and one `src/pages/about.astro` DELETED from visible prose as
|
||||
* *"a corporate-structure claim"*. *(This read "defeats a guard in this
|
||||
* file… that `aboutGraph`'s comment explicitly declines to assert". That
|
||||
* comment covers `ProfilePage`, `BreadcrumbList` and `memberOf` and says
|
||||
* nothing about SML — the citation was EMPTY. Found by
|
||||
* `adversarial-reviewer`: a claim whose referent cannot be reached is
|
||||
* unverifiable by construction, this repo's own rule, applied to the
|
||||
* argument for a revert. The transitive argument stands on its own.)* §4 also says "**alongside** the practice" where Q47 says
|
||||
* "operates **through**" — different relations, and only the first has a
|
||||
* row. **Q49** asks Pouya for the row. Until then, withheld.
|
||||
* 2. `worksFor` — **OMITTED, and Q49(b) declined it deliberately on
|
||||
* 2026-08-28.** Two grounds, either sufficient. §4 rows "Operator of SML
|
||||
* Company Ltd **alongside** the practice"; "the entity the practice
|
||||
* **operates through**" is a different structural relation with no row.
|
||||
* And `ProfessionalService.provider` is this Person, so `provider →
|
||||
* Person → worksFor → SML` asserts **transitively** a same-entity claim
|
||||
* that `src/pages/about.astro` deliberately removed from visible prose as
|
||||
* *"a corporate-structure claim"* — scoping the value to a bare name does
|
||||
* not reach that. See `PRACTICE_JOB_TITLE` in `site.ts`.
|
||||
* 3. `priceRange` — omitted until `/fees/` exists (build step 9). docs/04
|
||||
* gates it on that page being real.
|
||||
*
|
||||
* AND Q.Arb IS NOT IN `hasCredential`. It commenced August 2026 and is not
|
||||
* held. Q.Med is. That asymmetry is the whole point of the property.
|
||||
*/
|
||||
import { CONTACT, CREDENTIALS, PRACTICE_JOB_TITLE, SITE } from './site';
|
||||
import {
|
||||
CONTACT,
|
||||
CREDENTIALS,
|
||||
MEMBERSHIP_ORGS,
|
||||
PRACTICE_JOB_TITLE,
|
||||
SITE,
|
||||
} from './site';
|
||||
|
||||
/** Stable node ids, so pages cross-reference rather than duplicate. */
|
||||
export const PERSON_ID = `${SITE.url}/about/#person`;
|
||||
@@ -73,19 +70,19 @@ export const SERVICE_ID = `${SITE.url}/#practice`;
|
||||
* implication as hard as assertion, and a crawler summary is a place where an
|
||||
* implication travels unedited.
|
||||
*/
|
||||
export function personNode(imageUrl?: string) {
|
||||
export function personNode(
|
||||
imageUrl?: string,
|
||||
opts: { memberships?: boolean } = {},
|
||||
) {
|
||||
return {
|
||||
'@type': 'Person',
|
||||
'@id': PERSON_ID,
|
||||
name: SITE.name,
|
||||
url: `${SITE.url}/about/`,
|
||||
/* Q47: PRACTICE_JOB_TITLE, not ROLE.title — the boutique role stays in
|
||||
visible copy and out of this graph, which is what the ruling was for.
|
||||
The VALUE is the narrowest form §4 rows; it shipped for one pass as
|
||||
"Mediator and Commercial Arbitrator" and both review agents struck it as
|
||||
the role-shaped claim removed from `description` the previous day. See the
|
||||
constant in site.ts for the full reasoning, and Q49 for the open row.
|
||||
NO `worksFor` beside it — withheld pending the same question. */
|
||||
/* PRACTICE_JOB_TITLE, not ROLE.title (Q47), and §4 now rows the value:
|
||||
"Practised role — Mediator" [verified 2026-08-28 — Pouya, Q49]. Do not
|
||||
widen it to include arbitration — see the constant in site.ts. No
|
||||
`worksFor` beside it: Q49(b) declined the row. */
|
||||
jobTitle: PRACTICE_JOB_TITLE,
|
||||
description:
|
||||
'Mediator in Toronto, accepting commercial arbitration appointments. ' +
|
||||
@@ -106,6 +103,36 @@ export function personNode(imageUrl?: string) {
|
||||
},
|
||||
sameAs: [CONTACT.linkedin],
|
||||
email: `mailto:${CONTACT.email}`,
|
||||
/* `memberOf` — OPT-IN, AND ONLY `/about/` OPTS IN. Q53, ruled by Pouya
|
||||
2026-08-28: *"the memberships are already crawlable in /about/'s HTML, so
|
||||
withholding the triple reduces no exposure and only makes the graph less
|
||||
complete than the page."* **The reason he gave is page-specific**, so the
|
||||
field is too: /about/ shows the list, `/` does not.
|
||||
|
||||
⚠️ DO NOT DELETE THE `opts` PARAMETER AS REDUNDANT. It looks redundant —
|
||||
both pages serve the same `@id`, so a consumer that fetches both merges
|
||||
them and gets `memberOf` either way. It was deleted on exactly that
|
||||
reasoning and had to be put back: the argument is about what a *consumer*
|
||||
can derive, and the scoping is about what a *page* asserts on its own.
|
||||
Six records in this repository state the `/about/` scoping; the deletion
|
||||
made all six false at once, silently.
|
||||
|
||||
THE NAMES COME FROM `MEMBERSHIP_ORGS`, NOT FROM THE DISPLAY LIST, and the
|
||||
two differ on three of four lines — see that constant in site.ts, which
|
||||
carries the reason and the D13 exclusions that govern both. Only their
|
||||
LENGTH is asserted at compile time. **Content parity is manual.**
|
||||
|
||||
R10 fires on an event, not a date: re-confirm before any cutover or major
|
||||
republish, and re-stamp §4. That covers this field as well as the visible
|
||||
list. */
|
||||
...(opts.memberships
|
||||
? {
|
||||
memberOf: MEMBERSHIP_ORGS.map((name) => ({
|
||||
'@type': 'Organization',
|
||||
name,
|
||||
})),
|
||||
}
|
||||
: {}),
|
||||
...(imageUrl ? { image: imageUrl } : {}),
|
||||
};
|
||||
}
|
||||
@@ -113,6 +140,36 @@ export function personNode(imageUrl?: string) {
|
||||
/**
|
||||
* `ProfessionalService` for the home page, with the Person as `provider`.
|
||||
*
|
||||
* THE MASTHEAD IS TWO FIELDS HERE, NOT ONE STRING — Q50, ruled by Pouya
|
||||
* 2026-08-28: *"`ProfessionalService.name` takes the ratified masthead string.
|
||||
* Q33 reaches it; one claim should not have two forms."*
|
||||
*
|
||||
* The masthead is not one string, and schema.org has a field for each half, so
|
||||
* `name` + `slogan` is the mapping rather than a concatenation. Both read the
|
||||
* constants, which is what kills the variant.
|
||||
*
|
||||
* ⚠️ AND ON `/` — THE ONLY PAGE THIS NODE SHIPS ON — THE MASTHEAD DOES NOT
|
||||
* RENDER THE TAGLINE AT ALL. `SiteHeader.astro` gates it on `!isHome`,
|
||||
* deliberately, so the header does not repeat the hero. `SITE.tagline` is
|
||||
* visible on `/` as the **hero eyebrow** instead. That is the page-visible
|
||||
* counterpart `slogan` mirrors; do not justify this mapping by the masthead.
|
||||
*
|
||||
* ⚠️ DO NOT PUT THE TAGLINE BACK INTO `name`. Two independent reasons.
|
||||
* (1) On a `LocalBusiness`-family type `name` means the business's name; a name
|
||||
* plus a service list plus a city is the name-stuffing pattern search engines
|
||||
* discard a rich result for, and `areaServed` already carries Toronto and
|
||||
* Ontario. (2) It put an **unscoped "Arbitration"** into the node's most
|
||||
* prominent field — Q39's struck universal reappearing in machine-readable
|
||||
* form.
|
||||
*
|
||||
* **Reason (2) is mitigated, not discharged**, and that is stated rather than
|
||||
* glossed: the word is still in `slogan`. What makes it acceptable there is
|
||||
* that the identical unscoped string already ships in `<title>`, `og:title`,
|
||||
* `twitter:title` and the hero eyebrow, all ratified under Q33 — so excluding
|
||||
* it from one name-like field alone would be incoherent. `serviceType` stays
|
||||
* scoped because it **enumerates services**; a slogan and a title are names.
|
||||
* §9 Q50 records this as a deviation awaiting Pouya's line.
|
||||
*
|
||||
* `serviceType` lists what §4 Offerings actually records as offered now —
|
||||
* mediation, arbitration, med-arb. **Arbitration is scoped to commercial**
|
||||
* (Q39, 2026-08-27): family arbitration in Ontario carries prescribed training
|
||||
@@ -128,7 +185,8 @@ export function professionalServiceNode(imageUrl?: string) {
|
||||
return {
|
||||
'@type': 'ProfessionalService',
|
||||
'@id': SERVICE_ID,
|
||||
name: `${SITE.name} — Mediation & Arbitration`,
|
||||
name: SITE.name,
|
||||
slogan: SITE.tagline,
|
||||
url: `${SITE.url}/`,
|
||||
description:
|
||||
'Commercial mediation and arbitration for construction, technology, ' +
|
||||
@@ -182,61 +240,13 @@ export function homeGraph(imageUrl?: string) {
|
||||
* no visible breadcrumb, and the header nav marks it as current — so
|
||||
* 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` — **STILL WITHHELD, AND NOW ON NARROWER GROUNDS THAN THE
|
||||
* PAGE.** Q44 closed 2026-08-28 and `/about/` **does** publish all four
|
||||
* visibly, so the earlier reasoning ("this field is not a stricter standard
|
||||
* than the page; it is the same one") no longer holds. It is now
|
||||
* deliberately stricter, for one reason that Q44 did not touch and in fact
|
||||
* sharpened:
|
||||
*
|
||||
* **The ground is VOLATILITY, not cacheability** — and the first version of
|
||||
* this comment got that wrong in a way `adversarial-reviewer` showed proves
|
||||
* too much. It said "a scraped claim is cached and re-served by systems that
|
||||
* never re-read it", which is equally true of `hasCredential`, and
|
||||
* `hasCredential` ships. A later reader applying that principle
|
||||
* consistently would either strip Q.Med from the graph (wrong) or restore
|
||||
* `memberOf` (possibly wrong), because the stated reason does not
|
||||
* distinguish the two fields.
|
||||
*
|
||||
* **What distinguishes them:** a membership is a fact with a **renewal
|
||||
* cycle** — §4 records yearly renewal for **the OBA sections and the CTF**
|
||||
* and says **nothing** about ADRIC's or ADRIO's period — and Pouya has
|
||||
* declined to track the dates, so the claim's truth can change with nobody
|
||||
* holding the schedule. A designation is not on a renewal cycle this record
|
||||
* knows of. *(This paragraph said "a membership list is a set of yearly
|
||||
* renewing facts" until 2026-08-28 — the widened form, FOURTH occurrence,
|
||||
* twenty lines above this same comment's own warning that it "is still
|
||||
* wrong and still must not be written". It was also the stated ground for
|
||||
* withholding `memberOf`, so the withholding rested on a widened premise.
|
||||
* Found by `claims-auditor` on re-audit.)* Caching only matters because the
|
||||
* underlying fact
|
||||
* moves — so volatility is the reason and caching is the mechanism.
|
||||
*
|
||||
* ⚠️ **AND `hasCredential` IS NOT SAFE BY THAT TEST — see Q48**, raised in
|
||||
* this same change set: ADRIO states a membership-in-good-standing retention
|
||||
* condition for C.Med and C.Arb and states none for Q.Med, and the reason
|
||||
* it states none looks like page type rather than absence of a condition.
|
||||
* **If Q.Med retention IS contingent on ADRIO membership currency, then
|
||||
* `hasCredential` — which ships — carries the higher exposure of the two.**
|
||||
* That is an argument for answering Q48, not for adding `memberOf`.
|
||||
* OCNI lapsed quietly once already; §4 still carries it as "not current, do
|
||||
* not publish".
|
||||
*
|
||||
* **This is a judgement, not an instruction from Pouya.** Q44's Blocks
|
||||
* column listed `memberOf` among the things it gated, so closing Q44 does
|
||||
* unblock it; his ruling said "ship the group", which is the visible one,
|
||||
* and said nothing about the graph. Reversing this is four lines and his
|
||||
* call — it is flagged in the session report rather than buried here.
|
||||
*
|
||||
* *Two earlier versions of this comment were wrong on the facts: they said
|
||||
* the page published them visibly when it did not, and that "all four renew
|
||||
* yearly" when §4 records yearly renewal for the OBA sections and the CTF
|
||||
* only. The first is now true again; the second is still wrong and still
|
||||
* must not be written.*
|
||||
* 3. `memberOf` — **EMITTED HERE, and only here.** Q53, 2026-08-28. It is
|
||||
* opted into by this function and by no other; `personNode` carries the
|
||||
* constraint and the reason.
|
||||
*/
|
||||
export function aboutGraph(imageUrl?: string) {
|
||||
return {
|
||||
'@context': 'https://schema.org',
|
||||
'@graph': [personNode(imageUrl)],
|
||||
'@graph': [personNode(imageUrl, { memberships: true })],
|
||||
};
|
||||
}
|
||||
|
||||
+82
-102
@@ -127,6 +127,38 @@ export const CREDENTIALS = {
|
||||
*/
|
||||
export const BOUTIQUE = 'a Toronto litigation and ADR boutique' as const;
|
||||
|
||||
/**
|
||||
* The GRAPH form of the memberships — `Person.memberOf` in `src/data/schema.ts`.
|
||||
*
|
||||
* ⚠️ SEPARATE FROM `CREDENTIALS.memberships` ON PURPOSE, AND THEY DIFFER ON
|
||||
* THREE OF FOUR LINES: the display list carries the acronyms (`ADR Institute of
|
||||
* Canada (ADRIC)`) and the OBA's three sections; this list names bare
|
||||
* organisations. Only `Canadian Tax Foundation` is identical.
|
||||
*
|
||||
* **Why bare names:** `memberOf` points at an *organisation*, and nothing is
|
||||
* named "Ontario Bar Association — Construction & Infrastructure, ADR, and
|
||||
* Civil Litigation sections". A triple naming that cannot reconcile against the
|
||||
* real entity gives up most of what the field buys. This is a **narrowing** of
|
||||
* §4's row — §4 names the OBA as the body and then qualifies the sections — and
|
||||
* not an inference beyond it. Do not read it the other way and "restore" the
|
||||
* qualifiers into a name.
|
||||
*
|
||||
* ⚠️ THE SAME TWO EXCLUSIONS GOVERN THIS ARRAY, repeated here because this is
|
||||
* where an addition would land: **NOT OCNI** (§4: not current, do not publish)
|
||||
* and **NOT the Law Society**. Q51 is the distinction — the Law Society is the
|
||||
* **regulator**, so membership is licensure, which D13 bars; the OBA is a
|
||||
* **voluntary association**, which admits members it does not license.
|
||||
*
|
||||
* BOTH ARRAYS ARE THE SAME §4 ROW SEEN TWICE, so their lengths are asserted at
|
||||
* compile time — see `_MembershipParity` below. **Their contents are not.**
|
||||
*/
|
||||
export const MEMBERSHIP_ORGS = [
|
||||
'ADR Institute of Canada',
|
||||
'ADR Institute of Ontario',
|
||||
'Ontario Bar Association',
|
||||
'Canadian Tax Foundation',
|
||||
] as const;
|
||||
|
||||
/**
|
||||
* The boutique role and the litigation line — the two highest-risk strings on
|
||||
* the site, so they live here rather than being typed into a page.
|
||||
@@ -138,20 +170,14 @@ export const BOUTIQUE = 'a Toronto litigation and ADR boutique' as const;
|
||||
*/
|
||||
export const ROLE = {
|
||||
/**
|
||||
* §4 verbatim, and it is the VISIBLE role only.
|
||||
* §4 verbatim, and it is the VISIBLE role only. Rendered as
|
||||
* "I am {ROLE.title} at {ROLE.at}", always paired with BOUTIQUE (D16).
|
||||
*
|
||||
* NO LONGER THE JSON-LD `jobTitle` — Q47, ruled 2026-08-28. This string was
|
||||
* both the visible role line and the Person node's `jobTitle`, which put
|
||||
* "Director of Firm Operations" on a node whose `url` is this ADR practice's
|
||||
* `/about/` — so a consumer could attach the boutique title to this entity.
|
||||
* Pouya's ruling splits them: the graph carries PRACTICE_JOB_TITLE below,
|
||||
* while this string stays exactly where it was in visible copy ("I am
|
||||
* {ROLE.title} at {ROLE.at}").
|
||||
*
|
||||
* **The graph carries NO `worksFor`.** This sentence said it did — "the graph
|
||||
* now carries PRACTICE_JOB_TITLE below and `worksFor: SML Company Ltd`" —
|
||||
* which was true for one pass and was reverted the same day (Q49(b)). Verified
|
||||
* 2026-08-28: zero live `worksFor` properties in `src`.
|
||||
* NEVER the JSON-LD `jobTitle` — that takes PRACTICE_JOB_TITLE below (Q47).
|
||||
* §4's row is one fact with two halves and visible copy always pairs them;
|
||||
* a graph field carrying only "Director of Firm Operations", on a node whose
|
||||
* `url` is this practice's `/about/`, lets a consumer attach the boutique
|
||||
* title to this entity.
|
||||
*/
|
||||
title: 'Director of Firm Operations', // [verified 2026-08-25 — strategy brief §I]
|
||||
/** Always rendered with BOUTIQUE, never with a firm name (D16). */
|
||||
@@ -179,102 +205,37 @@ export const ROLE = {
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* The Person node's `jobTitle` — Q47, ruled by Pouya 2026-08-28.
|
||||
* The Person node's `jobTitle`. §4 Verified: **Practised role — "Mediator"**
|
||||
* `[verified 2026-08-28 — Pouya, Q49]`, supported by the Q.Med row and by
|
||||
* "Has completed multiple sole mediations".
|
||||
*
|
||||
* NOT `ROLE.title`, and that separation IS the ruling. §4's row is one fact with
|
||||
* two halves — *"Director of Firm Operations, Toronto litigation and ADR
|
||||
* boutique"* — and visible copy always pairs them. The JSON-LD emitted only the
|
||||
* first half, on a `Person` whose `url` is this practice's `/about/`, so a
|
||||
* consumer could attach the boutique title to this entity. `worksFor` could not
|
||||
* fix it, because D16 bars naming the boutique and there was no value it could
|
||||
* take.
|
||||
* NOT `ROLE.title`, and the separation is Q47's ruling: this field describes
|
||||
* *this practice*, the boutique role stays in visible copy, and D16 keeps the
|
||||
* boutique unnamed either way.
|
||||
*
|
||||
* His ruling breaks the bind by changing what the field is about: *"jobTitle
|
||||
* describes this practice, not the boutique role, which D16 keeps unnamed"* —
|
||||
* and that half holds: this constant names no boutique.
|
||||
*
|
||||
* **THE `worksFor` HALF OF THE RULING IS NOT IMPLEMENTED — Q49(b).** This
|
||||
* paragraph said *"`worksFor` becomes SML Company Ltd — verified, federally
|
||||
* incorporated, and the entity the practice operates through. Both are set"*.
|
||||
* Two defects, both found by `claims-auditor` on re-audit: **"Both are set" is
|
||||
* false** (reverted the same day), and *"the entity the practice operates
|
||||
* through"* was listed inside a run of verified attributes when **§4 rows only
|
||||
* "Operator of SML Company Ltd. `alongside` the practice"** — a different
|
||||
* structural relation, and precisely what Q49(b) is open on. Do not restate the
|
||||
* ruling's phrasing as though the register carried it.
|
||||
*
|
||||
* ⚠️ **IT SHIPPED FOR ONE PASS AS "Mediator and Commercial Arbitrator" AND THAT
|
||||
* WAS WRONG FOR A REASON I HAD NOT SEEN.** Both review agents found it
|
||||
* independently on 2026-08-28, which is this loop's strongest signal.
|
||||
*
|
||||
* The string `claims-auditor` struck from **this same node's `description`** on
|
||||
* 2026-08-27 was *"Mediator and commercial arbitrator in Toronto"*. The value
|
||||
* ruled for `jobTitle` is the same words minus the city — **in the most
|
||||
* role-asserting field in the vocabulary**, thirty lines below the comment in
|
||||
* `schema.ts` that explains why the words were struck. §4 verifies *"Has
|
||||
* completed multiple sole mediations"* and has **no counterpart row for a
|
||||
* completed arbitration** — only that appointments are *accepted*. Consumers
|
||||
* render `jobTitle` beside `name`: *Pouya Lajevardi — Mediator and Commercial
|
||||
* Arbitrator*, which invites the reader to supply a track record for both halves.
|
||||
*
|
||||
* **I flagged the wrong thing.** My note argued about scoping ("Commercial"),
|
||||
* and neither the note nor I noticed the whole string had already been struck on
|
||||
* different grounds. A flag aimed at the wrong defect reads as diligence and
|
||||
* provides none.
|
||||
*
|
||||
* **So this ships as the narrowest form §4 actually rows**, and Q47's purpose is
|
||||
* still served: Pouya's ruling was that `jobTitle` describe *this practice*
|
||||
* rather than the boutique role, and "Mediator" does exactly that. Nothing is
|
||||
* lost from the graph — `description` ("accepting commercial arbitration
|
||||
* appointments") and `serviceType` ("Commercial arbitration") both carry the
|
||||
* arbitration **offering**, and both cleared audit. Only the role-assertion is
|
||||
* gone.
|
||||
*
|
||||
* **AGENTS.md Q49 asks Pouya for the row.** If he wants the fuller title it
|
||||
* needs either a §4 row for arbitrator-as-practised-role, or an offering-shaped
|
||||
* value — `adversarial-reviewer` proposed `'Mediator; accepts commercial
|
||||
* arbitration appointments'`, which is honest and reads oddly for a job title.
|
||||
* His call, not one to take by tidying.
|
||||
* ⚠️ DO NOT WIDEN IT TO INCLUDE ARBITRATION. "Arbitrator" as a practised role
|
||||
* has **no §4 row** — the register verifies completed sole mediations, and for
|
||||
* arbitration only that appointments are *accepted*. `jobTitle` is the most
|
||||
* role-asserting field in the vocabulary and consumers render it beside `name`,
|
||||
* so "Mediator and Commercial Arbitrator" there invites the reader to supply a
|
||||
* track record for both halves. The arbitration **offering** is carried by
|
||||
* `description` and `serviceType`, which is where an offering belongs.
|
||||
*/
|
||||
// [derived from §4 — "Q.Med designation through ADRIC / ADRIO" + "Has completed
|
||||
// multiple sole mediations". NOT a row stamp: §4 has no row reading "Mediator",
|
||||
// and the row-level wording is what Q49(a) is open on. The 2026-08-25 date this
|
||||
// comment first carried was inherited from ROLE.title's row.]
|
||||
export const PRACTICE_JOB_TITLE = 'Mediator' as const;
|
||||
|
||||
/* `PRACTICE_ENTITY` LIVED HERE FOR ONE PASS AND IS DELETED WITH `worksFor`.
|
||||
/* NO `PRACTICE_ENTITY`, AND NO `Person.worksFor` — Q49(b), declined 2026-08-28.
|
||||
*
|
||||
* It existed only to populate `Person.worksFor`, which is withheld pending a §4
|
||||
* row (Q49). `adversarial-reviewer` found the defect that decided it, and it is
|
||||
* one the "name only, nothing else" scoping did **not** address: the
|
||||
* ProfessionalService node's `provider` **is** this Person, so
|
||||
* `provider → Person → worksFor → SML Company Ltd` asserts transitively exactly
|
||||
* what `src/pages/about.astro` declines to assert in prose — that the practice
|
||||
* and the company are the same entity. **The referent matters and the first
|
||||
* version of this sentence got it wrong:** it said "the comment four lines above
|
||||
* it", pointing at `aboutGraph`'s note in `schema.ts`, which covers
|
||||
* `ProfilePage`, `BreadcrumbList` and `memberOf` and says **nothing** about SML
|
||||
* Company Ltd. `adversarial-reviewer` read it and found the citation empty —
|
||||
* *"a claim whose referent cannot be reached is unverifiable by construction"*,
|
||||
* this repo's own rule, applied to the argument for a revert. The real referent
|
||||
* is `about.astro`'s deleted sentence: *"the company through which the
|
||||
* engineering work is done" — a corporate-structure claim.* The transitive
|
||||
* argument stands on its own; the evidence offered for it did not.
|
||||
* §4 rows "Operator of SML Company Ltd **alongside** the practice". "The entity
|
||||
* the practice **operates through**" is a different structural relation and has
|
||||
* no row. Two further reasons it must not come back on a tidy-up:
|
||||
*
|
||||
* Two further grounds, both recorded so this is not re-added casually:
|
||||
* - §4's row says "Operator of SML Company Ltd **alongside** the practice".
|
||||
* Q47's ruling says "the entity the practice **operates through**". Those are
|
||||
* different structural relations and the second has no §4 row.
|
||||
* - `/about/` already **removed** a sentence of this exact class from visible
|
||||
* copy — see about.astro: *"the company through which the engineering work is
|
||||
* done" — a corporate-structure claim*. Publishing it machine-readably while
|
||||
* declining it in prose is the stricter-in-public, looser-in-metadata shape.
|
||||
*
|
||||
* The original omission had TWO grounds — "either names the boutique (D16) **or
|
||||
* misstates the employer**". Q47 answers the first. The second is Q49.
|
||||
*
|
||||
* `SITE.entity` already carries the string for the footer. Re-adding a second
|
||||
* constant for the same name would be the drift this file keeps paying for.
|
||||
* - `ProfessionalService.provider` IS this Person, so
|
||||
* `provider → Person → worksFor → SML` asserts **transitively** that the
|
||||
* practice and the company are the same entity — the claim `about.astro`
|
||||
* deliberately removed from visible prose as "a corporate-structure claim".
|
||||
* Scoping the value to a bare name does not reach this.
|
||||
* - `SITE.entity` already holds the string for the footer. A second constant
|
||||
* for the same name is the drift this file keeps paying for.
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -597,6 +558,25 @@ type _SlugsWithoutAnArea = Exclude<
|
||||
>;
|
||||
export type _SlugCoverage = _AssertNever<_SlugsWithoutAnArea>;
|
||||
|
||||
/**
|
||||
* The two membership arrays must stay the same LENGTH — contents are not
|
||||
* checked and cannot be. They are two views of ONE §4 row, and the failure mode
|
||||
* is adding a membership to the page and not to the graph, which is otherwise
|
||||
* silent.
|
||||
*
|
||||
* ⚠️ IT FAILS `npm run check`, NOT `npm run build` — measured. Both the deploy
|
||||
* workflow and `scripts/deploy-local.sh` run `check` first, so the deploy path
|
||||
* is covered; a bare `astro build` is not. And it depends on both arrays keeping
|
||||
* `as const`: without it `length` widens to `number`, `number extends number` is
|
||||
* true, and this assertion passes forever while checking nothing.
|
||||
*/
|
||||
type _AssertTrue<T extends true> = T;
|
||||
export type _MembershipParity = _AssertTrue<
|
||||
(typeof CREDENTIALS.memberships)['length'] extends (typeof MEMBERSHIP_ORGS)['length']
|
||||
? true
|
||||
: false
|
||||
>;
|
||||
|
||||
/**
|
||||
* The five process steps. **HERE, NOT IN THE PAGE**, for the reason written
|
||||
* against PRACTICE_AREAS above and applied by `adversarial-reviewer` 2026-08-27:
|
||||
|
||||
@@ -315,8 +315,12 @@ const ARC = [
|
||||
* group two entries above. An unused abbreviation is noise, so it is omitted;
|
||||
* one word to reverse if he wants it.
|
||||
*
|
||||
* `memberOf` IS STILL WITHHELD FROM THE JSON-LD — see `src/data/schema.ts`.
|
||||
* That is a narrower decision than this one and it is explained there.
|
||||
* `memberOf` IS EMITTED FROM THIS PAGE'S JSON-LD (Q53), AND FROM A DIFFERENT
|
||||
* ARRAY. `src/data/schema.ts` builds it from `MEMBERSHIP_ORGS`, not from the
|
||||
* `CREDENTIALS.memberships` this group renders: the graph names the bodies, the
|
||||
* page also names the OBA's three sections. **Only their length is enforced, by
|
||||
* a compile-time assertion — content parity is manual.** So editing this list
|
||||
* means editing that one. They are the same §4 row seen twice.
|
||||
*/
|
||||
const CREDENTIAL_GROUPS = [
|
||||
{ title: 'Designations', items: CREDENTIALS.designations },
|
||||
|
||||
@@ -85,7 +85,7 @@ const graph = homeGraph(new URL(ldImage.src, Astro.site).href);
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title={`${SITE.name} · Mediation & Arbitration · Toronto`}
|
||||
title={`${SITE.name} · ${SITE.tagline}`}
|
||||
description="Commercial mediation and arbitration in Toronto. Construction, technology, energy, insurance and shareholder disputes, read as contracts and as engineering."
|
||||
imageAlt={PORTRAIT.alt}
|
||||
jsonLd={graph}
|
||||
|
||||
Reference in New Issue
Block a user