diff --git a/docs/remediation/TASKS.md b/docs/remediation/TASKS.md index 1f7d5dd1..5d8d3c82 100644 --- a/docs/remediation/TASKS.md +++ b/docs/remediation/TASKS.md @@ -93,6 +93,45 @@ and must not be cited as merge evidence. Rely on reviewer clearance + real CI. Three independent live instances in a single session — format gate, agent context reset, queue guard — is the class confirmed, not anecdote. +### D-19 — an integrity property that cannot exist at the layer it was specified + +Implementing D-18's manifest, the seat + a Codex security review reached **CWE-345**: the symlink +manifest and the source-hash marker both live in the **same same-UID writable generated tree**, so an +actor with that UID can plant a rogue link, regenerate _both_, retain the fingerprint, and pass. **No +local cryptographic construction fixes self-authentication** without a key outside that actor's +authority; relocating the marker changes the path, not the authority. + +The seat **escalated rather than describing self-authentication as tamper-resistant** — the explicit +failure mode the charter corollary demands. That is the corollary working, on its first real test. + +**Ruling — Option A: scope AC2 to accidental / independent / stale mutation; retain the design.** +Rationale, recorded so it can be challenged: + +1. **The undefendable boundary is not the weak link.** An actor with same-UID write can already edit the + source, the tests, `scripts/preflight.mjs` itself, and `.husky/*`. If they have that, _nothing_ in the + local checkout is trustworthy — hardening the manifest buys no real security while **implying + protection that does not exist**, which is worse than the gap. +2. **What AC2 is actually for.** These checks exist because a five-month-stale `.next` produced 19 + phantom `TS2307` errors indistinguishable from real ones (**D-5**). That is staleness, drift and + foreign residue — and against that class the design demonstrably works. +3. **A real trust anchor arrives later, from this mission's own architecture.** An anchor must live + outside the actor's authority; for a fleet running as one user that means a separate service — + precisely the **choke-point executor + PG spine** of Builds 1–2, which verify outside the worktree's + authority. Hand-rolling key distribution for a local preflight now would duplicate that work badly. +4. Option C (structural policy, no manifest) is strictly worse — it cannot detect a **removed** expected link. + +**Option A is acceptable only with honest labelling**, or it becomes the disease it is meant to cure: +the threat model stated verbatim in the code _and_ the PR ("does **not** defend against same-UID write; +no local construction can"), the words _tamper-proof / tamper-evident / secure_ barred from that +context, the scope carried in AC2's restatement, the residual risk named as a backlog item pointing at +the spine work, and every existing control kept RED-first. + +**The generalizable rule.** When a required property **cannot exist at the layer where it was +specified**, the honest moves are: implement what the layer _can_ guarantee, **state the boundary +precisely**, and record where the real guarantee will come from. **A known gap that is written down is +acceptable; a gap that is implied fixed is not.** Silence here would have shipped a verification +artifact that verifies nothing — with a green to prove it. + ### D-18 — two pre-registered criteria were mutually unsatisfiable, discoverable only at implementation Implementing D-17's fix surfaced a conflict **between** pre-registered criteria: