diff --git a/docs/remediation/BOARD.md b/docs/remediation/BOARD.md index 149424d9..cbf39eef 100644 --- a/docs/remediation/BOARD.md +++ b/docs/remediation/BOARD.md @@ -31,8 +31,8 @@ three times in one session by duplicating that table (D-26's class). Read the table. ⚠ **And re-derive any board claim from the provider before load-bearing use (D-43)** — the board is sole-written and has no independent verifier. -2. **`docs/remediation/TASKS.md` is authoritative**, not the newest voice in a chat. It holds 54 findings - (D-1…D-6 in `BOARD-LEDGER.md`, D-7…D-53 + D-38c in TASKS.md), every ruling with its rationale, and the +2. **`docs/remediation/TASKS.md` is authoritative**, not the newest voice in a chat. It holds 55 findings + (D-1…D-6 in `BOARD-LEDGER.md`, D-7…D-54 + D-38c in TASKS.md), every ruling with its rationale, and the requirements each finding placed on RM-02/RM-34/RM-50/RM-55. 3. **`MISSION.md` carries the first-class principles** — read them there, they are not listed here. Two added 2026-08-01: **the anchor must live outside the audited party's authority** (D-19/D-25/D-45, @@ -78,6 +78,6 @@ Roster rolled verbatim to [`BOARD-LEDGER.md`](./BOARD-LEDGER.md); live truth is ## Decisions log — full record in [`TASKS.md`](./TASKS.md) -All 54 findings (D-1…D-6 in `BOARD-LEDGER.md`, D-7…D-53 + D-38c in `TASKS.md`) and every ruling with +All 55 findings (D-1…D-6 in `BOARD-LEDGER.md`, D-7…D-54 + D-38c in `TASKS.md`) and every ruling with its rationale live there. **Not duplicated here.** The history of _why_ this board must not restate — six stale copies across two seams — is rolled verbatim into [`BOARD-LEDGER.md`](./BOARD-LEDGER.md). diff --git a/docs/remediation/TASKS.md b/docs/remediation/TASKS.md index 73293ceb..1dc3066f 100644 --- a/docs/remediation/TASKS.md +++ b/docs/remediation/TASKS.md @@ -641,6 +641,47 @@ a fourth anchor; ran independent code + security review **on its own fix**; comm (EROFS/EPERM) rather than substituting; named exit-97 as the known **#973/D-16** limitation rather than a finding. +### D-54 — three of this mission's hardest principles appear INDEPENDENTLY in another estate's spec, and it carries a refinement we lack + +A USC-estate governance spec (`installer-7`, for their `#63` allowlist validator) reached this pane as a +role-addressed cc. **No action taken — different estate, no authority, nothing in it constrains +mosaicstack.** But it converges on three principles this mission paid for in blockers, reached by +different people solving a different problem: + +| their clause | our finding | +| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **B** — the allowlist is **data the validator READS, never data it (or the validated party) WRITES**; git-tracked, reviewed-PR only, no runtime add path. _"A validator whose permitted set can be influenced by the thing it validates is not a validator."_ | **D-45** — the anchor must live outside the audited party's authority. **Their sentence is our five-arrival principle stated in one line.** And it is RM-02 blocker 2 exactly: `REQUIRED_GATE_INVENTORY` was a mutable constant **inside the PR-controlled verifier**. | +| **D** — unreachable / missing / unparseable / **EMPTY** allowlist ⇒ **REJECT ALL**, never default-permit. _"You cannot defeat the bounded shape by making its source unavailable."_ | **D-46** — no universally-quantified check may pass over an empty set. Same vacuity, same refusal. | +| **E** — **exact** membership of the resolved value; no substring, no pattern, no "looks-close". _"The instant someone adds a 'close enough' branch, it is a denylist again."_ | **D-40** — discriminator and comparison inputs must be type-strict. | + +**Independent convergence is the strongest signal available** — the same weight this mission gave +`planner-opus`/`planner-sol` agreeing without collusion (§1, C1–C7). Three principles, another estate, +another problem, no shared derivation. + +> **★ AND THEY HAVE A REFINEMENT WE DO NOT — ADOPT IT INTO RM-02's (d)-STRICT EXCLUSION WORK:** +> **fail-closed is not the same as fail-silent.** Their clause D distinguishes two rejections: +> +> - **"read OK, owner absent" ⇒ reject, QUIET** — normal operation. +> - **"could not read / empty while enforcing" ⇒ reject AND RAISE AN OPERATIONAL ALARM** — _a missing +> allowlist in production is an INCIDENT, not a silent deny._ +> +> **Our D-46 says non-emptiness is a precondition; it does not say the precondition's own failure must be +> LOUD.** A registry that rejects everything because its population vanished looks, from the outside, +> exactly like a registry with nothing to do. **That is D-23's inert guard wearing the opposite mask** — +> not a false green, a false quiet. **RM-02's non-empty precondition and enforced exclusion must +> distinguish "correctly found nothing to permit" from "could not determine what to permit," and alarm +> on the second.** + +**Their clause D also names a deploy-order constraint worth keeping:** seed the allowlist in an audited +commit **BEFORE** switching the validator to enforcing mode — otherwise fail-closed rejects every +legitimate owner at cutover. **Seed first, then enforce.** The same ordering trap applies to any gate we +switch from advisory to blocking. + +**Routing note — SECOND instance, hours after the rule:** this arrived addressed to **"orchestrator"**, a +role existing on both estates, which is precisely what D-53 made doctrine. The doctrine has not reached +`installer-7`. **Recurrence of a just-banked defect is evidence about PROPAGATION, not about the rule** — +and it is the same gap as D-51: a fix that exists is not a fix that has arrived. + ### D-53 — a sender label that was WRONG for hours while looking exactly right `agent-send.sh` derived the **sender** label from the `-L ` flag. So a cross-socket