The retired --idunn-rudp-health family is rejected by the binary; Raven is
liveness by runtime presence, Starfire and Nightwing by witness scripts.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Splice the B2 rework map (owner map, per-file cut, verification, live
relevance, subtraction estimate) under B2; add cuts D1, T1, T2, W1 and R1;
record Q-B2-1 (a), Q-B2-2 (fail at once), Q-R1 (a) and Q-B4 (routed by
Idunn's route proof, unrouted by admission plus workload; the Odin non-Ready
veto clause held open). B4 is blocked on the Odin-lifecycle authority audit.
B2, D1, R1 ready for Hands; W1, T1, T2 in progress on hands/idunn-w1-t1-t2.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
GitHub will not answer a bare blob id through plain fetch --stdin in a
blob:none clone; Git's own lazy fetch shape does. Proven against
GameCult/CultLib on Yggdrasil for partial and full clones.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
In a blob:none partial clone, fetching bare blob ids with --stdin made Git's
post-fetch connectivity check treat the id as a revision and fail with
"bad revision" / "did not send all necessary objects" against GitHub, which
broke a live deploy fetching a vendor gitlink's blob. Add
fetch.negotiationAlgorithm=noop, --recurse-submodules=no and
--filter=blob:none, the arguments Git's own lazy fetch uses.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A file:// origin delivers an explicitly wanted blob with or without the
promisor-style flags, so the real-shape fixture cannot fail on the bug that
GitHub triggers. The spy test already records the bulk fetch line; assert
it carries fetch.negotiationAlgorithm=noop, --recurse-submodules=no and
--filter=blob:none. Fails on the current arguments.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every existing source-driver fixture uses an origin without
uploadpack.allowFilter, so --filter=blob:none is ignored, the clone is
full, and bulk_fetch_objects never has a missing blob to fetch. This
fixture advertises the filter, so the checkout really lacks the blob, and
checks delivery with GIT_NO_LAZY_FETCH=1 so only the bulk fetch can supply
it. It fails on the current fetch arguments.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The constant was unix-only since 9475dfa while its uses are not, so the
Windows idunn-host has not compiled since S1. Found installing B3: Raven's
actuator (built 2026-09-11) cannot decode the new plan types.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ReadinessClass::of is the one class authority; recipes declare readiness.
Held records are never aborted by Idunn; cancel accepts a held pre-fence
Deploy. Silent means no byte; any byte then a stop is Refused. Soul: merge
with follow-ups, safe to install on Yggdrasil.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Trailers draw on the header budget instead of an unbounded loop. Content-Length
and chunk sizes are digits only (RFC 9112), and a header name with whitespace
is refused. Pins found by cargo-mutants: partial trailer, exact bounds on all
three framings, one byte then stop, unterminated chunk from a peer that keeps
going. ChallengeFailure::Silent documents what it actually is.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Operator ruling 2026-09-30 (F4): an operator may cancel a held Deploy that has
not fenced. Nothing was fenced, so the incumbent is untouched; the pre-fencing
abort releases the target. Idunn itself still never aborts a held record: the
held_disagreement guard on the yield path is unchanged and pinned.
The P1b test now calls supervise_one_admitted_generation directly with the
redeploy in Warming over a dead held incumbent, with a positive control (the
same redeploy over a dead non-held incumbent yields).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The previous commit's over-bound case used floor(bound / line) lines, which
can still fit under the bound once the status and Content-Length lines are
counted; the answer was accepted and the test failed. It now sends one whole
line more.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Two more mutants survived: the header-size bound was only tested far from its
edge, so doubling each line's cost went unseen; and the chunked trailer loop
was only exercised with a trailer present, so inverting it went unseen. The
bound is now tested one line inside and at its edge, and a chunked answer with
no trailer is read from a peer that keeps the socket open.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The header-size bound was tested only against answers that also stopped
short, so it never had to hold on its own; the interrupted-read retry was
exercised by no reader that could be interrupted. The header test now sends an
honest, whole answer whose headers alone exceed the bound, and a scripted
reader pins the retry and the silent/refused split at the Answer boundary.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The HTTP challenge read to end of stream, so a peer that answered in full and
kept the socket open (or answered 404 and kept it open) read as silence. It
now reads by Content-Length or chunked framing, refuses any non-2xx status,
and refuses bytes that are not a CultNet frame.
One rule for both transports: a peer that sent no byte is silent; a peer that
sent some bytes and stopped is refused. A truncated TCP frame used to read as
silence; that pinned test now expects a refusal.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
A held, undeclared generation that died reached the continuity mint, which
copied the undeclared Expected, was held at once, and owned the target for
good: cancel refuses continuity, so the declaring redeploy could never freeze.
Supervision now reports a dead held generation once and leaves it down and
its target free. With no continuity minted over it, a declaring redeploy in
Warming no longer yields to one either.
The yield path also aborted a pre-fence Deploy blocker without reading its
hold, which is Idunn aborting a held record. It now leaves a held blocker
alone.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
First cargo-mutants --in-diff pass over a61540b..aa1889b left 16 misses.
Deleted:
- the candidate challenge's own route-id check: rendering the Expected next
holds the same binding, so it could never decide anything.
- odin_can_observe in advance_warming: is_odin && !(!is_odin || observed) is
is_odin && !observed; two of the misses were operators in that detour.
Moved: which transactions are held for their evidence is now
DeploymentTransaction::held_disagreement, so "finished or aborting work is
never held" is a value with a test, not a local in resume_candidate.
Pinned: the admitted-generation topology refresh (taken once, then not
again), WarmingEvidence shape checks per source, the PresenceDisagrees text,
the plan's readiness declaration needing the shared-infrastructure kind, TCP
framed challenges (exact answer, bound, empty, non-CultNet, silence), RUDP
silence, and ChallengeFailure's text and source.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Boot re-proof by tag: the held-generation test used receipts that still
re-proved cleanly (boot reads the current Odin authority, not the stored
one), so re-proving them passed. The receipts are now authentic but not
Ready, so only skipping them lets the store boot.
Config error as silence: the candidate path renders Expected first, which
parses the same endpoints, so the challenge's own parse is reached only from
the stable path. A new test drives that parse directly.
First-Odin gate by name: the stub can now answer a first-Odin Warming
challenge, and a stateful provider not named odin is accepted while a
stateful target named odin that provides nothing is refused.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Tests for each rule the Soul pass found unpinned, each written to fail
under its own mutation:
- a stateful route-proof target through the Engine, Fencing to commit: the
lease is prepared and granted, Ready is refused without the exact lease
and recorded with it, boot re-authenticates the store at every stage and
Odin is never read;
- Warming challenges once and then advances on every tick;
- a stateful candidate may not answer its Warming challenge active;
- a presence holds the write lease exactly when it is not warming, and is
minted after its challenge;
- direct Warming evidence is bound to the bytes and digest it authenticated;
- candidate-vouched evidence is refused on a target Odin reports on;
- a pre-B3 transaction and a pre-B3 generation over a route-proof target are
held and reported once, not stepped every tick, and not re-derived;
- a stored record with no declared readiness is held;
- Odin is the class OdinSelf, not the name "odin";
- admission refuses an undeclared recipe with a typed error, before the
source is frozen; a recipe that declares its proof is planned;
- the driver's challenge failures: silence waits, every bad answer and every
local configuration error is an error;
- the capacity shortfall is read as a typed PresenceDisagrees.
Deleted because another owner already holds them, so no test can reach them:
the Routing and commit "route-proof Ready evidence" ensures (validation
refuses a missing receipt, the hold refuses the other party's), the write
lease comparison's warming arm (the authenticator refuses a warming presence
that claims a lease), and the direct-Warming refresh check (rehydration
authenticates the recorded answer as Odin's first).
Engine.source is a SourcePort, the seam the admission test needs.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
ReadinessClass::of is the only class authority. A target whose recipe
declares neither a route nor an Odin dependency, and does not provide the
rendezvous, has declared no way to prove readiness: of() returns a typed
UndeclaredReadiness naming the target, and admission refuses it after plan
compile, before anything is frozen or installed. The OdinCorrelated fallback
for an unrouted target is gone.
The evidence tag no longer decides the path. Boot re-authentication and
admitted-topology refresh choose by class; a stored transaction or admitted
generation whose evidence was vouched for by the other party than its
Expected requires is a typed ReadinessDisagreement, reported once and held,
not a step that errors every tick. Nothing re-derives around it.
"Is this Odin" is the class OdinSelf, not the name "odin": validation,
warming, the Odin authority lookup and the direct-warming checks read the
class. canonical_sha256 on WarmingEvidence and the token's unread evidence
field are deleted.
A bad answer to a direct challenge is an error. The driver splits its
failures into ChallengeFailure::Silent (refused, dropped, hung up, timed
out) and ::Refused (a malformed, foreign, oversized or non-raw answer, or a
local configuration error); only Silent waits. The capacity/disagreement
shortfall is returned as a typed PresenceDisagrees, not flattened to prose.
Odin-driven fixture worlds declare the Odin dependency in Expected and the
correlation they sign names its provider.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
A continuity abort demotes the shared key to Expected-only with its own
exact activation, and never withdraws the Expected. a148802 is reverted.
Pre-B1 terminal continuity aborts keep their phase under a
LegacySkippedBeforeB1 marker that only the lift can construct. Boot
reconciliation is the single owner of legacy residue and demotes only by
exact identity. Supervision records a failed pre-restart demotion and
defers instead of minting a continuity. Scheduler faults are isolated per
transaction and backed off, reported once and kept in the record. Queued
commands freeze every tick, so one wedged target cannot starve the
others. An unreadable history fails closed for freezing. boot is a
separate, tested step.
Soul made four passes. The first found boot-wedging on legacy records.
The second traced it to Self's ruling to reopen terminal records, which
was replaced with one owner for the cleanup. Pass three found
cross-target starvation, and pass four found fault re-arming. 241 tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Fault reports clear only when a step ran and succeeded, not on a backoff
skip or a handled failure.
- Fault notes are written through cleanup_evidence::last_error_envelope, so
an unretirable pre-B1 terminal record shows its fault; a failed note is
printed with the fault instead of swallowed.
- backoff_wait and is_waiting are pure and unit-tested; tick and resume
return values are pinned.
- migrate_transaction_record is the migration's only entry; the encoder that
can write a marker is private to cleanup_evidence.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- A tick's progress is a state change, never a last_error rewrite; freezing a
queued command no longer waits on other targets' progress (still at most
one freeze per tick, busy targets refused as before).
- Failing transaction steps back off (process-local, doubling from the poll
interval to 60s) instead of retrying every tick.
- Boot reconciliation runs the resident-issuer pass with history unreadable.
- Resume and retire faults are reported once per transaction and left in
last_error, which status renders.
- The legacy marker is a private-constructor type inside cleanup_evidence;
transaction_envelope refuses a record carrying it, the schema migration
writes through its own path.
- Tests: changing-error wedge, backoff, dead-candidate post-fence branch,
fault note, marker refusal, torn-history boot residue.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
A transaction seeded at AwaitingReady fails validation (no fencing evidence),
and nothing at Fencing makes a workload error, so the post-fence abort is
begun directly and the test pins that its failing step only waits.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Cargo-mutants on the previous commit missed the per-candidate progress flag
and the post-fence branch selection in resume_candidate. A repeated error
reports no progress; a dead candidate past the fence aborts; a wedged
post-fence abort only waits.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Soul's pass on the B1 fix batch found the lift's reopen of a terminal pre-B1
continuity abort could stop Idunn booting (the reopened record claims target
authority beside a live transaction, and the store was already migrated to v4),
and that one wedged abort stopped the whole scheduler.
- The lift no longer reopens anything. A terminal pre-B1 continuity abort that
issued an activation keeps its phase and completion and carries the typed
marker CleanupEvidence::LegacySkippedBeforeB1 on its topology_reconciliation.
Validation accepts that shape only for a terminal continuity abort. Boot
reconciliation, already the exact-activation owner of that residue, is the
only cleanup path. A pre-B1 abort still in flight lifts to Pending: it
already holds its target's authority, so the lift adds no claimant.
- A failed step of a pre-fence abort is recorded as a resumable error, never
handed to the post-fence abort, which refuses a pre-fence phase and failed
every tick.
- One transaction's error no longer fails run_scheduler_tick: each candidate
is resumed on its own and its fault logged, and retiring a terminal record
tries the next one when an archive fails. An unreadable control store still
fails the tick.
- serve is boot plus the loop, so a test can run the boot sequence.
Tests pin, through the Engine: the marker and no-reopen for each pre-B1
fixture; a resident terminal abort plus a live transaction plus a second
resident abort for one target; a withdrawn incarnation never re-published and
history keeping one copy after a crash between the archive steps; a wedged
abort leaving freezing alive; an unarchivable terminal leaving resume alive;
and boot demoting the residue.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
cargo-mutants over the batch's diff missed the lift's gate, the unexplained
projection accounting, the refusal count and the deferral clock. Tests now
cover each: the lift owes only a continuity that issued an activation; a live
transaction accounts for its own activation and nobody else's; three refusals
in history hold the restart ceiling; the deferral lands between now and now
plus its length.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Soul found B1's rule sound and its transition unsafe. This makes the rule's
old inputs impossible to reintroduce a stuck state from.
- The control store's legacy lift owns the transition. A pre-B1 continuity
abort that issued an activation lifts with topology_reconciliation Pending,
so the one resolution demotes its own activation. A record already terminal
under the old rule is reopened at Starting, since a terminal record cannot
owe work. History lifts records as written. Before this, one resident
record of that shape failed validation and ControlSnapshot::read refused the
whole store, so Idunn could not boot.
- Supervision owns the Expected-only precondition. When its pre-restart
demotion fails it mints no continuity and writes next_restart_at_unix_millis
on the generation's ContinuityBackoff (attempts and window untouched), so it
neither restarts over an undemotable projection nor retries every tick.
- Boot reconciles once: a projected activation that exactly matches the
activation a failed continuity in history (or a resident terminal record)
issued is demoted. Nothing is adopted; an activation no admitted generation,
live transaction or failed issuer accounts for is reported and left alone.
New read-only CultCacheTopologyDriver::projected_activation.
- Unreadable history.cc fails closed. The continuity restart ceiling and the
consumed-command check no longer read an empty history; they stop, and the
fault is reported once while it lasts (ReportOnce). The undecodable-record
report is a pure function, pinned.
- docs/deployment-authority.md no longer says the projection never drifts.
Tests: legacy fixtures written by the 9001b58 encoder for the three abort
shapes (a second throwaway generator, see the fixtures README), driven through
the Engine; the seeded-transaction helper now takes a command kind and an
incumbent, and a Deploy carries a frozen-source receipt and a signed brake
release, so Deploy commit, Deploy pre- and post-fence aborts and a continuity
abort over an incumbent run through the real phase machine.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The generation moves to v3 and the transaction to v4. They carry
ReadinessEvidence (the class is derived from Expected by ReadinessClass::of),
phase deadlines owned by one writer (enter_phase), RouteSupervisionState,
ContinuityBackoff, LeaseAdoptionEvidence and TerminalRecovery. The plan
moves to v3 with frozen deadline durations. A boot migration lifts every
legacy record with stored_at preserved. No decision reads the new fields
yet, so behaviour does not change at this cut.
Soul closed it after one fix batch. The first pass found every commit and
post-fence abort wedged by a deadline nothing cleared; Engine tests now
drive admissions and aborts to Complete. 204 tests. Filed forward: B3 must
give Odin its own readiness class before any route-proof admission ships,
or boot wedges; an unreadable history.cc must fail closed (B1 fix batch).
Back up control.cc before deploying: an older binary refuses a v4 store.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>