Key the projection by incarnation; publish Expected after the brake; consume commands once; add cancel

The projection kept one Expected/activation/lease slot per target. A
deployment's Sealing overwrote that slot with the candidate's Expected, the
incumbent failed activation-expected-projection on its next heartbeat and
exited, the deployment was aborted for having killed its incumbent, and the
command -- left resident after its transaction was retired to history --
read as queued and was frozen again. Odin cycled on that every few minutes.

- Topology driver records are keyed {target}@{expected sha}; the incumbent and
  the sealed candidate are projected side by side. One CAS mutation replaces
  the six bespoke loops. withdraw_incarnation removes only one incarnation;
  demote_to_expected_only replaces restore_admitted_expected_only and is used
  only for an incarnation whose process is gone. Legacy target-keyed records
  are retired on the first publish for that target.
- receive() takes the incarnation; the read-as-absence compensator for a
  correlation about another incarnation is gone.
- Candidate Expected is published as Starting's first step, after the brake
  admitted the transaction, not in Sealing before it.
- A pre-fencing abort withdraws only the candidate; a post-fencing abort also
  demotes the stopped incumbent.
- A consumed command is archived with its last transaction; status still
  answers for it from history.
- An engaged lifecycle brake stops continuity being minted instead of parking
  a transaction on the target.
- idunn cancel <command-id> retires a queued command as an operator refusal.

Verified with cargo test --lib in rust:1.95-bookworm on yggdrasil: 114 passed,
2 ignored.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-09-10 22:22:46 +02:00
commit 903e1c8e63
5 changed files with 1004 additions and 717 deletions

View file

@ -100,6 +100,24 @@ Every Idunn-managed deployment has an Odin-visible expected projection before
dependent services are promoted, and an Odin-observed runtime projection before
they are considered ready.
### Projection keying
The three truths are per incarnation, and so is the projection. Every
Expected, activation, and write-lease record Idunn publishes is keyed by
`{target}@{expected projection sha256}`; only the runtime presence trust
anchor is keyed by target, because it is provider lookup material shared by
every incarnation. Odin keys its presence and correlation records the same way
and reads Idunn's projection by that key.
A target being replaced therefore has two incarnations projected side by side:
the admitted incumbent under its key, the sealed candidate under its own.
Publishing the candidate cannot change what the incumbent reads about itself,
withdrawing a failed candidate removes only the candidate's records, and a
correlation Odin holds about one incarnation is never mistaken for evidence
about another. A record of those three types keyed by the bare target is the
shape of an earlier single-slot projection; Idunn retires such records the
first time it publishes for that target, and Odin never reads them.
## Source-owned deployment declaration
Each deployable repository publishes one small, reviewable declaration at a
@ -227,8 +245,10 @@ For a singleton incarnation:
root-owned actuation stage. The privileged driver never opens Git.
4. Build, test, and package inside the bound runners. Seal the artifact,
declaration, binding, launch contract, and input digests.
5. Derive and publish the release-bound Expected incarnation from the validated
sealed release and its exact compiled plan.
5. Derive the release-bound Expected incarnation from the validated sealed
release and its exact compiled plan. Publish it only once the deployment
brake has admitted this exact transaction, under the candidate's own
incarnation key, beside whatever the target's admitted incarnation projects.
6. Issue one opaque runtime-instance activation bound to the Expected digest,
pass the exact Expected and activation documents through the actuator's
isolated credential mechanism, and start the candidate privately. It has no