computedriven computedriven/docs/failure-model.md
Invariant under design (from review): Carrier Loss Finality — loss of a Carrier may invalidate an attachment, but neither loss detection nor replacement may itself create or res…

R0.4.2 failure model — written before the mechanism

Invariant under design (from review): Carrier Loss Finality — loss of a Carrier may invalidate an attachment, but neither loss detection nor replacement may itself create or restore authority.

Failure classes, distinguished

#ClassCarrier stateAttachment capabilityClosable by
1Orderly releasealiveheld livedetach() — the existing path, unchanged
2Local process/supervisor deathhardware alivelost (move-only value died with process)recover_attachment(CarrierCustody, &LifecycleAdmission) — custody exists only via a consuming suspend(), so an unplanned death leaves none; then orderly detach(). Otherwise SupervisorAttestation if the embodiment is unrecoverable. Not recovery from the evidence log: that path was reconstitute, deleted in R0.4.3 because it minted possession from knowledge
3Physical Carrier lossgonegoneloss finalization on a PhysicalDecommission basis (out-of-band witness) or FencingEpoch
4Network partitionalive, unreachableheld by A, unreachableNOT closable. The attachment stands. B is blocked. This is the design's load-bearing refusal.
5Ambiguous (A may be alive)unknownunknownonly a deliberate decision by the deployment's designated finality authority, expressed as a FencingEpoch advance; never by observation of unreachability

What is admissible as loss evidence

LossBasis deliberately has no Unreachable / Timeout / PingFailed / RouteWithdrawn variant. "I cannot reach A" is class 4 or 5 and closes nothing. A partition therefore cannot be used to steal a Locus: the strongest thing unreachability yields is an unclosable generation.

Identity vs validity (requirement 7)

Fencing epochs live inside LossBasis::FencingEpoch, i.e. inside closure evidence for one generation. LocusId, NodeId, WorkerId carry no epoch and never expire. Attachment validity may be fenced; identity is not lease-based.

Authority isolation (requirements 4–5)

Worker authority (Evidence/reconstruct) and carrier lifecycle (LifecycleEvent/replay_lifecycle) remain disjoint type families. Loss finalization and replacement appear only in the lifecycle family, so they cannot mint, widen, refresh, or restore Worker authority even by accident: reconstruct never reads lifecycle events. A replacement Carrier holds exactly the authority reconstructible from independently admissible evidence — usually none.

What R0 does and does not claim

R0 implements the evidence shape and replay semantics of loss finality, with in-process unforgeability (private constructors, capability objects). It does NOT implement a distributed lease/fencing protocol, and does not claim split-brain safety across independently maintained logs: the FinalityWarden capability stands in for "the deployment's designated finality authority", and its uniqueness/distribution is a deployment concern — the same stated limit as genesis. Within any single log, replay serializes: conflicting finalizations and double-takeovers are rejected.

The finality trust boundary — what a LossBasis value actually is

Established as an explicit scope boundary by R0.7's negative control NC1, which deliberately finalized a Carrier that was alive, running and reachable. `cd-core` did not refuse it. That is not a defect, and the distinction is load-bearing enough to state in one sentence:

LossBasis::PhysicalDecommission is an admissible finality basis attested through a trusted finality boundary. It is not a sensor result. It does not mean cd-core independently measured that a process died.

What cd-core verifies is lifecycle and provenance: that the admission is current, that the locus and mark match, that the named carrier is the live one, that the generation is the current one, and that a fencing epoch strictly increases. What it cannot verify, and must not try to, is the external physical fact. It has no sensor, and giving it one would be the error the whole model exists to refuse — a liveness signal accepted as a lifecycle input is a reachability fact promoted to authority, which is exactly what LossBasis has no variant for.

So the guarantee divides cleanly:

  cd-core guarantees      no reachability fact is an admissible basis
  the deployment supplies the attestation that a basis is true
  the harness measures    whether that attestation matches reality

R0.7's harness independently measured process absence over a plane the network faults do not touch, and refused the run when the measurement disagreed with the attestation. That gate is experimental evidence supporting the finality input. It is not a hidden cd-core guarantee and must never be described as one.

FinalityWarden already stands in for "the deployment's designated finality authority" (see the section above); this is the same boundary seen from the evidence side rather than the capability side.

Future terminology, deliberately not acted on now. DecommissionAttestation would say what the value is more honestly than PhysicalDecommission does, since the value is a claim by an authority rather than an observation. The enum is frozen and churning a frozen API for nomenclature is not worth a round; recorded here so the option is not lost.

Falsifiers this model must survive (implemented in R0.4.2)

  1. Partition alone: B cannot attach solely because A is unreachable.

  2. Stale loss evidence cannot close a newer generation.

  3. Two finalizations of the same generation: second is rejected in replay.

  4. Replacement grants zero Worker authority by itself.

  5. Revoked authority stays revoked through replacement.

  6. Recovery cannot mint a new generation.

  7. Orderly detach still works, unchanged, including mixed logs.

Open in the interactive atlas