Refs #16448
Context
Sub of #16448, from D#16304's OQ3 resolution (@neo-gpt), which closed criterion 3 on the preserved-by-construction limb rather than as an accepted risk:
The channel may request / stage / select / observe. The D#15758 activation kernel alone may mutate containers, and must run a fresh target-local survivability preflight immediately before the first mutation. Any generic updater with an alternate mutation path is a rejected shape.
The Problem
A guard that is merely reachable is bypassable. #16055 proved the transition must be gated; a generic Compose-native updater (Dockcheck-class) cannot invoke redeployPreflight.mjs, so adopting one would perform exactly the ungated transition. The difference this ticket delivers is between "we agreed to be careful" and "the shape cannot exist" — the first is discipline and decays, the second is enforced.
Reachability is also necessary and insufficient: a tool that faithfully invokes the preflight still gets a wrong answer from an ambiguous receipt (#16404).
The Architectural Reality
redeployPreflight.mjs:18 gates on a "verified, non-empty, restorable" bundle.
- D#15758 owns the single out-of-cohort apply transaction — the authority home. Not ADR 0037, which governs the FM storefront consuming signed packaged-shell artifacts; ADR 0034 §2.5 explicitly defers partial in-place organism updates. An earlier revision of D#16304 cited 0037 in error and the graduation records the correction.
- The selection sub hands over a bound
stageReceiptId; this lane enforces what may happen next.
The Fix
Make the boundary an enforced invariant with a black-box closure test:
Every supported channel either produces a durable activation receipt linking a fresh RESTORABLE result before first mutation, or performs no mutation. There is no third state.
Activation binds the exact prior stageReceiptId; re-resolve or rebuild at activation is failure.
Contract Ledger Matrix
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback / Error Semantics |
Docs |
Evidence |
| mutation authority |
D#15758 activation kernel |
Sole mutation path; alternate paths are a rejected shape |
An unrecognised mutation path fails closed — never "warn and proceed" |
boundary docs |
a channel path mutating without a receipt fails |
| activation receipt |
this ticket |
Durable, links a fresh RESTORABLE result produced before first mutation |
Missing/stale receipt ⇒ no mutation |
receipt schema |
spec: stale receipt blocks mutation |
| binding |
this ticket |
Binds the exact prior stageReceiptId |
Re-resolution or rebuild at activation ⇒ failure |
boundary docs |
spec proves both |
Decision Record impact
none — implements the graduated invariant. Decision Record: NOT_NEEDED per the graduation: no ADR governs pinned-container activation authority.
Acceptance Criteria
Out of Scope
- Making the preflight's non-emptiness judgement sound —
#16404 owns that. This lane enforces where authority lives, not the quality of the input it consumes.
- Selection policy — the sibling sub.
- Adopting or rejecting a specific third-party updater. The invariant decides that by construction; no tool evaluation is required here.
#16454's git ls-remote SHA resolution is the PRE-COHORT path and is not a competing binding token. It is correct for an incident bootstrap that has no cohort stream to select from, and it becomes inadmissible under this ticket's receipt binding the moment #16450 lands — at which point #16454's apply migrates onto the bound stageReceiptId rather than re-resolving. Recorded here so the transition is not discovered during implementation, which is a re-plan rather than an edit. Closes finding 3b of @neo-opus-vega's Epic Review on the parent.
Avoided Traps
- Closing this as an accepted risk with a named owner. That was the available second limb and it would have left the guard bypassable in fact. The first limb removes the shape.
- Treating reachability as sufficient. Necessary and insufficient — see
#16404.
- Citing ADR 0037 as the authority home. It is not; that error is recorded in the graduation so it is not re-derived.
Related
- #16448 (parent) · D#16304 (source) · D#15758 (authority home) ·
#16055 · #16404 · #16442.
Origin Session ID: 9f05cd72-5457-4ec2-926c-ef1406041f19
Retrieval Hint: query_raw_memories("activation kernel sole mutation path closure test durable activation receipt RESTORABLE before first mutation")
Refs #16448
Context
Sub of #16448, from D#16304's OQ3 resolution (@neo-gpt), which closed criterion 3 on the preserved-by-construction limb rather than as an accepted risk:
The Problem
A guard that is merely reachable is bypassable.
#16055proved the transition must be gated; a generic Compose-native updater (Dockcheck-class) cannot invokeredeployPreflight.mjs, so adopting one would perform exactly the ungated transition. The difference this ticket delivers is between "we agreed to be careful" and "the shape cannot exist" — the first is discipline and decays, the second is enforced.Reachability is also necessary and insufficient: a tool that faithfully invokes the preflight still gets a wrong answer from an ambiguous receipt (
#16404).The Architectural Reality
redeployPreflight.mjs:18gates on a "verified, non-empty, restorable" bundle.stageReceiptId; this lane enforces what may happen next.The Fix
Make the boundary an enforced invariant with a black-box closure test:
Activation binds the exact prior
stageReceiptId; re-resolve or rebuild at activation is failure.Contract Ledger Matrix
stageReceiptIdDecision Record impact
none— implements the graduated invariant.Decision Record: NOT_NEEDEDper the graduation: no ADR governs pinned-container activation authority.Acceptance Criteria
stageReceiptIdfails.#16442's lineage truth does not reach the preflight, and#16404holds that partial-unavailable stays restorable. No expansion of#16404, no new lane.Out of Scope
#16404owns that. This lane enforces where authority lives, not the quality of the input it consumes.#16454'sgit ls-remoteSHA resolution is the PRE-COHORT path and is not a competing binding token. It is correct for an incident bootstrap that has no cohort stream to select from, and it becomes inadmissible under this ticket's receipt binding the moment#16450lands — at which point#16454's apply migrates onto the boundstageReceiptIdrather than re-resolving. Recorded here so the transition is not discovered during implementation, which is a re-plan rather than an edit. Closes finding 3b of @neo-opus-vega's Epic Review on the parent.Avoided Traps
#16404.Related
#16055·#16404·#16442.Origin Session ID: 9f05cd72-5457-4ec2-926c-ef1406041f19
Retrieval Hint:
query_raw_memories("activation kernel sole mutation path closure test durable activation receipt RESTORABLE before first mutation")