From 6aaf089b05ac74531e6d9800877ac598e950a894 Mon Sep 17 00:00:00 2001 From: Pouya Lajevardi Date: Wed, 2 Sep 2026 07:59:50 -0400 Subject: [PATCH] feat: rule Q62 by stating the truth; strike the /med-arb/ gloss; re-stamp R18 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pouya's four rulings of 2026-09-01, applied 2026-09-02. Q62 — RULED "state the truth", not "remove the access". /legal/privacy/ now says two people can read the intake table, names their role, and adds the two stronger facts the false sentence had crowded out: the handler role holds PutItem only, and adr-sml-deploy is implicitDeny on all seven read and write actions. Wording is subject to Pouya's read-through — Q63(a), with a TODO(pouya) beside the copy. The ruling named one sentence; a vocabulary sweep found the falsehood in three places, and the audit then found two more. Five paragraphs now answer "who can see it" and change together. The tripwire stays permanently, per ruling, and grew from two alternatives to five. Every alternative is one string that reached dist/. Proven both ways against the pre-correction page rebuilt from bd282aa: exit 1 with 5 matches at dist/legal/privacy/index.html:54,67,67,68,72; exit 0 on the corrected page, self-test 12 patterns / 36 approved strings. /med-arb/ — the gloss is struck with no replacement, per ruling. The strike left "the section above" pointing at the ADRIC rule set and "the agreement" with no antecedent; both fixed. The bare designations line sitting under ADRIC's quoted competence requirement is also struck, which goes beyond the ruling and is flagged for Pouya. R18 — re-stamped, two-tier: (a)(c)(d) re-verified against a source, (b)(e)(f)(g) held on a cadence judgement. All seven hold, no shipped sentence changed. R18's trigger had NO cutover checklist item and had stamped five extracts of seven; both fixed. Candidate limb (h) flagged. R10 — fired and unsatisfied; left open on instruction. The evidence behind the new privacy sentence was weaker than the sentence. Re-measured: 33 of 33 roles simulated (23 of 26 carried inline policies nobody had read; the two CDK lookup roles can read the table), four trust policies, the CloudFormation escalation path for all five users, 0 federated providers, root recorded. Every read path terminates at the same two people. Two review rounds, 36 findings. 35 fixed, 1 declined. Five of round 2's were defects in round 1's own fixes; stopped at two per D19. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01Md3GndFqWPzK78xAoebsg5 --- AGENTS.md | 478 +++++++++++++++++- docs/01-architecture.md | 24 +- docs/05-backend-spec.md | 4 +- docs/06-deployment.md | 140 ++++- docs/09-cutover-runbook.md | 2 +- docs/reference/adr-institution-names.md | 12 + docs/reference/adric-rules.md | 13 + docs/reference/canada-privacy-technology.md | 13 + .../intake-table-access-verification.md | 271 +++++++++- docs/reference/ontario-construction-act.md | 25 + docs/reference/ontario-energy-regulatory.md | 14 + docs/reference/ontario-sabs-lat.md | 17 + .../reference/ontario-shareholder-remedies.md | 16 + scripts/check-claims.mjs | 104 +++- src/pages/legal/privacy.astro | 130 +++-- src/pages/med-arb.astro | 44 +- 16 files changed, 1181 insertions(+), 126 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 5935188..8afd2fa 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -704,11 +704,11 @@ the audience it targets. Revisit at month 12–18. `[verified 2026-08-25 — dec | Thing | Value | |---|---| | Framework | **Astro 7.2.9**, `output: 'static'` `[verified 2026-08-27 — npm view astro version, D1 as amended]`. `@astrojs/mdx` 7.0.8, `@astrojs/sitemap` 3.7.3, `sharp` 0.35.4 — all three at `latest`. Bumped from 7.2.7 at the step 1 → step 2 phase boundary under R11: 7.2.8 published 2026-08-26 and 7.2.9 on 2026-08-27, i.e. **two patches appeared inside 48 hours**, which is the argument for checking at boundaries rather than on failure. `engines` unchanged at `node >=22.12.0`, `npm >=9.6.5` `[verified 2026-08-27 — npm view astro@7.2.9 engines]` | -| **TypeScript — HELD at 6.x, and the hold is a peer constraint rather than a preference** | Pinned `^6.0.3`; `npm view typescript version` returns **7.0.2** `[verified 2026-08-31 — R11, re-run at the step 10 → 11 boundary after the run added five dependencies: **18 of 19 pins current**, this the only hold, `npm audit` 0 vulnerabilities. The earlier run that day, at the step 6 → 7 boundary, read 13 of 14]`. **The removal trigger was re-checked rather than recalled:** `npm view @astrojs/check@0.9.10 peerDependencies` still returns `{ typescript: '^5.0.0 || ^6.0.0' }`, so the hold stands. ⚠️ **AND THERE ARE TWO GATES, NOT ONE — corrected 2026-08-31, and this row named only the first for two days.** `npm view typescript-eslint peerDependencies` returns `{ typescript: '>=4.8.4 <6.1.0' }`, which is **tighter**: widening `@astrojs/check` alone would not lift the hold, so the trigger as recorded was unreachable. **A second consequence, live:** the pin is a caret, so if a 6.1.x ever ships, a plain `npm install` moves the tree into a peer-range breach with nothing in the repo saying so. Nothing is breached today — `npm ls typescript` resolves **6.0.3**, which is the highest stable 6.x on the registry. Found by running R11's own check rather than reading the row. **One major behind, which is the exact shape D1 was amended over — so the reason is recorded rather than the hold being silent.** `@astrojs/check@0.9.10` declares `peerDependencies: { typescript: '^5.0.0 \|\| ^6.0.0' }` `[verified 2026-08-29 — npm view @astrojs/check@0.9.10 peerDependencies]`, and `npm run check` is `astro check`, which is the type gate the deploy path runs before it builds. **Removal trigger: `@astrojs/check` AND `typescript-eslint` both widen to include 7** — either alone is not enough. Re-check at every phase boundary under R11 — this is a hold on a dependency's schedule, not on a judgement, so it lifts without a decision | +| **TypeScript — HELD at 6.x, and the hold is a peer constraint rather than a preference** | Pinned `^6.0.3`; `npm view typescript version` returns **7.0.2** `[verified 2026-08-31 — R11, re-run at the step 10 → 11 boundary after the run added five dependencies: **18 of 19 pins current**, this the only hold, `npm audit` 0 vulnerabilities. The earlier run that day, at the step 6 → 7 boundary, read 13 of 14]`. **The removal trigger was re-checked rather than recalled:** `npm view @astrojs/check@0.9.10 peerDependencies` still returns `{ typescript: '^5.0.0 \|\| ^6.0.0' }`, so the hold stands. ⚠️ **AND THERE ARE TWO GATES, NOT ONE — corrected 2026-08-31, and this row named only the first for two days.** `npm view typescript-eslint peerDependencies` returns `{ typescript: '>=4.8.4 <6.1.0' }`, which is **tighter**: widening `@astrojs/check` alone would not lift the hold, so the trigger as recorded was unreachable. **A second consequence, live:** the pin is a caret, so if a 6.1.x ever ships, a plain `npm install` moves the tree into a peer-range breach with nothing in the repo saying so. Nothing is breached today — `npm ls typescript` resolves **6.0.3**, which is the highest stable 6.x on the registry. Found by running R11's own check rather than reading the row. **One major behind, which is the exact shape D1 was amended over — so the reason is recorded rather than the hold being silent.** `@astrojs/check@0.9.10` declares `peerDependencies: { typescript: '^5.0.0 \|\| ^6.0.0' }` `[verified 2026-08-29 — npm view @astrojs/check@0.9.10 peerDependencies]`, and `npm run check` is `astro check`, which is the type gate the deploy path runs before it builds. **Removal trigger: `@astrojs/check` AND `typescript-eslint` both widen to include 7** — either alone is not enough. Re-check at every phase boundary under R11 — this is a hold on a dependency's schedule, not on a judgement, so it lifts without a decision | | Lint toolchain | ESLint **10.9.1**, `@eslint/js` 10.0.1, `globals` 17.11.0, `eslint-plugin-astro` **3.1.0**, `eslint-plugin-jsx-a11y` 6.10.2, `typescript-eslint` 8.68.0, `typescript` **6.0.3** — **every pin at the registry's `latest` except `typescript`** `[verified 2026-08-30 — npm view, all 14 pins, R11 at the step 5 → 6 boundary; thirteen current, one held]`. `@eslint/js` and `globals` are declared explicitly; before 2026-08-26 `eslint.config.js` imported them and they resolved only by npm hoisting accident. **Accessibility linting is on** — `flat/jsx-a11y-recommended`, 36 rules `[verified 2026-08-26 — 7 rules fired on a deliberately inaccessible .astro file]`. `eslint-plugin-jsx-a11y@6.10.2` declares a stale `eslint ^3..^9` peer range; a one-line `overrides` entry in `package.json` resolves it. ⚠️ **`eslint-plugin-astro@3.1.0` declares `node ^22.22.3 \|\| ^24.16.0 \|\| >=26.3.0`**, which excludes Pouya's Node 25.6.0 — `npm install` prints EBADENGINE there. Dev-time only, and `nvm use` (Node 22 LTS, per `.nvmrc`) clears it. **`typescript` — the hold, and it was too wide by a whole major until 2026-08-27.** `latest` is **7.0.2** and it is unusable here: `typescript-eslint@8.68.0` peers `typescript >=4.8.4 <6.1.0` and `@astrojs/check@0.9.10` peers `^5.0.0 \|\| ^6.0.0`, so taking 7 breaks **both** the linter and `astro check` `[verified 2026-08-27 — npm view peerDependencies]`. **But this row previously read "held at 5.x", and 6.0.3 is a stable release both peers accept** — so the pin sat a full major behind for no reason the record could name, in a row whose whole job is to name the reason. Now at **6.0.3**, the newest version compatible with both peers; `npx tsc --version` reports 6.0.3 and the full gate is green `[verified 2026-08-27]`. The 6.x listing is mostly `-dev` and `-beta` tags; **6.0.2 and 6.0.3 are the only stable 6.x releases**, which is why `npm view typescript version` (7.0.2) is not the number to pin against here. Re-check at the next phase boundary: the hold ends when `typescript-eslint` widens its peer range past `<6.1.0` | | OG card generator | **`satori` 0.33.4 + `sharp`** (already a dependency), plus **`@fontsource/geist` 5.3.0** and **`@fontsource/instrument-serif` 5.3.0** as devDependencies — all four at `latest`, `npm audit` **0 vulnerabilities** with them in the tree `[verified 2026-08-31 — npm view, npm audit]`. Added at build step 7b; discharges R15. Chosen over `astro-og-canvas` 0.13.0 (also 0 vulnerabilities): `sharp` was already here to rasterise satori's SVG, so it is one library rather than a CanvasKit wasm blob, and it renders the site's real fonts and tokens instead of approximating them. ⚠️ **THE FONT PACKAGES ARE A WORKAROUND AND THE REASON IS MEASURED, NOT ASSUMED.** satori parses TTF/OTF/WOFF and **not WOFF2**, and decompressing this site's own `public/fonts/geist-latin-wght-normal.woff2` to TTF then **throws inside satori's `opentype.js` fork** — `parseFvarAxis: Cannot read properties of undefined` — because Fontsource's subsetting drops the `name` records the variable font's `fvar` table points at. `@fontsource/*` ships static 400 cuts as `.woff`, which satori reads directly: same typefaces, same upstream 5.3.0 that `docs/reference/fonts-provenance.md` records for the committed files, same weight. **Build-time only — no visitor fetches these**, and they are not covered by that file's provenance table because they are not served. ⚠️ **AND `src/lib/og-card.ts` RESOLVES ITS ASSETS FROM `process.cwd()`, NOT `import.meta.url`.** With `import.meta.url` the build fails on `ENOENT .../dist/.prerender/chunks/../styles/tokens.css`: Astro bundles that module into `dist/.prerender/chunks/`, so `import.meta.url` is the CHUNK's location. **It works under `astro dev` and dies at build** — the third defect of that shape in this run, alongside the `animation-timeline` minifier fold and Prettier's `{/* */}` → `{/_ _/}` rewrite. **The card palette is parsed out of `src/styles/tokens.css`** rather than duplicated, and a missing token throws rather than falling back to a wrong colour | | Lighthouse | **INSTALLED AND RUNNING AGAIN — `npm run lighthouse`, build step 7a, 2026-08-31. `lighthouse@13.4.1` + `chrome-launcher@1.2.1`, both `latest`, `npm audit` 0 vulnerabilities with them in the tree** `[verified 2026-08-31 — npm view, npm audit]`. ⚠️ **THIS ROW'S OWN ADVISORY ATTRIBUTION WAS WRONG, AND THE WRONG ATTRIBUTION IS WHY THE BUDGET WAS UNMEASURABLE FOR FIVE DAYS.** It read: *"`@lhci/cli` was the sole source of all 10 `npm audit` findings (7 high, via `lighthouse → puppeteer-core → extract-zip`)"*. The first clause is true; **the parenthesis is not**, and it is the parenthesis an implementer reads. Measured from two probe lockfiles rather than recalled: `@lhci/cli@0.15.1` carries 10 findings (7 high) and **pins `lighthouse` 12.6.1**; the two high carriers are **`tmp@0.1.0`, a DIRECT dependency of `@lhci/cli` itself**, and **`extract-zip@2.0.1` via `@puppeteer/browsers`**. In `lighthouse@13.4.1`'s 109-package tree **both are ABSENT** and `npm audit` returns **0**. **So Lighthouse was never the carrier.** `@lhci/cli` is still `latest` at 0.15.1 and still carries all ten `[verified 2026-08-31]` — the tool that was unusable stayed unusable, and the one the budget actually needs was clean the whole time. `npm view` alone would not have found this; it took the lockfiles. **DELIBERATE DEVIATION FROM R11's LITERAL TRIGGER, recorded as one.** R11 says *"at step 7, put `@lhci/cli` back"*. It is not back. **What that costs, stated rather than summarised away:** `lhci autorun`'s declarative assertion config, the LHCI server, and CI upload/history. `scripts/lighthouse.mjs` replaces the first with an inline threshold and does not replace the other two — there is no run history, so a slow regression across builds is invisible; only an absolute breach fires. **AND IT IS A LOCAL GATE, NOT A CI CHECK.** Standalone Lighthouse drives an installed browser; the `act_runner` is not registered at all (Q23) and would need Chrome on the host. So: `npm run lighthouse` at a keyboard, plus a blocking item on `docs/06`'s cutover checklist. It is **not** wired into `npm run build` or either deploy path, and `docs/06` now says why in those terms — a check described as running where it cannot is Q22's defect in a different costume, which is the same trap this row just came out of from the other side. **Pages are enumerated from `dist/`, never listed** — a hand-written page list stops covering the site the first time a page is added. ⚠️ **THE ACCESSIBILITY CATEGORY IS MEASURED WITH `prefers-reduced-motion` FORCED, and the qualification must travel with the number.** Measured twice per condition on `/process/`: motion on → **96**, `color-contrast` failing on **24 nodes**; motion off → **100**, 0 nodes. The 24 were the scroll-driven reveal caught mid-flight — axe reported foregrounds such as `#d0cbc4` on `#f8f4ed` and **neither value is in this palette**; they are the real colours blended toward the background by an in-progress `opacity` keyframe. A category that reports 24 known-false nodes on ten of fourteen pages cannot surface the twenty-fifth real one. The reduced-motion rendering is not synthetic: it is the branch `global.css` ships for a real user setting, and the one in which every element sits at its final colour. **Performance is measured on a default profile**, where the animation runs. ⚠️ **AND THE RUNNER'S FIRST VERSION SET `cache-control: no-store` ON ITS OWN SERVER, WHICH FAILED THE `bf-cache` AUDIT ON EVERY PAGE** — *"pages whose main resource has cache-control:no-store cannot enter back/forward cache"*. Lighthouse resets storage between runs by default, so the header bought nothing and cost an audit, in a report whose whole job is to find defects. Removed; verified by toggling the one header, twice each way. **Both of these are the same rule: a measurement is a claim about your instrument.** **Baseline, 14 pages, 2026-08-31:** performance 99–100, accessibility 100, best-practices 100, SEO 100, CLS 0.000 on every page. One budget note — **`/` LCP 2.03 s against `docs/04`'s < 2.0 s**, and the LCP element is `p.hero-lede`, **text**, not the portrait `[verified 2026-08-31 — lcp-breakdown-insight]`. So `fetchpriority="high"` on the hero image would misdirect priority away from the Geist face that actually gates it; the remaining lever is `BaseLayout`'s three-face preload, which is a documented measured trade. Left alone deliberately, not overlooked | -| Node | **22 LTS line**, `.nvmrc` holds `22` so it tracks the latest 22.x rather than freezing at a floor. `package.json` declares **`engines.node` = `^22.13.0 || >=24`** (verbatim — it excludes Node 23, an EOL odd line, which a flat `>=22.13.0` would have admitted) and **`engines.npm >=9.6.5`** — the intersection of every dependency's own floor: Astro 7 and `@astrojs/mdx` 7 need `>=22.12.0`, ESLint 10 needs `^20.19.0 \|\| ^22.13.0 \|\| >=24` `[verified 2026-08-26 — npm view astro@7.2.7 engines, npm view eslint@10.9.1 engines]`. **Pouya's machine reports Node v25.6.0** `[verified 2026-08-26 — node -v]`, an odd-numbered non-LTS line; it satisfies the floor, but `nvm use` keeps local and CI on the same runtime | +| Node | **22 LTS line**, `.nvmrc` holds `22` so it tracks the latest 22.x rather than freezing at a floor. `package.json` declares **`engines.node` = `^22.13.0 \|\| >=24`** (verbatim — it excludes Node 23, an EOL odd line, which a flat `>=22.13.0` would have admitted) and **`engines.npm >=9.6.5`** — the intersection of every dependency's own floor: Astro 7 and `@astrojs/mdx` 7 need `>=22.12.0`, ESLint 10 needs `^20.19.0 \|\| ^22.13.0 \|\| >=24` `[verified 2026-08-26 — npm view astro@7.2.7 engines, npm view eslint@10.9.1 engines]`. **Pouya's machine reports Node v25.6.0** `[verified 2026-08-26 — node -v]`, an odd-numbered non-LTS line; it satisfies the floor, but `nvm use` keeps local and CI on the same runtime | | Styling | Plain CSS with custom properties. No Tailwind, no CSS-in-JS `[verified 2026-08-25]` | | Known HTML-conformance error | **Astro's `` + `densities` emits a duplicate-density `srcset`, and it is upstream of this repo.** The pattern is `url, url 1x, url 2x, url 3x` — the first candidate carries no descriptor and therefore defaults to `1x`, so two candidates claim the same density, which puts the document in error per the HTML spec. **Behaviour is benign** and selection is correct at DPR 1, 2 and 3 `[verified 2026-08-27 — measured in headless Chrome]`. It affects **4 of the 12 `srcset` attributes on `/`** — the `` elements of every `` using `densities`, i.e. the three `InfinityMark` instances. The hero portrait uses `widths` + `sizes` and emits clean `w` descriptors. **Consequence for the record: do not claim "HTML validator clean" for any page carrying a mark**, and do not re-open this as a defect in this repo — it is ``'s output, not ours. It would go if `InfinityMark` moved to `widths` + `sizes`, which would mean every call site supplying a `sizes` string for a fixed-size decorative image; not worth it for a conformance nit. Recorded on `adversarial-reviewer`'s request, 2026-08-27; first raised as step-1 review finding #8 | | Deploy ordering | **`/` must not be deployed before `/about/` exists**, and the reason is machine-readable rather than visible. The home page's `Person` JSON-LD sets `url` and `@id` to `https://adr.smlcompany.ca/about/`, which is a **404 until build step 3**. The `@id` resolves inside the page's own `@graph`, so `provider` is fine; `Person.url` is the exposure, and it is the one part of the page a crawler acts on rather than renders. Every internal link is in the same position, which is inherent to a nineteen-page build order — **but D11 already governs this: "Build everything, one clean cutover", and nothing deploys until step 11.** Recorded because `npm run deploy` is a single command from this machine and the guard is a decision rather than a mechanism. Raised by `adversarial-reviewer`, 2026-08-27 | @@ -723,6 +723,7 @@ the audience it targets. Revisit at month 12–18. `[verified 2026-08-25 — dec | Intake API | `adr-intake-api`, HTTP API `4tl0m5igkj`, endpoint `https://4tl0m5igkj.execute-api.ca-central-1.amazonaws.com` `[verified 2026-08-26]`. **One route, `POST /submissions`** → integration `0ftgjgv` (`AWS_PROXY`, payload format **2.0**, which is the format `handler.mjs` reads). Stage `$default`, auto-deploy on, **no throttling**, no access log. CORS allows `POST` from the site origin `[verified 2026-09-01 — get-routes, get-api, get-stages, get-integrations]`. `DisableExecuteApiEndpoint` is **false** and must stay false: the CloudFront origin **is** that hostname. The form's route (`POST /api/intake`) does not exist yet — `docs/09` Part 6 | | Intake Lambda | `adr-intake-handler`, `nodejs24.x`, **arm64**, handler `index.handler`, timeout **10 s**, memory **128 MB**, role `adr-intake-lambda-role`, **no environment variables**, no DLQ, code **1,527 bytes**, last modified 2026-05-26 `[verified 2026-09-01 — get-function-configuration]`. **That is still the HAND-BUILT function, not `backend/intake/handler.mjs`** — nothing has been deployed (D11). Its resource policy has **one** statement, `apigateway.amazonaws.com` conditioned on `SourceArn` `…/4tl0m5igkj/*/*/submissions` — **the old route's path only**, so a new route needs its own permission or API Gateway is refused and answers 500 with nothing in the Lambda log. The execution role is **sufficient as it stands**: `dynamodb:PutItem` on the table (write-only — it cannot read it), `ses:SendEmail`/`SendRawEmail`, plus `AWSLambdaBasicExecutionRole`. Deployment commands: `docs/09-cutover-runbook.md` Part 5 | | Intake table | `adr-intake-submissions` (DynamoDB, ca-central-1) `[verified 2026-08-26]`. ⚠️ **KEY SCHEMA: PARTITION KEY `submissionId` (S), NO SORT KEY** ``[verified 2026-09-01 — `aws dynamodb describe-table`]``. **This contradicted `docs/05`, which specified `pk`/`sk`, and `backend/intake/handler.mjs` was written to the spec** — a `PutItem` missing the key attribute fails the whole write with `ValidationException`, the handler catches it and returns the failure page, so **every submission would have been lost while looking like a browser problem**. A DynamoDB key schema cannot be altered after creation; the handler was changed to the table on 2026-09-01 and `docs/05` §Storage carries the correction and the declined alternative. PITR **`ENABLED`**, 35-day window `[verified 2026-09-01 — describe-continuous-backups]`. Encryption at rest uses the **AWS-owned key — there is no customer-managed KMS key** `[verified 2026-09-01 — describe-table returns no SSEDescription]`, which `/legal/privacy/` does not claim, so nothing published depends on it. **4 items predate this repo**, written by the hand-built handler, which writes **no `ttl`** — so they never expire; `docs/06` carries that as Pouya's call. **TTL IS `ENABLED`, `AttributeName: ttl`** ``[verified 2026-08-31 — Pouya ran `describe-time-to-live` and read `TimeToLiveStatus: ENABLED`]``. The handler side matches: `backend/intake/handler.mjs` writes `ttl` as a Number in **epoch seconds** at **24 months** (`RETENTION_MONTHS = 24`, added to `getUTCMonth()`), which is `docs/05` §Retention and the `ttl` row of its item table `[verified 2026-08-31 — read from the handler, not recalled]`. ⚠️ **IT WAS `DISABLED` AT FIRST VERIFICATION EARLIER THE SAME DAY, AND THAT IS RECORDED RATHER THAN OVERWRITTEN.** Pouya ran `describe-time-to-live` on **2026-08-31** and it returned `DISABLED`; he enabled it on **2026-08-31** and re-read `ENABLED` the same day. `/legal/privacy/` has stated since build step 10 that a record is *"deleted automatically by the database rather than by someone remembering to do it"* after 24 months, so **that promise was unbacked from the day it was written until the day it was enabled** — the handler wrote the attribute and nothing on the table consumed it. This is the Q22 shape on a public privacy commitment rather than on a deploy control: a documented mechanism that did not exist. ⚠️ **`ENABLED` PROVES THE SETTING, NOT THE BEHAVIOUR, AND THE BEHAVIOUR IS STILL UNPROVEN — §9 Q60 STAYS OPEN.** No record has been written with a near-future `ttl` and watched to disappear. `docs/06`'s cutover checklist carries that test as a blocking item, it is not ticked by reading this row or the handler code, and §12 R19 keeps it surfacing until a deletion has actually been observed | +| **Intake table — who can read it** | 🛑 **TWO PEOPLE, AND `/legal/privacy/` PUBLISHES THAT NUMBER, WHICH IS WHY IT LIVES IN §7 AND NOT ONLY IN A REFERENCE EXTRACT.** `user/pouya` and `user/lars`, both via group **`admins`** carrying `AdministratorAccess`. **Four roles can also read it** — two `cdk-hnb659fds-cfn-exec-role-*` (all seven actions; trust `cloudformation.amazonaws.com` only) and two `cdk-hnb659fds-lookup-role-*` (the four read actions; trust the account root, and `sts:AssumeRole` is **allowed only for those same two users**). **`adr-intake-lambda-role` holds `PutItem` ONLY** — implicitDeny on `GetItem`/`Query`/`Scan`/`BatchGetItem`/`UpdateItem`/`DeleteItem`. **`adr-sml-deploy` is implicitDeny on all seven.** The CDK/CloudFormation escalation path is implicitDeny for all three deploy users. No SAML, OIDC or Identity Center principal exists (0/0/0). No resource-based policy on the table. Root holds **no access keys**, MFA on. ``[verified 2026-09-02 — 5 users x 7 actions, **all 33** roles x 7 actions — 26 non-service-linked and, added 2026-09-02, the 7 service-linked ones every earlier sweep had excluded by `grep -v '^AWSServiceRole'`, all implicitDeny, 4 trust policies, 5 users x 6 CDK-path actions, all in `docs/reference/intake-table-access-verification.md` with the counts asserted per call]``. ⚠️ **THE ORIGINAL 2026-09-01 VERIFICATION WAS NOT ENOUGH FOR THE SENTENCE IT BACKED**: it screened roles with `list-attached-role-policies` alone, so it never saw that **23 of 26 roles carry inline policies** and that the two `lookup` roles can read the table. Four roles can, not two. The conclusion held; the reasoning did not. **THE PAGE GOES FALSE IF THIS CHANGES AND NOTHING IN AWS WILL SAY SO — §12 R21 is the trigger.** | | SES identities | Domain `smlcompany.ca` **verified for sending** `[verified 2026-08-26]`; addresses `info@`, `intake@`, `adr@` | | SES account | **Production access GRANTED** — out of the sandbox in `ca-central-1`, confirmed by AWS in writing and effective immediately `[verified 2026-08-26 — Q19 closed]`. Mail now reaches unverified recipients, so the inquirer confirmation in D18 works | | Mail hosting | **Google Workspace** — MX `1 smtp.google.com`; `google._domainkey` present, so Google DKIM is configured `[verified 2026-08-26 — DNS query]` | @@ -773,7 +774,8 @@ Nothing below can be invented. Each needs an answer from Pouya. | # | Question | Blocks | |---|---|---| -| **Q62** | 🛑 **`/legal/privacy/` TELLS THE PUBLIC SOMETHING FALSE ABOUT WHO CAN READ THE INTAKE TABLE, AND IT IS A PRIVACY POLICY.** The page says: *"The table is reachable by the function that writes to it and by one administrative account, which is mine — nobody else has access to the table. There is no team, no assistant and no external administrator."* **The account has an IAM group `admins` carrying `AdministratorAccess` with TWO members**, and `iam simulate-principal-policy` returns **allowed** for `dynamodb:GetItem`, `dynamodb:Query` and `dynamodb:Scan` on the table for both of them — identical access, by the same route, the other user's own attachments being only `IAMUserChangePassword` `[verified 2026-09-01 — the five users, the group, and a five-row simulation, all commands in `docs/reference/intake-table-access-verification.md`]`. So **both halves of the sentence are wrong**: a second account has access, and it belongs to a second administrator of a shared account (§10). The three deploy users are `implicitDeny`; two CDK bootstrap roles carry `AdministratorAccess` but are assumable only by the same two administrators; the writing role holds **`PutItem` only and cannot read the table**, which is a stronger fact than the page currently claims and is the part of the sentence that is true. **THE QUESTION, AND IT IS ONE OF TWO THINGS.** (1) **Remove the access** — take that user out of `admins`, or deny DynamoDB on this table — after which the sentence becomes true as written. ⚠️ Note the likely collision: **Q23 records the Gitea instance as jointly administered and blocked on "its second administrator"**, so that access is probably not only for this account and removing it may cost something elsewhere. (2) **State the true number** — how many people hold administrative access, and that the function which writes cannot read. ⚠️ **DO NOT RESOLVE IT BY SOFTENING.** *"Access is limited to authorised administrators"* is the shape §4 exists to bar: defensible, uninformative, and it would replace a false specific with a true vacancy on the one page where a reader describing a live dispute is entitled to the specific. **Why this was invisible until now:** it is the only claim on the site whose subject lives entirely outside the repository, so R14 applies — *"unverifiable by construction"* — and there was no committed artefact to compare it against. There is now. Raised by `claims-auditor`, D20 cutover pass, finding 8 | **`/legal/privacy/` going public, and therefore the cutover.** `src/pages/legal/privacy.astro` carries the `TODO(pouya)` beside the sentence; `docs/06`'s checklist carries it as one of three items blocking the whole list. It blocks no other page and no other decision | +| **Q63** | 🛑 **TWO THINGS `/legal/privacy/` STILL NEEDS FROM POUYA, AND THEY ARE ANSWERED IN THE SAME READ-THROUGH.** **(a) APPROVE THE §Who can see it WORDING.** Q62 settled what it must say and he reserved the wording in terms: *"Draft it; Pouya gives final approval on wording during his page read-through."* The draft is shipped in `dist/` and quoted in `docs/reference/intake-table-access-verification.md`. **This is a gate that existed only inside records marked closed until 2026-09-02** — the `TODO(pouya)` had been deleted, Q62 struck, and `docs/06`'s blocker ticked, so when Q60's TTL test passes **nothing mechanical or visual would have stopped unapproved copy publishing.** `adversarial-reviewer`, round 1. **(b) WHO ELSE CAN READ `info@smlcompany.ca`?** Nothing in this repository establishes it — §7 records the mail host (Google Workspace) and the SES identities, **not the mailbox's access list**, and a Workspace super-admin can reach any mailbox in the tenancy. Given that this project's AWS account, its Gitea instance and §10 are all jointly administered, the plausible case is that it is not only him. The copy is now written to assert **no** access list (*"anyone who can reach that mailbox"*), so nothing false is published either way — but a privacy policy that answers the table half with a measured number and the mail half with a shrug is answering the same question on two standards, and the reader is entitled to the specific on both. **(c) WHO HOLDS THE ROOT CREDENTIAL FOR THE AWS ACCOUNT?** The page's headline answer is a **count of people**, and root is the one path no policy constrains and no simulation can reach — it is not an IAM principal and does not appear in `list-users`. Two facts bound it: `AccountAccessKeysPresent: 0`, so there is no programmatic root credential, and MFA is on, so console access needs the root password and its device `[verified 2026-09-02]`. **If those are held by anyone other than the two administrators, "Two people can" is short by one.** The second paragraph is scoped to *"every user and every role"* and to who has been **granted** access, so it is unaffected either way — this reaches the first sentence only. Raised by `adversarial-reviewer`, round 2, which is also where the honest form of the objection came from: the artefact says in terms that this is not established, and a page was resting a count on it. **If he answers: put the fact in §7, make the sentence specific like the table sentence above it, and arm it with §12 R21's trigger.** Raised by `claims-auditor` and `adversarial-reviewer`, D20 cutover pass round 1, 2026-09-02 | **`/legal/privacy/` going public, and therefore the cutover.** `src/pages/legal/privacy.astro` carries the `TODO(pouya)`; `docs/06`'s checklist carries (a) as its own unticked item. It blocks no other page | +| ~~**Q62**~~ | ✅ **CLOSED 2026-09-02 — RULED *state the truth*, NOT *remove the access*. Pouya:** *"Rewrite the `/legal/privacy/` sentence to say exactly who can access the submissions table… the true number of people and their roles, stated specifically — not 'authorised administrators' or any other vacancy."* **Applied.** The page now opens §Who can see it with *"Two people can"*, states that the AWS account also runs systems unrelated to this practice and has two administrators, and says administrative access carries the ability to read the table. It then publishes the two facts the false sentence had been crowding out and which are **stronger** than what it claimed: the function that receives the form can only add a record and **cannot read the table back**, and the credential that publishes this website has **no access to the table at all**. ⚠️ **THE FIX TOUCHED THREE PLACES, NOT ONE, AND THE OTHER TWO ARE THE POINT.** A vocabulary sweep — `grep -rniE "no (team\|assistant\|outside\|external) [a-z]*\|nobody else\|no one else" src/` — found the same falsehood in different words **two sections up the same page**: §Where it is stored ended *"and no assistant or outside administrator"*, which the Q62 pattern could not see because it was anchored on the two sentences under the other heading. And the summary paragraph closed *"the honest answer to 'who can see this' is: me, and Google"* — which would have survived the correction directly above it and re-asserted the struck number. All three now change together and the page's own comment says so. **THE TRIPWIRE STAYS PERMANENTLY — his ruling in terms:** *"it bars the false-claim shape from returning, which is exactly what the freeze's breach exception exists for."* Extended from two alternatives to **five** — round 1 of the closing audit found a third published surface unbarred, and found the first extension had widened one alternative to four phrasings where one was published. Every alternative is now a single string that reached `dist/`, so nothing speculative entered a frozen script. **Proven both ways, on real published bytes and not on fixtures alone:** against the pre-correction page rebuilt from `bd282aa` it exits **1** with **5 matches** at `dist/legal/privacy/index.html:54, 67, 67, 68, 72` — 54 is the clause the first form missed and 72 the surface it could not see at all — and against the corrected page it exits **0**, self-test 12 patterns / **36** approved strings, with **six** negative fixtures drawn from the replacement copy itself. ⚠️ **The counts in this row said four/four/33/three until 2026-09-02**, describing the script as it stood before round 1's fix; on a frozen script the record of what it bars is the maintenance surface, so `adversarial-reviewer` round 2 was right to treat a stale count as a defect. ⚠️ **AND THE FIX AS FIRST WRITTEN INTRODUCED THREE DEFECTS OF ITS OWN, ALL FOUND BY THE D20 PASS ROUND 1 AND ALL NOW CORRECTED — see entry (an).** The replacement asserted *"No third party has access to it"* (an absolute negative that excludes a **disclosed processor**, which is the exact sentence struck from this page on 2026-08-31 as *"the most serious thing found in the step 7–10 review"*); it claimed *"every account and role in this infrastructure… that is checked rather than assumed"* over an artefact that had screened five users and **one** role; and it said *"the one other place a copy exists"* when the handler puts the whole submission into the confirmation it sends the inquirer, so a **third** copy sits with the reader's own provider — which this page already says two sections up. **Q62's own fix recreated Q62's shape twice.** **Two things are NOT resolved and are now Q63 rather than a footnote here** — the wording approval Pouya reserved, and the `info@smlcompany.ca` access list. The earlier form of this row called the mailbox point non-gating *"because the copy is true either way"*, which was **a guess about a fact nobody checked**; the copy is now written so it asserts no access list at all, and the question gates the page through Q63 with a `TODO(pouya)` beside it. Original finding follows. 🛑 **`/legal/privacy/` TELLS THE PUBLIC SOMETHING FALSE ABOUT WHO CAN READ THE INTAKE TABLE, AND IT IS A PRIVACY POLICY.** The page says: *"The table is reachable by the function that writes to it and by one administrative account, which is mine — nobody else has access to the table. There is no team, no assistant and no external administrator."* **The account has an IAM group `admins` carrying `AdministratorAccess` with TWO members**, and `iam simulate-principal-policy` returns **allowed** for `dynamodb:GetItem`, `dynamodb:Query` and `dynamodb:Scan` on the table for both of them — identical access, by the same route, the other user's own attachments being only `IAMUserChangePassword` `[verified 2026-09-01 — the five users, the group, and a five-row simulation, all commands in `docs/reference/intake-table-access-verification.md`]`. So **both halves of the sentence are wrong**: a second account has access, and it belongs to a second administrator of a shared account (§10). The three deploy users are `implicitDeny`; two CDK bootstrap roles carry `AdministratorAccess` but are assumable only by the same two administrators; the writing role holds **`PutItem` only and cannot read the table**, which is a stronger fact than the page currently claims and is the part of the sentence that is true. **THE QUESTION, AND IT IS ONE OF TWO THINGS.** (1) **Remove the access** — take that user out of `admins`, or deny DynamoDB on this table — after which the sentence becomes true as written. ⚠️ Note the likely collision: **Q23 records the Gitea instance as jointly administered and blocked on "its second administrator"**, so that access is probably not only for this account and removing it may cost something elsewhere. (2) **State the true number** — how many people hold administrative access, and that the function which writes cannot read. ⚠️ **DO NOT RESOLVE IT BY SOFTENING.** *"Access is limited to authorised administrators"* is the shape §4 exists to bar: defensible, uninformative, and it would replace a false specific with a true vacancy on the one page where a reader describing a live dispute is entitled to the specific. **Why this was invisible until now:** it is the only claim on the site whose subject lives entirely outside the repository, so R14 applies — *"unverifiable by construction"* — and there was no committed artefact to compare it against. There is now. Raised by `claims-auditor`, D20 cutover pass, finding 8 | *(closed)* | | ~~**Q61**~~ | ✅ **CLOSED 2026-09-01 — RULED *fix now*, IMPLEMENTED AND MEASURED.** The minimum-font-size sticky header obscured keyboard focus: **290 entirely-hidden focus stops of 1,455** under `minimumFontSize=32`, a WCAG 2.2 **SC 2.4.11 (AA)** failure, created by the 2026-09-01 header fix. The fix is two declarations on `html` in the existing `@media (min-width: 66rem)` block — the plain `calc(var(--header-h) + var(--space-4))` first as a fallback, then `max(calc(var(--header-h) + var(--space-4)), calc(10lh - 83px))`. **`1lh`, not `rem`: the font-metric units read the *used* font size**, which is the mechanism the withdrawn ruling's premise denied existed. **Result, on the identical grid with the pre-fix tree rebuilt in a worktree as the control: 290 → 0, control still 290.** Default-settings rendering unchanged: **0 differences over 352 page-widths × 17 fields**, positive control detecting exactly 1 injected difference. `scroll-padding-top` 97 px at the default, 287 px under the setting against a 270.56 px header; `1lh` on `` is 18 / 37 px **with every `.woff2` blocked**, identical, because `` keeps the UA family. A wider grid than the ruling asked for — **777 cells over 37 settings — went from 63 failing to 12, with no cell worse.** The 12 are `minimumFontSize=16` and `=20`, they are **pre-existing and reduced**, and they were deliberately not fixed under Pouya's *"stop and report, do not widen"*: the setting floors sub-root type without moving the root, so `1lh` reads a quantity that did not change. `docs/06` carries it as its own item | *(closed)* | | **Q60** | ⚠️ **HAS A TEST RECORD BEEN OBSERVED TO DISAPPEAR FROM THE INTAKE TABLE?** **Half one closed 2026-08-31: TTL is `ENABLED` with `AttributeName: ttl`, verified by command — §7 holds that status and this row does not restate it.** The question is now the second half alone, and it was never the smaller half. `/legal/privacy/` does not merely publish a retention *period* — it asserts a **mechanism**: *"the record is deleted automatically by the database rather than by someone remembering to do it"*. **`ENABLED` proves the setting; only a record written with a near-future `ttl` and watched to vanish proves the behaviour.** Two things this may NOT be answered from: the handler code, which writes the attribute and nothing more (that side is verified and is not what is being asked); and the table setting, which is what was just confirmed. ⚠️ **AND THE FIRST HALF IS THE REASON TO TRUST THE SECOND LESS, NOT MORE:** `describe-time-to-live` returned **`DISABLED`** when Pouya first ran it on 2026-08-31, so the sentence above was published against a mechanism that was not running, and nothing in the repo, the build or AWS reported it. A setting that was off for as long as nobody looked is not evidence that the behaviour now works. `TODO(pouya)` sits on the retention section of `src/pages/legal/privacy.astro`; `docs/06`'s cutover checklist carries the test as blocking; §12 R19 keeps it surfacing. **Why this is a numbered question and not only a checklist line:** `CLAUDE.md` requires a `TODO(pouya)` plus a §9 row when a page needs a fact the repository does not have, and this page needs one — a cutover checklist fires once, at cutover, and §9 is what a person editing this page reads. Raised by `adversarial-reviewer` round 2, 2026-08-31 | **`/legal/privacy/` going public.** Nothing else — no other page states the mechanism, verified by sweeping `dist/` for the retention vocabulary and reading each hit in context | | ~~Q59~~ | ✅ **RULED AND CLOSED 2026-08-31 — Pouya. OVERTIME RUNS FROM THE SESSION CAP**: the fourth hour of a half day, the seventh of a full day. Not the billed envelope. `/fees/` shipped at build step 9 on this ruling and `docs/07` carries it in full. ⚠️ **THIS ROW NAMED A CONSTANT THAT NO LONGER EXISTS** — `FEES.mediation.overtimeStartsAfterSessionHours` was deleted the same day as dead data: nothing read it, so reversing it would have changed nothing and failed nothing, which is Q22's shape at constant scope. **Where the ruling actually lives:** the trigger is rendered on `/fees/` from `halfDay.hours` / `fullDay.hours`, and `FEES.mediation.reservation` carries the half that publishes as prose. Found by `adversarial-reviewer` round 2 — §9 is what a later implementer reads to find where a ruling is recorded, so pointing it at a deleted identifier is the same defect one layer up. ⚠️ **AND THE RULING CAME WITH A SECOND HALF THAT ANSWERS THE ARITHMETIC ANOMALY THIS ROW EXISTED TO ESCALATE, WHICH THE TRIGGER ALONE COULD NOT.** His words: *"a full day reserves the day; half-day overtime is subject to availability."* **The full-day fee buys the DAY, not six hours of it.** Read as a price comparison the table below says the full-day rate is never the cheaper choice; read knowing what each fee reserves, the $2,000-narrowing-to-$500 spread is the price of certainty rather than a defect. The sentence is `FEES.mediation.reservation` and it publishes **adjacent to the overtime row**, not as a footnote — the same structural rule as `PROCESS_FRAMING` beside the five timings under Q43, because a reader who takes the number and skips the framing has read a different offer. **THE ANOMALY IS NOT CLOSED AND STAYS ON §12 R5.** The gap is in D14's own figures — the half-to-full step is $2,000 against $1,500 for three hours of overtime — and the reservation point explains what it buys without removing it; the spread is largest at three to five hours, which is the band a half-day booking actually overruns into. `docs/07` §Recorded dissent carries the table for the 12-month review. **The original question, kept because the shape of it is the lesson.** *Where does the overtime hour start?* `docs/07`'s card carried *"Overtime, per hour — $500"* and had never said what it was overtime **to**. Q58's ruling settled the two allowances and did not reach this; Q15–Q17's answer records the rate with no trigger. The two candidates were the session cap (3 h / 6 h) and the billed envelope (5 h / 9 h), and this repository was barred from picking one — a fee term is a fact we do not have, and `CLAUDE.md`'s rule for that is a question, not an inference. **It cost two strikes to hold that line:** a first pass at `docs/07`'s Q58 note asserted the session cap as applied fact and `adversarial-reviewer` struck it in the change set that wrote it; a round-1 fix then published the $500 rate on `/for-parties/` beside an unambiguous *"up to 3 hours"*, which **defines the trigger by adjacency** — nothing else on the page is a quantity it can attach to — and round 2 struck that too. Both strikes were right, and the ruling supplied the value they were waiting for | ~~`/fees/`, `/for-parties/`~~ — both now unblocked and shipped | @@ -838,7 +840,7 @@ Nothing below can be invented. Each needs an answer from Pouya. | ~~Q54~~ | **ANSWERED 2026-08-29 — ALL SIX PUBLISH, INCLUDING (c), AND THE ANSWER CREATED A THIRD CLASS IN §4.** Pouya: *"Publish all six, including (c). (c) ships as drafted."* His reasoning on the expensive one, recorded on his instruction: *"it is the strongest available answer to the med-arb objection, and cheaper in practice than it sounds — the arbitral phase runs on the evidentiary record, not the caucus, so the case where a neutral genuinely cannot decide without confidential material is uncommon. `/med-arb/` was raising the hardest question about med-arb and answering it only at the level of process design."* **§4 now carries `Conduct undertakings` as a class distinct from both credentials and offerings** — his ruling: *"They are not facts about experience; they are commitments Pouya has now made... and they bind."* The gate for the class is one line: he must have said it in terms. The six strings are `CONDUCT_UNDERTAKINGS` in `src/data/site.ts` and the three pages render them, so **a later softening shows up as a diff on one constant** — his instruction that softening is a change to a published commitment, made mechanical rather than left as a note. (a)(b)(c) ship on `/med-arb/` in a new §What I undertake; (d) on `/mediation/` §Confidentiality; (e) and (f) on `/arbitration/`, each **replacing** the third-person sentence that already stated the same proposition as an observation. ⚠️ **The stamp reads 2026-08-29, not the 2026-08-27 he named** — the drafts did not exist on 2026-08-27 (Q54 was raised 2026-08-28), so that date would predate the text. **RATIFIED 2026-08-30: 2026-08-29 stands.** Pouya: *"You're right that a commitment cannot predate its own text. My 2026-08-27 was the date I ruled, not the date the undertakings existed."* | — | | **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 `` 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 | +| ~~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 | | **Q23** | **Is a Gitea `act_runner` registered, and are Actions enabled in `app.ini`?** *The version half is closed:* the instance reports **1.27.2** `[verified 2026-08-26 — /api/v1/version]`, so the `vars` context is supported and the first-step guard is belt-and-braces rather than load-bearing. **What remains is not a fact to look up but a dependency on a person:** git.larsnolden.com is **jointly administered**, and both enabling Actions and registering a runner need the second administrator. Until then `npm run deploy` is the path, and it is documented rather than treated as a workaround | How deploys are triggered — not what they do | ## 10. Risks @@ -923,7 +925,7 @@ never being raised again. | R5 | **Fee review at 12 months.** Published rates are sticky; the right moment to move them is deliberate, not reactive. ⚠️ **ONE ITEM IS ALREADY WAITING AND IT IS ARITHMETIC RATHER THAN JUDGEMENT — added 2026-08-31:** the half-day-plus-overtime route is cheaper than the full-day rate at **every** session length, by $2,000 at three hours narrowing to $500 from six on, because the half-to-full step is $2,000 and three hours of overtime is $1,500. Written out in `docs/07` §Recorded dissent with the table, which is the section built for this review to test against. The **trigger** for the overtime hour is a separate open question — §9 Q59 | 2026-08-26 | D14 is priced for where the practice is going, not where it is. And the anomaly above was assigned to this reminder twice in one change set and written into neither place the reminder lives, which is the failure §12 exists to prevent | | 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~~ | ✅ **CLOSED 2026-09-01. The `ses-alerts` email subscription is CONFIRMED** — `aws sns list-subscriptions-by-topic` returns a real subscription ARN rather than the literal `PendingConfirmation` `[verified 2026-09-01]`, so the two bounce/complaint alarms reach `info@smlcompany.ca`. ⚠️ **It had been confirmed for some unknown part of six days while §7, `docs/05`, `docs/06` and this row all said the alarms fired into nothing.** That is the Q22 staleness in the **safe** direction, and the direction is why it lasted: nothing was broken, so nothing prompted anyone to re-read it. The generalisable half, and it is worth more than the row: **a record whose staleness is harmless is the record that stays stale longest**, because every other kind announces itself by breaking something. Re-read the harmless ones on a schedule or they are never re-read at all. *Previous text follows.* **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 | ⚠️ **A THIRD SURFACE, 2026-08-30: `/process/` §Confidentiality renders `MEMBERSHIP_ORGS[0]` ("I am a member of the ADR Institute of Canada").** It is rendered from the constant rather than typed, so the sweep this reminder prescribes reaches it — that was `adversarial-reviewer`'s finding and the fix, in that order. **DISCHARGED AS WRITTEN 2026-08-28 — AND RE-ARMED WITH AN EVENT TRIGGER INSTEAD OF A DATE. STILL LIVE.** Pouya re-confirmed all four memberships as current (Q44), which discharges the prohibition this row carried, and `/about/` now publishes the Memberships group. **The row does not close, because he declined renewal-date tracking**, and that was his instruction for what to do about it: *"Without renewal months it cannot fire on a date, so make it fire on an event: re-confirm memberships before any cutover or major republish, and re-stamp §4 when confirmed."* **THE TRIGGER: re-confirm before any cutover, and before any major republish. Then re-stamp §4 the same day.** **His reason, kept verbatim because it is the general principle and not a membership detail:** *"§4 already carries OCNI as lapsed and unpublishable, and that was found roughly a year late. A stamp with no trigger behind it goes stale silently, which is exactly how OCNI got onto a list of things to feature."* **Two things the discharge did NOT license.** (1) **No currency warranty on the page** — list the memberships, promise nothing about their future state; the struck sentence stays struck and nothing replaces it. (2) ~~`memberOf` stays out of the JSON-LD~~ — **SUPERSEDED. Q53, ruled 2026-08-28: EMIT IT.** `/about/`'s Person node now carries the four memberships as `Organization` nodes. Pouya took `adversarial-reviewer`'s argument: they are already crawlable in `/about/`'s HTML, so withholding the triple reduced no exposure and only made the graph less complete than the page. **The consequence for THIS reminder is that it now covers two surfaces** — re-confirming before a cutover means `src/data/schema.ts` as well as the visible list, and they must not be allowed to diverge. **Renewal periods, stated once and not widened again:** the OBA sections and the CTF renew yearly; §4 records **nothing** about ADRIC's or ADRIO's period, and the widened form ("all four renew yearly") reached four files before it was swept. *Previous text described the prohibition and the withheld group; it held for one session and did its job.* | 2026-08-26 | A credential that lapses quietly is the failure mode §4 exists to prevent, and OCNI already did exactly this. The group is on a public page now, which raises the cost of a lapse rather than lowering it — *(This rationale ended by pointing at **Q48** as a possible widening of the row. Q48 closed 2026-08-28 as not site-relevant — ADRIO retention governs whether Pouya keeps a designation, not what the site may say about holding one — so the clause is struck. §12 is read aloud every session; a live reminder pointing at a struck row produces a false surface every time.)*, not just a list | +| R10 | ⚠️ **FIRED AND STILL UNSATISFIED AS AT 2026-09-02 — THE CUTOVER EVENT HAS ARRIVED AND THE CONFIRMATION HAS NOT.** Asked of Pouya on 2026-09-02 as a one-line question — *are ADRIC, ADRIO, the three OBA sections and the CTF all still current?* — and left **open** on `docs/06`'s checklist on his instruction, alongside R18 which fired and **was** satisfied the same day. **It may not be ticked from the 2026-08-28 stamp.** That is the entire content of this reminder: a stamp is not a renewal receipt, and re-reading an old one is not re-confirming. When he answers, re-stamp **§4 and `src/data/schema.ts`** with the answer's date — both surfaces, because `memberOf` is emitted. Original text follows. ⚠️ **A THIRD SURFACE, 2026-08-30: `/process/` §Confidentiality renders `MEMBERSHIP_ORGS[0]` ("I am a member of the ADR Institute of Canada").** It is rendered from the constant rather than typed, so the sweep this reminder prescribes reaches it — that was `adversarial-reviewer`'s finding and the fix, in that order. **DISCHARGED AS WRITTEN 2026-08-28 — AND RE-ARMED WITH AN EVENT TRIGGER INSTEAD OF A DATE. STILL LIVE.** Pouya re-confirmed all four memberships as current (Q44), which discharges the prohibition this row carried, and `/about/` now publishes the Memberships group. **The row does not close, because he declined renewal-date tracking**, and that was his instruction for what to do about it: *"Without renewal months it cannot fire on a date, so make it fire on an event: re-confirm memberships before any cutover or major republish, and re-stamp §4 when confirmed."* **THE TRIGGER: re-confirm before any cutover, and before any major republish. Then re-stamp §4 the same day.** **His reason, kept verbatim because it is the general principle and not a membership detail:** *"§4 already carries OCNI as lapsed and unpublishable, and that was found roughly a year late. A stamp with no trigger behind it goes stale silently, which is exactly how OCNI got onto a list of things to feature."* **Two things the discharge did NOT license.** (1) **No currency warranty on the page** — list the memberships, promise nothing about their future state; the struck sentence stays struck and nothing replaces it. (2) ~~`memberOf` stays out of the JSON-LD~~ — **SUPERSEDED. Q53, ruled 2026-08-28: EMIT IT.** `/about/`'s Person node now carries the four memberships as `Organization` nodes. Pouya took `adversarial-reviewer`'s argument: they are already crawlable in `/about/`'s HTML, so withholding the triple reduced no exposure and only made the graph less complete than the page. **The consequence for THIS reminder is that it now covers two surfaces** — re-confirming before a cutover means `src/data/schema.ts` as well as the visible list, and they must not be allowed to diverge. **Renewal periods, stated once and not widened again:** the OBA sections and the CTF renew yearly; §4 records **nothing** about ADRIC's or ADRIO's period, and the widened form ("all four renew yearly") reached four files before it was swept. *Previous text described the prohibition and the withheld group; it held for one session and did its job.* | 2026-08-26 | A credential that lapses quietly is the failure mode §4 exists to prevent, and OCNI already did exactly this. The group is on a public page now, which raises the cost of a lapse rather than lowering it — *(This rationale ended by pointing at **Q48** as a possible widening of the row. Q48 closed 2026-08-28 as not site-relevant — ADRIO retention governs whether Pouya keeps a designation, not what the site may say about holding one — so the clause is struck. §12 is read aloud every session; a live reminder pointing at a struck row produces a false surface every time.)*, not just a list | | R11 | **Re-check dependency currency at every phase boundary in the build order** (`docs/01-architecture.md` §Build order, 11 steps). Run `npm view 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. ✅ **THE STEP-7 RE-ADD TRIGGER IS DISCHARGED, 2026-08-31 — and NOT as written.** It said *"at step 7, put `@lhci/cli` back"*. `@lhci/cli` is still 0.15.1, still `latest`, and still carries 10 findings (7 high) `[verified 2026-08-31]`, so the literal instruction would have re-added a tool with seven high-severity advisories. What shipped is **`lighthouse@13.4.1` + `chrome-launcher@1.2.1`, 0 vulnerabilities**, as `npm run lighthouse`. **The reason is that §7's own advisory attribution was wrong** — it blamed `lighthouse → puppeteer-core → extract-zip`; the carriers were `@lhci/cli`'s own `tmp` and `@puppeteer/browsers`' `extract-zip`, and neither exists in Lighthouse's tree. **The last clause of this trigger is the one that earned its place:** *"if the advisories are still unfixed, that is a decision to take deliberately, not a reason to leave the gap unstated."* They are still unfixed; the decision was taken; §7 records what it costs (no `lhci` assertion config, no server, no run history) and that the gate is local rather than CI, because standalone Lighthouse needs an installed browser and the runner has none. **All six UNAVAILABLE notices are deleted** — `docs/04` (budget table, Performance callout, post-launch checklist), `CLAUDE.md` (performance budget, definition of done), `/build` Phase 5, `docs/06` (PR checks, cutover checklist), `.claude/agents/adversarial-reviewer.md` §4. The **general** half of R11 — re-check every pin at every phase boundary — is untouched and still fires. ✅ **SWEPT AGAIN 2026-09-01, all 19 pins against `npm view`, and TWO MAJORS ARE DEFERRED BY RULING rather than left unstated:** `@astrojs/mdx` **^7.0.8 → 8.0.0** and `typescript` **^6.0.3 → 7.0.2**. Pouya's reasoning — *"npm audit is clean and majors mid-walkthrough add churn without user value"* — with `npm audit` at **0 vulnerabilities** `[verified 2026-09-01]`, which makes it a churn decision and not a security one, **and one that flips the moment that stops being true.** Both now sit on a new **Cutover prep** group at the head of `docs/06`'s cutover checklist, dated, because deferring a thing and forgetting it look identical three weeks later. Four more are a minor or patch behind and already satisfied by their carets, so they need no edit — `astro` 7.2.9 → 7.2.10, `@astrojs/sitemap` 3.7.3 → 3.7.4, `globals` 17.11.0 → 17.12.0, `typescript-eslint` 8.68.0 → 8.69.0; the other 13 are current. **This row is the deferral's reminder, not its replacement** — R11 fires at the next phase boundary regardless | 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 `ab` 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 `` 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 | @@ -931,9 +933,10 @@ never being raised again. | ~~R15~~ | ✅ **DISCHARGED 2026-08-31 — build step 7b. Seventeen pages and every future article now carry their own generated card; `/` and `/about/` keep the portrait, which Q40 called "not an interim" and which is unchanged.** `src/pages/og/[...slug].jpg.ts` renders them at build from `satori@0.33.4` + `sharp`; `src/data/og-cards.ts` is the registry; `SEO.astro` resolves which of the two kinds a page gets from its own pathname, so the decision lives in one data file rather than in nineteen call sites. `satori` over `astro-og-canvas@0.13.0` — both 0 vulnerabilities `[verified 2026-08-31]` — because `sharp` was already a dependency, so it is one library rather than a CanvasKit wasm blob, and it renders the site's real fonts and tokens instead of approximating them. **The interim note is deleted from `docs/04` and the cutover line from `docs/06`**, which is what this row's trigger asked for. ⚠️ **AND IT SURFACED A HOLE THAT IS WORTH MORE THAN THE ROW: TEXT BAKED INTO A JPEG CANNOT BE GREPPED BY `npm run check:claims`, WHICH UNDER D20 IS THE ONLY PER-STEP CLAIMS CONTROL THERE IS.** A card is the one surface on this site where new prose would face no mechanical check at all. So card copy is constrained structurally rather than editorially: **every headline is its page's own `

