The wait spacing a challenge whose record failed to land was removed only
when a challenge record for that target landed. It now carries the stamp of
the target's stored records (generation, meters, transactions) as they were
when the record failed, and the supervision pass drops it as soon as the
stamp differs: any write for the target landing, or the target retired or
withdrawn, returns the schedule to the stored value. A wait can no longer
hold a drift repair after the disk recovers.
Soul's probes become tests named for the rules: one reload per wait for a
re-drifting fragment, a proved wait of one observation age, a failed wait
that follows the stored doubling, a lost race leaving no wait, the wait
ending on a landed write, the wait ending with its target. The reloads()
helper is gated to unix (its use of the route stubs broke the Windows
--lib --tests check). Comments on the wait field and the failed-challenge
record now say what the code does.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
reloads() reads unix-only route stubs and has broken
`cargo check --target x86_64-pc-windows-gnu --lib --tests` since 8212b9d.
Gate it, and add that check to scripts/verify.sh so unix-only test code
cannot leak out of its cfg unnoticed.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The store error chain carries a fresh temp file name per attempt, so the
report-once key never matched twice. Report the root cause.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
replace_generation now tells a lost compare-exchange (another writer moved the
store: the pass ends and re-reads) from a write the store refused.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A supervision pass whose challenge record could not be written reported
progress, so serve() skipped its sleep, and the challenge wait lived only in
the store: a drifted fragment with a failing reload was reloaded every lap.
Progress is now a record that landed; the wait is also held in memory per
target until a record lands; the failed write is said once per target.
The stopped-restarting message says when the route ceiling reopens when the
ledger is full, so "free for a deployment" is true.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Continuity restarts are Survival; Survival counting is best-effort when
the ledger cannot record it, Forward stays fail-closed (2026-09-30).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The route gate derives the charge from the transaction's command kind: a
continuity's preflight and install are Survival (never refused, counted), only
a deployment's are Forward. A Survival that cannot be recorded is logged and
proceeds; a Forward that cannot be recorded is refused. A proved route
challenge whose write is lost ends the pass like a failed one instead of
failing it. status() draws its target union from one function.
Tests: continuity through a full ledger, uncounted survival vs refused forward,
the second-failure wait, the lost proved-challenge write, each v3 route
supervision field, and the admitted-or-metered union. The routed world takes a
command kind, so the refusal tests run as deployments.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Soul found W1 unenforced, T1 respelled in the validator and two T2 rows
unpinned; all fixed with mutation-killed tests (1afe046).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
cargo-mutants-style probe C26 (the resume backoff read without its longest
wait) survived: the clock-step test called is_waiting directly, not the resume
site. An Engine-level test now sets a real half-minute backoff, which holds,
and a day-ahead one, which is attempted.
docs/host-actuator.md said continuity gives up after three attempts; it is six
restarts inside an hour.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The probe at d32395a hung inside a library test and never reached the
Windows check. The check is fast and independent of the tests, so it
goes first and cannot be masked by a hang.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The resume backoff, not the ceiling, spaces the cleanup retries after the
abort is recorded; the test asserts the abort at once and then steps it out.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The workload rows were refused by the fixture on grounds outside the
rule, so they were dropped instead of asserted. The workload operand of
the owed rule stays pinned by the method-level test.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
live_entries only reads future entries as now, so a log that is never
written kept looking recent until the clock caught up: a refused route
actuation or an exhausted restart log stalled for the length of the step, not
one window. A refused forward actuation now writes the clamped log when it
changed, and a supervision pass settles the target's meters before deciding
from them, ending the pass with the write. The restart due time comes from the
raw last entry so the longest-wait guard is the one deciding a stepped-back
wait.
Also: the ported restart test tolerates an empty live set, the refused-preflight
test reads the transaction from history, and a held-record test no longer
depends on the host having no nginx.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A transaction holding a workload and no activation is refused by the
fixture before the cleanup rule is reached, so those rows could not
speak for the rule. The method-level owed test keeps the workload-only
case.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The route-proof world's hand-built promotion is deleted: the world runs over
stub host programs, so Routing installs and proves the route for real and
every former promote_by_hand is a real step. The salvage fixtures of the old
B2 are not ported.
New tests pin each ruling under its own mutation: a full ledger still admits
and counts every survival actuation, first deployments are metered, a refused
preflight starts no private-mount unit and fails at once with the reopen time,
the actuation log slides, a clock step stalls nothing past one window, a
failed challenge ends the pass instead of losing a CAS, a proved challenge
clears the degradation, both storms are bounded, restarts are spaced,
counted in the mint and read from the target's own log (unreadable history no
longer stops crash recovery), and the v3 lift is pinned over golden bytes cut
with the 583b2a7 encoder, refusing a record that shows retired meters.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The Pending post-fencing rows sat in a Fencing-phase transaction that is
refused for unrelated reasons, so the row could not say what it claimed.
Post-fencing rows now cover the recorded values a terminal abort carries.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Rows for a vertical tab before an extension, a carriage return before an
extension, and a size line ending in one or two carriage returns, so a
wider trim than SP and HTAB, or a stripped trailing carriage return,
cannot be taken.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The pre-fencing validator respelled the owed rule inline. Both abort
validators now compare against candidate_cleanup_owed, so the post-fencing
abort, which had no check on its recorded candidate cleanup, is held to
the same rule. One test drives both aborts through every activation and
workload row.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
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>
The Windows check on idunn-host lived only in README prose, so nothing
ran it and d32395a broke the Windows build unnoticed. verify.sh runs the
library tests and the x86_64-pc-windows-gnu check of idunn-host, and the
README names it as the verification command.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Records Q-O1 (Idunn proves; supersedes Q1 (b)), Q-O2, Q-O4, Q-O5 and the struck
Q-B4 held clause; Q-O3 open. Adds the audit site table and target authority
map (section 5), cuts X1, A1, B4prime, A2, A3, O-R, L-R, marks R1 superseded by
A1, records Odin's temporary fatal rule and the Soul open items, and updates the
Cut status block.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A target's route actuations and continuity restarts are sliding logs in one
TargetSupervision record (idunn.target_supervision.v1), created by the first
charge so first deployments are metered. The route driver asks a
RouteActuationGate before every group of host mutations; Forward changes can
be refused with a typed RouteActuationRefused, Survival ones (restoring the
admitted or incumbent route) are always admitted and always counted.
Generation moves to v4 with a typed lift from v3 that retires keys 18 and 20,
refuses a record showing the retired meters were written, and adds last_error
at key 21. Continuity restarts are counted in the mint CAS against the
target's own log; the history scan and both carry compensators are gone. Any
write to a generation or to its target record ends that target's supervision
pass. A due time further ahead than its owner's longest wait reads as due.
Tests do not build in this commit; the next one rebuilds them.
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>
RFC 9112 7.1 allows whitespace before a chunk extension and nowhere
else. The reader trimmed both ends of the size, so " 3" and "3 " were
taken. It now splits at the first ';', trims trailing SP and HTAB only
when an extension follows, and leaves parse_digits as the digit
authority. Rows use an honest body so only the size line differs.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The two-flag helper let either call site swap or fold an argument
unnoticed. DeploymentTransaction::candidate_cleanup_owed reads the
transaction itself, and a four-row table drives the method and both
intents.
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>