First typed Eureka campaign (idunn-watchdog). The typed target and rulings
live in Eureka's mind; this doc holds the rationale and design truths.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A deadline resolver runs before a live post-fence transaction's step. Once
the phase deadline F0 stamps on entry has passed, or an operator has asked
for it with `idunn expire`, the phase is resolved as Q3 rules:
- A candidate never issued a write lease (every stateless target, and a
stateful one still in Fencing or early Leasing) aborts to the incumbent
through the existing post-fencing path.
- A continuity always aborts: its candidate is the admitted release, and
supervision restarts it under the continuity backoff. A granted lease
with no adoption evidence names the failure `lease-not-adopted`.
- A deployment whose candidate was issued a lease is reported and left to
the operator. That is the open fork: what holds the incumbent after an
adopted-lease deployment, and whether a warming candidate's silence is
evidence of non-adoption, are not ruled.
Resume paths cannot extend a deadline: only `enter_phase` writes it. A
record lifted from before deadlines existed is timed once, from the first
time the resolver sees it.
Lease adoption is recorded with Ready (the candidate's presence, or Odin's
Ready correlation, held exactly the granted lease), and the terminal
record names `RestartAdmitted` for a continuity whose candidate adopted it.
F16: Commit goes on from the topology it admitted instead of returning, so
Odin re-stamping every tick no longer sends it round forever.
`idunn expire <command-id>` writes an `idunn.expiry_request.v1` record and
nothing else; the resolver reads it as a passed deadline, and a spent
request is deleted. A new control-store document type: an Idunn from before
this commit refuses a store holding one.
Tests commit Soul's F1 and F2 probes: a continuity whose route proof keeps
failing ends at its Routing deadline, and a withdrawal whose `ufw delete`
keeps failing reloads once.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`install` and `restore` skip the write, the firewall step and the reload
when the fragment on disk already equals what they would write. `restore`
still withdraws the endpoint when the prior membership is none, so a
withdrawal whose `ufw delete` failed repeats only that step.
That skip is sound only while bytes on disk are what nginx last loaded, so
every write whose reload fails is now undone: `restore` puts the previous
fragment back, and `install` puts the baseline back in both the rollback
and the fenced case (it used to retain the candidate for retry, which the
retry would now take for live). An install that never loaded needs no
reload to roll back.
Tests: a retry with an already-correct fragment performs zero reloads (install
and a withdrawal with a failing `ufw delete`); a failed reload puts the
fragment back so the retry reloads. Two engine tests that counted a reload
for withdrawing a never-installed route now count the endpoint withdrawal.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Operator ruling 3d A. Survival actuations are recorded, never counted or
refused. Soul: verify.sh clean at 057bdd5 (341); own mutants killed. Known,
not new: Survival retries inside one transaction reload nginx unbounded
(~120/h per target) until B5, which is the next Idunn cut. Operator
approved installing B2 ahead of B5 (2026-09-30).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
cargo-mutants on the 3d diff missed `|| -> &&` in render_supervision: no
test held meters with only survival entries under an unrouted generation.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ruling 3d A (2026-09-30): the 12/h per-target route actuation ceiling
counts only Forward actuations (deploys). Survival actuations (continuity
restarts, rollbacks, withdrawals, admitted-route repairs) are recorded for
visibility in a separate TargetSupervision.route_survivals log (key 6,
newest 12 kept) and are never counted against the ceiling or refused by it.
A target whose continuity spent its six restarts can therefore always be
rescued by a deploy.
Each Survival path keeps its own bound: a continuity's actuations the
restart log and its doubling wait, an admitted-route repair the challenge
backoff, a deployment's rollback or withdrawal the Forward change it
undoes. A candidate whose route proof keeps failing now reloads at most
twice the ceiling per window (12 installs, each with its rollback) instead
of 12.
status prints the survival record beside the ceiling line.
TargetSupervision stays at v1 with the added slot: no installed Idunn has
written the record (B2 is merged, not installed).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Operator: "do map the cut that'll ensure it doesn't happen again". Q3 A is
ruled (rotate before prod); Q1 A and Q2 A are Self defaults.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
TargetSupervision holds a sliding actuation log and the continuity restart
log (Q-B2-1 a); Forward can be refused (fails at once with the reopen
time, Q-B2-2), Survival is never refused and counted when it can be;
continuity restarts are Survival; a full disk neither spins supervision
nor reports unlanded writes as progress. Generation v4 with a typed lift
from v3 (irreversible; back up control.cc and history.cc before install).
Four Soul passes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
continuity_gives_up_on_a_release_that_will_not_start came from main with the
old rule (three failed restarts per generation, counted from history). The
branch owns the ceiling in TargetSupervision meters now (six per window), and
the test exercised no production code: it filtered transactions in a local
closure and compared to the constant, which the meters changed.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
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>