`, character for character**, the kicker renders `CREDENTIALS.designations`, and **`npm run og:proof` enforces both against the built HTML** — it fails if the registry and the page disagree in either direction, and it also confirms every `og:image` resolves to a file that exists. That check found a straight-versus-typographic apostrophe on its first run. **A page with no registry entry is a build error, not a fallback to the portrait** — R15's failure mode was never the wrong image, it was the wrong image shipping *invisibly* and reading as intentional, and a silent fallback recreates it exactly. **What is NOT discharged and is deliberately left open:** the check compares strings, so it cannot see a card that renders badly — a headline that overflows, a mark that clips. `npm run og:proof -- --sheet` writes a contact sheet of every card for that, and **a human still has to look**; `docs/06`'s cutover item says so. Two cards were read at step 7b (`/practice/energy/`, the longest headline, and `/practice/insurance/`) and rendered correctly | 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 cost nothing and worked, which is exactly the R13 shape | | ~~R16~~ | ✅ **DISCHARGED 2026-08-31 — build step 9, which is the trigger this row set. The one-page PDF exists, is committed at `public/pouya-lajevardi-bio.pdf`, and `/about/` links it.** Q45's two open sub-decisions are both taken, and the second one is what makes the first safe. **(a) Generated at build, or authored once? NEITHER — and the third option answers this row's actual objection.** The bio is a PAGE, `src/pages/bio.astro`, so every line of it is reviewed by the same apparatus as every other page: `astro check`, `npm run check:claims` on the built HTML, the per-step code review, and the cutover claims pass. `npm run bio:pdf` then RENDERS the PDF from the built page through Chrome, with **no new dependency** — `chrome-launcher` is already a devDependency because Lighthouse needs it. That is aimed squarely at what this row said the problem was: *"It is the one artefact class this project's review apparatus cannot reach… a PDF circulated with an appointment proposal is read once, by the reader who matters most, and never seen by a reviewer again."* A rendering of a reviewed page is back inside the apparatus. **It is deliberately NOT part of `astro build`** — CI has no Chrome, and a build step that cannot run in CI is Q22's shape again — so the PDF is committed, which R14 wants anyway. **(b) Does it carry anything the site does not? NO, and that is the answer that avoids the §4 question this row flagged.** Every line renders from `CREDENTIALS`, `ROLE`, `BOUTIQUE`, `PRACTICE_AREAS`, `FEES` and `CONTACT`. No matter list — which this row correctly said *"would collide with §4 Forbidden directly"* — no referees, and no figure that is not on `/fees/`. The fee summary IS there, because this row's own reasoning is that an appointment proposal needs the rate card as much as the bio. ⚠️ **`npm run bio:pdf` ASSERTS ONE PAGE and writes nothing if the count is wrong** — counted from the PDF's own page objects, cross-checked against the page tree's `/Count`. A one-page bio that silently becomes two is invisible from the source, because it depends on the print stylesheet, the paper size and how much §4 has grown. **And reading the rendered PDF caught a real breach the source review had not:** the opening sentence read *"I act as a neutral in commercial disputes — as a mediator, as an arbitrator in commercial matters…"*, whose leading clause scoped **mediation**, which Q56 leaves unscoped deliberately. `/bio/` is `noindex` and out of the sitemap: it is a condensed duplicate of `/about/` and `/fees/`. **What is NOT discharged:** nothing in the build regenerates the PDF. It must be re-rendered and re-committed whenever `/bio/`, §4, the rate card or the print styles change, and `docs/06`'s cutover checklist carries that | 2026-08-28 | It is the one artefact class this project's review apparatus cannot reach. A web page is re-reviewed by every audit and re-checked by every build; a PDF circulated with an appointment proposal is read once, by the reader who matters most, and never seen by a reviewer again | | R17 | **THE DEPLOY KEY'S FIRST ROTATION IS DUE 2026-11-26, AND THAT DATE IS THE WHOLE ROW.** Access key for `adr-sml-deploy` created **2026-08-26**; D3 commits to **quarterly** rotation. Pouya's instruction when Q22 closed: *"Put the DATE in the R-series reminder, not the intention."* **Rotation procedure is in `docs/06-deployment.md` §Key rotation** — create the second key, update the Gitea secrets, verify a deploy, **then** delete the first; never delete before verifying, or the next push fails with no way to authenticate the fix. **Then set the next date here (2027-02-26) rather than deleting the row.** Also re-run **all nine** `simulate-principal-policy` checks after any policy edit (they are listed and reproducible in `docs/reference/deploy-credential-verification.md` §5) — the narrowness is the control (§10), and a widened policy is invisible from inside the repo. **The key is currently UNUSED — `AccessKeyLastUsed` returns `ServiceName`/`Region` = `N/A` and no `LastUsedDate`** — because deploys still run locally via `npm run deploy`; that does not pause the clock, and an unused long-lived key is exactly the one nobody remembers to rotate | 2026-08-28 | This is the reminder D3 has been waiting for a subject since 2026-08-26. §10 records the reason it matters more here than on a normal project: the secret lives on **jointly-administered** infrastructure, and the account also holds another business's client-database backups. A static key on shared infrastructure is only as safe as its age and its scope, and **nothing in the repo, the build, or AWS will prompt anyone on either.** §7 carries the inventory; this row carries the date | -| R18 | **THE SIX `docs/reference/` EXTRACTS BEHIND `/practice/*` ARE DATED 2026-08-29, AND SIX SHIPPED SENTENCES TURN ON FACTS THAT MOVE.** Build step 5 put statute, regulation, tribunal and bill status onto public pages — sourced, but **sourced as at one day**. The volatile ones, in order of how fast they move: **(a) federal Bill C-36** — `/practice/technology/` says it *"was introduced in June 2026 and was at second reading when this page was written"*; if it receives royal assent the page is wrong about the most load-bearing fact on it. **(b) the Ontario regulation under `Electricity Act` s. 28.1** — `/practice/energy/` says it *"had not been made as of August 2026"*. **(c) the ERO 026-0853 consultation**, comment period to **12 September 2026**. **(d) the Tribunals Ontario annual report** — `/practice/insurance/` publishes FY2024-25 figures and the extract records that a 2025-26 edition was never ruled out. **(e) the SABS**, amended with effect 1 July 2026. **(f) the ADRIC National Mediation Rules**, under review by ADRIC's own committee. **(g) ADRIC's Code of Ethics** — added 2026-08-30, build step 6. `/process/` §Confidentiality quotes it verbatim from `docs/reference/adr-institution-names.md` (retrieved 2026-08-29) **with a live link to ADRIC's page**, which is what makes it checkable and also what makes a stale quotation visible. It is the slowest-moving item here — a professional code, not a bill — so it does not change the cadence; it is listed because the trigger below says "all six" and there are now seven. **THE TRIGGER: re-check all seven extracts before any cutover, and before any republish that turns on one of them — the same event trigger R10 uses.** Then re-stamp the extract. **A page that was true when it was written and is false when it is read is still a false page**, and this is the first change set on the project to put that class of fact into public copy at volume | 2026-08-29 | Six sentences, six files, one retrieval date. Nothing here fires on its own; a fact with a shelf life and no owner is exactly what §12 exists for | +| R18 | ✅ **RE-CHECKED 2026-09-01 — the cutover fire. ALL SEVEN HOLD AND NO SHIPPED SENTENCE CHANGED.** Verified by Pouya (architect verification, Claude web) and recorded here with the sources, because the trigger is *"re-check before any cutover"* and this is that cutover. ⚠️ **THE STAMP IS TWO-TIER ON PURPOSE AND THE TIERS MUST NOT BE COLLAPSED: three limbs were re-verified against a source; four are held unchanged on a CADENCE JUDGEMENT rather than a fresh retrieval.** Writing all seven as "re-checked" would be the OCNI failure in miniature — a stamp that reads like a check and records a belief. ⚠️ **AND A CANDIDATE EIGHTH LIMB WAS FOUND WHILE STAMPING, FLAGGED RATHER THAN ADOPTED — (h)**: `/practice/construction/` publishes *"Ontario Power Generation … applied in March 2026 for a licence to operate it"*, a **pending application** that moves the way (a) moves. Not false today — the application was made, and a completed past act stays true — so it blocks nothing; but unlike (a) the sentence is **not time-anchored**, and a reader takes it as current status. **Pouya's call at the next re-check: adopt it as (h), or time-anchor the sentence and drop it.** **RE-VERIFIED AGAINST A SOURCE:** **(a) Bill C-36** — still at second reading in the House of Commons; latest completed stage **first reading, 2026-06-15**; no advance since `[re-checked 2026-09-01 — ]`. `/practice/technology/`'s *"was at second reading when this page was written"* stands. **This is the fastest mover of the seven and it needs no page edit while it sits, and one the day it moves.** **(d) the Tribunals Ontario annual report** — **no 2025-26 edition is published; FY2024-25 remains current** `[re-checked 2026-09-01 — ]`, so the figures `/practice/insurance/` publishes are still the latest. **This also closes an open item at the foot of `docs/reference/ontario-sabs-lat.md`** which had recorded *"NOT CONFIRMED either way… given today's date, one may well have been published"* — the honest gap is now answered. **(c) ERO 026-0853** — comment period to **2026-09-12** still open `[re-checked 2026-09-01]`. **HELD UNCHANGED ON A CADENCE JUDGEMENT, NOT RE-RETRIEVED — `[assumed 2026-09-01 — Pouya: unchanged by their nature at this cadence]`:** **(b)** the regulation under `Electricity Act` s. 28.1, **(e)** the SABS, **(f)** the ADRIC National Mediation Rules, **(g)** ADRIC's Code of Ethics. The quoted bytes in every extract are still the original retrieval and were not re-fetched; the digests in `adric-rules.md` were not recomputed, so that stamp says nothing about whether the page changed. ⚠️ **AND THE TRIGGER HAD NOWHERE TO FIRE, WHICH IS Q22'S SHAPE.** R18 names a cutover as its event and **`docs/06`'s cutover checklist carried no R18 item** — R10's was there, R18's was not, so a control documented here could not run where it was documented to run. **`docs/06` now carries one**, ticked for this cutover and re-armed for the next republish. Found 2026-09-02 while recording the re-stamp. ⚠️ **AND THE FIRST PASS STAMPED FIVE EXTRACTS OF SEVEN.** `ontario-construction-act.md` and `ontario-shareholder-remedies.md` carry the same standing "re-check before cutover" header and got no stamp, so a reader could not tell whether they were considered or missed — the same defect as this row having no checklist item, one notch smaller. Both are stamped now; `git grep -l "R18 re-check — cutover pass" -- docs/reference` returns **7**, and the set difference against `git grep -l "Re-check before cutover"` is **empty**. `adversarial-reviewer`, round 1. **THE ROW STAYS LIVE**: the trigger is an event and events recur. Original text follows. **THE SIX `docs/reference/` EXTRACTS BEHIND `/practice/*` ARE DATED 2026-08-29, AND SIX SHIPPED SENTENCES TURN ON FACTS THAT MOVE.** Build step 5 put statute, regulation, tribunal and bill status onto public pages — sourced, but **sourced as at one day**. The volatile ones, in order of how fast they move: **(a) federal Bill C-36** — `/practice/technology/` says it *"was introduced in June 2026 and was at second reading when this page was written"*; if it receives royal assent the page is wrong about the most load-bearing fact on it. **(b) the Ontario regulation under `Electricity Act` s. 28.1** — `/practice/energy/` says it *"had not been made as of August 2026"*. **(c) the ERO 026-0853 consultation**, comment period to **12 September 2026**. **(d) the Tribunals Ontario annual report** — `/practice/insurance/` publishes FY2024-25 figures and the extract records that a 2025-26 edition was never ruled out. **(e) the SABS**, amended with effect 1 July 2026. **(f) the ADRIC National Mediation Rules**, under review by ADRIC's own committee. **(g) ADRIC's Code of Ethics** — added 2026-08-30, build step 6. `/process/` §Confidentiality quotes it verbatim from `docs/reference/adr-institution-names.md` (retrieved 2026-08-29) **with a live link to ADRIC's page**, which is what makes it checkable and also what makes a stale quotation visible. It is the slowest-moving item here — a professional code, not a bill — so it does not change the cadence; it is listed because the trigger below says "all six" and there are now seven. **THE TRIGGER: re-check all seven extracts before any cutover, and before any republish that turns on one of them — the same event trigger R10 uses.** Then re-stamp the extract. **A page that was true when it was written and is false when it is read is still a false page**, and this is the first change set on the project to put that class of fact into public copy at volume | 2026-08-29 | Six sentences, six files, one retrieval date. Nothing here fires on its own; a fact with a shelf life and no owner is exactly what §12 exists for | | R19 | ⚠️ **DYNAMODB TTL BACKS A PUBLISHED PRIVACY PROMISE AND `/legal/privacy/` ASSERTS THE MECHANISM, NOT JUST THE PERIOD.** **§7 records the status and its stamp; this row deliberately does not restate it** — one place for a service status, or the copy that goes stale is the one nobody re-reads. **THE TRIGGER, and its two halves are not interchangeable: re-run `describe-time-to-live` and confirm `ENABLED`, THEN write a record with a near-future `ttl` and confirm it actually disappears.** `ENABLED` proves the setting; only the test record proves the behaviour. Writing the attribute proves neither — the handler's side is verified and is not what this row is about. Both halves are on `docs/06`'s cutover checklist and the question is §9 Q60. Re-stamp §7 the same day, **and when you do, sweep for the copies: this fact reached five files outside §7 in one change set and had to be pulled back.** Close this row only when the test record has been observed to vanish | 2026-08-31 | **This is R9's exact shape at higher stakes.** R9 exists because the SES alarms are configured and notify nobody until one subscription is confirmed — a control that reads as covered and is not. Here the control backs a **statement to the public on a privacy policy**, which is the one class of claim this project treats as unrecoverable, and the failure is silent in both directions: nothing in the repo, the build or AWS reports that records are accumulating forever. A cutover checklist fires once; §12 is read aloud every session | | R20 | ⚠️ **THE SEVENTH NAV ITEM ARMS TWO MEASURED HEADER DEFECTS, AND ITS TRIGGER IS A CONTENT EVENT RATHER THAN A DATE.** `SiteHeader` computes `showInsights` from the collection — Insights joins the masthead **automatically at two published articles** — so nothing in the build, the specs or a person's memory stands between publishing article #2 and arming both of these. With seven items **and fallback font metrics** (what a reader on `docs/04`'s Slow 4G profile sees during the `font-display: swap` window, at the DEFAULT text size, no reader setting involved) the header measures **141 px across a contiguous 1056–1091 px band** instead of 81 px: **(a)** it then collapses **60 px** when Geist swaps in, on all 22 pages, against the CLS < 0.05 budget; and **(b)** 141 px exceeds the 97 px `scroll-padding-top`, so "Skip to content" lands with **44 px of `#main` behind the sticky header** — and (b) is **new as of 2026-09-01**, the previous build's 86.97 px stayed under 97 px and covered 0. ⚠️ **HARDENED FROM A TRIGGER INTO A GATE — Pouya's ruling, 2026-09-01: NO SEVENTH NAV ITEM SHIPS UNTIL THE FALLBACK-METRICS DEFECT IS FIXED.** So fixing it is a **prerequisite of publishing the second Insights article**, not a follow-up to it, and *"font metric overrides on the fallback face or equivalent — to be designed then, not now"*. ⚠️ **AND THE GATE IS A BUILD FAILURE, NOT A CROSS-REFERENCE — corrected 2026-09-01 by `adversarial-reviewer`, round 2, in the same session that wrote the weaker version.** It was first implemented as three prose pointers, justified with the claim that the comment on `showInsights` in `SiteHeader.astro` is *"the only one of the three a person editing an article's front matter is likely to be reading"*. **That was backwards**: someone editing `src/content/insights/*.mdx` has no reason to open a header component. And it did not gate: with two articles flipped to `draft: false`, `npm run build` succeeded and `check`, `check:claims`, `og:proof`, `check:intake` and `lint` all exited 0 while both defects shipped. **`SiteHeader.astro` now THROWS when `published.length >= 2`**, with the measurements and the instruction in the message; it fires on both deploy paths, on the machine of whoever publishes. **Proven, not assumed:** two articles were temporarily published, `npm run build` exited **1** naming R20, and the files were restored and the restoration verified by `git diff --exit-code` plus an unchanged `dist` digest. The prose pointers remain — `docs/06`'s `/insights/` state item and its seventh-nav-item item under **Technical**, the latter deliberately unticked and marked NOT a cutover blocker — but they document the gate rather than being it. This project already knew the remedy: `content.config.ts` refuses `draft: false` without `reviewedByPouya: true` rather than trusting a comment, and `check:intake`/`og:proof` exist because a duplicated fact needs a mechanism. *Previous wording follows, and it was too weak: it asked for a re-measurement and a ruling at publication time, which leaves the defect shipping if the person publishing does not read this file.* **THE TRIGGER: before publishing the second Insights article, re-measure the masthead with seven items under blocked webfonts, and rule.** The two candidate fixes are raising the desktop breakpoint past 1091 px — which changes the normal-settings layout in that band — or giving Geist a metric-matched `size-adjust` fallback; both are outside the scope the header step was given, and both close (a) and (b) together. **Why this is a §12 row and not only a `docs/06` line:** a cutover checklist fires once, at cutover, and this arms itself later, on an editorial decision taken by someone who will not be reading the deployment spec. `docs/02` §Reflow carries the measurements | 2026-09-01 | It is latent today and invisible from inside the repo: six nav items never wrap, so every check passes, and the defect appears the day a second article ships. That is R13's shape — a temporary state that becomes permanent because nothing prompts anyone — with the added twist that the prompt would have to fire on a content event. Raised by `adversarial-reviewer`, round 2 | +| R21 | 🛑 **`/legal/privacy/` PUBLISHES A COUNT OF THE PEOPLE WHO CAN READ THE INTAKE TABLE, AND NOTHING IN AWS, THE BUILD OR THIS REPOSITORY REPORTS WHEN THAT COUNT CHANGES.** The page says **two**, measured (§7). **Add a third administrator, remove `lars` from `admins`, attach a DynamoDB policy to any of the 33 roles, **hand the root credential to a third person**, or resolve Q23's Gitea dependency by changing his access — and the privacy policy becomes false with every check still green.** `check:claims`'s `sole-administrator-q62` pattern does **not** cover this: it bars the OLD false shape from returning and is blind to the world moving under the NEW sentence. That asymmetry is the whole reason this row exists. **THE TRIGGER, and it is the same event trigger R10 and R18 use: re-run the verification in `docs/reference/intake-table-access-verification.md` before any cutover, and before any republish that turns on it. Then re-stamp §7 the same day.** The counts are the assertion — seven decisions per role call, six per CDK-path call, two per-resource decisions per assume call — because a call that silently received one bogus action name answers `implicitDeny` and reads exactly like a clean row, which is how the first run of that sweep produced 22 uniformly clean rows and no measurement at all. **Removal is the live direction:** Q23 records the Gitea instance as jointly administered and blocked on its second administrator, so `lars`'s access is plausibly load-bearing elsewhere — and if it goes, `check-claims.mjs`'s `rule:` line carries the instruction (rewrite the page, then narrow the pattern deliberately). Raised by `adversarial-reviewer`, D20 cutover pass round 1, 2026-09-02: R9's and R19's shape at R19's stakes — a statement to the public on a privacy policy, backed by a fact with no owner. | 2026-09-02 | The 2026-09-01 verification is a photograph of a shared AWS account that two people administer and that runs four other projects. A stamp with no trigger behind it goes stale silently, and §4 already records OCNI as the precedent for exactly that | | ~~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 | — | @@ -941,6 +944,469 @@ never being raised again. # Change Log +## 2026-09-02 (an) — Q62 is answered by stating the truth, and Q62's own fix then recreated Q62's shape twice; the `/med-arb/` gloss is struck and the strike leaves two referents dangling; R18 fires, is satisfied, and is found to have had nowhere to fire and to have fired over five files of seven; the evidence behind the new privacy sentence was weaker than the sentence until it was re-measured; and the approval gate Pouya reserved was left living only inside records marked closed + +**Pouya's four rulings, 2026-09-02**, taken in one pass. The production-run tree +of 2026-09-01 was committed as authorized first: **`bd282aa`**, 30 files, ++3,257 / −144. + +### 1. Q62 — RULED *state the truth*, and it took three edits, not one + +His ruling, verbatim: *"state the truth. Rewrite the `/legal/privacy/` sentence +to say exactly who can access the submissions table… the true number of people +and their roles, stated specifically — not 'authorised administrators' or any +other vacancy."* + +**The sentence that shipped is quoted in §9 Q62 and is not restated here.** + +⚠️ **THE RULING NAMED ONE SENTENCE AND THE FALSEHOOD WAS IN THREE PLACES.** The +sweep that found the other two, and it is the vocabulary sweep rather than the +subject sweep: + +``` +grep -rniE "no (team|assistant|outside|external) [a-z]*|nobody else|no one else" \ + src/ --include='*.astro' --include='*.ts' --include='*.mdx' +``` + +Output, prose lines only: `privacy.astro:207` *"No one else receives it."*, +`privacy.astro:208` *"…and no assistant or outside administrator."*, +`privacy.astro:267` the ruled sentence. **Line 208 is the same falsehood in +different words, in a different section, and the `sole-administrator-q62` +pattern could not see it** — the pattern was anchored on the two sentences under +§Who can see it. A second read found the third: the summary paragraph closed +*"the honest answer to 'who can see this' is: me, and Google"*, which would have +survived a correction in the paragraph directly above it and re-asserted the +struck number four lines later. + +So the page answers the question in places that change together, and its own +comment says so rather than narrating the historical fixes. **It turned out to be +four, not three** — the copy count in the closing paragraph was the fourth, and +round 1 of the audit found it false for a different reason again (§6, finding 3). + +⚠️ **AND THE SWEEP ABOVE WAS RUN OVER `src/` ONLY, WHICH IS WHY TWO SPECS WENT ON +SAYING THE PAGE WAS FALSE FOR A DAY.** See §11. The `docs/`-wide sweep is quoted +there; recording it here would be recording the version that missed. + +### 2. The tripwire stays, and grew from two alternatives to five + +His ruling: *"The tripwire pattern STAYS permanently — it bars the false-claim +shape from returning, which is exactly what the freeze's breach exception exists +for."* So the pattern outlives the copy it was written against, and the +`DELETE THIS PATTERN when Q62 is ruled` instruction inside it is replaced by the +opposite instruction. + +**Every addition is a `dist/` string**, which is what keeps a frozen script +frozen: `no assistant or outside administrator`, +`one administrative account, which is mine`, and — added in round 1 of the +closing audit — `the honest answer to "who can see this" is: me`. Nothing +speculative was added, no refactor was made, and the alternation is a tripwire on +five specific published strings rather than a rule about a class. §8 below +records what round 1 found wrong with the first form of this, including an +over-bar that is now accepted deliberately with its cost written down. + +**Proven both ways, on real published bytes rather than on fixtures alone.** +The pre-correction page was rebuilt from `bd282aa` with the **new** scanner: + +The first form of the pattern returned **4 matches**; after round 1's fifth +alternative it returns **5**, and the full run is quoted in §8. Line 54 is the +clause the first form missed and line 72 is the surface it could not see at all. +Against the corrected page it exits **0**. The restoration of the corrected +source was verified by digest with both sides asserted present, not by +`git diff` alone. + +### 3. `/med-arb/` — the gloss is struck, with nothing in its place + +His ruling: *"strike the gloss sentence. The ADRIC-sourced material carries the +page. No replacement claim, no competence claim."* §Why this practice's lede is +now the `DESIGNATIONS_HELD_LINE` clause alone. The constraint is recorded in the +section's own comment — **do not refill this paragraph** — because a +deliberately empty paragraph is indistinguishable from an unfinished one to a +later reader, and the last two passes at this section both refilled it. + +### 4. R18 — fired, satisfied, and found to have had nowhere to fire + +Re-checked 2026-09-01 by Pouya. **All seven limbs hold; no shipped sentence +changed**, confirmed against `dist` rather than against the specs. The stamp is +**two-tier on purpose**: (a), (c) and (d) were re-verified against a source and +carry `[re-checked]`; (b), (e), (f) and (g) are held unchanged on a cadence +judgement and carry `[assumed]`. Collapsing those into one word would be the +OCNI failure in miniature. + +**(d) also closes an open item** at the foot of +`docs/reference/ontario-sabs-lat.md`, which had honestly recorded *"NOT +CONFIRMED either way… given today's date, one may well have been published"*. +No 2025-26 edition exists; FY2024-25 remains current. + +⚠️ **AND R18's TRIGGER HAD NOWHERE TO FIRE — Q22's SHAPE AGAIN.** R18's trigger +is *"before any cutover"* and **`docs/06`'s cutover checklist carried no R18 +item.** R10's was there; R18's was not. A control documented in §12 could not +run in the place §12 says it runs. `docs/06` now carries one, ticked for this +cutover and re-armed for the next republish. + +### 5. R10 — fired and NOT satisfied, left open on instruction + +The cutover event has arrived and the confirmation has not. Asked as a one-line +question; `docs/06`'s item stays open per his instruction. It may not be ticked +from the 2026-08-28 stamp, which is the whole content of the reminder. + +### 6. The D20 cutover pass was re-run over the fixes, and Q62's own fix had recreated Q62's shape — twice + +**Why it was re-run at all, since D20 says once.** `docs/06`'s item is +*"`claims-auditor` run over EVERY page in `dist/`, findings resolved"*, and the +2026-09-01 pass returned **FAIL with eight**. A FAIL whose fixes are never +re-audited leaves *findings resolved* asserted rather than checked — so this is +the same pass **completing**, the way a review's round 2 completes round 1, not a +per-step audit reinstated. Recorded because the distinction is the whole of D20. + +**Round 1 of the closing pass returned 23 findings across the two agents. +Twenty-two fixed, one declined.** Five of the eight claims findings were in the +Q62 fix itself: + +| # | the defect the fix introduced | why it is the same shape | +|---|---|---| +| 1 | *"No third party has access to it"* | An **absolute negative that excludes a disclosed processor.** This page carried *"No other third party receives it"* until 2026-08-31, when it was struck as *"the most serious thing found in the step 7–10 review"* — because AWS and Google both receive the data. A new absolute negative was written **three paragraphs below the comment recording that** | +| 2 | *"every account and role in this infrastructure… that is checked rather than assumed"* | A universal over every principal in a multi-tenant AWS account, **prefixed with a claim that it had been checked**, resting on an artefact that had simulated five users and one role | +| 3 | *"the one other place a copy exists"* | The handler puts the whole submission into the confirmation it sends the **inquirer**, under `What you sent:` — so a third copy sits with the reader's own provider, which §Where it is stored **already tells them two sections up** | +| 4 | *"the copy in my mail is readable by me and by Google"* | An enumeration of a mailbox access list **this repository does not establish**, standing one paragraph under *"that is measured rather than assumed"* | +| 5 | `LAST_UPDATED` left at 31 August | On the change set that rewrote the page's central disclosure. The constant's own comment says *"Bump this on ANY substantive edit"*, and the page publishes two undertakings that this date moves | + +**And `docs/09` Part 7.2 had already written the instruction that was not +followed.** Its decision table says, on the expected outcome, *"`/legal/privacy/`'s +'your IP address' is inaccurate — **fold it into the Q62 edit on the same page** +rather than leaving two wrong sentences there."* The Q62 edit shipped without it. +The page now describes what is actually recorded: a network address that is +**usually not the reader's**, because `requestContext.http.sourceIp` behind the +`/api/*` behaviour is a CloudFront edge. The old sentence also promised abuse +investigation a CDN address cannot support. + +### 7. The evidence file was weaker than the sentence it backed, and closing that took real measurement + +Round 1 found the artefact had screened roles with `list-attached-role-policies` +alone. Re-measured, with the counts asserted per call: + +- **23 of 26 non-service-linked roles carry inline policies that were never + read.** Simulating all 26 across seven actions: **four roles can read the + table, not two.** The two `cdk-hnb659fds-lookup-role-*` grant the four read + actions through an inline `LookupRolePolicy` that a managed-policy screen + cannot see. +- **Trust policies read for all four.** The `cfn-exec` pair trusts + `cloudformation.amazonaws.com` and nothing else; the `lookup` pair trusts the + account root, so the gate is the caller's identity policy — and + `sts:AssumeRole` is **allowed for `pouya` and `lars` only**, implicitDeny for + all three deploy users (ten per-resource decisions). +- **The CloudFormation escalation path this file named and left untested is now + measured**: five users × six actions, and `meshkini-backend-deploy` and + `gitea-deploy-meshkinilaw` are **implicitDeny on all six**. That was the + finding that mattered — either one, had it been able to drive CloudFormation, + would have read the table without appearing in the original five-row table, + and *"Two people can"* would have been **wrong**. +- **No federated surface exists at all**: SAML 0, OIDC 0, Identity Center 0. +- **Root is recorded rather than omitted**: not an IAM principal, cannot be + simulated, `AccountAccessKeysPresent: 0`, MFA on. The page is scoped to *"every + user and every role"* and to who has been **granted** access, so it does not + claim anything about root — which is why it is not a bare *"nobody else can"*. + +**The conclusion held; the reasoning did not.** That distinction is the reason +R14 exists. + +⚠️ **AND THE INSTRUMENT FAILED FIRST, UNIFORMLY, IN THE DIRECTION THAT READS AS +CLEAN.** The role sweep was first run as `--action-names $ACTS`. **zsh does not +word-split parameter expansions**, so `simulate-principal-policy` received **one** +action name — the whole seven-action string — and answered it: `implicitDeny` for +22 roles and `allowed` for the four with a `*` grant, because `*` matches a bogus +action too. Twenty-two clean rows and a plausible four. **The tell was the shape +of the output, not the verdict**: one decision per role where there should have +been seven. Every loop now asserts its count — seven per role call, six per +CDK-path call, two per-resource decisions per assume call. This is the sixth time +this class has cost on this project and the second on the "uniformly good" side. + +### 8. Two mechanisms were repaired and one over-bar was accepted deliberately + +`check-claims.mjs`, still frozen and still a tripwire: + +- The operator-facing **`rule:` line** was left in the present tense, asserting + the page claims sole administrative access. It is the first thing printed on + failure. Rewritten, and it now names the third path nobody had written down: + **if that access is ever actually removed, the pattern starts failing the build + on TRUE copy**, and the answer is neither to delete it nor work around it. +- **Alternative 3 had been widened to four phrasings where one was published.** + Pinned. ⚠️ **And pinning does not close it**, which is stated in the file + rather than papered over: the truthful receipt-scoped sentence *contains* the + published string, so any pattern catching one catches the other. Adding that + truthful form as a negative fixture **failed the self-test on the first run** — + the instrument check doing exactly its job. So the over-bar is deliberate and + its cost is written down: the clause cannot be published in **any** scoping + without failing the build. The alternative, a lookahead tuned to one guessed + phrasing, is the speculative pattern the freeze bars. +- **A third published surface was unbarred** — the summary the Q62 row itself + said *"would have re-asserted the struck number"*. Restoring it passed at exit + 0. Now a fifth alternative. + +**Re-proven both ways after the changes**, against the pre-correction page +rebuilt from `bd282aa`: + +``` +check:claims exit=1 — sole-administrator-q62, 5 matches + dist/legal/privacy/index.html:54 "no assistant or outside\n administrator" + dist/legal/privacy/index.html:67 "one administrative account, which is mine" + dist/legal/privacy/index.html:67 "nobody else has access to\n the table" + dist/legal/privacy/index.html:68 "There is no team, no assistant and no external\n administrator" + dist/legal/privacy/index.html:72 "honest answer\n to \"who can see this\" is: me" +``` + +and exit **0** on the corrected page, self-test 12 patterns / 36 approved +strings. **The negative fixtures went stale within the hour** when the audit +rewrote three of the four paragraphs they were copied from; re-synced, and the +file now says they must be. + +### 9. The approval gate existed only inside records marked closed — Q63 + +Pouya reserved the wording: *"Draft it; Pouya gives final approval on wording +during his page read-through."* Closing Q62 deleted the `TODO(pouya)`, struck the +§9 row and ticked `docs/06`'s blocker — each correct on its own, and the net +effect was that **the only surviving record of an open approval requirement was +prose inside three records marked ✅ CLOSED**. `docs/06`'s banner then said one +thing blocked the list, so when Q60's TTL test passes **nothing mechanical or +visual would have stopped unapproved copy publishing.** + +**Q63 opened**, with a `TODO(pouya)` beside the copy and its own unticked +checklist item: **(a)** approve the wording; **(b)** who else can read +`info@smlcompany.ca`. On (b), the earlier form of the Q62 row called it +non-gating *"because the copy is true either way"* — **that was a guess about a +fact nobody checked**, which is the thing this file exists to stop. The copy is +now written to assert no access list at all, so nothing false publishes; the +question gates on **standards** rather than on truth, because a privacy policy +that answers the table half with a measured number and the mail half with a shrug +is answering one question on two standards. + +### 10. A published fact with no owner got one — §7 row and §12 R21 + +Who can read the table is now **on a public page** and lived only in a reference +extract and a struck §9 row. **Add a third administrator, remove `lars` from +`admins`, attach a DynamoDB policy to any of the 33 roles, or resolve Q23's Gitea +dependency by changing his access — and the privacy policy becomes false with +every check still green.** The tripwire does not cover it: it bars the **old** +false shape and is blind to the world moving under the **new** sentence. That +asymmetry is why **R21** exists, with R10's and R18's event trigger. §7 carries +the row. + +### 11. Four records still instructed the struck versions, and R18 had fired over five files of seven + +- **`docs/05`:449** — an unticked definition-of-done item reading *"IT DOES NOT, + AS AT 2026-09-01"*, quoting the deleted sentence as live copy and ending *"it + blocks that page going public"*. Two governing specs disagreed about whether + `/legal/privacy/` could publish, and **the stale one was the list a person + follows at cutover.** The cause: the Q62 sweep was run over `src/` only. +- **`docs/01`:391** — still directed *"a published rule set, presented to ADRIC's + membership"*, the exact form the audit struck. Page fixed, spec still telling + the next implementer to write the false version — the Q.Arb lesson again. + Its item 4 also still said the section *"says… that he holds both + designations"*, which finding (i) removed. +- **The evidence artefact** quoted the struck sentence under a heading reading as + current, and framed the ruling as one of two open options. Both now dated and + resolved, with the shipped sentences quoted so the comparison R14 exists for + can actually be made. +- **R18 stamped five extracts of seven.** `ontario-construction-act.md` and + `ontario-shareholder-remedies.md` carry the same standing re-check header and + got nothing, so a reader could not tell whether they were considered or missed + — **the same defect as R18 having no checklist item, one notch smaller.** + +**The sweep, run across `docs/` this time and not only `src/`:** + +``` +$ grep -rniE "no (team|assistant|outside|external) [a-z]*|nobody else has access|no one else receives" docs/ .claude/ CLAUDE.md +docs/05-backend-spec.md:449: - [ ] **Table access matches what `/legal/privacy/` says about it.** ⚠️ **IT DOES NOT… +docs/reference/intake-table-access-verification.md:25: > administrative account, which is mine — nobody else has access to the table. +docs/reference/intake-table-access-verification.md:26: > There is no team, no assistant and no external administrator. +``` + +Three hits, two files; the extract's two are the quotation of the defect and are +now marked struck. **And the stamp assertions, because a sweep is a command:** + +``` +$ git grep -l "R18 re-check — cutover pass" -- docs/reference | wc -l +7 +$ comm -23 <(git grep -l "Re-check before cutover" -- docs/reference | sort) \ + <(git grep -l "R18 re-check — cutover pass" -- docs/reference | sort) +(empty) +``` + +### 12. `/med-arb/`: the strike left two referents dangling and one adjacency standing + +- *"The section above is the part to read"* resolved, after the strike, to + **§Rules — the ADRIC quotations** — so it read as telling counsel that ADRIC's + rules are what to read before proposing a med-arb. `adric-rules.md` Finding 4 + bars exactly that: the extract *"supports no statement of what any rule + requires, permits or provides"*. And *"the agreement"* lost its only + antecedent, which the struck sentence had supplied. Now **"The three + commitments above"** and **"the med-arb agreement"**. +- **The bare `DESIGNATIONS_HELD_LINE` sentence was left sitting directly beneath + ADRIC's quoted *"requires a high level of practitioner competence"*.** Both + sentences are individually §4-verified; the pair reads as the designations + meeting that bar, and **ADRIC answers its own sentence with the Chartered + Med-Arb** — not held, struck from this site entirely. The 2026-08-30 fix took + the competence proposition out of the heading; Pouya's 2026-09-01 ruling took + out the definitional gloss; **this is the third pass at the same paragraph**, + and the section now makes **no credential claim at all**. `/about/` publishes + them and the JSON-LD carries them. + ⚠️ **THIS GOES BEYOND THE RULING AND IS FLAGGED AS SUCH.** Pouya ruled *"no + replacement claim, no competence claim"*, which is the principle it follows, + but he ruled on the gloss sentence and not on this one. It is one line to + restore and the alternative remedy — trimming the competence clause out of a + sourced quotation — was rejected as the worse of the two. +- The meta description promised *"how it differs from arb-med"* while `docs/01` + records that the page **states no differentia on purpose** (no committed + source, R14). Now *"why it is not arb-med"*, which is the page's own wording. + +### 13. Declined, with the reason recorded + +**§Rules' heading, *"There is a published rule set for this."*** The auditor +ranked it last of eight and asked for the status or a stated decline. **Declined.** +ADRIC does publish the document, so *published* is literally accurate; Q46(b)'s +standard is that a rule set's **name** is a fact about a published document; and +the very next clause of the paragraph states that a **discussion draft** was what +was presented to the membership. A status qualifier in the heading would restate +the sentence beneath it. Recorded so a later reader can see the judgement was +made rather than missed. + +### 14. Pre-existing render repairs in `AGENTS.md`, noted so they are not mistaken for content + +Three malformed table rows, all pre-existing at `bd282aa`, all one escaped pipe: +§9's `Q32-orig` row rendered **four cells in a three-column table**, and two §7 +rows split their cells on the `||` inside npm semver ranges (`^5.0.0 || ^6.0.0`, +`^22.13.0 || >=24`). §7 is read at cutover and §9 every session, so these are +maintenance of the file, not edits to history — the Change Log's own copies of +the same strings were deliberately left alone. Assertions: §7 **51 rows, 0 +malformed**; §9 **73 rows, 0 malformed**; §12 **23 rows, 0 malformed**. + +### 15. Round 2 — thirteen findings, and this is the measurement D19 exists for + +**Three of round 1's twenty-two fixes introduced new defects and two did not fix +the finding they answered.** Recording the ratio, because it is the argument for +round 2 and the argument against round 3 in the same number. + +**The two blocking ones were both in the Q62 copy, again:** + +1. **The replacement IP paragraph hedged *whose* address is stored ("usually not + yours") and then asserted flatly that "it is not precise enough to identify + you"** — false in exactly the residual case the hedge admits, and written to + an outcome the repository has not measured. Worse, `docs/09` Part 7.2's + **outcome-2 row carried no instruction to correct the page**, so two of three + branches had nothing reconciling the copy with the measurement. The page now + states only **why** each field is kept, which is true in all three branches, + and 7.2's outcome-2 row carries the correction instruction. *This is the + Q62 shape a third time: a public claim about infrastructure that nothing in + the repo verifies.* +2. **"every user and every role in the account was simulated" was true of 26 of + 33 roles.** Every role loop in the evidence file filters + `grep -v '^AWSServiceRole'`, and the assertion was written as *"twenty-six + role rows"* — so the seven service-linked roles were outside the claim rather + than inside it, and a service-linked role for a backup or migration service + can read table contents. **Closed by measurement rather than by narrowing the + sentence:** all 7 are `implicitDeny` on all seven actions, 49 decisions, count + asserted. **The enumeration is 33 of 33** and the published sentence is + literally true. + +**And the record of the frozen script described a version that did not ship.** +Four counts were stale — "two alternatives to **four**" (five), "**4 matches**" +(five), "**33** approved strings" (36), "the **three** replacement sentences as +negative fixtures" (six) — and one fixture comment said "the four published +clauses" above five. **The consequence was worse than the arithmetic:** the +recorded proof cited `:54, 67, 67, 68`, which is exactly what the pattern returns +*without* alternative 5 — so **the whole of round 1's third-surface fix had never +been run against rebuilt pre-correction bytes** and rested on its own fixture. It +has been now: + +``` +check:claims exit=1 — sole-administrator-q62, 5 matches + dist/legal/privacy/index.html:54 "no assistant or outside\n administrator" + dist/legal/privacy/index.html:67 "one administrative account, which is mine" + dist/legal/privacy/index.html:67 "nobody else has access to\n the table" + dist/legal/privacy/index.html:68 "There is no team, no assistant and no external\n administrator" + dist/legal/privacy/index.html:72 "honest answer\n to \"who can see this\" is: me" +``` + +**On a frozen script the record of what it bars IS the maintenance surface**, so a +stale count there is a defect and not a typo. + +**Root was resting under the headline answer.** The page's first sentence is a +**count of people**; the addendum says in terms that *"who holds the root +credentials is not established in this repository"*, and root is the one path no +policy constrains and no simulation reaches. Now **Q63(c)**, answered in the same +read-through, and added to **R21**'s trigger list. The second paragraph is +unaffected — it is scoped to *"every user and every role"* and to who has been +**granted** access — which is why that scoping was worth the words. + +**Five more of mine, all the same species: a record describing a state the same +change set had deleted.** + +- `docs/06`'s med-arb item said *"§Why this practice's lede is now the + designations clause alone"* — **written in the commit that removed that + clause**, and it is the very failure `docs/01`'s corrected entry complains + about, four hundred lines away in the same commit. +- The evidence artefact's addendum quoted round 1's **pre-fix** sentence as live, + so one file quoted two different sentences as the shipped one. Fixed by + pointing at the single quotation block instead of re-quoting: one copy of a + fact, in one place. +- The new "these change together" comment said **four places / three paragraphs** + where there are five and four — and the paragraph it omitted from its own list + was the measured enumeration, the one that goes stale on its own. A partial + sweep, inside the comment warning against partial sweeps. +- `docs/06`'s R10 item called itself *"the only cutover item waiting on him that + is not a waiting period"*, in a change set that added two more. +- The provenance line said *"every figure below was read on 2026-09-01"* above an + addendum measured on 2026-09-02. + +**Three smaller ones, all shipped or read lines:** `/med-arb/`'s description went +from *"how it differs from arb-med"* to *"why it is not arb-med"* — still a +promise of a reason the page is barred from giving — and is now *"that it is not +arb-med"*, which is what the page says. The heading *"Both halves, in one +practice"* lost its referent when the designations sentence went, and is now +*"Both processes"*, which the `

` supplies. And `docs/05`'s field table still +said `sourceIp`, `userAgent` → *"abuse investigation only"* while the page had +stopped stating **any** purpose — a spec and a page disagreeing about **why** +data is held, which is the disclosure PIPEDA turns on. + +**Also fixed: alternative 5's window was `\W{0,8}`**, and `\W` matches both `<` +and the block sentinel, so it was bounded by neither while the file's own comment +asserted every window uses the safe class. No live false positive; the next +person to copy its shape would have inherited the hole. Now `[^\w<]{0,8}`. + +⚠️ **AND THE D19 COMMENT-BULK FINDING LANDED WITH RECEIPTS.** The +`sole-administrator-q62` object had become **78 lines of prose around one line of +regex**, and round 2's findings 5, 7, 8 and 11 were all *statements inside this +change set's own new prose that were already false, one day old.* That is +precisely Pouya's 2026-08-28 measurement — a second record to keep true, becoming +a source of defects about the record. Trimmed to **47 lines**, keeping the three +load-bearing constraints (`\s+` vs literal spaces; one published string per +alternative; the deliberate over-bar and its cost) and moving the drafting +narrative here, where a reader looks for how something got here. + +### 16. Stopped at two rounds, per D19, and here is the arithmetic + +Round 1: **23 findings** across `claims-auditor` and `adversarial-reviewer` — 22 +fixed, 1 declined. Round 2: **13 findings plus 3 minor** — all fixed, and **five +of them were defects in round 1's own fixes** with two more being fixes that did +not fix. Round 1 also found five defects inside Q62's fix, which was itself +round 1's subject. + +So across both rounds roughly **a third of all findings were defects introduced +by the previous round's repairs**, which is the ratio D19 was written on. **There +is no round 3.** Fix what round 2 found and ship — Pouya's ruling, and the +reasoning is stated here so a later reader does not read the cap as laxness. + +**Gates on the shipping bytes, every one run and its exit status read:** +`check` 0 (0 errors) · `build` 0 (23 pages) · `check:claims` **0** (12 patterns, +36 approved strings) · `og:proof` 0 · `check:intake` 0 · `lint` 0 · +`router.test.mjs` 0 (30/30) · `lighthouse` 0, worst of 23 **99/100/100/100**, +CLS 0.000, LCP 2.03 s on `/` reported not asserted · the `animation-timeline` +minifier grep returns nothing (exit 1) · 0 `.js` files in `dist` · three +`aws s3 sync --dryrun` passes at **51 / 56 / 52** lines with 2 deletes, nothing +written. + +**NOTHING WAS DEPLOYED.** Pouya's instruction stands: the deploy happens only on +his explicit word after his read-through. + ## 2026-09-01 (am) — The production run: Q61 fixed and closed, the intake backend and distribution given an executable runbook — and reading the running system found four launch blockers the specs could not see, one of them a false statement on the privacy policy **Pouya's direction:** *"get to production as soon as possible; nothing new gets diff --git a/docs/01-architecture.md b/docs/01-architecture.md index 12236a8..83e45f8 100644 --- a/docs/01-architecture.md +++ b/docs/01-architecture.md @@ -386,11 +386,27 @@ the C.Med-Arb endpoint" until 2026-08-29; C.Med-Arb is off the site.)* Q.Arb, which is what med-arb requires. The page says he conducts med-arb and stops."* The section is **rewritten, not edited** — it earned its credibility from an incomplete credential and now says what med-arb demands of one - neutral and that he holds both designations. + neutral. ⚠️ **AND IT NO LONGER RESTATES THE DESIGNATIONS EITHER — + 2026-09-02, `claims-auditor` D20 pass, finding F.** §Why this practice held a + bare `DESIGNATIONS_HELD_LINE` sentence sitting directly beneath §Rules' + quotation of ADRIC requiring *"a high level of practitioner competence"*, so + the designations read as meeting a bar ADRIC answers with the Chartered + Med-Arb — struck from this site entirely. The section now makes **no + credential claim at all**; `/about/` publishes them and the JSON-LD carries + them. Do not reinstate one here. 5. **The ADRIC Med-Arb Rules**, which this spec did not mention and which exist: - a published rule set, presented to ADRIC's membership at its 2019 annual conference, drafted for domestic - commercial disputes and designed to work with its Mediation and Arbitration - Rules. Sourced: `docs/reference/adric-rules.md` Finding 2. Quote ADRIC's own + ~~a published rule set, presented to ADRIC's membership~~ — **CORRECTED + 2026-09-02, `claims-auditor` D20 pass, finding 6.** The source says a + **discussion draft** was presented, not the rules; `adric-rules.md` Finding 2 + records no adoption and no effective date, in deliberate contrast to the + Arbitration Rules ("effective March 1, 2025") and the Mediation Rules ("the + existing rules remain in effect"). The page was corrected on 2026-09-01 and + **this line still instructed the struck form for a day** — the Q.Arb lesson + exactly: page fixed, spec still telling the next implementer to write the + false version. Write it as **presented to the membership as a discussion + draft at ADRIC's 2019 annual conference** — drafted for domestic commercial + disputes and designed to work with its Mediation and Arbitration Rules. + Sourced: `docs/reference/adric-rules.md` Finding 2. Quote ADRIC's own framing rather than paraphrasing it, and **keep its superlatives inside the quotation marks** — Finding 5 lists the two not to lift. diff --git a/docs/05-backend-spec.md b/docs/05-backend-spec.md index 7b96d1c..1ba44b2 100644 --- a/docs/05-backend-spec.md +++ b/docs/05-backend-spec.md @@ -211,7 +211,7 @@ against this row. | `submissionId` | `` — **the partition key.** Fixed by the table; the notification email prints this value verbatim so it can be pasted into the console | | `submittedAt` | `` — an ordinary attribute, not a sort key | | fields | as above | -| `sourceIp`, `userAgent` | abuse investigation only | +| `sourceIp`, `userAgent` | ~~abuse investigation only~~ — ⚠️ **AMENDED 2026-09-02: that purpose holds for `userAgent` and `submittedAt`, and NOT for `sourceIp`.** Behind the `/api/*` behaviour `requestContext.http.sourceIp` is a CloudFront edge, so it identifies the network rather than the sender and cannot serve an abuse investigation. `/legal/privacy/` now states the two purposes separately — timestamp and user-agent for abuse, the address as something that simply arrives with the request. **A spec and a page disagreeing about WHY data is held is the disclosure PIPEDA actually turns on**, and this row said one thing while the page said another for a day. `docs/09` Part 7.2 measures the field; if it holds the reader's own address, this row and that paragraph both change. `adversarial-reviewer`, round 2 | | `consentAt` | `` — when the consent box was submitted | | `ttl` | epoch seconds — **the input to automatic deletion; see §Retention for why writing it is not the mechanism** | @@ -446,7 +446,7 @@ Plausible or Fathom, cookieless, no consent banner. - [ ] **TTL set and verified by test record.** ⚠️ **THIS ONE BACKS A PUBLISHED PROMISE.** `/legal/privacy/` states that records are deleted automatically after 24 months, and it asserts the **mechanism**, not only the period. The handler writes the `ttl` attribute — epoch seconds, 24 months, confirmed against this spec `[verified 2026-08-31]` — and **writing the attribute is not the mechanism**: TTL must also be enabled on the table, which is a table setting the code cannot see. **`AGENTS.md` §7 holds that status and its stamp; this line does not restate it** — it restated it once, went stale within the day, and had to be pulled back (§12 R19). **The test record is what closes this item, not the status:** `ENABLED` proves the setting, a record written with a near-future `ttl` and observed to vanish proves the behaviour. Tracked as §9 Q60 - [x] **PITR enabled** — `ENABLED`, 35-day window `[verified 2026-09-01 — describe-continuous-backups]` - [ ] KMS customer-managed key. **Not on the table: encryption at rest is with the AWS-owned key** `[verified 2026-09-01 — describe-table returns no SSEDescription]`. **Not claimed on `/legal/privacy/`** — the page says "encrypted at rest", which is unconditionally true of every DynamoDB table and does not mention a customer-managed key, so nothing published depends on it. An improvement, not a blocker -- [ ] **Table access matches what `/legal/privacy/` says about it.** ⚠️ **IT DOES NOT, AS AT 2026-09-01.** The page says *"nobody else has access to the table… no external administrator"*; the account's `admins` group carries `AdministratorAccess` and has **two** members, and `simulate-principal-policy` returns **allowed** for `dynamodb:GetItem`/`Query`/`Scan` for both. Evidence and commands: `docs/reference/intake-table-access-verification.md`. §9 **Q62**, and it blocks that page going public +- [x] ✅ **Table access matches what `/legal/privacy/` says about it — 2026-09-02.** **The access is unchanged; the page now states it.** Pouya ruled *state the truth* rather than *remove the access* (§9 Q62), so the page publishes two administrators of a shared account, and adds the two stronger facts the false sentence had crowded out: the handler role holds `PutItem` **only**, and `adr-sml-deploy` is `implicitDeny` on all seven read **and** write actions. Evidence and commands: `docs/reference/intake-table-access-verification.md`, whose enumeration was **extended on 2026-09-02** — the original screened roles by `list-attached-role-policies` alone, missing that 23 of 26 non-service-linked roles carry inline policies and that the two CDK `lookup` roles can read the table. Four roles can, not two; all four terminate at the same two people. ⚠️ **THIS LINE SAID "IT DOES NOT" FOR A DAY AFTER THE PAGE WAS CORRECTED, AND IT IS A DEFINITION-OF-DONE LIST SOMEONE FOLLOWS AT CUTOVER** — the Q62 sweep was run over `src/` only, so it could not reach a spec. `adversarial-reviewer`, round 1. The sweep across `docs/` is in the Change Log entry - [ ] Both emails send; SPF/DKIM/DMARC aligned; inbox-tested, not spam-tested - [ ] **CloudWatch alarms on Lambda `Errors` and API Gateway `5xx`** — replacing the DLQ item, which is struck: a DLQ on a **synchronously** invoked function never receives anything, so the alarm on its depth would have been permanently green. See §Notification. The handler writes to DynamoDB **before** sending mail, so the protection this item was pointing at is in the code rather than in a queue - [x] **Form usable by keyboard only.** Errors are announced by the browser's own validation, which with no script is the only thing that can announce them inline — `role="alert"` needs a live region and something to write into it diff --git a/docs/06-deployment.md b/docs/06-deployment.md index 314842e..4eba7c7 100644 --- a/docs/06-deployment.md +++ b/docs/06-deployment.md @@ -395,19 +395,49 @@ Then invalidate `/*`. > reversing them puts 22 of 23 pages behind a 403 for as long as a CloudFront > deployment takes. -> 🛑 **THREE THINGS BLOCK THIS ENTIRE LIST AS AT 2026-09-01, AND TWO OF THEM WERE -> FOUND BY READING THE RUNNING SYSTEM RATHER THAN THE SPECS.** +> 🛑 **TWO THINGS BLOCK THIS ENTIRE LIST AS AT 2026-09-02, AND ONE OF THEM IS A +> WAITING PERIOD RATHER THAN A TASK.** > -> 1. **`/legal/privacy/` states something false about who can read the intake -> table** — §9 **Q62**, evidence in -> `docs/reference/intake-table-access-verification.md`. A privacy policy is -> the wrong page to be wrong on, and this one is wrong about third parties' -> dispute information. -> 2. **Q60 is still open** — TTL is `ENABLED` and no record has been watched to -> disappear, and the same page asserts the mechanism. `docs/09` Part 10 is the -> test and its answer arrives days after it starts, so **start it early**. -> 3. **`claims-auditor`'s D20 pass returned six copy findings on 2026-09-01; -> five are corrected and one is a ruling** — the `/med-arb/` gloss, below. +> *(This said ONE for part of 2026-09-02, and that was a defect: the wording +> approval Pouya reserved had been recorded only inside records marked closed — +> the `TODO(pouya)` deleted, Q62 struck, this callout ticked — so when Q60 passed, +> nothing would have stopped unapproved copy publishing. `adversarial-reviewer`, +> D20 pass round 1.)* +> +> 1. **Q60 — the retention MECHANISM has still not been observed.** TTL is +> `ENABLED` and no record has been watched to disappear, and +> `/legal/privacy/` asserts the mechanism, not merely the period. `docs/09` +> Part 10 is the test; its earliest useful reading is **48 hours** after the +> record is written and it does not call failure before **7 days**, so +> **start it before anything else on this page.** It is the one blocker that +> is a waiting period rather than a task. +> 2. **Q63 — `/legal/privacy/` needs two answers from Pouya**, both in the same +> read-through: **(a)** approval of the §Who can see it wording, which he +> reserved when he ruled Q62 (*"Pouya gives final approval on wording during +> his page read-through"*), and **(b)** who else can read +> `info@smlcompany.ca`, which this repository does not establish. (b) is +> written so nothing false publishes either way; (a) is a straight gate. See +> the unticked item under **Copy and claims** below. +> +> ✅ **CLOSED 2026-09-02 — Q62.** `/legal/privacy/` no longer states anything +> false about who can read the intake table. Pouya's ruling was **state the +> truth**, not remove the second administrator's access: the page now says two +> people can read it, names their role, and adds the two stronger facts the +> false sentence had been crowding out — the writing function cannot read the +> table, and the deploy credential has no access to it at all. The +> `sole-administrator-q62` tripwire in `check-claims.mjs` **stays permanently** +> by the same ruling, extended from two alternatives to **five**: the clause the +> first form could not see two sections up the same page, the summary that would +> have re-asserted the struck number four lines below the corrected paragraph, +> and the sentence that carried the false count. Proven both ways against the +> pre-correction page rebuilt from `bd282aa` — **exit 1 with 5 matches**, exit 0 +> on the corrected page. +> **Wording is subject to Pouya's read-through — §9 Q63(a), and it has its own +> unticked item below.** +> +> ✅ **CLOSED 2026-09-02 — the `/med-arb/` gloss.** Struck, with no replacement +> and no competence claim, per ruling. The ADRIC-sourced material carries the +> section. **Cutover prep — deferred maintenance, done BEFORE the checklist below** @@ -464,8 +494,28 @@ the decision is re-readable rather than re-litigated. instruments its extract checked — and its own note then disclaimed that conclusion as the Commissioner's words; `/med-arb/` said the ADRIC Med-Arb Rules were presented to the membership where the source says a **discussion - draft** was). Three remain and each has its own item below or above: - the `/med-arb/` gloss (a ruling), Q60, and Q62. + draft** was). ✅ **Two of the three remaining were ruled and closed + 2026-09-02** — Q62 (the page now states the measured truth) and the + `/med-arb/` gloss (struck, no replacement). + + ⚠️ **AND THE PASS WAS RE-RUN OVER THOSE TWO FIXES ON 2026-09-02, WHICH IS + WHAT MAKES THE ITEM CLOSEABLE — IT RETURNED FAIL WITH EIGHT MORE.** This is + the same pass completing, not a per-step audit reinstated: a FAIL whose + fixes are never re-audited leaves *"findings resolved"* asserted rather than + checked. **Five of the eight were in the fixes themselves** — the + replacement copy reintroduced an absolute third-party negative of the + shape struck from this page on 2026-08-31, claimed an enumeration the + evidence file did not support, asserted *"the one other place a copy + exists"* when the inquirer's confirmation carries the whole submission, + left `LAST_UPDATED` at 31 August on the change set that rewrote the page's + central disclosure, and left *"your IP address"* standing when `docs/09` + Part 7.2 had said in terms to fold it into the Q62 edit. Two were on + `/med-arb/`: the struck gloss left *"the section above"* pointing at the + ADRIC rule set and *"the agreement"* with no antecedent, and the bare + designations line was left sitting directly under ADRIC's competence + quotation. One was declined with a reason (§Rules' heading — see the + Change Log). **All corrected or declined; the pass is clean on findings + and the item is open only on the human halves above.** **Two things about that result are worth carrying forward.** The pass found no defect in any claim about Pouya, his credentials or his designations — @@ -478,6 +528,26 @@ the decision is re-readable rather than re-litigated. have flagged correct copy and demanded the struck form. It read §4 instead. That is the fifth stale claim found in that file and it is not the agent's to fix +- [ ] 🛑 **POUYA HAS APPROVED THE `/legal/privacy/` §Who can see it WORDING — + §9 **Q63**(a).** Separate from the item below and narrower: Q62's ruling + settled what that section must **say**; he reserved the **wording**. The + draft is in `dist/` and quoted in + `docs/reference/intake-table-access-verification.md`. + ⚠️ **THIS ITEM EXISTS BECAUSE THE GATE HAD NO MECHANISM.** On 2026-09-02 + the `TODO(pouya)` was deleted from the source, Q62 was struck in §9 and the + blocker in the callout above was ticked — all correctly, and the net effect + was that the only surviving record of an **open** approval requirement was + prose inside three records marked ✅ CLOSED. When Q60's TTL test passes, + nothing mechanical or visual would have stopped copy Pouya has not read. + `adversarial-reviewer`, D20 pass round 1. The `TODO(pouya)` is reinstated + beside the copy and §9 Q63 is open; this is the third surface, and it is + the one a person following this list at cutover actually reads +- [ ] **Q63(b) answered, or accepted as unanswerable** — who else can read + `info@smlcompany.ca`. **Not a gate on truth**: the copy asserts no access + list, so nothing false publishes either way. It is a gate on **standards** — + the page answers the table half with a measured number and the mail half + without one, and a reader is entitled to the specific on both. If he + answers, the fact goes in §7 and §12 **R21**'s trigger covers it - [ ] **Pouya has read every page against `AGENTS.md` §4.** The human pass. It is the other half of D20 and it is not delegable — his reading is what the per-step audit was traded for. @@ -502,6 +572,29 @@ the decision is re-readable rather than re-litigated. **§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. + ⚠️ **STILL OPEN AS AT 2026-09-02 AND IT IS A ONE-LINE ANSWER.** Pouya was + asked on 2026-09-02. It is **one of three** items waiting on him that are + not waiting periods — the other two are Q63(a)'s wording approval and his + own read-through, both above; the earlier form of this line called it the + only one, in a change set that added the other two + (`adversarial-reviewer`, round 2). The question: *"are ADRIC, ADRIO, the three OBA sections and the + CTF all still current?"* Answer it, then re-stamp §4 and `schema.ts` with + the cutover date. Do not tick this from the 2026-08-28 stamp — a stamp is + not a renewal receipt, which is the whole of R10. +- [x] ✅ **THE SEVEN VOLATILE `docs/reference/` EXTRACTS RE-CHECKED — `AGENTS.md` + §12 R18, whose trigger is the same "before any cutover" event R10 uses.** ⚠️ **THIS ITEM DID NOT EXIST UNTIL 2026-09-02 AND THAT + WAS THE DEFECT**: R18 names a cutover as its trigger and the cutover + checklist carried no item to fire it, which is Q22's shape — a documented + control living somewhere it cannot run. R10 was on this list; R18 was not. + **Re-checked 2026-09-01 by Pouya. All seven hold and no shipped sentence + changed.** Three were re-verified against a source and four are held + unchanged on a cadence judgement rather than a fresh retrieval — the + distinction is stamped per limb in `AGENTS.md` §12 R18 and in each + extract, because "re-checked" and "not looked at, judged slow" are not the + same stamp and collapsing them is how OCNI lapsed. + **Re-fire this on the next republish that turns on one of them**, and note + that the fastest mover — Bill C-36 — needs no page edit while it sits at + second reading and needs one the day it does not. - [ ] **The OBA sections stay listed; the LSO stays out** — a check that nobody has tidied the two into one list, not an open question. `AGENTS.md` **Q51 answered 2026-08-28**: the Law Society is the **regulator**, so membership @@ -814,8 +907,23 @@ the decision is re-readable rather than re-litigated. Not a conformance failure of the same shape as Q61: a partial obscuring is not SC 2.4.11, which is about a component **entirely** hidden. `docs/02` §Reflow carries the 777-cell grid -- [ ] ⚠️ **THE `/med-arb/` GLOSS NEEDS A RULING — `claims-auditor`, D20 pass, - finding 1.** §Why this practice says *"Med-arb is not a third service +- [x] ✅ **THE `/med-arb/` GLOSS — RULED AND STRUCK, 2026-09-02.** Pouya: + *"strike the gloss sentence. The ADRIC-sourced material carries the page. + No replacement claim, no competence claim."* Applied: the definitional + gloss is struck. ⚠️ **AND SO IS THE DESIGNATIONS CLAUSE THAT THE FIRST + VERSION OF THIS ITEM SAID WAS "NOW THE LEDE" — corrected 2026-09-02, + `adversarial-reviewer` round 2, which found this line describing a page + state the same change set had deleted.** Round 1 of the closing claims + pass found that a bare `DESIGNATIONS_HELD_LINE` sitting directly beneath + §Rules' quotation of ADRIC requiring *"a high level of practitioner + competence"* read as meeting that bar. **§Why this practice now carries an + acceptance sentence and no credential claim at all**; `/about/` publishes + the designations and the JSON-LD carries them. The constraint is recorded + in the section's own comment in `src/pages/med-arb.astro`. **The original + finding is kept below unstruck**, because it is the reasoning behind a + paragraph that is deliberately thin, and a later reader who cannot see why + will fill it. + `claims-auditor`, D20 pass, finding 1: §Why this practice said *"Med-arb is not a third service bolted onto mediation and arbitration; it is the two of them run under one agreement"*, and one section above the page publishes ADRIC's own words: med-arb is *"not merely the merging of separate mediation and arbitration diff --git a/docs/09-cutover-runbook.md b/docs/09-cutover-runbook.md index 5912973..4a4366a 100644 --- a/docs/09-cutover-runbook.md +++ b/docs/09-cutover-runbook.md @@ -672,7 +672,7 @@ AWS address, not yours. Three outcomes and each has a different consequence: | what `sourceIp` holds | what it means | |---|---| | an **AWS** address (not the `checkip` value) | As designed. The field records the CDN, so it **cannot serve abuse investigation**, and `/legal/privacy/`'s *"your IP address"* is inaccurate — fold it into the Q62 edit on the same page rather than leaving two wrong sentences there | -| **your** address, matching `checkip` | Better than expected, and worth knowing before anyone relies on it. Do not conclude it is trustworthy: verify it is not simply echoing a header by resubmitting with `-H 'X-Forwarded-For: 8.8.8.8'` and confirming `8.8.8.8` is **not** what lands | +| **your** address, matching `checkip` | Better than expected, and worth knowing before anyone relies on it. Do not conclude it is trustworthy: verify it is not simply echoing a header by resubmitting with `-H 'X-Forwarded-For: 8.8.8.8'` and confirming `8.8.8.8` is **not** what lands. ⚠️ **AND CORRECT `/legal/privacy/` §What is collected**, whose network-address paragraph says the address is *"normally the network's own rather than your connection's"* — wrong in this branch, and it understates what is held about the reader. This row carried **no instruction at all** until 2026-09-02, so two of these three outcomes had nothing reconciling the page with the measurement (`adversarial-reviewer`, round 2) | | `8.8.8.8` after that resubmission | **Stop.** The field is client-controlled and a record can be made to name an uninvolved third party. Revert to storing nothing rather than storing that | ⚠️ **AN EARLIER REVISION OF THE HANDLER READ `x-forwarded-for` HERE, AND THAT WAS diff --git a/docs/reference/adr-institution-names.md b/docs/reference/adr-institution-names.md index 46b599e..9f4568f 100644 --- a/docs/reference/adr-institution-names.md +++ b/docs/reference/adr-institution-names.md @@ -13,6 +13,18 @@ cite it. Do not paraphrase a fact into a page that is not stated here. > date and effective date below is as at the retrieval date and nothing more. > Re-check before cutover, and before any republish that turns on one of them. +> ### R18 re-check — cutover pass, 2026-09-01 +> +> The trigger fired. `AGENTS.md` §12 R18 holds the per-limb findings and +> the sources; this stamp does not restate them. **The quoted bytes below +> are still the original retrieval and were not re-fetched** — what was +> re-checked is whether the *facts* they support have moved. +> +> - **(g) ADRIC's Code of Ethics, quoted verbatim on `/process/` — NOT +> RE-RETRIEVED.** Held unchanged on a cadence judgement `[assumed +> 2026-09-01 — Pouya]`. It is the slowest-moving of the seven; the live link +> on `/process/` is what makes a stale quotation visible to a reader. + **Topic as researched:** The Canadian ADR institutions this practice names, and the exact form of their names — ADRIC / ADRIO rule sets, designations, codes; ADR Chambers; early neutral evaluation and dispute-system design --- diff --git a/docs/reference/adric-rules.md b/docs/reference/adric-rules.md index b5de624..510908f 100644 --- a/docs/reference/adric-rules.md +++ b/docs/reference/adric-rules.md @@ -10,6 +10,19 @@ construction. This is the same fetch-before-writing that caught **It caught one immediately. See Finding 1.** +> ### R18 re-check — cutover pass, 2026-09-01 +> +> The trigger fired. `AGENTS.md` §12 R18 holds the per-limb findings and +> the sources; this stamp does not restate them. **The quoted bytes below +> are still the original retrieval and were not re-fetched** — what was +> re-checked is whether the *facts* they support have moved. +> +> - **(f) the ADRIC National Mediation Rules, under review by ADRIC's own +> committee — NOT RE-RETRIEVED.** Held unchanged on a cadence judgement +> rather than a fresh fetch `[assumed 2026-09-01 — Pouya]`. The digests in +> the Provenance table below are the 2026-08-28 bytes and were not +> recomputed, so this stamp says nothing about whether the page changed. + ## Provenance | | | diff --git a/docs/reference/canada-privacy-technology.md b/docs/reference/canada-privacy-technology.md index 966ebd1..6313808 100644 --- a/docs/reference/canada-privacy-technology.md +++ b/docs/reference/canada-privacy-technology.md @@ -21,6 +21,19 @@ not published. > at second reading on the retrieval date and could be law, or dead, by the time > anyone reads this. **Re-check before cutover.** +> ### R18 re-check — cutover pass, 2026-09-01 +> +> The trigger fired. `AGENTS.md` §12 R18 holds the per-limb findings and +> the sources; this stamp does not restate them. **The quoted bytes below +> are still the original retrieval and were not re-fetched** — what was +> re-checked is whether the *facts* they support have moved. +> +> - **(a) Bill C-36 — RE-VERIFIED UNMOVED** `[re-checked 2026-09-01 — Pouya, +> ]`. Still at second +> reading in the House of Commons; latest completed stage is first reading, +> 2026-06-15; no advance since. `/practice/technology/`'s sentence stands as +> written. + **Topic as researched:** Canadian technology / data / AI dispute context — privacy legislation status as at 2026-08-29, Ontario public-sector and health privacy statutes, data residency law, and Canadian arbitral-institution rules for technology/AI disputes --- diff --git a/docs/reference/intake-table-access-verification.md b/docs/reference/intake-table-access-verification.md index be9b7d1..15e4531 100644 --- a/docs/reference/intake-table-access-verification.md +++ b/docs/reference/intake-table-access-verification.md @@ -10,16 +10,56 @@ one claim on the site whose subject was entirely outside the repo. Raised by `claims-auditor` in the D20 cutover audit, 2026-09-01, finding 8. -**Provenance.** Every figure below was read from AWS on **2026-09-01** with the -commands listed at the end, run read-only as `arn:aws:iam::327082975128:user/pouya`. +**Provenance.** Figures in the ORIGINAL sections were read from AWS on +**2026-09-01**; everything in the **2026-09-02 addendum** at the foot of this file +was read on 2026-09-02, and it supersedes the original role screen. Both were run +read-only as `arn:aws:iam::327082975128:user/pouya` with the commands listed at +the end. No command in this file creates or changes anything. Re-run them rather than trusting this file; it is dated for that reason. --- -## The claim being checked +## ✅ RULED AND APPLIED — 2026-09-02 -`src/pages/legal/privacy.astro`, §Who can see it: +**Pouya ruled `state the truth`, not `remove the access`** (§9 Q62, ruled +2026-09-01, applied 2026-09-02). Option 2 below is the one taken; option 1 was +declined. `lars`'s membership of `admins` is **unchanged**. + +**The shipped sentences**, so this file can be compared against the live page +rather than against a struck one: + +> Two people can. The table sits in an Amazon Web Services account that also +> runs systems unrelated to this practice, and that account has two +> administrators — me, and one other person who administers it with me. +> Administrative access to the account carries the ability to read the table, so +> both of us can read what you send. + +> No one outside those two people has been granted access to the table, and that +> is measured rather than assumed: every user and every role in the account was +> simulated against this table, and the only ones that come back able to read it +> lead to those same two people. + +> The function that receives the form **can only add a record — it cannot read +> the table back.** And the credential that publishes this website has **no +> access to the table at all**, for reading or for writing. + +**Wording is subject to Pouya's read-through approval** — §9 **Q63**, with a +`TODO(pouya)` beside the copy. The measurement is settled; the phrasing is not. + +⚠️ **AND THE ENUMERATION BELOW WAS NOT ENOUGH TO SUPPORT THE SECOND OF THOSE +SENTENCES. See the addendum at the foot of this file**, which is what the page +actually rests on. Read it before citing the five-row table. + +--- + +## The claim being checked — ⚠️ STRUCK 2026-09-01, QUOTED HERE AS THE DEFECT + +This is **no longer on the page.** It is kept because it is the string +`check-claims.mjs`'s `sole-administrator-q62` pattern permanently bars, and a +tripwire whose target is not recorded anywhere becomes unmaintainable. + +`src/pages/legal/privacy.astro`, §Who can see it, **as it stood at `bd282aa`**: > The table is reachable by the function that writes to it and by one > administrative account, which is mine — nobody else has access to the table. @@ -75,9 +115,13 @@ access, and it belongs to a second administrator of a shared account. `meshkini*`/`gitea*` users are evidence of that on the IAM surface, not just in the S3 bucket listing §10 describes. -## What has to happen before `/legal/privacy/` goes public +## What had to happen before `/legal/privacy/` went public — ✅ RESOLVED BY OPTION 2 -Tracked as `AGENTS.md` §9 **Q62**. It is one of two things and both are Pouya's: +Tracked as `AGENTS.md` §9 **Q62**, **closed 2026-09-02 on option 2.** Kept +unstruck because the reasoning is what makes the ruling re-readable, and because +option 1 remains live in one direction: if that access is ever actually removed, +the page and the tripwire both have to change, and `check-claims.mjs`'s `rule:` +line carries that instruction. 1. **Remove the access** — take `lars` out of `admins`, or replace that membership with a policy that denies DynamoDB on this table — and then this @@ -139,3 +183,218 @@ parameter-expansion bug (`$ACCT:user/` parses `:u` as a history modifier). The loop above brace-quotes `${U}` for that reason, prints one line per principal so a silently-skipped iteration is visible as a missing row, and suppresses nothing. **Five rows, or the run did not happen.** + +--- + +## ⚠️ ADDENDUM 2026-09-02 — THE ENUMERATION ABOVE WAS INCOMPLETE IN THREE WAYS, AND ITS CONCLUSION SURVIVES ANYWAY + +**Why this addendum exists.** `/legal/privacy/` publishes a completeness claim +about who can read this table — the second of the three sentences quoted at the +top of this file, under **The shipped sentences**. Written as it stood, this file +did not support it. + +*(This paragraph quoted a different sentence until 2026-09-02 — round 1's +**pre-fix** wording, *"every account and role in this infrastructure…"*, which +the audit then struck. So this file briefly quoted two different sentences as the +live one, in the two halves of the same document, which defeats the comparison +R14 exists for. Fixed by pointing at the block above rather than re-quoting it: +one copy of a fact, in one place. `adversarial-reviewer`, round 2.)* Under R14 the artefact is what a reviewer compares the +claim against, so a claim stronger than its artefact is unverifiable by +construction even when it happens to be true. + +**What was missing.** + +1. **`aws iam list-role-policies` was never run.** The command block above lists + only `list-attached-role-policies`, which returns *managed* policies. **23 of + the 26 non-service-linked roles carry inline policies**, and none of them had + been read. The screen for "broad policies" could not have seen an inline grant. +2. **No role was ever simulated against the table.** Access was inferred from + policy *names* (`AdministratorAccess`) rather than measured as a decision. +3. **The five users were simulated for reads only** — `GetItem`, `Query`, `Scan`. + So the page's *"the credential that publishes this website has no access to the + table at all"* covered three read actions and said "at all". + +**What the measurement found, and it changes the role count.** Simulating all 26 +non-service-linked roles across **seven** actions — `GetItem`, `Query`, `Scan`, +`BatchGetItem`, `PutItem`, `UpdateItem`, `DeleteItem`: + +| role | decision on the table | trust | +|---|---|---| +| `cdk-hnb659fds-cfn-exec-role-…-ca-central-1` | **allowed on all 7** | `cloudformation.amazonaws.com` only | +| `cdk-hnb659fds-cfn-exec-role-…-us-east-1` | **allowed on all 7** | `cloudformation.amazonaws.com` only | +| `cdk-hnb659fds-lookup-role-…-ca-central-1` | **allowed on the 4 READS**, denied on writes | `arn:aws:iam::327082975128:root` | +| `cdk-hnb659fds-lookup-role-…-us-east-1` | **allowed on the 4 READS**, denied on writes | `arn:aws:iam::327082975128:root` | +| `adr-intake-lambda-role` | `PutItem` **only**; implicitDeny on the other six | `lambda.amazonaws.com` | +| the other 21 | implicitDeny on all 7 | — | + +**So FOUR roles can read the table, not the two this file recorded.** The two +`lookup` roles were missed by exactly the gap above: their grant is the inline +`LookupRolePolicy`, and `list-attached-role-policies` returns nothing for them. + +**Why the published sentence is nevertheless correct.** The question is not how +many roles exist but which *people* they lead back to. + +- The two **cfn-exec** roles trust `cloudformation.amazonaws.com` and nothing + else. No human can assume them; they are reachable only by deploying a + CloudFormation/CDK stack, which requires a principal who can deploy one. +- The two **lookup** roles trust the account root, which delegates the decision + to the caller's own identity policy. Simulated for `sts:AssumeRole` against + both role ARNs, for all five users, reading `ResourceSpecificResults` (ten + per-resource decisions, not five — `EvaluationResults` is one entry per + **action**, and an earlier pass here asserted the wrong count): + +| principal | assume `lookup-…-ca-central-1` | assume `lookup-…-us-east-1` | +|---|---|---| +| `user/pouya` | **allowed** | **allowed** | +| `user/lars` | **allowed** | **allowed** | +| `user/adr-sml-deploy` | implicitDeny | implicitDeny | +| `user/gitea-deploy-meshkinilaw` | implicitDeny | implicitDeny | +| `user/meshkini-backend-deploy` | implicitDeny | implicitDeny | + +- The **CloudFormation escalation path this file named and left untested** — + *"a real path to the table for anyone who can deploy a CDK stack"* — is now + measured. Simulated for `cloudformation:CreateStack`, `UpdateStack`, + `CreateChangeSet`, `ExecuteChangeSet`, `iam:PassRole` and `sts:AssumeRole`, + five users × six actions = **30 decisions**, count asserted: + +| principal | the CDK / CloudFormation path | +|---|---| +| `user/pouya` | **allowed** on all six | +| `user/lars` | **allowed** on all six | +| `user/adr-sml-deploy` | implicitDeny on all six | +| `user/gitea-deploy-meshkinilaw` | implicitDeny on all six | +| `user/meshkini-backend-deploy` | implicitDeny on all six | + + This is the finding that mattered most, because `meshkini-backend-deploy` is by + its name another project's backend-deploy credential and + `gitea-deploy-meshkinilaw` is held on a **jointly administered** Gitea instance + (Q23). Either one, had it been able to drive CloudFormation, would have read + the table without appearing in the five-row table above — and *"Two people + can"* would have been wrong. Neither can. + +- **And the seven roles every sweep here had excluded BY CONSTRUCTION are now + measured too.** Every role loop in this file filters `grep -v + '^AWSServiceRole'`, and the assertion was written as *"twenty-six role rows"* — + so a service-linked role was outside the claim rather than inside it, which + matters because a service-linked role for a backup or migration service can + read table contents. All **7** (`APIGateway`, `CloudFrontLogger`, + `InternetMonitor`, `RDS`, `ResourceExplorer`, `Support`, `TrustedAdvisor`) are + **implicitDeny on all seven actions** — 49 decisions, count asserted + `[verified 2026-09-02]`. **So the enumeration is 33 of 33 roles, not 26 of + 33**, and the page's *"every user and every role in the account"* is now + literally true. Raised by `adversarial-reviewer`, round 2. + +- **There is no federated identity surface at all**: `list-saml-providers` **0**, + `list-open-id-connect-providers` **0**, `sso-admin list-instances` **0** + `[verified 2026-09-02]`. So "every user and every role" is not leaving out a + federated principal, because there is none to leave out. + +Every read path therefore terminates at `pouya` or `lars`. **The count of people +is two, and it is now the result of an enumeration rather than of a policy name.** + +**The account root user, recorded because an enumeration that quietly omits it is +not an enumeration.** Root is not an IAM user and does not appear in +`list-users`, so it cannot be simulated and no policy constrains it — root can +always read the table. Two facts bound it: `get-account-summary` reports +`AccountAccessKeysPresent: 0`, so **there is no programmatic root credential**, +and `AccountMFAEnabled: 1`. Root access therefore requires the root password and +its MFA device. **The page does not mention root and should not**: an account +owner's own credential is inherent to every cloud account and is not a third +party who has been granted access — which is why the shipped sentence is scoped +to *"every user and every role"* and to who has been *granted* access, rather +than to a bare "nobody else can". Who holds the root credentials is not +established in this repository; it is not a page-blocking fact, and it is noted +here rather than guessed at. + +**Two page sentences are now supported that were not before.** + +- *"The function that receives the form can only add a record and cannot read the + table back"* — `adr-intake-lambda-role` returns `allowed` for `PutItem` and + `implicitDeny` for `GetItem`, `Query`, `Scan`, `BatchGetItem`, `UpdateItem` and + `DeleteItem`. Previously this rested on reading the policy document; it is now + the simulator's decision. +- *"the credential that publishes this website has no access to the table at + all"* — `adr-sml-deploy` is `implicitDeny` on all **seven**, so "at all" now + covers writes and deletes as well as reads. + +**And it corroborates §10 from the IAM surface.** Of the 26 non-service-linked +roles, **9 belong to CDK bootstrap** and **14 to four unrelated production +systems** in the same account — which is what `/legal/privacy/` now tells a +reader in as many words. *(Their role names were listed here until 2026-09-02 and +are not any more: this is a committed file, they are another project's IAM +surface, and the count carries the whole of the argument. `adversarial-reviewer`, +round 2.)* + +⚠️ **THE INSTRUMENT FAILED FIRST, UNIFORMLY, AND IN THE DIRECTION THAT READS AS +CLEAN.** The role sweep was first run as `--action-names $ACTS` with the seven +actions in a shell variable. **zsh does not word-split parameter expansions**, so +`simulate-principal-policy` received **one** action name — the whole string — and +answered it: `implicitDeny` for 22 roles, and `allowed` for the four with a `*` +grant, because `*` matches a bogus action too. Twenty-two clean rows and a +plausible four. The tell was the shape of the output, not the verdict: one +decision per role where there should have been seven. **The fix is the assertion, +not the memory** — the loop now counts `EvaluationResults` per call and refuses a +row that does not carry exactly seven, and the users' assume check counts +`ResourceSpecificResults` and refuses a row that does not carry exactly two. +`CLAUDE.md` records this class five times over; this is the sixth, and it is the +"uniformly good" half. + +### Commands — the ones this addendum rests on + +Read-only, run as `user/pouya` in `ca-central-1`. No stderr suppressed, exit +status read on every call, and note the **literal** action lists: they are not in +a variable, which is the whole point above. + +```bash +# 1. Inline policies — the command the original block never ran. +aws iam list-roles --query 'Roles[].RoleName' --output text \ + | tr '\t' '\n' | grep -v '^AWSServiceRole' \ + | while IFS= read -r R; do + aws iam list-role-policies --role-name "$R" --query 'PolicyNames' --output text + done + +# 2. Every non-service-linked role, seven actions, decision asserted per row. +# The count check is what makes a broken call loud instead of clean. +aws iam simulate-principal-policy \ + --policy-source-arn "arn:aws:iam::327082975128:role/" \ + --action-names dynamodb:GetItem dynamodb:Query dynamodb:Scan \ + dynamodb:BatchGetItem dynamodb:PutItem dynamodb:UpdateItem \ + dynamodb:DeleteItem \ + --resource-arns "arn:aws:dynamodb:ca-central-1:327082975128:table/adr-intake-submissions" \ + --query 'length(EvaluationResults)' --output text # must print 7 + +# 3. Trust policies of the four roles that can read. +aws iam get-role --role-name --query 'Role.AssumeRolePolicyDocument' + +# 4. Who can assume the two lookup roles — per RESOURCE, not per action. +aws iam simulate-principal-policy \ + --policy-source-arn "arn:aws:iam::327082975128:user/" \ + --action-names sts:AssumeRole \ + --resource-arns "arn:aws:iam::327082975128:role/cdk-hnb659fds-lookup-role-327082975128-ca-central-1" \ + "arn:aws:iam::327082975128:role/cdk-hnb659fds-lookup-role-327082975128-us-east-1" \ + --query 'EvaluationResults[].ResourceSpecificResults[].{R:EvalResourceName,D:EvalResourceDecision}' \ + --output text # must print 2 rows +``` + +```bash +# 5. The CloudFormation / CDK escalation path, per user. Six actions, literal. +aws iam simulate-principal-policy \ + --policy-source-arn "arn:aws:iam::327082975128:user/" \ + --action-names cloudformation:CreateStack cloudformation:UpdateStack \ + cloudformation:CreateChangeSet cloudformation:ExecuteChangeSet \ + iam:PassRole sts:AssumeRole \ + --query 'EvaluationResults[].{A:EvalActionName,D:EvalDecision}' --output text + +# 6. Federated identity surfaces, and root. +aws iam list-saml-providers --query 'length(SAMLProviderList)' +aws iam list-open-id-connect-providers --query 'length(OpenIDConnectProviderList)' +aws sso-admin list-instances --query 'length(Instances)' +aws iam get-account-summary \ + --query 'SummaryMap.{AccessKeysPresentRoot:AccountAccessKeysPresent,MFA:AccountMFAEnabled}' +``` + +**Five user rows and twenty-six role rows, or the run did not happen.** And for +every simulation: **seven decisions per role call, six per CDK-path call, two +per-resource decisions per assume call** — the counts are the assertion, because +a call that silently received one bogus action name answers `implicitDeny` and +reads exactly like a clean row. diff --git a/docs/reference/ontario-construction-act.md b/docs/reference/ontario-construction-act.md index 4b1bffe..b20db72 100644 --- a/docs/reference/ontario-construction-act.md +++ b/docs/reference/ontario-construction-act.md @@ -13,6 +13,31 @@ cite it. Do not paraphrase a fact into a page that is not stated here. > date and effective date below is as at the retrieval date and nothing more. > Re-check before cutover, and before any republish that turns on one of them. +> ### R18 re-check — cutover pass, 2026-09-01 +> +> ⚠️ **THIS FILE CARRIES THE STANDING RE-CHECK INSTRUCTION ABOVE AND WAS +> NOT ONE OF R18's SEVEN LIMBS, AND IT WENT UNSTAMPED IN THE FIRST PASS.** +> Five of seven extracts were stamped and two were not, so a reader could +> not tell whether this one was considered and found non-volatile or simply +> missed. Found by `adversarial-reviewer`, 2026-09-02 — the same +> control-fires-over-part-of-its-scope defect as R18 having no checklist +> item, one notch smaller. **Nothing here was re-retrieved.** +> +> - **No R18 limb, but ONE CANDIDATE LIMB, and it is flagged rather than +> silently adopted.** `/practice/construction/` publishes: *"Ontario Power +> Generation … applied in March 2026 for a licence to operate it."* That is a +> **pending application**, so it moves the way limb (a) moves. It is not +> false today — the application was made, and a completed past act stays +> true — which is why this is a note and not a blocker. But a reader takes it +> as current status, and unlike limb (a) the sentence is **not time-anchored** +> ("when this page was written"). **For Pouya at the next re-check: adopt it +> as R18 limb (h), or time-anchor the sentence and drop it.** +> - The rest is stable: Part II.1 in force since 2019-10-01, and ODACC's own +> statement that it is the Authorized Nominating Authority. The ODACC 2025 +> Annual Report is cited for institutional facts rather than for figures, so +> it does not carry limb (d)'s exposure `[verified 2026-09-02 — swept +> `dist/practice/construction/index.html`]`. + **Topic as researched:** Ontario construction dispute resolution — the statutory machinery (Construction Act, R.S.O. 1990, c. C.30); plus verification of the OPG Darlington New Nuclear Project and Bruce Power's Bruce C Project --- diff --git a/docs/reference/ontario-energy-regulatory.md b/docs/reference/ontario-energy-regulatory.md index b6e38e9..b7cc7ed 100644 --- a/docs/reference/ontario-energy-regulatory.md +++ b/docs/reference/ontario-energy-regulatory.md @@ -13,6 +13,20 @@ cite it. Do not paraphrase a fact into a page that is not stated here. > date and effective date below is as at the retrieval date and nothing more. > Re-check before cutover, and before any republish that turns on one of them. +> ### R18 re-check — cutover pass, 2026-09-01 +> +> The trigger fired. `AGENTS.md` §12 R18 holds the per-limb findings and +> the sources; this stamp does not restate them. **The quoted bytes below +> are still the original retrieval and were not re-fetched** — what was +> re-checked is whether the *facts* they support have moved. +> +> - **(c) ERO 026-0853 — RE-VERIFIED UNMOVED** `[re-checked 2026-09-01 — +> Pouya]`. The comment period to 2026-09-12 is still open. +> - **(b) the regulation under `Electricity Act` s. 28.1 — NOT RE-RETRIEVED.** +> Held unchanged on a cadence judgement rather than a fresh retrieval +> `[assumed 2026-09-01 — Pouya: unchanged by its nature at this cadence]`. +> That is a weaker stamp than (c) and is written weaker on purpose. + **Topic as researched:** Ontario electricity/energy regulatory processes that generate disputes: OEB leave to construct (OEB Act, 1998 ss. 90/92/95/96), the IESO and market participation, the IESO connection assessment process (SIA/CIA), large-load and data-centre grid connection (Electricity Act, 1998 s. 28.1), and Ontario Bill 40 --- diff --git a/docs/reference/ontario-sabs-lat.md b/docs/reference/ontario-sabs-lat.md index fdcecca..d2f40ad 100644 --- a/docs/reference/ontario-sabs-lat.md +++ b/docs/reference/ontario-sabs-lat.md @@ -13,6 +13,22 @@ cite it. Do not paraphrase a fact into a page that is not stated here. > date and effective date below is as at the retrieval date and nothing more. > Re-check before cutover, and before any republish that turns on one of them. +> ### R18 re-check — cutover pass, 2026-09-01 +> +> The trigger fired. `AGENTS.md` §12 R18 holds the per-limb findings and +> the sources; this stamp does not restate them. **The quoted bytes below +> are still the original retrieval and were not re-fetched** — what was +> re-checked is whether the *facts* they support have moved. +> +> - **(d) the Tribunals Ontario annual report — RE-VERIFIED UNMOVED** +> `[re-checked 2026-09-01 — Pouya, +> ]`. +> **No 2025-26 report is published; FY2024-25 remains current**, so the +> figures `/practice/insurance/` publishes are still the latest. This closes +> the open item at the foot of this file, which asked exactly that question. +> - **(e) the SABS, amended with effect 2026-07-01 — NOT RE-RETRIEVED.** Held +> unchanged on a cadence judgement `[assumed 2026-09-01 — Pouya]`. + **Topic as researched:** Ontario accident benefits (SABS) disputes — regulation, Minor Injury Guideline, the LAT-AABS dispute route, tribunal caseload volume, mediation references in tribunal materials, and FSRA's role --- @@ -341,6 +357,7 @@ honest, and on this project it is the half that has twice been skipped. - **Whether a more recent annual report than 2024-25 exists (i.e. a 2025-26 report covering the year ending March 31, 2026).** - *Searched:* WebSearch for Tribunals Ontario annual report LAT AABS caseload; retrieved the 2024-25 report, which is dated June 30, 2025 and is the most recent surfaced. - *Outcome:* NOT CONFIRMED either way. The 2024-25 report (fiscal year ending March 31, 2025) is the latest located as of 2026-08-29, but no search was run specifically to rule out a 2025-26 edition. Given today's date, one may well have been published. Re-check before publishing any 'most recent' or 'latest available' framing around these figures. + - *Outcome, R18 re-check:* **CONFIRMED — no 2025-26 edition is published, and FY2024-25 remains current** `[re-checked 2026-09-01 — Pouya, ]`. This closes the item as originally posed. The caution in the line above is retained rather than struck, because it is about a FRAMING and not about this fact: nothing on `/practice/insurance/` calls these figures the most recent or the latest available, and nothing should start to — a 2025-26 edition will appear eventually and a bare year label goes stale gracefully where a superlative does not. - **What the SABS amendments effective July 1, 2026 actually changed.** - *Searched:* Noted the consolidation banner on the e-Laws SABS page ('From July 1, 2026') and the tribunal's warning that 'Changes to the Statutory Accident Benefits Schedule effective July 1, 2026 may impact your insurance benefits'. Did not fetch O. Reg. 383/24 or the amending instruments. - *Outcome:* NOT ESTABLISHED. Search-result snippets suggested that certain benefits became optional, but no primary amending regulation was fetched, so nothing about the substance of the July 2026 changes is asserted here. The s. 3(1) definitions and the s. 18(1) $3,500 limit quoted above ARE from the post-July-2026 consolidation and are current as retrieved. diff --git a/docs/reference/ontario-shareholder-remedies.md b/docs/reference/ontario-shareholder-remedies.md index d97ae78..d37f7b3 100644 --- a/docs/reference/ontario-shareholder-remedies.md +++ b/docs/reference/ontario-shareholder-remedies.md @@ -13,6 +13,22 @@ cite it. Do not paraphrase a fact into a page that is not stated here. > date and effective date below is as at the retrieval date and nothing more. > Re-check before cutover, and before any republish that turns on one of them. +> ### R18 re-check — cutover pass, 2026-09-01 +> +> ⚠️ **THIS FILE CARRIES THE STANDING RE-CHECK INSTRUCTION ABOVE AND WAS +> NOT ONE OF R18's SEVEN LIMBS, AND IT WENT UNSTAMPED IN THE FIRST PASS.** +> Five of seven extracts were stamped and two were not, so a reader could +> not tell whether this one was considered and found non-volatile or simply +> missed. Found by `adversarial-reviewer`, 2026-09-02 — the same +> control-fires-over-part-of-its-scope defect as R18 having no checklist +> item, one notch smaller. **Nothing here was re-retrieved.** +> +> - **No volatile limb at this cutover.** The facts this file supports on +> `/practice/shareholder/` are OBCA sections and case law, which do not move +> at this cadence, and a sweep of the built page for dates, statuses and +> "as of" framings returned nothing time-anchored `[verified 2026-09-02 — +> swept `dist/practice/shareholder/index.html`]`. + **Topic as researched:** Ontario/Canada shareholder, partnership and closely-held business disputes — statutory remedies (oppression, dissent/appraisal, winding up), the Partnerships Act, arbitration references in the corporations statutes; plus an independent re-check of Ontario family arbitration training requirements. --- diff --git a/scripts/check-claims.mjs b/scripts/check-claims.mjs index 73d9bc1..7e5c9ce 100644 --- a/scripts/check-claims.mjs +++ b/scripts/check-claims.mjs @@ -259,28 +259,52 @@ const PATTERNS = [ }, { id: 'sole-administrator-q62', - rule: 'Q62 — /legal/privacy/ claims sole administrative access to the intake table, and that is FALSE.', + rule: + 'Q62 — the sole-administrative-access claim on /legal/privacy/ was FALSE ' + + 'and is permanently barred from returning. The page does NOT make it now; ' + + 'if this fired, something reintroduced the shape. ' + + "⚠️ IF THE SECOND ADMINISTRATOR'S ACCESS IS EVER ACTUALLY REMOVED, this " + + 'pattern starts failing the build on TRUE copy, and the answer is neither ' + + 'to delete it nor to work around it: re-run the verification in ' + + '`docs/reference/intake-table-access-verification.md`, rewrite the page to ' + + 'the new measured truth, and narrow THIS pattern deliberately with a ' + + 'Change Log entry. Q23 records the Gitea instance as jointly administered, ' + + 'so that removal is live rather than hypothetical.', incident: 'The page shipped "nobody else has access to the table. There is no team, ' + - 'no assistant and no external administrator." The AWS account has an ' + - '`admins` IAM group carrying AdministratorAccess with TWO members, and ' + - '`simulate-principal-policy` returns allowed for dynamodb:GetItem, Query ' + - 'and Scan on the table for both ' + - '[verified 2026-09-01 — docs/reference/intake-table-access-verification.md]. ' + - 'THE REACHED-DIST CONDITION IS WHY THIS PATTERN EXISTS AT ALL: the ' + - 'sentence was in dist/legal/privacy/index.html, `build`, `check` and this ' + - 'script all exited 0 over it, and the only thing between it and a live ' + - 'privacy policy was a TODO(pouya) in a JSX comment — which Astro strips, ' + - 'so `grep -rn "TODO(pouya)" dist/` returned nothing. The gate was human ' + - 'memory. Found by `adversarial-reviewer`, 2026-09-01. ' + - 'DELETE THIS PATTERN when Q62 is ruled: either the access is removed and ' + - 'the sentence becomes true, or the sentence is rewritten. It is a tripwire ' + - 'on one specific published falsehood, not a rule about a class.', - /* `\s+`, NOT LITERAL SPACES: `compressHTML` collapses whitespace between - tags and leaves it alone inside a text node, so the published bytes read - "nobody else has access to\n the table". A literal-space version - runs, prints `ok`, and exits 0 with the breach in `dist/`. */ - re: /nobody\s+else\s+has\s+access\s+to\s+the\s+table|there\s+is\s+no\s+team,\s+no\s+assistant\s+and\s+no\s+external\s+administrator/gi, + 'no assistant and no external administrator." while TWO principals could ' + + 'read it. It was in dist/, `build`, `check` and this script all exited 0 ' + + 'over it, and the only thing between it and a live privacy policy was a ' + + 'TODO(pouya) in a JSX comment — which Astro strips. The gate was human ' + + 'memory. Pouya ruled the pattern PERMANENT on 2026-09-01: it no longer ' + + 'describes live copy, it bars the shape. Do not delete it, and do not ' + + 'loosen it into a rule about a class. Full history: AGENTS.md entry (an).', + /* THREE CONSTRAINTS, AND THEY ARE WHY THIS IS SHAPED AS IT IS. + + 1. `\s+`, NOT LITERAL SPACES. `compressHTML` collapses whitespace between + tags and leaves it alone inside a text node, so the published bytes + read "nobody else has access to\n the table". A literal-space + version runs, prints `ok`, and exits 0 with the breach in `dist/`. + + 2. EACH ALTERNATIVE IS ONE STRING THAT REACHED `dist/`, NEVER A FAMILY. + The first draft of alternative 3 was `(?:or|and)\s+(?:outside|external)` + — four phrasings where one was published, so three had no probe and no + negative fixture, which is the freeze's stated condition. + + 3. ALTERNATIVE 3 IS A DELIBERATE OVER-BAR AND THIS IS ITS COST. The + truthful receipt-scoped sentence CONTAINS the published string, so any + pattern catching one catches the other — adding that truthful form as a + negative fixture failed the self-test, which is the instrument check + working. So: the clause "no assistant or outside administrator" cannot + be published here in ANY scoping, true or false, without failing this + build. That is the right trade for a phrase that has already put a + false statement on a privacy policy, and `rule:` says what to do. A + lookahead tuned to one guessed phrasing would be the speculative + pattern the freeze bars. + + The window in alternative 5 is `[^\w<]{0,8}`, not `\W{0,8}`: `\W` matches + `<` and the block sentinel, so it would have been bounded by neither. */ + re: /nobody\s+else\s+has\s+access\s+to\s+the\s+table|there\s+is\s+no\s+team,\s+no\s+assistant\s+and\s+no\s+external\s+administrator|no\s+assistant\s+or\s+outside\s+administrator|one\s+administrative\s+account,\s+which\s+is\s+mine|honest\s+answer\s+to\s+[^\w<]{0,8}who\s+can\s+see\s+this[^\w<]{0,8}\s*is:\s+me/gi, }, ]; @@ -367,23 +391,47 @@ const FIXTURES = { 'C.Med-Arbitration', ], 'sole-administrator-q62': [ - /* The two published clauses, verbatim from dist/legal/privacy/. */ + /* The FIVE published clauses from dist/legal/privacy/ as it stood at + `bd282aa`, before the Q62 correction. The first form of the pattern + caught only the first two: clauses 3 and 4 are the same falsehood in + different words in a different section, and clause 5 is the summary + that would have re-asserted the struck number. */ 'nobody else has access to the table', 'There is no team, no assistant and no external administrator.', + 'no analytics on the submission, and no assistant or outside administrator.', + 'The table is reachable by the function that writes to it and by one administrative account, which is mine', + /* The third surface — the summary that would have re-asserted the struck + number four lines below the corrected paragraph. */ + 'So the honest answer to "who can see this" is: me, and Google as the company that runs my mail.', ], 'struck-universal-q39': [ 'Anyone may be appointed an arbitrator in Ontario', 'nothing in law gates the role', ], }, - /* Every one of these is real published or spec-approved copy on this site. */ + /* Mostly real published or spec-approved copy on this site. A few are + deliberate NEAR MISSES — truthful sentences about the same subject that + were never published — because a pattern also has to be proven silent on + the wording a correction is likely to reach for. Where a fixture is one of + those, the comment beside it says so. */ mustNotMatch: [ - /* NEGATIVE FIXTURES FOR `sole-administrator-q62` — the approved copy nearest - to the two clauses it catches. The pattern is deliberately anchored on the - two published sentences rather than on the ideas in them, because the - replacement wording is not yet decided and a looser pattern would fire on - whatever Q62's ruling produces. These four are what "nearest" means: the - same page's true sentences about the same subject. */ + /* NEGATIVE FIXTURES FOR `sole-administrator-q62`. The first three are the + REPLACEMENT COPY ITSELF, verbatim from the corrected `/legal/privacy/` — + which is the fixture that matters, because Q62's ruling required this + pattern to be proven silent on the true sentence as well as loud on the + false one. THEY MUST BE RE-SYNCED WHENEVER THAT COPY CHANGES — round 1's + set went stale within the hour, when the audit rewrote three of the four + paragraphs they were copied from. The rest are near misses on the same + subject: the pattern is anchored on five strings that reached `dist/`, not + on the ideas in them, so a truthful sentence about administrative access + must pass. */ + 'Two people can. The table sits in an Amazon Web Services account that also runs systems unrelated to this practice, and that account has two administrators — me, and one other person who administers it with me.', + 'No one outside those two people has been granted access to the table, and that is measured rather than assumed: every user and every role in the account was simulated against this table, and the only ones that come back able to read it lead to those same two people.', + 'Two things in the system are narrower than I am, and they are worth stating because they are the part you cannot check for yourself.', + 'No one else is sent it. There is no CRM, no mailing list and no analytics on the submission.', + 'Which means there are three copies, not one. The notification in my own mailbox, which is on Google Workspace — so Google holds a copy of whatever you sent me, and so does anyone who can reach that mailbox.', + /* The replacement summary, which must not trip the third-surface alternative. */ + 'Which means there are three copies, not one. The record in the table, which the two people above can read.', 'The table is reachable by the function that writes to it.', 'Two accounts hold administrative access to the AWS account, and the function that writes to the table cannot read it.', 'Nobody else has access to my mailbox.', diff --git a/src/pages/legal/privacy.astro b/src/pages/legal/privacy.astro index c91c6cc..ea14d4a 100644 --- a/src/pages/legal/privacy.astro +++ b/src/pages/legal/privacy.astro @@ -81,7 +81,7 @@ const RETENTION_MONTHS = 24; /** Bump this on ANY substantive edit. A privacy policy with a stale date is a * policy a reader cannot tell they are reading an old version of. */ -const LAST_UPDATED = '31 August 2026'; +const LAST_UPDATED = '2 September 2026'; /* Rendered from the form's own field list, so the two cannot drift. `consent` and the honeypot are absent from `INTAKE_FIELDS` deliberately and are @@ -122,10 +122,30 @@ const COLLECTED = INTAKE_FIELDS.map((field) => field.label);
    {COLLECTED.map((label) =>
  • {label}
  • )}
+ { + /* ⚠️ DO NOT WRITE "your IP address" HERE, AND DO NOT CONCLUDE ANYTHING + ABOUT WHETHER THE ADDRESS IDENTIFIES ANYONE. The handler stores + `requestContext.http.sourceIp` — behind the `/api/*` behaviour that + is a CloudFront edge, so the expected value is Amazon's. **Expected, + not measured:** `docs/09` Part 7.2 measures it at cutover and + enumerates three outcomes, one of which is that the reader's own + address does land. This copy therefore states only why the field is + kept, which is true in all three. A previous form hedged "usually + not yours" and then asserted "not precise enough to identify you" — + false in exactly the branch the hedge admitted. `claims-auditor`, + then `adversarial-reviewer` round 2. */ + }

