v30: HireAmino plan of record v30

Lets Codex build three new items: 30, the console findings screens (spec and frozen review set are ready); 31, the import, claim, check, stop-watching and baseline screens; 32, branded console emails. Approving does not allow any merge, deploy or production change; each still needs your exact line. It also records that a passkey-signed approval like this one counts (WHI-327).

Decisions on v30

Exactly what you're approving

The plan text below, SHA-256 6f3577ede67c19d052789f22283dcf8b96a4a3d3b0aac24aa506f73e4b305cb8. Codex builds from this text, not from later edits.

# HireAmino plan of record (v30)

**In force once Abhi approves v30**: by his passkey-signed approval of this exact text at [approve.hireamino.com](<http://approve.hireamino.com>) ([WHI-327](<https://linear.app/whiteboardvc/issue/WHI-327>)), or by typing "Proceed per HireAmino plan of record v30." in the replacement Codex chat. Until he does, v29 stays the authorized version, and it has no Codex work left: 27c and its correction are live and verified (10-29). **Correction (2026-10-29):** Abhi answered "Sent it" in the PM chat, but Codex then reported that the replacement Codex chat has received only v29's approval. **v30 is authorized only by Abhi's own approval:** his passkey-signed approval of this text, which Codex verifies itself under the standing rule Abhi gives in its chat, or his typed line there. v1 was approved by Abhi on 2026-10-16 ("approved - publish the plan and start the reviews"). v2 ("yes, make the v2 change"), v3 (sent to Codex) and v4 ("yes, add [WHI-273](<https://linear.app/whiteboardvc/issue/WHI-273/single-source-or-drift-gate-the-duplicated-audit-faq>) to the plan as v4"), v5 ("yes, add node24 to v1.9.0 as plan v5"), v6 ("yes, add [WHI-246](<https://linear.app/whiteboardvc/issue/WHI-246/published-skill-batch-scorepy-emits-one-unlabelled-cross-lane-gap>) as v6"), v7 ("yes, v7"), v8 ("yes, v8"), v9 ("yes, v9"), v10 ("yes, v10"), v11 ("yes v11") v12 ("yes v12") v13 ("Approve v13 part a but not part b") v14 ("yes v14") v15 ("Yes v15") v16 ("yes v16") v17 ("yes v17") v18 ("Yes", 2026-10-22) and v19 ("Ship PR 33 as is and do the three fixes in a follow-up PR.", 2026-10-22) are Abhi's. v20 (sent to Codex 2026-10-23) is Abhi's. v21 to v27 (sent to Codex 2026-10-23/24) are Abhi's; v24's D1–D3 were decided by Abhi: "Start with Your domains. Take your recommendations on D1–D3 (no verdict in the list for now; re-entering sends a fresh dashboard link; leave the 2 duplicates). Add it to the plan for Codex." v26 (2026-10-24; Abhi's decision, relayed verbatim by the HireAmino Linear Product session: "Queue [WHI-311](<https://linear.app/whiteboardvc/issue/WHI-311/our-pinned-public-suffix-list-is-three-weeks-stale-and-the-weekly>) (refresh the public-suffix list and make its weekly alarm reach someone) right after #24, then scope engine 1.11.0.") was sent 10-24. v27 (2026-10-24) adds the engine 1.11.0 train that v26 told the Product Lead to scope; Abhi sent it on 10-24 ("Sent Codex: Proceed per HireAmino plan of record v27"). v28 (2026-10-24) queues the console finding lifecycle behind 1.11.0, plus a test-only console fix that can start now, and was sent by Abhi on 2026-10-25 ("Sent Codex: Proceed per HireAmino plan of record v28"). v29 (2026-10-25) adds #29 from Abhi's [WHI-9](<https://linear.app/whiteboardvc/issue/WHI-9/close-remaining-customer-trust-security-and-configuration-debt>) decision ("[WHI-9](<https://linear.app/whiteboardvc/issue/WHI-9/close-remaining-customer-trust-security-and-configuration-debt>): Option B (work on 2 and 3 now, 6 can remain to be part of Part B)"), moves Part B's 27a migration to `0006`, and records his [WHI-44](<https://linear.app/whiteboardvc/issue/WHI-44/hold-every-engine-consumer-to-the-conformance-gate-before-it-is>) decision ("[WHI-44](<https://linear.app/whiteboardvc/issue/WHI-44/hold-every-engine-consumer-to-the-conformance-gate-before-it-is>): Option A"). Abhi sent v29 on 2026-10-25 ("Sent Codex: Proceed per HireAmino plan of record v29"). Under the 10-28 control plane, an approval counts only when Abhi gives it directly in the replacement Codex chat; he approved v29's 27c there (Codex's evidence on [WHI-15](<https://linear.app/whiteboardvc/issue/WHI-15/add-bounded-idempotent-re-checks>), comment `b861e43a`). v30 (2026-10-29) queues the console screens and branded console emails. Abhi chose to start it without his [WHI-294](<https://linear.app/whiteboardvc/issue/WHI-294/console-screens-for-the-claimed-domain-loop-import-claim-baseline-and>) page ideas ("Go ahead without", 10-29); they can join #31. State read at 2026-10-29T21:30Z. Every change bumps the version and adds a changelog line. Comments point here.

## How authority works under this plan

1. **Abhi authorizes by version**, in his live message: *"Proceed per HireAmino plan of record vN."* Since 10-28 it counts only when he says it directly in the replacement Codex execution chat. A relay, a Linear comment or an issue status is evidence, not authority. **From 2026-10-29 ([WHI-327](<https://linear.app/whiteboardvc/issue/WHI-327>)):** a passkey-signed approval of version vN at [approve.hireamino.com](<http://approve.hireamino.com>) also counts, once Abhi has told Codex in that chat to accept it. Codex verifies the signature itself (`verify-approval.mjs`, against Abhi's pinned key) and builds from the signed snapshot of this document, not from later edits. It covers plan versions only.
2. **That authorizes Codex to:**
   * build the items in the Codex queue under the start rule below;
   * **revise any Product Lead HOLD on the same branch**, within those items and their stated scope.
3. **It never authorizes:** merges, deploys, workflow dispatches, releases or tags, production reads or writes, settings or credential changes, or any work not listed here. Each of those still needs Abhi's exact live line. **"Deploys" means production (v9).** Some repos deploy an isolated staging copy automatically when a non-`main` branch is pushed: amino-monitor's `staging.yml`, whose guard proves there are no production routes, cron, queues, D1 or R2. Those pushes are CI and need no separate line.
4. **Codex cites the version** in every PR note. If this document's current version differs from the authorized one, Codex starts nothing new and asks.
5. **The Product Lead** (Claude) keeps this document current, and bumps the version for any change in order, scope or sequencing. A version bump needs Abhi's renewed "proceed" before Codex acts on the change. State-only refreshes don't bump the version.

## Start rule

**The numbers are priority, not a strict line.** An item may start as soon as **its own prerequisites** are met, even if a lower-numbered item is blocked on something unrelated. When several items are startable, take the **lowest number** first. **"Merged"** means merged on GitHub. **"Verified live"** means the Product Lead has posted the landed check. The repo rules below still apply.

## Codex queue

| \# | Item | Repo | Prerequisites | State at v18 |
| -- | -- | -- | -- | -- |
| 1 | [WHI-251](<https://linear.app/whiteboardvc/issue/WHI-251/a-dmarc-record-above-the-registrable-root-is-invisible-to-the-audit>) Step 2: skills (B1–B3) | amino-skills #27 | none | **merged** `ccfdddf3` |
| 2 | [WHI-266](<https://linear.app/whiteboardvc/issue/WHI-266/every-engine-identity-gate-carries-a-hand-edited-literal-derive-them>) Phase B: Action identity gates | amino-audit-action #14 | none | **merged** `1ec9efce` |
| 3 | [WHI-266](<https://linear.app/whiteboardvc/issue/WHI-266/every-engine-identity-gate-carries-a-hand-edited-literal-derive-them>) Phase C: site identity gates | amino-site [Derive website engine identity from pinned source (WHI-266 Phase C)](<https://linear.app/whiteboardvc/review/derive-website-engine-identity-from-pinned-source-whi-266-phase-c-010a8c860583>) | none | **merged** `1094a931`, **verified live** |
| 4 | [WHI-190](<https://linear.app/whiteboardvc/issue/WHI-190/the-audit-page-reports-a-failed-dns-lookup-as-a-missing-record-the>): /audit inconclusive notice **plus the existence pre-check (v3)** | amino-site [Surface inconclusive audit results without reclassifying findings (WHI-190)](<https://linear.app/whiteboardvc/review/surface-inconclusive-audit-results-without-reclassifying-findings-whi-d205f0eb1822>) | #3 verified live (**met**) | **merged** `a0acd92a`, **verified live** (A/B/C pass). See [WHI-190](<https://linear.app/whiteboardvc/issue/WHI-190/the-audit-page-reports-a-failed-dns-lookup-as-a-missing-record-the>). |
| 4b | [WHI-273](<https://linear.app/whiteboardvc/issue/WHI-273/single-source-or-drift-gate-the-duplicated-audit-faq>) **(A): canonical /audit FAQ artifact in skills** (new in v4) | amino-skills | none | **merged** `eb43da04` (skills PR 28). Scope on [WHI-273](<https://linear.app/whiteboardvc/issue/WHI-273/single-source-or-drift-gate-the-duplicated-audit-faq>). |
| 5 | [WHI-251](<https://linear.app/whiteboardvc/issue/WHI-251/a-dmarc-record-above-the-registrable-root-is-invisible-to-the-audit>) Step 2: engine 1.7.0 | amino-audit-engine | #1 merged (**met**) **and #4b merged**; branch from engine `main` `1ccfe113`; **pin skills at #4b's merge SHA** | **merged** `903dbd7f` (engine PR 12). Gate: 10/10 on the engine harness, 0 parity disagreements; control 1.6.0 scored 2/10. |
| 6 | [WHI-251](<https://linear.app/whiteboardvc/issue/WHI-251/a-dmarc-record-above-the-registrable-root-is-invisible-to-the-audit>) Step 2 consumer repins = [WHI-266](<https://linear.app/whiteboardvc/issue/WHI-266/every-engine-identity-gate-carries-a-hand-edited-literal-derive-them>) **Phase D**: the site PR (with [WHI-273](<https://linear.app/whiteboardvc/issue/WHI-273/single-source-or-drift-gate-the-duplicated-audit-faq>) **(B)**) and the Action repin. **v7: the Action repin is the four identity paths only; Node 24 moves to #6b.** | site + Action | #5 merged (**met**); the site repin also needs #4 merged (**met**) | **site: merged** `3333ccd1` (site PR 35), **verified live**. **Action repin: merged** `d2334c31` (Action PR 15). Nothing is published until v1.9.0. |
| 6b | Action **Node 24** (moved out of #6 in v7): `action.yml` `using: "node20"` → `"node24"`, plus the narrowed host-surface gate (spec under Repo rules) | amino-audit-action | #6 Action repin merged (**met**) | **merged** `3ab9bc7c` (Action PR 16). **v1.9.0 is ready for Abhi to publish** (`hireamino-factory/action-v1.9.0-release.md`). |
| 7 | [WHI-240](<https://linear.app/whiteboardvc/issue/WHI-240/a-verified-claim-is-permanent-and-locks-that-domain-name-product-wide>) step 1: strict DNS proof | console, then monitor | none for the console refactor; the monitor half needs it merged | **Step 1 complete.** Console merged `3501d250`. Monitor merged `d39f3596` (PR 27), **deployed and checked live**. Step 3 (exclusivity removal plus stop-watching) is queue **#14**; no further decision is needed. |
| 8 | [WHI-254](<https://linear.app/whiteboardvc/issue/WHI-254/three-leftovers-after-the-psl-adoption-a-third-registrable-domain>): PSL leftovers | skills + engine | #4b merged (skills PRs touching shared files go one at a time); its engine half rides #5 only if ready before #6 starts | **skills half merged** `d7efb19e` (skills PR 29). The engine half is **#8b**. |
| 8a | [WHI-254](<https://linear.app/whiteboardvc/issue/WHI-254/three-leftovers-after-the-psl-adoption-a-third-registrable-domain>) **fixture correction (new in v9)**: mark the skill-only STARTTLS finding in `mx-provider-psl-distinct` and `mx-provider-psl-same` | amino-skills | #10 merged (**met**); one skills PR at a time | **merged** `9fec9215` (skills PR 31). Gate: engine 1.7.0 now fails only #8b's two defects, with 0 STARTTLS failures. |
| 8b | [WHI-254](<https://linear.app/whiteboardvc/issue/WHI-254/three-leftovers-after-the-psl-adoption-a-third-registrable-domain>) **engine half (new in v8)**: items 1, 2 and 4 in the engine, under the next contract version | amino-audit-engine | #8a merged (**met**); pin skills at `9fec9215aaea093faa762338e8f23206fb13a516` | **merged** `7a6eb179` (engine PR 13), contract **1.8.0**. Gate: corpus 72/0 on web and Action, differential 51,714/0, vectors 78/78. Spec under Repo rules. **Its site and Action repins are now #16 (v11), done once at 1.9.0.** Monitor/console adopting the engine's adapter text verbatim comes after that. |
| 9 | [WHI-245](<https://linear.app/whiteboardvc/issue/WHI-245/audit-the-headline-and-effortvalue-plan-blend-all-three-lanes>): /audit lanes | amino-site | #6's site repin merged (**met**) | **merged** `26a32c5f` (site PR 37), **verified live**; Done. |
| 10 | [WHI-246](<https://linear.app/whiteboardvc/issue/WHI-246/published-skill-batch-scorepy-emits-one-unlabelled-cross-lane-gap>): published skill batch output, **split by lane** (A), **failure is not absence** (B), and **D1**: a revoked or malformed DKIM key counts as 1 outbound gap (decided by Abhi 2026-10-16) **(new in v6)** | amino-skills | #8's skills PR merged (one skills PR at a time) | **merged** `75328d83` (skills PR 30); **Done**. Scope and D1 on [WHI-246](<https://linear.app/whiteboardvc/issue/WHI-246/published-skill-batch-scorepy-emits-one-unlabelled-cross-lane-gap>); expectations `whi-246-expectations.md` (K1–K11), probe `whi-246-probe.py`. Nothing deploys and no engine change. |
| 11 | [WHI-223](<https://linear.app/whiteboardvc/issue/WHI-223/dependency-batch-6-open-upgrade-prs-plus-the-fleet-wrangler-bump>) **part 1 (new in v8)**: the 9 GitHub-Actions Dependabot PRs in amino-monitor (15, 16, 18), amino-inbox (12, 15, 16) and amino-warmup (7, 9, 11) | monitor, inbox, warmup | none | **merged and deployed:** monitor `c37c024e` (PR 29), inbox `9b9199a1` (PR 17), warmup `284ef573` (PR 12). Each production deploy succeeded on wrangler-action v4.1.3; `/monitor`, `/headers` and `/warmup` all return 200. |
| 12 | [WHI-174](<https://linear.app/whiteboardvc/issue/WHI-174/merge-amino-site-pr-13-track-the-parked-blog-drafts-after-re-running>) **(new in v8)**: carry out Abhi's 2026-09-17 decision ("Option A — merge it") on amino-site PR 13 (`.gitignore` + `parked/` only) | amino-site | none: it doesn't overlap #9's files | **merged** `f4a6eba0` (site PR 13), **verified live** (all draft URLs 404); Done. |
| 13 | [WHI-287](<https://linear.app/whiteboardvc/issue/WHI-287/email-action-links-act-on-a-plain-get-a-mail-scanner-can-sign-in-prove>) **(new in v10)**: email action links act only on a click. A GET shows a confirmation page; a POST acts. Covers console sign-in and mailbox proof, and monitor unsubscribe and confirm. RFC 8058 one-click POST keeps working. | console first, then monitor | none | **Done.** Monitor `898127dd` live since 10-17; console half deployed 10-21 (Deploy run 39696209729, `504eb525`). A real sign-in link, confirmed by the click, on 10-22; [WHI-287](<https://linear.app/whiteboardvc/issue/WHI-287/email-action-links-act-on-a-plain-get-a-mail-scanner-can-sign-in-prove>) closed. |
| 14 | [WHI-240](<https://linear.app/whiteboardvc/issue/WHI-240/a-verified-claim-is-permanent-and-locks-that-domain-name-product-wide>) **step 3 (new in v10)**: remove console exclusivity (migration `0004` drops `uq_claims_verified_name`, adds a per-workspace verified index) and add `POST /api/claims/{id}/release` (owner-only, evidence kept) | console | #13's console PR merged (**met** 10-17, `2d253923`) | **merged** `42df28dd`, **deployed 10-21** (console `504eb525`; `0004` applied with 0 claims before). The anonymous release route answers 401 (it was 404). |
| 15 | [WHI-280](<https://linear.app/whiteboardvc/issue/WHI-280/engine-marks-which-findings-an-inconclusive-lookup-affects-whi-190>) **skills half (new in v11)**: per-finding `unconfirmed` marker, naming the failing lookup, in the Python skill plus corpus | amino-skills | none (skills train free) | **merged** `466eb8c1` (skills PR 32, 10-17). The HOLD (two failed lookups each mark their own dependents, 14 markers) is resolved, per the [WHI-280](<https://linear.app/whiteboardvc/issue/WHI-280/engine-marks-which-findings-an-inconclusive-lookup-affects-whi-190>) 10-17 review comment. Rule and expected-marking table in the [WHI-280](<https://linear.app/whiteboardvc/issue/WHI-280/engine-marks-which-findings-an-inconclusive-lookup-affects-whi-190>) 10-16 comment. The existing `inconclusive-*` rows gain markers; `preservation.py` records exactly those changes. |
| 15b | [WHI-280](<https://linear.app/whiteboardvc/issue/WHI-280/engine-marks-which-findings-an-inconclusive-lookup-affects-whi-190>) **engine half (new in v11)**: the same marker, contract **1.9.0** | amino-audit-engine | #15 merged (**met**); pin skills at `466eb8c16b61b66e4c5d3aef7243e197023cd10c` | **merged** `dacfde0f` (engine PR 14, 10-17), contract 1.9.0. Corpus 72/0 on web and Action, closing the 7 fixtures and 14 markers measured at #15's reviewed head. Corpus 0 failed on web and Action; the [WHI-254](<https://linear.app/whiteboardvc/issue/WHI-254/three-leftovers-after-the-psl-adoption-a-third-registrable-domain>) differential stays 0. |
| 16 | **Consumer repins to engine 1.9.0 (new in v11)**: site and Action, **once**, carrying 1.8.0 ([WHI-254](<https://linear.app/whiteboardvc/issue/WHI-254/three-leftovers-after-the-psl-adoption-a-third-registrable-domain>)) plus 1.9.0 ([WHI-280](<https://linear.app/whiteboardvc/issue/WHI-280/engine-marks-which-findings-an-inconclusive-lookup-affects-whi-190>)). Each consumer **displays** the marker and never re-derives it. **v12: also the Posture Audit Worker and the console's engine pin**, both still on 1.5.0 ([WHI-44](<https://linear.app/whiteboardvc/issue/WHI-44/hold-every-engine-consumer-to-the-conformance-gate-before-it-is>), 10-17). | site + Action + posture Worker + console | #15b merged; the Action half needs nothing more (v13); the console half needs #14 merged (one console PR at a time) | **Done.** Site `aea1e105` live 10-18. Engine service `10e0a8e3` deployed 10-21 (version `5a7d3b78`; pre- and post-checks ALL OK). Console `504eb525` deployed 10-21. **Action v1.9.0 published 10-21,** `@v1` **=** `5a73cfa4`**.** The S2 baseline (10-22) recorded engine `dacfde0f`, contract 1.9.0. [WHI-280](<https://linear.app/whiteboardvc/issue/WHI-280/engine-marks-which-findings-an-inconclusive-lookup-affects-whi-190>) and [WHI-251](<https://linear.app/whiteboardvc/issue/WHI-251/a-dmarc-record-above-the-registrable-root-is-invisible-to-the-audit>) closed. |
| 17 | [WHI-9](<https://linear.app/whiteboardvc/issue/WHI-9/close-remaining-customer-trust-security-and-configuration-debt>) **monitor hardening (new in v12)**: (A) tests and canaries for the RUA decompression ceiling and the row cap; (B) four baseline headers on every monitor HTML response (`X-Frame-Options: DENY`, `frame-ancestors 'none'`, `nosniff`, `Referrer-Policy: same-origin`), with no script or style policy | amino-monitor | none | **monitor PR 31 ready at** `6fd36e81` merged `f542c97b`, **deployed and verified live** (10-17: every monitor URL shows the four headers; the [WHI-287](<https://linear.app/whiteboardvc/issue/WHI-287/email-action-links-act-on-a-plain-get-a-mail-scanner-can-sign-in-prove>) checks are unchanged). Scope and named tests are in the [WHI-9](<https://linear.app/whiteboardvc/issue/WHI-9/close-remaining-customer-trust-security-and-configuration-debt>) 10-17 comment. One PR: one merge line, and one production deploy on merge. |
| 18 | [WHI-223](<https://linear.app/whiteboardvc/issue/WHI-223/dependency-batch-6-open-upgrade-prs-plus-the-fleet-wrangler-bump>) **part 2 (new in v14)**: the GitHub-Actions Dependabot bumps in amino-site (PRs 26, 29, 36) and amino-skills (PRs 19, 20, 33), as **one combined PR per repo** (the #11 pattern) | amino-site, amino-skills | site: no other site PR open; skills: one skills PR at a time | **Site: merged** `735abbd5` **(PR 40), deployed and verified live 10-19** (wrangler-action v4 proven on the site). Was: ready at `9a36f1a2` (deploys on merge). **Skills PR 34: Product Lead HOLD (10-19).** Add `.github/workflows/conformance.yml` to its own `paths:` filters so the new pins actually run; conformance never ran at `f1818fb0`. Details on [WHI-223](<https://linear.app/whiteboardvc/issue/WHI-223/dependency-batch-6-open-upgrade-prs-plus-the-fleet-wrangler-bump>). |
| 19 | [WHI-289](<https://linear.app/whiteboardvc/issue/WHI-289/console-ci-a-test-in-localmjs-fails-intermittently-and-the-gate-canary>) **(new in v14)**: the console gate canary prints its substrate's `FAIL` lines; then find and fix the intermittently failing `local.mjs` test | amino-console | one console PR at a time | **Merged** `504eb525` **(console PR 15, 10-19)**; [WHI-289](<https://linear.app/whiteboardvc/issue/WHI-289/console-ci-a-test-in-localmjs-fails-intermittently-and-the-gate-canary>) is in Backlog awaiting a named recurrence. Was: ready at `5d8ef1b1` (reviewed 10-19; no deploy). The flake didn't reproduce in 100 runs, so only the diagnostic ships, as the spec allows. |
| 20 | [WHI-240](<https://linear.app/whiteboardvc/issue/WHI-240/a-verified-claim-is-permanent-and-locks-that-domain-name-product-wide>) **step 4, stage 1 (new in v15)**: proof-only monitoring per watcher (Abhi 10-19, "A, 30 days"), built with `PROOF_ENFORCEMENT="off"` so behaviour is unchanged; migration `004` | amino-monitor | #17 merged (**met**); one monitor PR at a time | **Merged** `dcfeafea` **and deployed 10-22** (stage 1, enforcement off). `004` was applied first (13/12/11/0 exact). The deploy was dispatched with Abhi's OK after GitHub lost the push trigger. The new-watcher path is proven live on `yoloemails.app`. **Owed before stage 2:** the both-rows-entitled dedupe test, and no page may render an empty `_amino-verify` value for a token-less row. |
| 21 | **Engine contract 1.10.0 train (new in v16)**: [WHI-290](<https://linear.app/whiteboardvc/issue/WHI-290/failed-non-critical-lookups-caa-bimi-dnskey-dkim-still-read-as-absence>) (failed CAA, BIMI, DNSKEY, DKIM and `_smtp._tls` lookups get the `unconfirmed` marker) plus [WHI-293](<https://linear.app/whiteboardvc/issue/WHI-293/report-broken-dnssec-as-a-real-finding-today-a-bogus-zone-reads-as>) (broken DNSSEC reported as **"DNSSEC validation is failing"**, severity **critical**, Abhi 10-19). **v17 adds** [WHI-12](<https://linear.app/whiteboardvc/issue/WHI-12/implement-finding-lifecycle-with-an-exact-remedy>) **Part A:** a stable `rule_id` and `discriminator` on every finding, additive and with no display change | skills → engine → site, Action, posture Worker, console | 21a skills: one skills PR at a time. 21b engine: 21a merged; pin skills at its merge. 21c consumers: 21b merged; the console half needs no open console PR | **21a merged** as `553a47fa` (skills PR 35, 2026-10-22 20:06Z, on Abhi's line; parents and tree verified, push CI green). **21b merged** as `2ba2fa09` (engine PR 15, 2026-10-22 22:24Z, on Abhi's line; review PASS, parents and tree verified, push CI green). **21c merged** (2026-10-23), all after a Product Lead review PASS. Site PR 42 merged as `a324a919` and is live; the site half of #21d passes. Posture Worker PR 5 (`2997ee7a`) and console PR 16 (`2decce1c`) were merged and deployed together. Action PR 18 merged as `e1f373ba`, under the v21 six-file exception. Deploy and live records are on [WHI-290](<https://linear.app/whiteboardvc/issue/WHI-290/failed-non-critical-lookups-caa-bimi-dnskey-dkim-still-read-as-absence>). **The Action v1.10.0 release waits on #21e.** History: HOLD at `d85488da` (10-19) for the amended bogus-DNSSEC rule and the `mta_sts.not_applicable` rename, fixed at `bd04bd08`. Scopes: [WHI-290](<https://linear.app/whiteboardvc/issue/WHI-290/failed-non-critical-lookups-caa-bimi-dnskey-dkim-still-read-as-absence>), [WHI-293](<https://linear.app/whiteboardvc/issue/WHI-293/report-broken-dnssec-as-a-real-finding-today-a-bogus-zone-reads-as>) (10-19 plus its amendment), [WHI-12](<https://linear.app/whiteboardvc/issue/WHI-12/implement-finding-lifecycle-with-an-exact-remedy>) Part A. 21b/21c expectations amended 10-19 (consumer identity inventory). |
| 21e | **The Action's docs name** `dns.google` **(new in v23).** Engine 1.10.0's DNSSEC probe also queries Google Public DNS (`dns.google`), but only to confirm a DNSSEC validation failure. Two published sentences say the Action contacts only `cloudflare-dns.com`: the README's Privacy paragraph and SECURITY.md's "What this Action does" paragraph. **Docs only:** change exactly those two sentences to the wording quoted on [WHI-290](<https://linear.app/whiteboardvc/issue/WHI-290/failed-non-critical-lookups-caa-bimi-dnskey-dkim-still-read-as-absence>) (10-23, from `action-v1.10.0-release.md` §0), and nothing else (no `src/`, tests or identity paths). **Known-bad:** `git grep -n 'cloudflare-dns.com' -- README.md SECURITY.md` must show both lines also naming `dns.google`. | amino-audit-action | #21c Action merged (**met**, `e1f373ba`) | **merged** as `2984b47b` (Action PR 19, 2026-10-23, after a Product Lead review PASS). **v1.10.0 published** at that commit and `v1` moved; the smoke test on `--branch v1` passed and the Marketplace lists it. [WHI-290](<https://linear.app/whiteboardvc/issue/WHI-290/failed-non-critical-lookups-caa-bimi-dnskey-dkim-still-read-as-absence>) and [WHI-293](<https://linear.app/whiteboardvc/issue/WHI-293/report-broken-dnssec-as-a-real-finding-today-a-bogus-zone-reads-as>) **Done**; carve-out [WHI-312](<https://linear.app/whiteboardvc/issue/WHI-312/the-dnssec-validation-is-failing-findings-action-label-says-enable>). |
| 22 | [WHI-306](<https://linear.app/whiteboardvc/issue/WHI-306/monitor-dashboard-says-minor-gaps-nothing-is-broken-for-a-domain-with>) **interim (new in v18)**: the monitor's Posture card says "Minor gaps · Nothing is broken" for a domain with no SPF and no DMARC (live on `yoloemails.app`). Fix the verdict and name the weak checks; no monitor output asserts an all-clear. Spec under Repo rules. The structural fix is [WHI-81](<https://linear.app/whiteboardvc/issue/WHI-81/watchtower-consumes-the-posture-audit-worker-its-own-posture-code-is>), not this item. | amino-monitor | none (independent of #21; one monitor PR at a time) | **Merged** as `b6896dd3` (monitor PR 33, 2026-10-22 20:38Z, on Abhi's line; shipped as is, parents and tree verified). Its three gaps move to #22b. Deploy and live check: see [WHI-306](<https://linear.app/whiteboardvc/issue/WHI-306/monitor-dashboard-says-minor-gaps-nothing-is-broken-for-a-domain-with>). Expectations: `review-harnesses/whi-306-expectations.md`. Deploys on merge. |
| 22b | [WHI-308](<https://linear.app/whiteboardvc/issue/WHI-308/whi-306-follow-up-a-correct-dkim-rotation-reads-needs-work-and-some>) **(new in v19)**: the [WHI-306](<https://linear.app/whiteboardvc/issue/WHI-306/monitor-dashboard-says-minor-gaps-nothing-is-broken-for-a-domain-with>) follow-up. R1: DKIM gone or revoked counts only when no observed selector is usable (engine 1.9.0's sibling rule, and what `gapScore()` counts). R2: on a non-Clean card, the parked note never calls the posture good. R3: no all-clear phrasing in any alert email, on the alerts page or on the card, tested as a class. Spec under Repo rules and on [WHI-308](<https://linear.app/whiteboardvc/issue/WHI-308/whi-306-follow-up-a-correct-dkim-rotation-reads-needs-work-and-some>). | amino-monitor | #22 merged (**met**); branch from `b6896dd37eda239006d7819d187b0ac66630ca31` (one monitor PR at a time) | **Merged** as `4c2e3a87` (monitor PR 34, 2026-10-23 02:21Z, after a Product Lead review PASS; it deployed on merge). Expectations: `review-harnesses/whi-306-followup-expectations.md`. Deploys on merge. |
| 23 | [WHI-309](<https://linear.app/whiteboardvc/issue/WHI-309/a-watch-only-monitor-customer-cant-get-back-to-their-dashboard-after-7>) **(new in v24)**: re-entering a domain and email you already watch emails a fresh dashboard link for that subscription (or re-sends a pending confirmation) and never adds a row. The response page is the same either way. Spec: the Linear document "Spec: Your domains phase 1 (plan v24 #23 / #23b / #23c)" on [WHI-294](<https://linear.app/whiteboardvc/issue/WHI-294/console-screens-for-the-claimed-domain-loop-import-claim-baseline-and>), section #23. | amino-monitor | none; branch from `4c2e3a87eae0ea2499d79befb0d40949fd3851af` | **merged** as `0574f529` (monitor PR 35) and deployed; verified live by Abhi; [WHI-309](<https://linear.app/whiteboardvc/issue/WHI-309/a-watch-only-monitor-customer-cant-get-back-to-their-dashboard-after-7>) **Done**. |
| 23b | [WHI-294](<https://linear.app/whiteboardvc/issue/WHI-294/console-screens-for-the-claimed-domain-loop-import-claim-baseline-and>) **phase 1 (new in v24)**: the console's `/` becomes a read-only "Your domains" page: the workspace's assets plus the proven mailbox's active subscriptions, each monitored row with an "Email me my dashboard link" form that posts to #23. No posture verdict (D1). Spec: the same document, section #23b. | amino-console | #23 merged **and deployed**; branch from `2decce1c0d039e3f98f14ab5dabccb804b8dbb59` | **merged** as `0d2c21ba` (console PR 17) and deployed by dispatch (version `f4ab0686`); Abhi's signed-in look pending. |
| 23c | [WHI-310](<https://linear.app/whiteboardvc/issue/WHI-310/monitors-fortune-50-card-hides-the-checks-a-domain-fails-if-every>) **(new in v24)**: the Fortune 50 card shows "Publishes DMARC · Behind" for a domain with no DMARC, from a new `dmarcPublished` count in `benchmark.json`. Site half (scan and schema) first, then the monitor card. SPF is deferred. Spec: the same document, section #23c. | amino-site, then amino-monitor | site half: none (branch from `a324a919191277a55394a2c25e6bc3ade080cb98`); monitor half: #23 merged (one monitor PR at a time) | **merged and live**: site PR 43 as `45bc0e58` (benchmark.json `dmarcPublished` 50); monitor PR 36 as `a6411e09`. Abhi's dashboard look pending. |
| 24 | [WHI-307](<https://linear.app/whiteboardvc/issue/WHI-307/monitor-tells-a-domain-with-spf-all-that-it-authorizes-no-senders-at>) **(new in v25)**: the monitor's `sendingPosture()` honours the `all` qualifier and term order (RFC 7208). Only a hard `-all` with no real sender before it supports "doesn't send mail"; `+all` and bare `all` mean sending is allowed; `~all`, `?all` and implicit `?all` stay unknown; terms after `all`, and `redirect=` when `all` exists, are ignored. Spec: Codex's 17-row matrix and rendered expected answers on [WHI-307](<https://linear.app/whiteboardvc/issue/WHI-307/monitor-tells-a-domain-with-spf-all-that-it-authorizes-no-senders-at>) (10-23), accepted by the Product Lead. Files: `src/engine.js`, `test/sending-posture.mjs`, `test/sending-posture-canary.mjs`, `test/local.mjs`, `package.json`; no `src/index.js` behaviour change (STOP if one is needed). | amino-monitor | none; branch from `a6411e097e083b368c90ce98a665d1aab2c787e4` | **merged** as `510230e7` (monitor PR 37, 10-24, after a Product Lead re-review PASS) and deployed (version `9bae58af`). [WHI-307](<https://linear.app/whiteboardvc/issue/WHI-307/monitor-tells-a-domain-with-spf-all-that-it-authorizes-no-senders-at>) **Done**. |
| 25 | [WHI-311](<https://linear.app/whiteboardvc/issue/WHI-311/our-pinned-public-suffix-list-is-three-weeks-stale-and-the-weekly>) **(new in v26)**: refresh the pinned Public Suffix List in skills and make its weekly alarm reach someone. **Skills only in this item** ([WHI-311](<https://linear.app/whiteboardvc/issue/WHI-311/our-pinned-public-suffix-list-is-three-weeks-stale-and-the-weekly>) Part A1 plus Part B). The engine, monitor and console adopt the refreshed bytes inside the 1.11.0 train (Parts A2–A4), so consumers move once ([WHI-215](<https://linear.app/whiteboardvc/issue/WHI-215/one-pinned-public-suffix-artifact-retire-the-three-hand-written>)). **A1:** run `generate.py --source-file` on one reviewed upstream snapshot, recorded by VERSION, COMMIT and source SHA-256. Change exactly `public-suffix/public_suffix_rules.tsv`, `public-suffix/provenance.json` and the skill copy `amino-deliverability-audit/skills/amino-deliverability-audit/scripts/public_suffix_rules.tsv`; grep every file carrying the old hash first, and give a reason for any other file. **Part B:** red only on an ICANN-section change or a pin older than 45 days. Other drift is a green run with the full report in the step summary, and a network or parse failure stays exit 2. A red run opens or updates one GitHub issue (the workflow gains `issues: write`). **Known-bad:** K1, K2 and K5 on [WHI-311](<https://linear.app/whiteboardvc/issue/WHI-311/our-pinned-public-suffix-list-is-three-weeks-stale-and-the-weekly>). Review against the pinned snapshot, never live upstream. | amino-skills | after #24 (Abhi's order); branch from skills `main` `553a47fa2bf368cf08b14c39e393f2d243c476b0`; one skills PR at a time | **merged** as `5f8d2f6d` (skills PR 36, 10-24, after a Product Lead review PASS). [WHI-311](<https://linear.app/whiteboardvc/issue/WHI-311/our-pinned-public-suffix-list-is-three-weeks-stale-and-the-weekly>)'s A2–A4 move with #26. **A2–A4 landed with #26 (10-28). The Product Lead's close check passed 10-29** ([WHI-311](<https://linear.app/whiteboardvc/issue/WHI-311/our-pinned-public-suffix-list-is-three-weeks-stale-and-the-weekly>) comment `e725f2e0`; known-bad checks K3 and K4 go red). [WHI-311](<https://linear.app/whiteboardvc/issue/WHI-311/our-pinned-public-suffix-list-is-three-weeks-stale-and-the-weekly>) waits only on Abhi marking it Done. |
| 26 | **Engine contract 1.11.0 train (new in v27):** `rule_evaluation` ([WHI-12](<https://linear.app/whiteboardvc/issue/WHI-12/implement-finding-lifecycle-with-an-exact-remedy>) Part B's prerequisite), plus [WHI-312](<https://linear.app/whiteboardvc/issue/WHI-312/the-dnssec-validation-is-failing-findings-action-label-says-enable>) (the critical DNSSEC row's label becomes "Fix DNSSEC signing"), [WHI-311](<https://linear.app/whiteboardvc/issue/WHI-311/our-pinned-public-suffix-list-is-three-weeks-stale-and-the-weekly>) A2–A4 (the refreshed list reaches the engine, monitor and console), and [WHI-254](<https://linear.app/whiteboardvc/issue/WHI-254/three-leftovers-after-the-psl-adoption-a-third-registrable-domain>)'s leftover (monitor CI runs the 78 official list vectors). Spec: the Linear document "Spec: engine contract 1.11.0 (plan v27 #26)" on [WHI-12](<https://linear.app/whiteboardvc/issue/WHI-12/implement-finding-lifecycle-with-an-exact-remedy>), which sets the contract, the files each step may change, and the known-bad checks. | skills → engine → site, Action, posture Worker, console, monitor | **26a skills:** #25 merged; one skills PR at a time. **26b engine:** 26a merged; pin skills at its merge. **26c consumers:** 26b merged; the Worker and console go live together. **26d live:** Product Lead. | **26a startable** (#25 merged; skills `main` `5f8d2f6d`); v27 sent 10-24. Console Part B is #27. **26a merged** as `8c777970` (skills PR 37, 2026-10-27, on Abhi's line; parents and tree verified, push CI green). **26b is startable:** branch from engine `main` `2ba2fa09`, and pin skills at `8c777970f22eeb0588fdaed5c7154f057a9b3ccf`. The 26b review kit is frozen, and its hashes are on the 1.11.0 issue. **26b in review:** engine PR 16 at `9a70373e` got a Product Lead HOLD on 10-28 (one rule-input fix: the two non-pass TLS-RPT rules need apex MX as an input). Everything else passed. **READY on 10-28 at** `24450892` (HOLD cleared: 80 cases with 0 HOLD; 15 of 15 planted defects red). **26b merged** as `2db97bdb` (engine PR 16, 2026-10-28, on Abhi's line; parents and tree verified, push CI green, no deploy). **26c is startable** from engine `main` `2db97bdbd34b95dcd733042bc99aaeef93b5fea0`. **26c reviewed 10-28:** Action PR 20, monitor PR 38, Worker PR 6 and console PR 20 are READY, with merge lines with Abhi. Site PR 44 is on HOLD, tests only: the site wrapper's metadata and probe pass-through has no failing test. The Worker and console go live together. **Merged 10-28 on Abhi's lines:** Action `26c53b88`, console `81787850`, Worker `37ffdbc1` (none of the three deployed) and monitor `b8dfd642` (deployed and live as version `c71ef59a`). **The Worker and console pair is live and proven on 10-28:** Worker `c7316431` (redeployed into `0e338…`; the first deploy had landed in the old account), console `84ce310b`, and a fresh baseline storing 1.11.0 with all 56 `rule_evaluation` keys. **Action v1.11.0 published 10-28** (`v1` → `26c53b88`; Marketplace current). **Site PR 44 merged and live 10-28** as `3e47d065` (deployed; the apex serves it). **Worker PR 7 merged** as `aef6b5d8` (no deploy). **26d passed 10-28:** the site and the Action show "Fix DNSSEC signing", and [hireamino.com](<http://hireamino.com>) is 56/56 conclusive with an unchanged display. **Row 26 is done.** |
| 27 | **Console finding lifecycle (new in v28):** [WHI-12](<https://linear.app/whiteboardvc/issue/WHI-12/implement-finding-lifecycle-with-an-exact-remedy>) Part B, with [WHI-16](<https://linear.app/whiteboardvc/issue/WHI-16/verify-resolution-and-preserve-the-evidence-trail>) and [WHI-15](<https://linear.app/whiteboardvc/issue/WHI-15/add-bounded-idempotent-re-checks>). Spec: the Linear document "Spec: [WHI-12](<https://linear.app/whiteboardvc/issue/WHI-12/implement-finding-lifecycle-with-an-exact-remedy>) Part B, the console finding lifecycle (27a/27b/27c)" on [WHI-12](<https://linear.app/whiteboardvc/issue/WHI-12/implement-finding-lifecycle-with-an-exact-remedy>). It sets the rules, the API, the expected answers, the files each PR may change and the known-bad checks, and it replaces the 10-19 Part B comment and the 10-23 amendment. **27a** console: findings, projection and user transitions, with migration `0006` (v29: #29 takes `0005`). **27b** monitor: the re-check allowances added to `ENTITLEMENTS`; no behaviour change. **27c** console: re-check and limits, using a byte-identical copy of the monitor's `src/entitlements.js`. | amino-console, amino-monitor | **27a:** starts when #26c's console PR has merged **and #29 has merged** (v29); merges after #26d. **27b:** after #26c's monitor PR merges. **27c:** after 27a and 27b merge. One console PR at a time. | The console deploys by dispatch only, and 27a's dispatch applies `0006`. **27b merged 10-28** as `79ce22ec` (monitor PR 39; deployed, version `d76f49fa`, pages unchanged). **27a** (console PR 21 at `f8f9ecc6`): review passed 10-28. Its production measurement passed 10-28 (4 observations; only the 1.11.0 one can open findings). **27a merged 10-28** as `edccd27d` (parents and tree verified, push CI green). **27a is live 10-28:** console deploy run 40778839394 at `edccd27d` applied `0006` (ledger row 6) and deployed Worker `fa8e8d7b`. The live check passed: [yoloemails.app](<http://yoloemails.app>) has 9 `open` findings, each with its fix; [hireamino.com](<http://hireamino.com>) (1.9.0 only) has 0; 4 projection markers; 0 `rechecking`. The issue tracking verified resolution moves to In Progress and closes after 27c's live re-check, not with 27a. **27c's withheld set was frozen 10-28** (probe SHA-256 `042b575e…`, rule map `82b8bd9f…`). The reference passes 6/6 published and 29/29 withheld, and still passes the 27a probe. Console `main` `edccd27d` and the 27a reference both fail 0/6 and 0/29. All 35 planted defects go red. The spec's eight open 27c readings were settled 10-28 in its new "27c clarifications" paragraph; the per-root cap stays hard, as D7 ratified. **27c was approved by Abhi in the replacement Codex chat** (Codex's evidence on [WHI-15](<https://linear.app/whiteboardvc/issue/WHI-15/add-bounded-idempotent-re-checks>), `b861e43a`). **27c merged 10-29** as `ddff0960` (console PR 22, READY at `c391416c`) and was deployed (run 40940952432, Worker `a42c8011`). Its live check failed one step: D1 rejects `LIKE` patterns over 50 bytes, and the test shim didn't enforce that. It failed closed. **The correction, console PR 23, merged 10-29** as `17d48c20` (READY at `5c3b8186`; the shim now enforces D1's limit, and the old limiter goes red under it). **It is live 10-29:** run 40955990488, Worker `fb07c879`, no migration. **The live re-check passed** ([WHI-15](<https://linear.app/whiteboardvc/issue/WHI-15/add-bounded-idempotent-re-checks>) comment `8e5b7055`): replay, the per-finding floor (429 with the next time), a baseline admitted 6 s after a re-check, and the separate baseline floor. **Row 27 is done.** [WHI-15](<https://linear.app/whiteboardvc/issue/WHI-15/add-bounded-idempotent-re-checks>) stays open only for its UI criterion (#30). [WHI-16](<https://linear.app/whiteboardvc/issue/WHI-16/verify-resolution-and-preserve-the-evidence-trail>) closes after a live re-check returns `resolved`. The Product Lead's frozen 27a and 27c probe hashes are on [WHI-12](<https://linear.app/whiteboardvc/issue/WHI-12/implement-finding-lifecycle-with-an-exact-remedy>). |
| 28 | **Console test clock race (new in v28):** [WHI-289](<https://linear.app/whiteboardvc/issue/WHI-289/console-ci-a-test-in-localmjs-fails-intermittently-and-the-gate-canary>)'s test-only fix. (1) T22 reads the clock before and after the claim request. (2) The 8 fixed-window bursts (T25: 2; T21: 6) run with `Date.now` pinned, restored in `finally`. Scope, expected answers and known-bad checks: the Product Lead's 10-24 comment on [WHI-289](<https://linear.app/whiteboardvc/issue/WHI-289/console-ci-a-test-in-localmjs-fails-intermittently-and-the-gate-canary>). `test/local.mjs` **only.** | amino-console | **startable now**, from console `main` `0d2c21ba54dd9a441af523f5ccad9cfc5de69f6b`. Finish it before #26c's console PR opens (one console PR at a time). | **merged** `73430e3c` (console PR 18, 2026-10-26, on Abhi's line; push CI green; deploys nothing). Closed. |
| 29 | **One mailbox, one account, and a session workspace selector (new in v29):** [WHI-9](<https://linear.app/whiteboardvc/issue/WHI-9/close-remaining-customer-trust-security-and-configuration-debt>) register rows 2 and 3, from Abhi's decision on 2026-10-25. Row 2 is [WHI-318](<https://linear.app/whiteboardvc/issue/WHI-318/console-an-email-address-leads-to-at-most-one-account-so-break-glass>): an email address leads to at most one console account, enforced by a database `UNIQUE` index on a new `users.signin_email` that only a proven sign-in sets; the break-glass link and `mailboxProven()` both read it. Row 3 is [WHI-303](<https://linear.app/whiteboardvc/issue/WHI-303/233b-a-session-workspace-selector-whi-9-register-row-3-building-now-as>): the active workspace is held on the session, with a chooser and `POST /workspaces/select`. Spec: the Linear document "Spec: one mailbox, one account, and a session workspace selector (plan v29 #29)" on [WHI-9](<https://linear.app/whiteboardvc/issue/WHI-9/close-remaining-customer-trust-security-and-configuration-debt>). It sets the rules, the expected answers (S1–S11, R1–R9), the files the PR may change, the existing tests that change and why (T9, T10, T24, T29), and the known-bad checks. **One console PR, migration** `0005`**.** | amino-console | after #28 merges (**met 10-26**): branch from `73430e3c86e7d6300769d200bba76dcb6edfb82d`. One console PR at a time: if #26c's console PR becomes startable first, it goes first and #29 rebases. | merging deploys nothing; the console dispatch applies `0005`. Before the merge line, the `duplicate-signin-email-pregate` result is posted (expected 0; 0 measured 10-25). **2026-10-27: console PR 19 READY at** `2b25ddc5` (the tests-only HOLD at `1f877670` is cleared): frozen probe 20/20 published and 24/24 withheld, all 23 planted defects caught. The pre-gate was measured at **0** on 10-27 with controls. **Merged** as `5c1c41c1` (2026-10-27, on Abhi's line; parents and tree verified, push CI green). **Deployed and verified live on 10-27:** dispatch run 40437475003 applied `0005`, version `b17da7a2`. Both issues are closed; [WHI-9](<https://linear.app/whiteboardvc/issue/WHI-9/close-remaining-customer-trust-security-and-configuration-debt>) is closed too (10-27): the final register is amino-security issue 11, and Abhi accepted row 7, the amino-inbox unsubscribe key. The Product Lead's frozen probe hash is on [WHI-9](<https://linear.app/whiteboardvc/issue/WHI-9/close-remaining-customer-trust-security-and-configuration-debt>). |
| 30 | **Findings screens (new in v30):** [WHI-294](<https://linear.app/whiteboardvc/issue/WHI-294/console-screens-for-the-claimed-domain-loop-import-claim-baseline-and>) phase 2a. A per-domain findings page: counts, and one card per finding with its severity (a stored finding has no impact field, so "impact" is the severity, shown as given), evidence and **exact remedy on every plan**, its lifecycle state, "needs a re-check" with its reason, and why there's no baseline when there isn't one. Finding detail: the event trail and the before and after observation links ([WHI-16](<https://linear.app/whiteboardvc/issue/WHI-16/verify-resolution-and-preserve-the-evidence-trail>)'s evidence trail). The declared transitions (accept and dismiss need a note). The re-check button: remaining today, the next available time, the result and its reason, and each refusal in plain words. **Server-rendered under the current CSP** (`default-src 'none'`, no client script): form-encoded page routes call the **same** internals as the JSON API (`transitionFinding`, the re-check path), with no second handler. The precedent is the workspace-select form at `api.js:70`. Post, redirect, get; a server-generated `delivery_key` on the re-check form; owner-only writes; same-origin; light theme; display only. Each screen is exercised in a real browser before merge. Rules, expected answers and known-bad checks: the Product Lead's #30 spec, the Linear document "Spec: the findings screens (plan v30 item 30, <issue id="653e6709-c9c2-4e26-94df-45fa2f788b81" href="https://linear.app/whiteboardvc/issue/WHI-294/console-screens-for-the-claimed-domain-loop-import-claim-baseline-and">WHI-294</issue> phase 2a)", posted 10-29 on [WHI-294](<https://linear.app/whiteboardvc/issue/WHI-294/console-screens-for-the-claimed-domain-loop-import-claim-baseline-and>). | amino-console | #27 live (**met 10-29**). **Starts only when the Product Lead's #30 spec and its frozen held-out probe hashes are posted** (**both posted 10-29**: probe SHA-256 `901c45d9…`, comment `10fa9bc7`) on [WHI-294](<https://linear.app/whiteboardvc/issue/WHI-294/console-screens-for-the-claimed-domain-loop-import-claim-baseline-and>). Branch from console `main` `17d48c20a75578d0e8f38bbc2c6e2152d4adb637`. One console PR at a time. | new in v30. It closes [WHI-15](<https://linear.app/whiteboardvc/issue/WHI-15/add-bounded-idempotent-re-checks>)'s last criterion ("The UI explains when the next re-check is available"). |
| 31 | **Import, claim, check, stop-watching and baseline screens (new in v30):** [WHI-294](<https://linear.app/whiteboardvc/issue/WHI-294/console-screens-for-the-claimed-domain-loop-import-claim-baseline-and>) phase 2b, on APIs that are already live (`GET /api/import/candidates`, `POST /api/import`, `POST /api/claims/check`, `POST /api/claims/{id}/release`, `POST /api/roots/{id}/baseline`). The same rules as #30. It completes the flow that [WHI-17](<https://linear.app/whiteboardvc/issue/WHI-17/drive-the-claimed-domain-loop-in-a-real-browser>) (the real-browser loop) and [WHI-82](<https://linear.app/whiteboardvc/issue/WHI-82/s6-the-audit-save-this-and-keep-watching-handoff-survives-sign-in>) (the /audit handoff survives sign-in) need. | amino-console | #30 merged (one console PR at a time), and the Product Lead's #31 spec posted. | new in v30. |
| 32 | **Branded console emails (new in v30):** [WHI-305](<https://linear.app/whiteboardvc/issue/WHI-305/console-emails-are-bare-plain-text-monitor-emails-are-branded-one-look>). The monitor's email layout becomes the one canonical copy. The console vendors it with a drift guard and gains the monitor's wordmark gate. Both console emails (sign-in, and confirm your email) use it and keep a plain-text part, and the copy says what the click does and how long the link lasts. Done when a real Gmail inbox shows both, with no new spam-folder placement. | amino-monitor first (it can run beside #30), then amino-console (it queues behind any open console PR) | the Product Lead's #32 spec posted on [WHI-305](<https://linear.app/whiteboardvc/issue/WHI-305/console-emails-are-bare-plain-text-monitor-emails-are-branded-one-look>). | new in v30. |

**Repo rules:**

* **One open PR per repo where files overlap.** The site goes in a train (<pull-request id="1977ae79-d076-4e32-8ab9-b6662672c82a" href="https://linear.app/whiteboardvc/review/derive-website-engine-identity-from-pinned-source-whi-266-phase-c-010a8c860583">Derive website engine identity from pinned source (WHI-266 Phase C)</pull-request> → <pull-request id="5fbc6756-e363-4905-b3c7-89d0932a79a9" href="https://linear.app/whiteboardvc/review/surface-inconclusive-audit-results-without-reclassifying-findings-whi-d205f0eb1822">Surface inconclusive audit results without reclassifying findings (WHI-190)</pull-request> → the Step 2 repin → <issue id="aa9f6ea6-cc74-4520-8370-048d0351dc4c" href="https://linear.app/whiteboardvc/issue/WHI-245/audit-the-headline-and-effortvalue-plan-blend-all-three-lanes">WHI-245</issue>); each changes the render-equivalence hash. Skills PRs (#4b, #8, #8a, #10, #15) go one at a time.
* **The Phase D criterion:** a real behaviour-changing bump edits **zero identity-gate files**. The Action repin's diff is the four identity paths and nothing else (v7). **v13 exception, #16 only:** the reviewed display block plus its narrowed gate, as specified under Repo rules. **v20 exception, #21c Action repin only:** `test/conformance.mjs` may change in exactly two ways, and no other line, file or `src/` path may change. (a) The <issue id="23d82ae8-84e5-4a01-bad7-14b5af7f5185" href="https://linear.app/whiteboardvc/issue/WHI-280/engine-marks-which-findings-an-inconclusive-lookup-affects-whi-190">WHI-280</issue> display contract's inconclusive-fixture count goes from 7 to 8, still asserted exactly. (b) `fixtureQ` passes the fixture's `input.dnssecProbe` through as `q.dnssecProbe`, the way the canonical runner's `mockQ` does. **Known-bad:** undo either edit and its named check goes red. **v21 adds the third and last file:** `test/engine-suite-canary.mjs`, a retarget only. Its anchor and replacement move to engine 1.10.0's guarded block (`… && finding.unconfirmed === undefined) {` / `finding.unconfirmed = reason;`). The mutation (`reason` → `inconclusiveReason`) and the named diagnostic stay the same. **Proven complete (Product Lead trial, 10-23):** with exactly these six files on Action `main` `5a73cfa4`, every step of `npm test` passes, and so do both CI-only steps (`canary-fetch-pinned-skills.sh` 13/13, and the clean-clone Action run on [hireamino.com](<http://hireamino.com>) with engine SHA-256 `71b90919…`). Controls: the old canary fails on 1.10.0, and the retargeted canary with a no-op mutation fails. The site's diff is the four identity paths plus **reviewed, non-gate content changes**: the FAQ generated from the <issue id="68478f1e-4638-498a-ac53-7cfe6c308a5b" href="https://linear.app/whiteboardvc/issue/WHI-273/single-source-or-drift-gate-the-duplicated-audit-faq">WHI-273</issue> artifact (only the DMARCbis answer changes) and the render-equivalence expectation for the changed output.
* **#6b, Node 24 (v7).** Checked against Action `main` `1ec9efce`. The only files that read `action.yml` are `test/host-surface-equivalence.mjs` and `test/action-migration-canary.mjs`; `action.yml:41` is the only `node20` in the repo.
  * `action.yml`: exactly one line changes, `using: "node20"` → `using: "node24"`.
  * `test/host-surface-equivalence.mjs`: the expected `action.yml` is the `ae04a36` baseline with **exactly one** substitution, `using: "node20"` → `using: "node24"`.
    * It fails if that line isn't in the baseline exactly once.
    * The current file must be byte-identical to the expected file.
    * The pass message states the one allowed difference.
    * The `src/index.mjs` check is unchanged.
  * `test/action-migration-canary.mjs` gets three canaries that must fail by name, using the existing clone pattern:
    1. any other byte changed in `action.yml`;
    2. `action.yml` left at `node20`;
    3. a different runtime (`node22`).
  * Nothing else changes. Dogfood runs on every PR. At the PR head it must pass and show **no** "target Node.js 20" deprecation naming `./`.
* **#11, combined dependency PRs (v9).**
  * In each of amino-monitor, amino-inbox and amino-warmup, Codex opens **one** PR on current `main` that applies all three bumps, and closes the superseded Dependabot PRs:
    * checkout v7.0.1 `3d3c42e5aac5ba805825da76410c181273ba90b1`;
    * setup-node v7.1.0 `949feb2413d6458794dcd2491c4babbbce0c15c1`, the same version in all three repos;
    * wrangler-action v4.1.3 `953926a2e2182532811c01a25e53647d93bf07c0`.
  * Every `uses:` is pinned to that full SHA, with a matching `# vX.Y.Z` comment.
  * **Why:** checkout and setup-node edit adjacent lines in `deploy.yml`, so merging them one at a time conflicts, and every merge to `main` deploys production. Building monitor on current `main` also clears the stale-base test failure on Dependabot PR 18.
  * **One merge line and one post-merge deploy check per repo.** That deploy is the proof of the wrangler-action v4 major.
  * Site and skills Dependabot PRs wait until their trains clear.
* **#8a, the** <issue id="237d8dcf-a36d-4c9f-a0bc-b1c98c1a60fc" href="https://linear.app/whiteboardvc/issue/WHI-254/three-leftovers-after-the-psl-adoption-a-third-registrable-domain">WHI-254</issue> **fixture correction (v9).**
  * **The defect:** on skills `main`, the expected `Could not establish STARTTLS to primary MX` finding in `mx-provider-psl-distinct` and `mx-provider-psl-same` lacks the `"surfaces": ["skill"]` and `notApplicable` fields that all 17 other STARTTLS fixtures carry. `SPEC.md` says a surface may omit a finding only through `surfaces` plus a non-empty `notApplicable`.
  * **The fix:** add exactly those two fields to those two entries, byte-copied from an existing STARTTLS entry such as `dane-validated-tlsa`. No other fixture changes. Update the two `WHI254_NEW_DIGESTS` in `preservation.py`.
  * **The new gate:** every expected STARTTLS finding must carry `surfaces: ["skill"]` and a non-empty `notApplicable` for `web` and `action`. Canary-prove it by deleting the marking from one row.
  * **Proof:** run engine `main` `903dbd7f`'s web runner against the new skills head. The only failures left must name the two #8b engine defects (provider collapse, null/null report destination), with no STARTTLS diagnostic.
* **#8b,** <issue id="237d8dcf-a36d-4c9f-a0bc-b1c98c1a60fc" href="https://linear.app/whiteboardvc/issue/WHI-254/three-leftovers-after-the-psl-adoption-a-third-registrable-domain">WHI-254</issue> **engine half (v8).** Measured on engine `903dbd7f`:
  * **Item 1:** `engine.mjs:10808` still uses `labels.slice(-2)` for the MX provider. It becomes `registrableDomain(host) || host`.
  * **Item 2:** `engine.mjs:11230` still compares `registrableDomain(dest) !== registrableDomain(domain)`, so null equals null. It becomes same-org only when both sides are non-null and equal.
  * **Item 4:** two normalization disagreements with the merged Python. A 64-octet label returns the name, but must return `null`. `0x7f.1` returns `null`, but must return `0x7f.1`.
  * The widened `public-suffix/differential.py` (corpus + artifact sweep + 5 probes) becomes **release-blocking** in engine CI with **0 disagreements**.
  * The 3 <issue id="237d8dcf-a36d-4c9f-a0bc-b1c98c1a60fc" href="https://linear.app/whiteboardvc/issue/WHI-254/three-leftovers-after-the-psl-adoption-a-third-registrable-domain">WHI-254</issue> corpus rows must pass on the web surface, and the 78 official vectors must stay 78/78.
  * New contract version. No other behaviour change.
* **#16, the Posture Worker and the console (v12).**
  * **Worker** (`amino-posture-audit`): re-vendor the engine at #15b's merge with a matching `provenance.json`. Update the hard-coded engine check in `src/service.mjs`, and both pins in `.github`: the engine pin, and the skills pin, which must equal the engine's. The existing gates pass unchanged.
  * **Console:** `src/posture.js` `POSTURE_CONTRACT` moves to the same engine SHA and contract `1.9.0`. The existing mismatch tests keep passing, and the baseline canary still goes red.
  * **Deploy order (Abhi, at a desk):** first the Worker, by manual `wrangler deploy --var WORKER_COMMIT:<merge sha>` (it has no deploy workflow), then the console dispatch straight after. In between, baselines fail closed (`health_engine_mismatch`) and store nothing.
  * Ideally the S2 walkthrough runs after both deploys.
* **#16, the Action half (v13).** Built on Action `main` `3ab9bc7c`.
  * **Repin:** the four identity paths move to engine `dacfde0f` (contract 1.9.0) and skills `466eb8c1`.
  * **Display, in** `src/index.mjs` `renderSummary()`**.** It mirrors the live /audit wording and reads only `finding.unconfirmed`, never computing it.
    1. For an inconclusive domain, one caution line under its heading: *"We couldn't finish checking this domain. A DNS lookup failed (*`<inconclusive_reason>`*), so anything reported below as missing may be wrong, especially findings marked Not confirmed. Re-run before acting on it."*
    2. A marked row's Issue cell becomes `<title> (Not confirmed: <unconfirmed>)`.
    3. In the fix disclosure, a marked entry starts with *"Re-run the check first. If it's still reported: "*.
    4. Unmarked rows, verdicts, `fail-on`, `passed` and `audit-complete` are **byte-identical in behaviour**.
  * **The gate (rule 6: it freezes this file).** `test/host-surface-equivalence.mjs` holds `src/index.mjs` to the `ae04a36` baseline plus reviewed substitutions. Add **exactly one** new reviewed substitution, this display block. Any other byte stays red. In `test/action-migration-canary.mjs`, add canaries that go red by name:
    * any other byte changed in `src/index.mjs`;
    * the display block removed;
    * the reason taken from `inconclusive_reason` instead of `finding.unconfirmed`.
  * `test/conformance.mjs`**:** on the 7 `inconclusive-*` fixtures, marked rows show the label with their own reason, and unmarked rows don't.
  * **Release:** after the merge, the Product Lead re-targets `hireamino-factory/action-v1.9.0-release.md` to the merge SHA (`3ab9bc7c` is superseded), then Abhi publishes.
* **#18, combined Actions bumps (v14).**
  * **amino-site:** one PR on current `main` that pins every `uses:` of each action to the same versions #11 proved on monitor, inbox and warmup:
    * checkout v7.0.1 `3d3c42e5aac5ba805825da76410c181273ba90b1`;
    * setup-node v7.1.0 `949feb2413d6458794dcd2491c4babbbce0c15c1`;
    * wrangler-action v4.1.3 `953926a2e2182532811c01a25e53647d93bf07c0`.

    Each pin carries a matching `# vX.Y.Z` comment. Close Dependabot PRs 26, 29 and 36.
  * **amino-skills:** one PR with the same checkout and setup-node pins, plus setup-python v7.0.0, whose **full SHA is derived from GitHub's tag**, never typed. Close Dependabot PRs 19, 20 and 33.
  * **Gates checked (rule 6):**
    * site `test/workflow-action-pins.mjs` requires a full 40-character SHA, so it's compatible;
    * skills `conformance/check.py` asserts path filters, Python versions and steps in `conformance.yml`, not `uses:` lines, so it's compatible.

    No other gate reads these lines.
  * **Proof:** every workflow is green at the PR head with nothing skipped. For the site, the post-merge deploy succeeds and `build.txt` serves the merge, which proves wrangler-action v4 on the site.
  * **Not in scope:** the fleet Wrangler npm version (4.120.1). That is a separate item.
* **#19, the flaky console test (v14).**
  * **First,** `.github/scripts/canary-assert-suite-ran.sh` prints its substrate log's `FAIL` lines (and a short tail) whenever the substrate isn't healthy. **Known-bad check:** inject a deliberate `FAIL` into the substrate, and the canary output must name it.
  * **Then** reproduce the flake. For example, run `local.mjs` repeatedly under parallel CPU load and look for clock, rate-limit-window or ordering dependence.
  * **Either** fix the test so it's deterministic (an injected clock, say), with a named reproduction that fails before the fix, **or**, if it can't be reproduced in a stated number of stressed runs, record that on <issue id="4bcc400d-9c0a-4184-8a73-7b668e89d226" href="https://linear.app/whiteboardvc/issue/WHI-289/console-ci-a-test-in-localmjs-fails-intermittently-and-the-gate-canary">WHI-289</issue> and ship only the canary change, so the next occurrence names the test.
  * No production code changes.
* **#21, the 1.10.0 train (v16).**
  * **21a, skills:** the Python skill and the shared corpus.
    * Add the new `inconclusive-*` rows from <issue id="3c6557fd-f3b1-478f-a4f6-18a867bf5a92" href="https://linear.app/whiteboardvc/issue/WHI-290/failed-non-critical-lookups-caa-bimi-dnskey-dkim-still-read-as-absence">WHI-290</issue>: each non-critical lookup failing alone, plus an all-lookups-fail row and conclusive-empty controls.
    * Add an optional fixture map, `dnsCheckingDisabled`, supported by both runners and documented in SPEC.md, with the 4 DNSSEC rows from <issue id="957da3ad-cb0c-4b6c-a979-5d3bf4523bbb" href="https://linear.app/whiteboardvc/issue/WHI-293/report-broken-dnssec-as-a-real-finding-today-a-bogus-zone-reads-as">WHI-293</issue>.
    * `preservation.py` records exactly those changes.
    * Amended 10-19 (<issue id="957da3ad-cb0c-4b6c-a979-5d3bf4523bbb" href="https://linear.app/whiteboardvc/issue/WHI-293/report-broken-dnssec-as-a-real-finding-today-a-bogus-zone-reads-as">WHI-293</issue> **HOLD):** bogus = **both** Cloudflare and Google return SERVFAIL with checking enabled **and** DNSKEY records with checking disabled. The ordinary lookup's failure only triggers the probe; it is not evidence. The Python probe uses `dig +dnssec` and `dig +cd +dnssec` against `@1.1.1.1` and `@8.8.8.8`, for this one check only.
  * **21b, engine 1.10.0:** the same rules.
    * The probe (`cd=0` and `cd=1` on both providers, per the 10-19 amendment) and the second provider (Google) live **only** inside `createDefaultAdapters()`. `test/purity.mjs` enforces that.
    * The two-provider rule is tested with mocked providers.
    * The corpus passes with 0 failures on web and Action; the <issue id="237d8dcf-a36d-4c9f-a0bc-b1c98c1a60fc" href="https://linear.app/whiteboardvc/issue/WHI-254/three-leftovers-after-the-psl-adoption-a-third-registrable-domain">WHI-254</issue> differential stays at 0; the vectors stay 78/78.
  * **21a/21b, also (v17),** <issue id="82e2f951-5525-4291-90a5-013ee89a8d5b" href="https://linear.app/whiteboardvc/issue/WHI-12/implement-finding-lifecycle-with-an-exact-remedy">WHI-12</issue> **Part A:** every finding carries a stable `rule_id` (namespaced, never renamed, independent of title text and values) and a `discriminator` (`""` when the rule is one per asset).
    * The draft table is in the <issue id="82e2f951-5525-4291-90a5-013ee89a8d5b" href="https://linear.app/whiteboardvc/issue/WHI-12/implement-finding-lifecycle-with-an-exact-remedy">WHI-12</issue> 10-19 scope. The PR inventories **every** emit site, and a source test fails on any finding without a `rule_id`.
    * The corpus asserts both fields, closed-world. Python stays at parity.
    * **Known-bad checks:** drop `rule_id` from one emit → red; the same rule with a different value (e.g. SPF at 12 vs 13 lookups) keeps the same `rule_id` → red if it changes; two DKIM selectors → two discriminators. The null-MX MTA-STS row is `mta_sts.not_applicable` (10-19).
  * **21c, consumers:** repins only, because every surface already renders `finding.unconfirmed` (#16) and a new finding needs no display code.
    * **v22, posture Worker HOLD revision (PR 5, same branch).** `src/service.mjs` `instrumentAdapters()` rebuilds `dns` with only `query` and `meta`, so the engine never sees `dnssecProbe`. A broken-DNSSEC domain therefore reads "DNSSEC not enabled" in the Worker and the console, but "DNSSEC validation is failing" (critical) on the site and in the Action. The full spec is the reply on <issue id="3c6557fd-f3b1-478f-a4f6-18a867bf5a92" href="https://linear.app/whiteboardvc/issue/WHI-290/failed-non-critical-lookups-caa-bimi-dnskey-dkim-still-read-as-absence">WHI-290</issue> (`4fb33c91`), with these rules:
      * the instrumented `dns` exposes the adapter's `dnssecProbe` unchanged when it exists, and stays without one when it doesn't;
      * **the only** `src/` **changes are in** `src/service.mjs`**:** this pass-through in `instrumentAdapters()`, and counting the probe in the run record (below);
      * `test/helpers/fixtures.mjs` `fixtureAdapters()` supplies `dns.dnssecProbe` from `fixture.input.dnssecProbe`, the way the skills runner's `mockQ` does;
      * a Worker test asserts the 7 probe rows' DNSSEC finding through `service.audit()`: 3 critical "validation is failing", 4 low "not enabled" with `unconfirmed`;
      * **the run record counts the probe:** a `dnssecProbes` field gives the number of probe calls, and `subrequests` includes their DoH fetches (4 per call, the default adapter's two providers × checking on/off). Healthy rows' counts are unchanged; if any pinned count changes, say why.
      * **Known-bad:** dropping the pass-through turns the 3 critical rows red; dropping the test seam turns it red; leaving the probe out of `subrequests` turns the count check red.
    * The site deploys on merge.
    * Then the posture Worker deploy (`wrangler deploy`) and the console dispatch.
    * The Action ships in the next release. **If v1.9.0 hasn't been published by then, fold everything into that one release.**
  * **21d, live (Product Lead):**
    * `dnssec-failed.org` shows "DNSSEC validation is failing" (critical), with the other absence rows "Not confirmed";
    * `hireamino.com` shows "DNSSEC not enabled", unmarked;
    * a healthy domain is unchanged.
  * 22, monitor (<issue id="7e33419c-290a-41fa-84ed-9451012fcc4b" href="https://linear.app/whiteboardvc/issue/WHI-306/monitor-dashboard-says-minor-gaps-nothing-is-broken-for-a-domain-with">WHI-306</issue> **interim; v18):**
    * **Rule:** the Posture card's verdict comes from the weakest check's engine severity, not from the count. Interim severities are taken verbatim from engine 1.9.0: SPF missing, SPF `+all` and SPF over 10 lookups are high; DMARC missing is critical; DMARC `p=none` is high; DMARC `pct<100` is medium; an observed DKIM selector gone or revoked, or RSA ≤1024, is high. **(v19: for gone or revoked, superseded by #22b R1.)**
    * Any high or critical check means **"Needs work"**. "Minor gaps" applies only when every weak check is medium or lower. "Clean" only at 0.
    * The card **names** every weak or missing check.
    * **No monitor output asserts an all-clear** ("Nothing is broken" or similar) on any page, email or alert text. Today the phrase is in the Posture card and in the `watch` alert severity line.
    * `gapScore()` and the "of 6" scale stay as they are; `test/local.mjs:808` keeps passing.
    * A snapshot with no stored state shows the count only, with no "minor" verdict and no all-clear.
    * **Known-bad checks:** `g <= 2` mapped to "Minor gaps" regardless → the yoloemails row is red; the list removed → red; "Nothing is broken" back in any rendered output → red; DMARC missing rated medium → red.
  * 22b, monitor (<issue id="5537f79b-21fa-4990-b84e-87277edb06d3" href="https://linear.app/whiteboardvc/issue/WHI-308/whi-306-follow-up-a-correct-dkim-rotation-reads-needs-work-and-some">WHI-308</issue>; v19):
    * **R1:** DKIM gone or revoked counts as a weak check only when **no** observed selector is usable. This is engine 1.9.0's healthy-sibling rule, and exactly what `gapScore()` counts. RSA ≤1024 stays per selector, as `gapScore()` counts it. **Invariant on every card:** "0 of 6" if and only if nothing is listed.
    * **R2:** on a non-Clean card, the parked-domain note may say the domain doesn't send mail, but never that its posture is good.
    * **R3:** no alert email, the alerts page or the Posture card says or implies that nothing is wrong or nothing needs doing. Known instances: the `dkim_testing` impact ("Nothing breaks today") and the Improvement legend ("No action needed"). The guard renders every `ALERT_META` type's email and the alerts page, and rejects the class. True statements scoped to one change or one sender are fine.
    * **Known-bad checks:** per-selector revoked back → the rotated-key row is red; the parked note on a non-Clean card → red; "Nothing breaks today" back → red; "No action needed" back on the Improvement legend → red.
    * Out of scope: <issue id="3cf4ae03-a58e-40b0-989c-93e62339cf0a" href="https://linear.app/whiteboardvc/issue/WHI-307/monitor-tells-a-domain-with-spf-all-that-it-authorizes-no-senders-at">WHI-307</issue> (`+all` classed as "sends nothing").

## Product Lead scoping queue (v8), mine before any of these becomes a Codex item

1. <issue id="1ae83d25-cb40-4809-949a-5402af6fb54a" href="https://linear.app/whiteboardvc/issue/WHI-9/close-remaining-customer-trust-security-and-configuration-debt">WHI-9</issue>: one-time links are consumed by a plain GET. On console `main` `3501d250`, `/auth/email/verify` and `/auth/mailbox-proof/verify` are GET routes (`index.js:28,30`) that call `consumeLink` (`auth.js:275,322`). A mail scanner prefetching the link spends it before the person clicks. **Scoped as** <issue id="eefad3e1-a0f8-4167-a382-049e6e2c856e" href="https://linear.app/whiteboardvc/issue/WHI-287/email-action-links-act-on-a-plain-get-a-mail-scanner-can-sign-in-prove">WHI-287</issue>, which is queue #13 (v10). The same flaw also covers monitor unsubscribe and confirm. **v12:** the monitor hardening slice is queue #17. The rest of <issue id="1ae83d25-cb40-4809-949a-5402af6fb54a" href="https://linear.app/whiteboardvc/issue/WHI-9/close-remaining-customer-trust-security-and-configuration-debt">WHI-9</issue> stays on <issue id="1ae83d25-cb40-4809-949a-5402af6fb54a" href="https://linear.app/whiteboardvc/issue/WHI-9/close-remaining-customer-trust-security-and-configuration-debt">WHI-9</issue>.
2. <issue id="779a1196-9c86-449b-9229-b3b301e4a5ba" href="https://linear.app/whiteboardvc/issue/WHI-21/phase-a-instrument-the-public-funnel-from-visit-to-sign-in">WHI-21</issue>: **reconciled 10-16**, development side. The conflicting "conversion rates" criterion is replaced: counts only, never a cohort or channel conversion rate. **Not urgent; not queued.**
3. <issue id="23d82ae8-84e5-4a01-bad7-14b5af7f5185" href="https://linear.app/whiteboardvc/issue/WHI-280/engine-marks-which-findings-an-inconclusive-lookup-affects-whi-190">WHI-280</issue>: **scoped 10-16; now queue #15 and #15b (v11).**
4. <issue id="869536c8-9fcd-4c58-af69-fc0df4aa2c6f" href="https://linear.app/whiteboardvc/issue/WHI-240/a-verified-claim-is-permanent-and-locks-that-domain-name-product-wide">WHI-240</issue>, revoke/transfer: **scoped as queue #14 (v10). Correction:** this needed no Abhi decision. His 10-06 "no exclusivity" decision already answers it; what's owed is step 3 plus an explicit stop-watching action.
5. <issue id="9dd79718-d8a2-47c6-865d-dcf39b71525c" href="https://linear.app/whiteboardvc/issue/WHI-47/verify-whether-ownership-and-plan-caps-can-be-bypassed-via-the-public">WHI-47</issue>: **answered from source 10-16**. The cap is enforced at sign-up, confirm and scan, and the resolver is canary-proved. The route-level test rides #13's monitor PR (v11), then <issue id="9dd79718-d8a2-47c6-865d-dcf39b71525c" href="https://linear.app/whiteboardvc/issue/WHI-47/verify-whether-ownership-and-plan-caps-can-be-bypassed-via-the-public">WHI-47</issue> closes. **Closed 10-17:** the test is live, and production shows 0 owners over cap.
6. **New, 10-16:** <issue id="869536c8-9fcd-4c58-af69-fc0df4aa2c6f" href="https://linear.app/whiteboardvc/issue/WHI-240/a-verified-claim-is-permanent-and-locks-that-domain-name-product-wide">WHI-240</issue> **step 4.** The monitor still enforces single-owner (`enroll()`, `src/index.js:126-137`), against the 10-06 "no exclusivity, on either surface". It needs the ratified `pending`/`verified` grants. **Abhi changed the grant on 10-19:** *"I want to limit monitoring to only folks who can prove ownership of the domain"*. This replaces his 10-16 option A, and the v13 step 4 item was not approved. Monitoring needs DNS or report proof, and a confirmed mailbox alone grants nothing. To be re-scoped (<issue id="869536c8-9fcd-4c58-af69-fc0df4aa2c6f" href="https://linear.app/whiteboardvc/issue/WHI-240/a-verified-claim-is-permanent-and-locks-that-domain-name-product-wide">WHI-240</issue>), including the notice and window for existing mailbox-only watchers, then brought back as a plan version. **Decided 10-19, "A, 30 days"** (current proof; a 30-day window). Scoped, and queued as **#20** (stage 1, v15).

## Full open-issue ledger (v8)

Every open HireAmino issue across the four projects (31 at 2026-10-16T08:30Z), with one disposition each. Codex checks this ledger, as well as the queue, before saying nothing is available.

| Disposition | Issues |
| -- | -- |
| **In the queue above** | <issue id="4e298bf6-e785-43fa-8194-356ce4c8e65b" href="https://linear.app/whiteboardvc/issue/WHI-251/a-dmarc-record-above-the-registrable-root-is-invisible-to-the-audit">WHI-251</issue>, <issue id="30d15732-625b-4e4c-81b3-2a3b0c64e55f" href="https://linear.app/whiteboardvc/issue/WHI-266/every-engine-identity-gate-carries-a-hand-edited-literal-derive-them">WHI-266</issue>, <issue id="237d8dcf-a36d-4c9f-a0bc-b1c98c1a60fc" href="https://linear.app/whiteboardvc/issue/WHI-254/three-leftovers-after-the-psl-adoption-a-third-registrable-domain">WHI-254</issue>, <issue id="869536c8-9fcd-4c58-af69-fc0df4aa2c6f" href="https://linear.app/whiteboardvc/issue/WHI-240/a-verified-claim-is-permanent-and-locks-that-domain-name-product-wide">WHI-240</issue> (step 1 done), <issue id="aa9f6ea6-cc74-4520-8370-048d0351dc4c" href="https://linear.app/whiteboardvc/issue/WHI-245/audit-the-headline-and-effortvalue-plan-blend-all-three-lanes">WHI-245</issue>, <issue id="60daea5d-4c50-4fe6-bdb6-a0534c1121f2" href="https://linear.app/whiteboardvc/issue/WHI-246/published-skill-batch-scorepy-emits-one-unlabelled-cross-lane-gap">WHI-246</issue>, <issue id="1a782426-459d-465e-bc94-5f0ae1344d9a" href="https://linear.app/whiteboardvc/issue/WHI-223/dependency-batch-6-open-upgrade-prs-plus-the-fleet-wrangler-bump">WHI-223</issue>, <issue id="5ec8eb70-ccc4-41cb-9f99-b471fc475b9c" href="https://linear.app/whiteboardvc/issue/WHI-174/merge-amino-site-pr-13-track-the-parked-blog-drafts-after-re-running">WHI-174</issue> |
| **Product Lead scoping first** | The rest of <issue id="1ae83d25-cb40-4809-949a-5402af6fb54a" href="https://linear.app/whiteboardvc/issue/WHI-9/close-remaining-customer-trust-security-and-configuration-debt">WHI-9</issue>, and <issue id="869536c8-9fcd-4c58-af69-fc0df4aa2c6f" href="https://linear.app/whiteboardvc/issue/WHI-240/a-verified-claim-is-permanent-and-locks-that-domain-name-product-wide">WHI-240</issue> step 4 (monitor no-exclusivity). Now queued: <issue id="eefad3e1-a0f8-4167-a382-049e6e2c856e" href="https://linear.app/whiteboardvc/issue/WHI-287/email-action-links-act-on-a-plain-get-a-mail-scanner-can-sign-in-prove">WHI-287</issue> (#13), <issue id="869536c8-9fcd-4c58-af69-fc0df4aa2c6f" href="https://linear.app/whiteboardvc/issue/WHI-240/a-verified-claim-is-permanent-and-locks-that-domain-name-product-wide">WHI-240</issue> step 3 (#14), <issue id="23d82ae8-84e5-4a01-bad7-14b5af7f5185" href="https://linear.app/whiteboardvc/issue/WHI-280/engine-marks-which-findings-an-inconclusive-lookup-affects-whi-190">WHI-280</issue> (#15/#15b), and <issue id="9dd79718-d8a2-47c6-865d-dcf39b71525c" href="https://linear.app/whiteboardvc/issue/WHI-47/verify-whether-ownership-and-plan-caps-can-be-bypassed-via-the-public">WHI-47</issue>'s test (rides #13). <issue id="779a1196-9c86-449b-9229-b3b301e4a5ba" href="https://linear.app/whiteboardvc/issue/WHI-21/phase-a-instrument-the-public-funnel-from-visit-to-sign-in">WHI-21</issue> is reconciled and not urgent. |
| **Waits on Abhi** | <issue id="8b1b297c-0971-4e8f-93b2-2667b463a235" href="https://linear.app/whiteboardvc/issue/WHI-13/s2-persist-the-first-baseline-with-coverage-metadata">WHI-13</issue> (S2 walkthrough). <issue id="28c22dd7-03d7-4217-8414-2e66fe541e16" href="https://linear.app/whiteboardvc/issue/WHI-233/console-workspace-selection-is-non-deterministic-and-role-is-never">WHI-233</issue> (233a is live. Its "two journeys on staging" criterion can't run: there's no console staging. The owner journey rides the S2 walkthrough. 233b is trigger-gated: re-measure before any multi-membership feature). <issue id="89d03256-8eaa-4fb9-8902-57462692bba4" href="https://linear.app/whiteboardvc/issue/WHI-222/cloudflare-and-dns-hygiene-expiring-keys-2fa-enforcement-retire-the">WHI-222</issue> (his account and DNS steps). |
| **Chain behind** <issue id="8b1b297c-0971-4e8f-93b2-2667b463a235" href="https://linear.app/whiteboardvc/issue/WHI-13/s2-persist-the-first-baseline-with-coverage-metadata">WHI-13</issue> | <issue id="82e2f951-5525-4291-90a5-013ee89a8d5b" href="https://linear.app/whiteboardvc/issue/WHI-12/implement-finding-lifecycle-with-an-exact-remedy">WHI-12</issue> → <issue id="b4917ece-857d-4ecb-a146-14aa76c229b1" href="https://linear.app/whiteboardvc/issue/WHI-15/add-bounded-idempotent-re-checks">WHI-15</issue> → <issue id="944f22fc-6fb5-47be-8cec-5f3ba8078b8d" href="https://linear.app/whiteboardvc/issue/WHI-16/verify-resolution-and-preserve-the-evidence-trail">WHI-16</issue> → <issue id="5a24a01f-fff6-4a5d-ab7a-f79c4ba8de91" href="https://linear.app/whiteboardvc/issue/WHI-17/drive-the-claimed-domain-loop-in-a-real-browser">WHI-17</issue> and <issue id="00acce2d-0e40-4029-97bc-2bb8be1d0365" href="https://linear.app/whiteboardvc/issue/WHI-82/s6-the-audit-save-this-and-keep-watching-handoff-survives-sign-in">WHI-82</issue>; <issue id="fbbcc175-bc70-48d6-b655-e4239ff9a128" href="https://linear.app/whiteboardvc/issue/WHI-45/phase-b-instrument-the-claimed-domain-loop-from-claim-to-verified">WHI-45</issue>. <issue id="82e2f951-5525-4291-90a5-013ee89a8d5b" href="https://linear.app/whiteboardvc/issue/WHI-12/implement-finding-lifecycle-with-an-exact-remedy">WHI-12</issue>'s scope must fold in the constraints recorded on <issue id="8b1b297c-0971-4e8f-93b2-2667b463a235" href="https://linear.app/whiteboardvc/issue/WHI-13/s2-persist-the-first-baseline-with-coverage-metadata">WHI-13</issue> (09-30) and <issue id="944f22fc-6fb5-47be-8cec-5f3ba8078b8d" href="https://linear.app/whiteboardvc/issue/WHI-16/verify-resolution-and-preserve-the-evidence-trail">WHI-16</issue> (10-12). <issue id="b4917ece-857d-4ecb-a146-14aa76c229b1" href="https://linear.app/whiteboardvc/issue/WHI-15/add-bounded-idempotent-re-checks">WHI-15</issue> must re-check its rate limits against <issue id="0a2ef769-576c-4d8d-abb8-5b88bf29f80a" href="https://linear.app/whiteboardvc/issue/WHI-26/reconcile-the-free-and-pro-entitlement-contract">WHI-26</issue> (Done 10-15). **Gap:** no issue owns the console screens for import, claim and baseline, which <issue id="5a24a01f-fff6-4a5d-ab7a-f79c4ba8de91" href="https://linear.app/whiteboardvc/issue/WHI-17/drive-the-claimed-domain-loop-in-a-real-browser">WHI-17</issue> and <issue id="00acce2d-0e40-4029-97bc-2bb8be1d0365" href="https://linear.app/whiteboardvc/issue/WHI-82/s6-the-audit-save-this-and-keep-watching-handoff-survives-sign-in">WHI-82</issue> need. File it when <issue id="82e2f951-5525-4291-90a5-013ee89a8d5b" href="https://linear.app/whiteboardvc/issue/WHI-12/implement-finding-lifecycle-with-an-exact-remedy">WHI-12</issue> is scoped. |
| **Deferred, with reason** | <issue id="b5544c0b-de87-446e-bf1d-a5cfe1ed800d" href="https://linear.app/whiteboardvc/issue/WHI-81/watchtower-consumes-the-posture-audit-worker-its-own-posture-code-is">WHI-81</issue> (needs a scope, plus a read-only export of enrolled domains that only Abhi can run). <issue id="d48858ad-02bb-4817-ac75-685fe678aa23" href="https://linear.app/whiteboardvc/issue/WHI-44/hold-every-engine-consumer-to-the-conformance-gate-before-it-is">WHI-44</issue> (closes as each consumer is covered; waits on <issue id="b5544c0b-de87-446e-bf1d-a5cfe1ed800d" href="https://linear.app/whiteboardvc/issue/WHI-81/watchtower-consumes-the-posture-audit-worker-its-own-posture-code-is">WHI-81</issue> and an MCP/API adapter). |
| **Closed in v8** | <issue id="06ea459c-a3b5-4d15-87d8-19788032bd8e" href="https://linear.app/whiteboardvc/issue/WHI-215/one-pinned-public-suffix-artifact-retire-the-three-hand-written">WHI-215</issue>: all six acceptance criteria are evidenced, and its leftovers live in <issue id="237d8dcf-a36d-4c9f-a0bc-b1c98c1a60fc" href="https://linear.app/whiteboardvc/issue/WHI-254/three-leftovers-after-the-psl-adoption-a-third-registrable-domain">WHI-254</issue> and <issue id="4e298bf6-e785-43fa-8194-356ce4c8e65b" href="https://linear.app/whiteboardvc/issue/WHI-251/a-dmarc-record-above-the-registrable-root-is-invisible-to-the-audit">WHI-251</issue>. |
| **Owned by the HireAmino GTM thread, not sequenced here** | <issue id="ab79fe4e-e4b3-4cd1-a8ec-d5d1eed357d6" href="https://linear.app/whiteboardvc/issue/WHI-18/choose-one-90-day-audience-and-channel-hypothesis">WHI-18</issue>, <issue id="0d4092e7-26a7-4030-9979-d01fc1fdfafc" href="https://linear.app/whiteboardvc/issue/WHI-19/run-the-first-earned-distribution-experiment">WHI-19</issue>, <issue id="f06d96eb-aaf8-46c5-9b92-168f1b165801" href="https://linear.app/whiteboardvc/issue/WHI-20/review-the-channel-test-and-decide-stop-repeat-or-scale">WHI-20</issue>, <issue id="c89836c9-d154-4bf5-8bbd-ad6361069d74" href="https://linear.app/whiteboardvc/issue/WHI-22/restore-the-lead-tracker-and-import-staged-run-17-rows">WHI-22</issue>, <issue id="241f3f12-9a45-4f0b-8f42-12fc0620e7e1" href="https://linear.app/whiteboardvc/issue/WHI-23/decide-the-monitoring-to-remediation-boundary">WHI-23</issue>, <issue id="aa6bf82d-7f08-4109-939b-5e6c51bf95b3" href="https://linear.app/whiteboardvc/issue/WHI-24/set-retention-and-anomaly-aware-ingestion-limits-from-measurement">WHI-24</issue>, <issue id="0aa27fa2-ef3d-4919-84bf-073c1fee0329" href="https://linear.app/whiteboardvc/issue/WHI-25/define-the-paid-mcpapi-tool-and-metering-contract">WHI-25</issue>, <issue id="9c965e0a-6841-48ce-95da-da7b9a448a4b" href="https://linear.app/whiteboardvc/issue/WHI-28/measure-rua-source-cardinality-on-a-real-sending-domain">WHI-28</issue>. Handed off with the record conflicts found: <issue id="ab79fe4e-e4b3-4cd1-a8ec-d5d1eed357d6" href="https://linear.app/whiteboardvc/issue/WHI-18/choose-one-90-day-audience-and-channel-hypothesis">WHI-18</issue>'s conversion criterion vs the 10-07 rule; <issue id="0d4092e7-26a7-4030-9979-d01fc1fdfafc" href="https://linear.app/whiteboardvc/issue/WHI-19/run-the-first-earned-distribution-experiment">WHI-19</issue>'s blocked-by <issue id="779a1196-9c86-449b-9229-b3b301e4a5ba" href="https://linear.app/whiteboardvc/issue/WHI-21/phase-a-instrument-the-public-funnel-from-visit-to-sign-in">WHI-21</issue> vs the 10-05 amendment; <issue id="c89836c9-d154-4bf5-8bbd-ad6361069d74" href="https://linear.app/whiteboardvc/issue/WHI-22/restore-the-lead-tracker-and-import-staged-run-17-rows">WHI-22</issue>'s wrong milestone (UI-only removal); <issue id="9c965e0a-6841-48ce-95da-da7b9a448a4b" href="https://linear.app/whiteboardvc/issue/WHI-28/measure-rua-source-cardinality-on-a-real-sending-domain">WHI-28</issue> needs a consented sending domain. |

## Who presses merge

**Claude presses merge, only on Abhi's exact live line** (`Merge <repo> PR <n> at <sha>, merge commit, mergeCausesDeploy=…`), after Claude's gate on that same SHA, and following the release checklist (`hireamino-factory/runbooks/release-checklist.md`). **Codex never merges.** A head that changes after a gate needs a new gate.

## Deploy order (kept separate from the build order)

1. **Site:** <pull-request id="1977ae79-d076-4e32-8ab9-b6662672c82a" href="https://linear.app/whiteboardvc/review/derive-website-engine-identity-from-pinned-source-whi-266-phase-c-010a8c860583">Derive website engine identity from pinned source (WHI-266 Phase C)</pull-request> ✅ → <pull-request id="5fbc6756-e363-4905-b3c7-89d0932a79a9" href="https://linear.app/whiteboardvc/review/surface-inconclusive-audit-results-without-reclassifying-findings-whi-d205f0eb1822">Surface inconclusive audit results without reclassifying findings (WHI-190)</pull-request> (<issue id="feb26a7d-62ce-4e95-8af2-78a29192a783" href="https://linear.app/whiteboardvc/issue/WHI-190/the-audit-page-reports-a-failed-dns-lookup-as-a-missing-record-the">WHI-190</issue>) → the Step 2 repin with the FAQ from the artifact (Phase D) → <issue id="aa9f6ea6-cc74-4520-8370-048d0351dc4c" href="https://linear.app/whiteboardvc/issue/WHI-245/audit-the-headline-and-effortvalue-plan-blend-all-three-lanes">WHI-245</issue> (lanes). Each one is verified live before the next merges.
2. **Action:** #14 ✅ → the Step 2 repin (#6, four identity paths) → Node 24 (#6b) → **v1.9.0 release**, published by Abhi. The notes are final: `hireamino-factory/action-v1.9.0-release.md`, target `3ab9bc7c`.
3. **Monitor:** <issue id="869536c8-9fcd-4c58-af69-fc0df4aa2c6f" href="https://linear.app/whiteboardvc/issue/WHI-240/a-verified-claim-is-permanent-and-locks-that-domain-name-product-wide">WHI-240</issue> step 1, after the console refactor merges. The console's part merges with no deploy; Abhi dispatches the console deploy separately.

## What deploys

| Repo | On merge |
| -- | -- |
| amino-site | deploys [hireamino.com](<http://hireamino.com>) |
| amino-monitor | deploys |
| amino-console | nothing; manual dispatch (Abhi) |
| amino-skills, amino-audit-engine | nothing |
| amino-audit-action | nothing; a release (v1.9.0, after #6 and #6b) is published by Abhi |
| amino-posture-audit | nothing; manual `wrangler deploy` (Abhi) |

## Product Lead queue (Claude)

* ~~**v30: write the #30 spec and freeze its held-out probe**~~ **Done 10-29** (comment `10fa9bc7` on the findings-screens issue: proven 0/53 and 0/20 on console `main`, 53/53 and 20/20 on a local reference build, all 21 planted defects red). The rest of this bullet is kept for the record: (hashes only, on [WHI-294](<https://linear.app/whiteboardvc/issue/WHI-294/console-screens-for-the-claimed-domain-loop-import-claim-baseline-and>)). Codex starts #30 only after both are posted. The spec settles two questions. (1) The findings read doesn't carry the per-finding minute: either show it from a 429's `next_available_at`, or add `next_recheck_at` per finding to the read (a small API addition inside #30's scope). (2) A findings page GET projects on read, so the post-deploy live check is a production write that needs Abhi's recorded authorization.
* **Then:** the #31 and #32 specs; the [WHI-82](<https://linear.app/whiteboardvc/issue/WHI-82/s6-the-audit-save-this-and-keep-watching-handoff-survives-sign-in>) spec, buildable after #31; the [WHI-12](<https://linear.app/whiteboardvc/issue/WHI-12/implement-finding-lifecycle-with-an-exact-remedy>) Part C spec, which needs a monitor-to-console report-data link first (the console has no sender data yet: `GET /api/roots/{id}/senders` returns an empty list marked `rua_wiring_phase3`); and the [WHI-81](<https://linear.app/whiteboardvc/issue/WHI-81/watchtower-consumes-the-posture-audit-worker-its-own-posture-code-is>) (Watchtower) D1 and D2 questions for Abhi, so that Watchtower can be v31.
* ~~Review 27c (console PR 22) and its correction (console PR 23)~~ **Done 10-29:** both merged and live, and the live re-check passed.
* ~~Re-gate and verify amino-site PR 34~~ done: verified live 2026-10-16.
* ~~Review #5~~ done: merged 2026-10-16. ~~Review #6 site half~~ done: merged + live. ~~#6 Action repin, #7, #8~~ done and merged. ~~#6b, #8a, #9, #10, #11, #12~~ merged (#9, #11 and #12 verified live). ~~#8b~~ merged. Review #14, #15b, #16 and #17 as they land; their expectations are written first. Verify `@v1` after Abhi publishes v1.9.0. Then work the scoping queue.
* ~~**v26: scope engine contract 1.11.0 after #25.**~~ **Done 10-24:** spec on [WHI-12](<https://linear.app/whiteboardvc/issue/WHI-12/implement-finding-lifecycle-with-an-exact-remedy>), queued as #26 in v27. It covers:
  * [WHI-12](<https://linear.app/whiteboardvc/issue/WHI-12/implement-finding-lifecycle-with-an-exact-remedy>) Part B (`rule_evaluation`; amendment comment `b86c93f9`, Codex's 56-rule inventory `afc9e4c6`, frozen expectations `review-harnesses/whi-12-1.11.0-expectations.md`, SHA-256 `f6554103…`);
  * [WHI-312](<https://linear.app/whiteboardvc/issue/WHI-312/the-dnssec-validation-is-failing-findings-action-label-says-enable>) (the critical DNSSEC row's label);
  * [WHI-311](<https://linear.app/whiteboardvc/issue/WHI-311/our-pinned-public-suffix-list-is-three-weeks-stale-and-the-weekly>) A2–A4 (the engine, monitor and console list refresh).
  * Output: a spec, plus a plan version for Abhi.
* ~~**Scope**~~ [WHI-12](<https://linear.app/whiteboardvc/issue/WHI-12/implement-finding-lifecycle-with-an-exact-remedy>) ~~**Part B.**~~ **Done 10-24:** spec on [WHI-12](<https://linear.app/whiteboardvc/issue/WHI-12/implement-finding-lifecycle-with-an-exact-remedy>), queued as #27 in v28. The 27a probe is frozen (SHA-256 `01d30866…`), proven 0/41 on console `main`, 41/41 on a local reference build, with all 19 planted defects red. 27c's withheld set gets frozen before 27c is authorized.
* ~~**Scope**~~ [WHI-9](<https://linear.app/whiteboardvc/issue/WHI-9/close-remaining-customer-trust-security-and-configuration-debt>) ~~**rows 2 and 3**~~ **Done 10-25** (Abhi chose option B): spec on [WHI-9](<https://linear.app/whiteboardvc/issue/WHI-9/close-remaining-customer-trust-security-and-configuration-debt>), queued as #29 in v29, with [WHI-318](<https://linear.app/whiteboardvc/issue/WHI-318/console-an-email-address-leads-to-at-most-one-account-so-break-glass>) filed for row 2. The probe is frozen (SHA-256 `de17080b…`). It passes 5/20 and 3/24 on console `main`, and 20/20 and 24/24 on a local reference build, and all 18 planted defects go red. The final register goes to `hireamino/amino-security` when [WHI-9](<https://linear.app/whiteboardvc/issue/WHI-9/close-remaining-customer-trust-security-and-configuration-debt>) closes.
* [WHI-44](<https://linear.app/whiteboardvc/issue/WHI-44/hold-every-engine-consumer-to-the-conformance-gate-before-it-is>) **Done 10-25** (Abhi chose option A): the MCP/API criterion moved to [WHI-25](<https://linear.app/whiteboardvc/issue/WHI-25/define-the-paid-mcpapi-tool-and-metering-contract>), and [WHI-44](<https://linear.app/whiteboardvc/issue/WHI-44/hold-every-engine-consumer-to-the-conformance-gate-before-it-is>) is blocked by [WHI-81](<https://linear.app/whiteboardvc/issue/WHI-81/watchtower-consumes-the-posture-audit-worker-its-own-posture-code-is>) and closes with its cutover.
* ~~**Review #28 (console PR 18)**~~ **Done 10-25: ready to merge at** `be8bfdd2` ([WHI-289](<https://linear.app/whiteboardvc/issue/WHI-289/console-ci-a-test-in-localmjs-fails-intermittently-and-the-gate-canary>)). All 8 burst pins and both TTL bounds are proven by planted bugs.
* ~~**Review #26a (skills PR 37)**~~ **Done 10-25: HOLD at** `0855cc4e` on one rule ([WHI-12](<https://linear.app/whiteboardvc/issue/WHI-12/implement-finding-lifecycle-with-an-exact-remedy>)). `dmarc.missing` ignored a failed ancestor lookup. The cause was my spec's unnamed "9 own-record rules". Codex revises on the branch; I re-run `whi-12-26a-scenarios.py` on the new head.
* Keep this document current.
* With Abhi at a desktop: the [WHI-13](<https://linear.app/whiteboardvc/issue/WHI-13/s2-persist-the-first-baseline-with-coverage-metadata>) S2 baseline walkthrough.
* Open design: [WHI-47](<https://linear.app/whiteboardvc/issue/WHI-47/verify-whether-ownership-and-plan-caps-can-be-bypassed-via-the-public>)'s plan-cap half and [WHI-81](<https://linear.app/whiteboardvc/issue/WHI-81/watchtower-consumes-the-posture-audit-worker-its-own-posture-code-is>)'s design gaps.

## Awaiting Abhi

1. **Approve v30 at [approve.hireamino.com](<http://approve.hireamino.com>)** with Touch ID, after registering his passkey once, then paste the one-time standing-rule message into the replacement Codex chat ([WHI-327](<https://linear.app/whiteboardvc/issue/WHI-327>)). That replaces typing "Proceed per HireAmino plan of record v30." there, which still works. Not yet received (Codex, 10-29). Item 30's spec and frozen probe hashes are ready on the findings-screens issue. (~~v29~~ was sent 10-25; its last item, 27c, was approved in the replacement chat and is live 10-29.) Then a merge line per item as each Product Lead review passes.
2. ~~Publish Action v1.9.0; the console dispatch; the #16 deploys~~ **Done 10-21** (Action v1.9.0 and `@v1` = `5a73cfa4`; engine service `10e0a8e3`; console `504eb525` with `0004`).
3. ~~WHI-233a staging review~~ **withdrawn 10-16; the criterion was amended with Abhi's OK:** the console has no staging environment. The owner journey happens during the S2 walkthrough (item 4), when Abhi signs in. The refusal journey needs a second membership, which production doesn't have; 7 named canaries cover it. The amended criterion is recorded on [WHI-233](<https://linear.app/whiteboardvc/issue/WHI-233/console-workspace-selection-is-non-deterministic-and-role-is-never>).
4. [WHI-117](<https://linear.app/whiteboardvc/issue/WHI-117/decision-abhi-upgrade-hireamino-to-github-team-for-enforced-branch>)\*\*:\*\* GitHub Team ($4/mo).
5. ~~The S2 walkthrough~~ **Done 10-22** ([WHI-13](<https://linear.app/whiteboardvc/issue/WHI-13/s2-persist-the-first-baseline-with-coverage-metadata>) closed; a second domain, `yoloemails.app`, also passed end to end).
6. **MTA-STS:** Steps 0, 2 and 4.
7. **Remove the unused Codex GitHub App.**
8. [WHI-222](<https://linear.app/whiteboardvc/issue/WHI-222/cloudflare-and-dns-hygiene-expiring-keys-2fa-enforcement-retire-the>) account and DNS steps.
9. [WHI-311](<https://linear.app/whiteboardvc/issue/WHI-311/our-pinned-public-suffix-list-is-three-weeks-stale-and-the-weekly>): **mark it Done.** The Product Lead's close check passed 10-29 (comment `e725f2e0`); the status change needs your click.

## Changelog

* **v30 (2026-10-29):** v29 is complete: 27c and its D1 correction are live and verified (row 27). Adds **#30** and **#31**, the [WHI-294](<https://linear.app/whiteboardvc/issue/WHI-294/console-screens-for-the-claimed-domain-loop-import-claim-baseline-and>) console screens (findings first, then import, claim, check, stop-watching and baseline), and **#32**, branded console emails ([WHI-305](<https://linear.app/whiteboardvc/issue/WHI-305/console-emails-are-bare-plain-text-monitor-emails-are-branded-one-look>)). #30 starts only after the Product Lead's spec and frozen held-out probe are posted. Abhi chose to start without his page ideas ("Go ahead without", 10-29). Left out on purpose: [WHI-21](<https://linear.app/whiteboardvc/issue/WHI-21>) and [WHI-45](<https://linear.app/whiteboardvc/issue/WHI-45>) (funnel events, deferred); [WHI-314](<https://linear.app/whiteboardvc/issue/WHI-314>) (waits for the next monthly F50 scan); [WHI-292](<https://linear.app/whiteboardvc/issue/WHI-292>) (optional Wrangler alignment); [WHI-44](<https://linear.app/whiteboardvc/issue/WHI-44/hold-every-engine-consumer-to-the-conformance-gate-before-it-is>) (closes with [WHI-81](<https://linear.app/whiteboardvc/issue/WHI-81/watchtower-consumes-the-posture-audit-worker-its-own-posture-code-is>)); [WHI-222](<https://linear.app/whiteboardvc/issue/WHI-222/cloudflare-and-dns-hygiene-expiring-keys-2fa-enforcement-retire-the>) (Abhi's own account steps); and the GTM-owned issues ([WHI-18](<https://linear.app/whiteboardvc/issue/WHI-18/choose-one-90-day-audience-and-channel-hypothesis>) to 20, 22 to 25 and 28), untouched. The same save refreshes state: rows 25 and 27, "Awaiting Abhi", and [WHI-312](<https://linear.app/whiteboardvc/issue/WHI-312/the-dnssec-validation-is-failing-findings-action-label-says-enable>) is Done (10-29). Needs Abhi's "Proceed per HireAmino plan of record v30" in the replacement Codex chat, or, from 10-29, his passkey-signed approval of this text ([WHI-327](<https://linear.app/whiteboardvc/issue/WHI-327>), live at [approve.hireamino.com](<http://approve.hireamino.com>)). Adding that approval route changes no order, scope or sequencing, so v30 keeps its number.
* **v29 (2026-10-25):** adds **#29**, one mailbox per account plus a session workspace selector ([WHI-318](<https://linear.app/whiteboardvc/issue/WHI-318/console-an-email-address-leads-to-at-most-one-account-so-break-glass>) and [WHI-303](<https://linear.app/whiteboardvc/issue/WHI-303/233b-a-session-workspace-selector-whi-9-register-row-3-building-now-as>), [WHI-9](<https://linear.app/whiteboardvc/issue/WHI-9/close-remaining-customer-trust-security-and-configuration-debt>) register rows 2 and 3), from Abhi's [WHI-9](<https://linear.app/whiteboardvc/issue/WHI-9/close-remaining-customer-trust-security-and-configuration-debt>) decision (option B) and the Product Lead's spec on [WHI-9](<https://linear.app/whiteboardvc/issue/WHI-9/close-remaining-customer-trust-security-and-configuration-debt>). Scoping found that row 2 is reachable today: an email-link sign-in followed by a Google sign-in with the same address makes two accounts. Production has no duplicates yet (measured 10-25). Part B's 27a now takes migration `0006` and starts after #29. It also records the [WHI-44](<https://linear.app/whiteboardvc/issue/WHI-44/hold-every-engine-consumer-to-the-conformance-gate-before-it-is>) decision (option A): the MCP/API gate criterion moved to [WHI-25](<https://linear.app/whiteboardvc/issue/WHI-25/define-the-paid-mcpapi-tool-and-metering-contract>).
* **v28 (2026-10-24):** adds **#27**, the console finding lifecycle ([WHI-12](<https://linear.app/whiteboardvc/issue/WHI-12/implement-finding-lifecycle-with-an-exact-remedy>) Part B, [WHI-16](<https://linear.app/whiteboardvc/issue/WHI-16/verify-resolution-and-preserve-the-evidence-trail>), [WHI-15](<https://linear.app/whiteboardvc/issue/WHI-15/add-bounded-idempotent-re-checks>)). It's three PRs (27a console, 27b monitor, 27c console) behind the 1.11.0 train, from the Product Lead's spec on [WHI-12](<https://linear.app/whiteboardvc/issue/WHI-12/implement-finding-lifecycle-with-an-exact-remedy>). Two of that spec's corrections were measured: on the pinned engine, `neverssl.com` is always `partial`, so a "completed only" rule would never resolve its findings; and a failed TLSA lookup emits an unmarked `transport.dane_missing`, so findings open only when their own rule is conclusive. Also adds **#28**, [WHI-289](<https://linear.app/whiteboardvc/issue/WHI-289/console-ci-a-test-in-localmjs-fails-intermittently-and-the-gate-canary>)'s test-only clock-race fix, startable now.
* **v27 (2026-10-24):** adds **#26**, the engine contract 1.11.0 train (`rule_evaluation`, [WHI-312](<https://linear.app/whiteboardvc/issue/WHI-312/the-dnssec-validation-is-failing-findings-action-label-says-enable>)'s label, [WHI-311](<https://linear.app/whiteboardvc/issue/WHI-311/our-pinned-public-suffix-list-is-three-weeks-stale-and-the-weekly>) A2–A4, [WHI-254](<https://linear.app/whiteboardvc/issue/WHI-254/three-leftovers-after-the-psl-adoption-a-third-registrable-domain>)'s monitor vectors), from the Product Lead's spec on [WHI-12](<https://linear.app/whiteboardvc/issue/WHI-12/implement-finding-lifecycle-with-an-exact-remedy>). 26a starts only after #25 merges.
* **v26 (2026-10-24):** adds **#25**, the skills half of [WHI-311](<https://linear.app/whiteboardvc/issue/WHI-311/our-pinned-public-suffix-list-is-three-weeks-stale-and-the-weekly>): the PSL refresh from one reviewed snapshot, and an alarm that goes red only when it matters and opens or updates a GitHub issue when it does. The engine, monitor and console adopt the refreshed list inside the 1.11.0 train. After #25, the Product Lead scopes engine contract 1.11.0; no Codex build is queued for it yet. Also records the #24 HOLD (PR 37) and lets its revision add the two new tests to the three monitor workflows.
* **v25 (2026-10-23):** adds **#24**, [WHI-307](<https://linear.app/whiteboardvc/issue/WHI-307/monitor-tells-a-domain-with-spf-all-that-it-authorizes-no-senders-at>) (the SPF `all` qualifier and term order in `sendingPosture()`), from Codex's read-only scope, which the Product Lead accepted as the spec. Records #23, #23b and #23c merged and deployed.
* **v24 (2026-10-23):** adds **#23, #23b and #23c**, "Your domains" phase 1 ([WHI-294](<https://linear.app/whiteboardvc/issue/WHI-294/console-screens-for-the-claimed-domain-loop-import-claim-baseline-and>)) with [WHI-309](<https://linear.app/whiteboardvc/issue/WHI-309/a-watch-only-monitor-customer-cant-get-back-to-their-dashboard-after-7>) and [WHI-310](<https://linear.app/whiteboardvc/issue/WHI-310/monitors-fortune-50-card-hides-the-checks-a-domain-fails-if-every>), on Abhi's decisions D1–D3 (no verdict in the list; re-entering sends a fresh dashboard link; leave the 2 duplicate pairs). The spec, with expected answers, known-bad checks and the files each item may change, is a Linear document on [WHI-294](<https://linear.app/whiteboardvc/issue/WHI-294/console-screens-for-the-claimed-domain-loop-import-claim-baseline-and>). Each item names the test and gate files it may update, so a pinned test isn't a reason to stop. Also records #21e merged and Action v1.10.0 published.
* **v23 (2026-10-23):** adds **#21e**, a docs-only Action PR, before the v1.10.0 release. The README and SECURITY.md say the Action contacts only `cloudflare-dns.com`, but engine 1.10.0 also queries `dns.google` (`engine.mjs:196`; engine 1.9.0 had only Cloudflare). The Marketplace shows the README at the tag, so publishing first would ship a false privacy statement. The review session found it; I confirmed it by grep of Action `main` `e1f373ba`, where these are the only two resolver-naming sentences. Also refreshes #21c to merged: site, Worker, console and Action. The monitor #22b is merged too.
* **v22 (2026-10-23):** adds the #21c posture Worker HOLD revision. The Worker's adapter wrapper drops `dnssecProbe`, so 3 of the 7 probe rows differ from the engine, and live `dnssec-failed.org` reads "not enabled" in the Worker. This was found by the Product Lead review session, and my own reading of `src/service.mjs` at `84ea8738` confirms it. It's my spec defect: the 21c inventory said "values only" for the Worker without checking that the Worker wraps the engine's adapters. v22 also requires the run record to count the probe's DoH fetches. *(Wording corrected 02:3xZ, before relay: the two* `src/service.mjs` *changes, the pass-through and the count, are the only* `src/` *changes. An earlier sentence called the pass-through "the only* `src/` *logic change". The scope is unchanged.)* State: site PR 42 PASS; console PR 16 PASS (merge held for lockstep); monitor PR 34 PASS.
* **v21 (2026-10-23):** completes the #21c Action exception. Codex stopped correctly a second time: `test/engine-suite-canary.mjs` still targeted the 1.9.0 source line, which 1.10.0 wraps in an own-record guard. v20 was my defect: I named only the file Codex reported and didn't trial-run the whole suite. For v21 I built all six files and ran every `npm test` step separately, plus the two CI-only steps. All pass, so no further file is needed.
* **v20 (2026-10-23):** one scope exception. The #21c Action repin may also change `test/conformance.mjs`, test-only. Its inconclusive-fixture count goes from 7 to 8, because the 1.10.0 corpus adds `inconclusive-all-lookups-fail`. `fixtureQ` gains the canonical `dnssecProbe` seam, because that fixture is the only inconclusive one carrying probe input. Codex stopped correctly at the v7 four-path rule ([WHI-290](<https://linear.app/whiteboardvc/issue/WHI-290/failed-non-critical-lookups-caa-bimi-dnskey-dkim-still-read-as-absence>), 10-23); without this exception, the Action's display harness can't run the new DNSSEC row. State: the #21c site, Worker and console PRs and #22b's monitor PR 34 are delivered and await Product Lead review.
* **v19 (2026-10-22):** PR 33 (#22) ships as is, on Abhi's call ("Ship PR 33 as is and do the three fixes in a follow-up PR."). Adds **#22b** ([WHI-308](<https://linear.app/whiteboardvc/issue/WHI-308/whi-306-follow-up-a-correct-dkim-rotation-reads-needs-work-and-some>)) for the three gaps the Product Lead review found at `19440774`: a correct DKIM rotation reads "Needs work · 0 of 6"; the parked note says "perfectly good posture" on a Needs-work card; and `dkim_testing` and the Improvement legend still reassure. R1 supersedes #22's DKIM sentence, which I wrote too loosely. Also files [WHI-307](<https://linear.app/whiteboardvc/issue/WHI-307/monitor-tells-a-domain-with-spf-all-that-it-authorizes-no-senders-at>) (`+all` classed as "sends nothing"), not queued. State: #21a merged (`553a47fa`); #21b startable.
* **v18 (2026-10-22):** adds **#22**, the [WHI-306](<https://linear.app/whiteboardvc/issue/WHI-306/monitor-dashboard-says-minor-gaps-nothing-is-broken-for-a-domain-with>) interim fix: the monitor's Posture card told a domain with no SPF and no DMARC "Minor gaps · Nothing is broken", while the console's baseline for the same domain reported critical and high. It also refreshes the states after the 10-21/22 desk session (#13, #14, #16 and #20 done or deployed; #21a in re-review), and records the 10-19 amendment to the bogus-DNSSEC rule in #21's Repo rules. Approved by Abhi ("Yes").
* **v17 (2026-10-19):** #21 (the 1.10.0 train) also carries [WHI-12](<https://linear.app/whiteboardvc/issue/WHI-12/implement-finding-lifecycle-with-an-exact-remedy>) **Part A**, a stable `rule_id` and `discriminator` on every engine finding. The console's finding lifecycle ([WHI-12](<https://linear.app/whiteboardvc/issue/WHI-12/implement-finding-lifecycle-with-an-exact-remedy>) Part B) needs a fingerprint that doesn't change when a value in a title changes. It's additive, so the consumers still repin once. Approved by Abhi ("yes v17").
* **v16 (2026-10-19):** adds **#21**, the engine contract 1.10.0 train: [WHI-290](<https://linear.app/whiteboardvc/issue/WHI-290/failed-non-critical-lookups-caa-bimi-dnskey-dkim-still-read-as-absence>) (failed non-critical lookups marked `unconfirmed`) plus [WHI-293](<https://linear.app/whiteboardvc/issue/WHI-293/report-broken-dnssec-as-a-real-finding-today-a-bogus-zone-reads-as>) (broken DNSSEC reported as "DNSSEC validation is failing", severity critical). Skills, then the engine, then consumer repins and the live check, as one train, so there's one site deploy and one Action release. Approved by Abhi ("yes v16"; critical severity accepted as recommended).
* **v15 (2026-10-19):** adds **#20**, [WHI-240](<https://linear.app/whiteboardvc/issue/WHI-240/a-verified-claim-is-permanent-and-locks-that-domain-name-product-wide>) step 4 stage 1: proof-only monitoring per watcher under Abhi's 10-19 decision ("A, 30 days"), shipped with enforcement off. Stage 2 is a later one-line flip. Approved by Abhi ("Yes v15").
* **v14 (2026-10-19):** adds **#18** ([WHI-223](<https://linear.app/whiteboardvc/issue/WHI-223/dependency-batch-6-open-upgrade-prs-plus-the-fleet-wrangler-bump>) part 2: one combined Actions-bump PR each for site and skills, reusing #11's proven pins) and **#19** ([WHI-289](<https://linear.app/whiteboardvc/issue/WHI-289/console-ci-a-test-in-localmjs-fails-intermittently-and-the-gate-canary>): make the console gate canary name its substrate failure, then fix the flaky test). Both are startable now and neither changes production behaviour. Approved by Abhi ("yes v14").
* **v13 (2026-10-19):**
  * **One Action release instead of two:** #16's Action half no longer waits for a v1.9.0 publish. It repins to engine 1.9.0 with the "Not confirmed" display and a narrowed host-surface gate, then ships as the single v1.9.0 release.
  * [WHI-240](<https://linear.app/whiteboardvc/issue/WHI-240/a-verified-claim-is-permanent-and-locks-that-domain-name-product-wide>) **step 4 (monitor no-exclusivity) was proposed and not approved.** Abhi changed the grant: monitoring only for people who prove ownership. It will be re-scoped.
  * Approved by Abhi ("Approve v13 part a but not part b").
* **v12 (2026-10-17):**
  * Widens **#16** to the Posture Audit Worker and the console's engine pin. Both still run engine 1.5.0 while /audit runs 1.7.0, so console baselines could disagree with /audit for the same domain. Found in the [WHI-44](<https://linear.app/whiteboardvc/issue/WHI-44/hold-every-engine-consumer-to-the-conformance-gate-before-it-is>) evidence check.
  * Adds **#17**, one monitor PR for [WHI-9](<https://linear.app/whiteboardvc/issue/WHI-9/close-remaining-customer-trust-security-and-configuration-debt>): tests for the two untested RUA limits, plus four baseline headers on monitor pages. The risk register's trigger fired when [WHI-287](<https://linear.app/whiteboardvc/issue/WHI-287/email-action-links-act-on-a-plain-get-a-mail-scanner-can-sign-in-prove>)'s confirmation pages shipped.
  * Approved by Abhi ("yes v12").
* **v11 (2026-10-16):** adds **#15/#15b**, [WHI-280](<https://linear.app/whiteboardvc/issue/WHI-280/engine-marks-which-findings-an-inconclusive-lookup-affects-whi-190>) per-finding markers (skills, then engine 1.9.0). Adds **#16**: **one** consumer repin to 1.9.0, replacing separate 1.8.0 repins, so there's one site deploy and one Action release instead of two. #13's monitor PR also carries [WHI-47](<https://linear.app/whiteboardvc/issue/WHI-47/verify-whether-ownership-and-plan-caps-can-be-bypassed-via-the-public>)'s route-level cap test. Approved by Abhi ("yes v11", agreeing with fewer deploys and releases).
* **v10 (2026-10-16):** adds **#13** [WHI-287](<https://linear.app/whiteboardvc/issue/WHI-287/email-action-links-act-on-a-plain-get-a-mail-scanner-can-sign-in-prove>), email action links that act on a plain GET. A mail scanner opening the link can start a session, prove a mailbox, or silently stop a customer's monitoring alerts. Also adds **#14**, [WHI-240](<https://linear.app/whiteboardvc/issue/WHI-240/a-verified-claim-is-permanent-and-locks-that-domain-name-product-wide>) step 3: drop console exclusivity per Abhi's 10-06 decision, plus an explicit stop-watching action. Approved by Abhi ("yes, v10").
* **v9 (2026-10-16):** three corrections.
  1. New **#8a**: skills PR 29 ([WHI-254](<https://linear.app/whiteboardvc/issue/WHI-254/three-leftovers-after-the-psl-adoption-a-third-registrable-domain>)) shipped two fixtures without the skill-only STARTTLS marking, so they could never pass on web or Action. The Product Lead gated them on Python only; Codex found it while building #8b. #8b now waits on #8a.
  2. **"Deploys" means production.** Automatic, isolated staging deploys on non-`main` pushes are CI.
  3. **#11** becomes one combined PR per repo. Adjacent-line conflicts plus a production deploy on every merge made nine single-bump merges the wrong unit.
     Approved by Abhi ("yes, v9").
* **v8 (2026-10-16):** adds a **full open-issue ledger**. Codex's audit found the plan silent on open work, though it only covered issues numbered 1 to 100. The real count is 31 open issues across the four HireAmino projects. Every one now has a disposition, and the 8 commercial decisions go to the GTM thread. New queue items: **#8b** (the [WHI-254](<https://linear.app/whiteboardvc/issue/WHI-254/three-leftovers-after-the-psl-adoption-a-third-registrable-domain>) engine half, measured), **#11** (9 Dependabot PRs in monitor, inbox and warmup) and **#12** (Abhi's 09-17 decision on site PR 13). New Product Lead scoping queue, including the confirmed GET-consumed one-time links ([WHI-9](<https://linear.app/whiteboardvc/issue/WHI-9/close-remaining-customer-trust-security-and-configuration-debt>)). Record fixes: [WHI-215](<https://linear.app/whiteboardvc/issue/WHI-215/one-pinned-public-suffix-artifact-retire-the-three-hand-written>) closed, stale blockers removed, the [WHI-80](<https://linear.app/whiteboardvc/issue/WHI-80/posture-audit-worker-one-deployable-posture-capability-behind-a>) residuals pointed to [WHI-13](<https://linear.app/whiteboardvc/issue/WHI-13/s2-persist-the-first-baseline-with-coverage-metadata>). Approved by Abhi ("yes, v8").
* **v7 (2026-10-16):** splits the Action half of **#6**. v5 had asked for the four identity paths plus Node 24 "and nothing else". But the Action's host-surface gate requires `action.yml` to be byte-identical to `ae04a36`, so that diff could never pass. The Product Lead didn't check the gate; Codex stopped correctly. Now the **#6** Action repin is the four identity paths only, with zero gate edits, which keeps the Phase D proof clean. New **#6b** makes the Node 24 switch with the gate narrowed to that one line, plus three canaries. v1.9.0 ships after both. Approved by Abhi ("yes, v7").
* **v6 (2026-10-16):** adds **#10** [WHI-246](<https://linear.app/whiteboardvc/issue/WHI-246/published-skill-batch-scorepy-emits-one-unlabelled-cross-lane-gap>), after #8 because both edit skills, and skills PRs go one at a time. The published skill's batch scorer prints one Gap number that mixes all three lanes. Run against test domains, it also prints "clean" next to missing inbound controls, reports a failed DMARC or SPF lookup as missing with no warning, and reports a failed existence lookup as "did not resolve". Includes D1, Abhi's decision that a revoked or malformed DKIM key counts as an outbound gap. Approved by Abhi.
* **v5 (2026-10-16):** #6's Action PR also switches `action.yml` to `runs.using: "node24"`. GitHub removed Node 20 from runners on 2026-09-23, and our Action still declares `node20`, so every customer workflow gets a deprecation warning naming it. Our Dogfood run shows *"The following actions target Node.js 20 but are being forced to run on Node.js 24: ./"* and passes on Node 24, so the switch is proven to work. It ships in v1.9.0. Requested by Abhi.
* **v4 (2026-10-16):** adds **#4b** [WHI-273](<https://linear.app/whiteboardvc/issue/WHI-273/single-source-or-drift-gate-the-duplicated-audit-faq>), a single-source /audit FAQ. Its skills artifact must merge before **#5**, which now pins skills at #4b's merge, not `ccfdddf`, because the site's skills pin must equal the engine's. **#6**'s site PR also generates the FAQ from that artifact. **#8** now waits for #4b (one skills PR at a time). The reason: the duplicated FAQ let a false claim survive in Step 1, and would have shipped stale Step 2 wording with green gates. Approved by Abhi.
* **v3 (2026-10-16):** scope addendum to #4. [WHI-190](<https://linear.app/whiteboardvc/issue/WHI-190/the-audit-page-reports-a-failed-dns-lookup-as-a-missing-record-the>) also fixes the existence pre-check, which showed "Couldn't find that domain" on *failed* lookups (live on `dnssec-failed.org`).
* **v2 (2026-10-16):** the build order becomes priority plus prerequisites (the start rule).
* **v1 (2026-10-16):** first version, approved by Abhi.