- Submitting the form also records the date and time, your IP address - and your browser's user-agent string. Those three are kept for - investigating abuse of the form and are not used for anything else. + Submitting the form also records the date and time and your browser's + user-agent string. Those two are kept for investigating abuse of the + form and are not used for anything else. +

+

+ It also records the network address the request arrived from. This + site sits behind a content delivery network, so that address is + normally the network's own rather than your connection's — which is + why it is kept simply because it arrives with the request, and not as + a way of identifying anyone.

Nothing else on this site collects personal information. There is no @@ -204,9 +224,10 @@ const COLLECTED = INTAKE_FIELDS.map((field) => field.label); what they keep.

- No one else receives it. There is no CRM, no mailing list, no - analytics on the submission, and no assistant or outside - administrator. + No one else is sent it. There is no CRM, no mailing list and no + analytics on the submission. Who can read what is stored is a + different question from who it is sent to, and it is answered under + "Who can see it" below.

How long it is kept

@@ -236,43 +257,76 @@ const COLLECTED = INTAKE_FIELDS.map((field) => field.label);

Who can see it

{ - /* ⚠️ THIS SAID "Nobody else has access" AND THE SECTION TWO ABOVE HAD - JUST NAMED GOOGLE. The Google correction was applied to §Where it is - stored and not swept into the section actually headed with the - question a reader asks — so the page answered "who can see the names - of the opposing parties I gave you?" with *nobody else* under that - heading and *Google* under a different one. Fixing one section and - not the section that answers the same question is the sweep failure - `CLAUDE.md` describes. Found by `adversarial-reviewer` round 2. */ + /* ⚠️ FIVE PARAGRAPHS ANSWER "WHO CAN SEE IT" AND THEY CHANGE + TOGETHER: this section's four — the count, the measured enumeration, + the two narrow credentials, the three copies — and §Where it is + stored's last one. Every defect here has been a partial sweep of that + set, and there have been four. + **The enumeration paragraph is the one that goes stale on its own**, + because it is a claim about the present state of an AWS account: §12 + **R21** is its trigger, and + `docs/reference/intake-table-access-verification.md` holds the + commands. `check-claims.mjs`'s `sole-administrator-q62` pattern is a + permanent bar on the old shape returning (Pouya, ruled 2026-09-01). */ } { - /* TODO(pouya): the sentence below is FALSE as at 2026-09-01 and this - page must not go public until you rule — §9 Q62. The AWS account has - an `admins` IAM group carrying `AdministratorAccess` with TWO - members, you and one other person, and - `simulate-principal-policy` returns **allowed** for - `dynamodb:GetItem`/`Query`/`Scan` on this table for both. - Evidence and commands: - `docs/reference/intake-table-access-verification.md`. - THE QUESTION: do you remove that access — which may be the same - co-administrator Q23's Gitea instance depends on, so it is not free - — or does this paragraph state the true number? Nothing here may be - softened into "authorised administrators": on this page a reader is - entitled to the specific, and a true vacancy is worse than a false - specific only in that it cannot be caught. - Raised by `claims-auditor`, D20 cutover audit, finding 8. */ + /* TODO(pouya): TWO THINGS, BOTH FOR YOUR READ-THROUGH — §9 Q63. + (1) APPROVE THE WORDING BELOW. Your ruling settled what it must say; + you reserved the wording. Nothing else gates it. + (2) WHO ELSE CAN READ `info@smlcompany.ca`? The paragraph below says + "anyone who can reach that mailbox", which is true whatever the + answer — but §7 records the mail host and the SES identities and NOT + the mailbox's access list, so this repository cannot state the + number a reader of a privacy policy is entitled to. If the Workspace + is administered by anyone else, or the address is a shared alias, + say so and this becomes specific like the table sentence above it. + Raised by `claims-auditor` and `adversarial-reviewer`, D20 cutover + pass, 2026-09-02. */ }

- I can. The table is reachable by the function that writes to it and by - one administrative account, which is mine — nobody else has access to - the table. There is no team, no assistant and no external - administrator. + Two people can. The table sits in an Amazon Web Services account that + also runs systems unrelated to this practice, and that account has two + administrators — me, and one other person who administers it with me. + Administrative access to the account carries the ability to read the + table, so both of us can read what you send. I would rather tell you + that than give you the tidier answer.

- The one other place a copy exists is the notification email, which - sits in the Google Workspace mailbox named above. So the honest answer - to "who can see this" is: me, and Google as the company that runs my - mail. + No one outside those two people has been granted access to the table, + and that is measured rather than assumed: every user and every role in + the account was simulated against this table, and the only ones that + come back able to read it lead to those same two people. Amazon Web + Services operates the table, as Where it is stored above says — + a company that runs a database is not someone who has been given access + to it, and both of those are true at once. +

+

+ Two things in the system are narrower than I am, and they are worth + stating because they are the part you cannot check for yourself. The + function that receives the form + can only add a record — it cannot read the table back. And the credential that publishes this website has + no access to the table at all, for reading or for + writing. +

+ { + /* ⚠️ THREE COPIES, NOT TWO, AND THE THIRD IS THE READER'S OWN. This + said "the one other place a copy exists" and named only my mailbox — + while the handler puts the whole submission into the confirmation it + sends the inquirer, under "What you sent:" (the second + `SendEmailCommand` in `backend/intake/handler.mjs`). So a copy sits + with the reader's provider, which §Where it is stored already tells + them. An absolute enumeration standing one section from the page's + own counter-example is what Q62 was; this is the same shape and it + was introduced by Q62's own fix. Found by `claims-auditor`. */ + } +

+ There are therefore three copies of what you send. The record in the + table, which the two people above can read. The notification in my own + mailbox, which is on Google Workspace — so Google holds a copy of + whatever you sent me, and so does anyone who can reach that mailbox. + And the confirmation that went to you, which sits with whoever runs + your email; that copy is in your hands rather than mine.

Cookies and analytics

diff --git a/src/pages/med-arb.astro b/src/pages/med-arb.astro index f1cee22..72c0090 100644 --- a/src/pages/med-arb.astro +++ b/src/pages/med-arb.astro @@ -25,7 +25,7 @@ import Undertaking from '../components/Undertaking.astro'; import { getImage } from 'astro:assets'; import ogDefault from '../assets/og-portrait.jpg'; import { medArbGraph } from '../data/schema'; -import { CONDUCT_UNDERTAKINGS, DESIGNATIONS_HELD_LINE } from '../data/site'; +import { CONDUCT_UNDERTAKINGS } from '../data/site'; const ldImage = await getImage({ src: ogDefault, @@ -61,7 +61,7 @@ const graph = medArbGraph({ {/* ---- 1. Hero -------------------------------------------------------- */} @@ -238,38 +238,32 @@ const graph = medArbGraph({ {/* ---- 6. Why this practice -------------------------------------------- */} { - /* ⚠️ THIS SECTION MUST NOT ANSWER THE ADRIC COMPETENCE QUOTATION ABOVE IT. - For one pass it did: the heading read "Med-arb asks one neutral to be - competent at both" — a restatement, in this site's voice, of ADRIC's - "requires a high level of practitioner competence" quoted in the section - immediately above — and the designations then answered it by adjacency. - **The source answers its own sentence with a DIFFERENT designation**: the - same ADRIC page points at the Chartered Med-Arb and a Med-Arb Foundational - Course, and `docs/reference/adrio-designations.md` Finding 3 calls the - Q-level designations "an intermediate step". So the page was borrowing a - third party's competence standard and supplying an answer that party does - not give. `claims-auditor`, round-2 audit, 2026-08-30 — the gloss lens. - - The heading and lede now state what this practice holds and offers, with - no competence proposition and no bridge to the quotation above. */ + /* ⚠️ THIS SECTION MAKES NO CLAIM ABOUT COMPETENCE AND NO CLAIM ABOUT WHAT + MED-ARB IS, AND BOTH SILENCES ARE DELIBERATE. §Rules above quotes ADRIC + requiring "a high level of practitioner competence", and ADRIC answers its + own sentence with the Chartered Med-Arb and a Foundational Course — + neither held, and C.Med-Arb is struck from this site entirely (§4). So + anything in here that reads as meeting that standard is borrowing a third + party's bar and answering it in this site's voice. That has now been + removed three times: from the heading (2026-08-30), from the definitional + gloss (Pouya's ruling, 2026-09-01) and from the bare designations line + that was left sitting directly beneath the quotation (2026-09-02). + **Do not refill this paragraph, and do not restate a designation here** — + /about/ publishes them, and the JSON-LD carries them. */ }
- Both halves, in one practice. + Both processes, in one practice.

- {DESIGNATIONS_HELD_LINE}. Med-arb is not a third service bolted onto - mediation and arbitration; it is the two of them run under one - agreement, in the order the agreement sets. -

-

- I accept med-arb appointments now, in commercial matters. The section - above is the part to read before proposing one: the agreement does the - work, and it does it before the mediation starts. + I accept med-arb appointments now, in commercial matters. The three + commitments above are the part to read before proposing one: the + med-arb agreement does the work, and it does it before the mediation + starts.

Mediation →