Commit graph

591 commits

Author SHA1 Message Date
Meta Vens
d9846e8847 Cut c2c: route-continuity invariant 5 states the continuity forward retry
A continuity past its post-fencing deadline is left to the operator and retries
forward on a capped backoff; a stateless deployment aborts to its incumbent; a
stateful deployment is left to the operator (ruling post-fence-forward-retry).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 18:39:33 +02:00
Meta Vens
bff308aea7 Cut c2c: expire's refusal names its reason without reading the deadline predicate
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 18:39:32 +02:00
Meta Vens
18c5b643a7 Every persisted detail goes through bounded_detail; delete truncate
require_detail judges bytes, truncate cut chars, so a long multibyte build
error made the abort write invalid and wedged the record in Sealing.
bounded_detail keeps head and tail within 2048 bytes, drops NUL, and
never returns empty. Also bounds gate-wait notes, cancel notes, and the
continuity deferral reason at their writers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 18:37:38 +02:00
Meta Vens
cc4a72ad43 Cut c2c: a record left to the operator backs off to the continuity cap
ResumeBackoff stores the ceiling it was armed with and the skip check reads it.
resume_ceiling is the continuity cap (300 s) for a record that leaves_to_operator
and the short cap otherwise, for every such record: a forward-retrying
continuity, a stateful deploy, a wedged abort, a drain. A step that returns Ok
without moving a record left to the operator is backed off like a failed
attempt, so a silent candidate is challenged once per backoff, not every poll.
Nothing in TargetSupervision is touched.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 18:37:03 +02:00
Meta Vens
81ab69046b Negative test: long multibyte sealing failure must abort and free the target
Fails at 5b421c3 (abort write refused by require_detail).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 18:36:55 +02:00
Meta Vens
063409489e Cut c2c: a continuity past Fencing retries forward and pages, never aborts
PhaseEnd::RetryForward: phase_end answers it for every continuity at or past
Fencing, because aborting restores the body its candidate already runs (ruling
c2c-retry-decided-by-record). The resolver leaves it to the operator
(operator-required incident, report_once) and the phase step keeps running.
leaves_to_operator covers it. DeploymentTransaction::expirable is the one
spelling the expire CLI, the spent-request retirement and the resolver's
requested flag read: a continuity past Fencing cannot be expired. Deploy keeps
abort-to-incumbent and the stateful operator-required arm.

Tests: the PhaseEnd table, the Routing deadline forward retry and its incident
episode, the stateful deadline, expiry refusal and spent-request retirement,
and a deployment still aborting to its incumbent. Abort-mechanics tests begin
their aborts directly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 18:33:29 +02:00
Meta Vens
58f213fe15 Cut c2c: boot lift returns a wedged continuity abort to forward retry
A pre-c2c Idunn aborted a continuity at its phase deadline, which stops the
only running copy of the admitted body. At boot, a continuity abort that has
not stopped its running candidate (candidate_cleanup Pending, lease_withdrawal
not Complete, workload observed, issued lease exact on disk) is withdrawn and
the record retimed, the exact inverse of begin_post_fencing_abort. Negative
tests carry the live shapes of tx-4eaed669 (Routing, adopted lease) and
tx-039b91e9 (AwaitingReady, granted lease); the lift's refusals are pinned per
predicate input.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 18:24:22 +02:00
Meta Vens
8230c544ac Cut c2b fix: a pre-fencing abort keeps its deadline through its last cleanup write (a Sealing waiter's abort could not finish) 2026-10-19 17:58:13 +02:00
Meta Vens
9844806eb1 Cut c2b fix: the waiter's own entry attempt drives the owner harness 2026-10-19 17:56:28 +02:00
Meta Vens
95e8076618 Cut c2b fix: the stop-first owner harness uses the host-actuator world with its workload port 2026-10-19 17:55:04 +02:00
Meta Vens
2ff57533b1 Cut c2b fix: a test world runs a host-actuator target's workload through its own port 2026-10-19 17:53:58 +02:00
Meta Vens
c6805d48a7 Cut c2b fix: restore stop_first_binding's runner split 2026-10-19 17:51:38 +02:00
Meta Vens
8b6c539a6a Cut c2b fix: the stop-first harness owner runs on a systemd unit 2026-10-19 17:51:02 +02:00
Meta Vens
a254a3e6a5 Cut c2b fix: pin the forever-waits at the waiter, the pre-fence abort deadline, the stateful incident lifecycle and the archive vanish
Negative tests (a)(b)(c) are one marked harness that ages a deadline only when
one exists and ends on the waiter's own record, so at the base they fail at the
waiter assertion (still waiting), not at setup. (c) now runs the Odin gate-wait
it names: a stop-then-start continuity on a systemd unit observes and waits,
where the host-actuator step of a world with no actuator errs at once.

New: a stop-first owner's wedged pre-fence abort pages and ends its waiter; a
waiter's own wedged pre-fence abort pages beside a standing owner; a stateful
deploy's incident is silent under an early expiry, one per episode, and closes
while the record goes on; an unparsable drain plan is bounded; a transaction
gone from both live set and history stays a fault.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 17:49:14 +02:00
Meta Vens
21849eb097 Cut c2b fix: a drain whose stored plan no longer parses is bounded, not unbounded
deadline_for_current_activity's drain arm returned None when parsed_inputs
failed (the running binary re-parses and re-admits the frozen binding), which
left the drain with no deadline, unpaged, and disarmed every waiter behind it.
The retire time is now the promotion plus the drain when the binding parses,
and otherwise now; the frozen committing duration from it bounds the drain.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 17:48:03 +02:00
Meta Vens
0bfadcfc71 Cut c2b test: pin the stateful-deploy arm of leaves_to_operator and the incident close predicate
Survivors of cargo mutants --in-diff on 9ea6c71..126d710: the OperatorRequired
clause of leaves_to_operator (now a table beside phase_end) and the close
predicate (a vanished subject closes while another transaction is still left).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 16:10:11 +02:00
Meta Vens
126d710de3 Cut c2b: operator-required incident, opened at the decision site and closed when spent
IncidentCondition::OperatorRequired (subject: transaction id) opens in
leave_to_operator, only for a record that leaves_to_operator, and closes as
recovered in close_spent_operator_incidents once no transaction in the
snapshot is left to the operator. Incident writes are never progress.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 14:39:42 +02:00
Meta Vens
a14055115c Cut c2b: owner deadlines; a waiter never waits on an owner Idunn will not finish
wait_for_owner disarms a waiter Warming deadline (the owner bounds the wait)
and ends the waiter through its own pre-fencing abort when the owner leaves to
the operator (owner-left-to-operator); it never aborts the owner. The resolver
times Warming for every transaction, lifts a deadline onto a record that needs
one, skips an owned waiter, and leaves an abort or drain past its deadline to
the operator (report only; the incident follows). Rulings c2b-waiter-ends-on-
operator-owner, c2b-warming-deadline, c2b-abort-and-drain-deadlines.

Negative tests recorded failing at 9ea6c71.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 14:37:21 +02:00
Meta Vens
86926c4e42 Cut c2b: one derivation of every deadline; Warming, aborts and drains are timed
WARMING_DEADLINE_SECONDS and PRE_FENCING_ABORT_DEADLINE_SECONDS are Idunn
constants (no PhaseDeadlines field: plan ids stay). DEADLINE_PHASES is the one
spelling of the deadline range. deadline_for_current_activity derives the
duration of a phase, an abort from its beginning, or a drain to its retire;
retime is the only non-test writer. leaves_to_operator is derived from it.
Validation asks for an activity, not a post-fencing phase. Records written by
this cut are forward-only (ruling c2b-forward-only-records).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 14:23:59 +02:00
Meta Vens
ffb22e368b Cut c2b: the post-fencing abort stops its candidate before revoking the lifetime-held lease
ruling c2b-abort-stops-before-revoke; fixes follow-up
ghostlight-abort-lease-before-stop. Mirrors advance_fencing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 14:15:47 +02:00
Meta Vens
3265ccb575 Cut c2b test: an abort stops a candidate that holds its lease before revoking it
Negative test for ghostlight-abort-lease-before-stop: the candidate holds the
lease lock until stopped. Recorded failing at this commit; the fix follows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 14:15:07 +02:00
Meta Vens
9ea6c71921 Cut 2 test: the stop-first fixture builds without a network input
A host-native runner has no network profile, so the host-actuator recipe
drops the external input the systemd recipe fetches.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 14:01:59 +02:00
Meta Vens
94d3b53b55 Cut 2 fixes: stop-then-start handover fixture, supervision owner skip, rebase preflight, archive-as-progress
- Add an engine-level stop-then-start fixture (route-less host-actuator plan)
  and a test that two such transactions never both enter Starting, in either
  order; it kills enter taking the CAS only at Fencing and takes_target_at
  ignoring the rollout. Discharges follow-up stop-first-handover-fixture.
- Pin supervision's skip of an owned target: a fenced generation is not
  refreshed from Odin, and a stop-first owner's stopped incumbent is not
  restarted.
- The rebase test now carries a route preflight, so keeping it dies.
- The step that ends a transaction archives it inside its write; the progress
  read now treats a terminal archived record as progress, not a fault.
- enter's doc no longer claims every phase move goes through it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 14:00:49 +02:00
Meta Vens
5b421c3cc7 Deploy provenance target: no per-deploy operator gate, typed provenance on the transaction
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 13:04:27 +02:00
Meta Vens
6ea0d127d8 Cut 2 test: a finished transaction retired mid-handover is not a lost race
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 12:15:19 +02:00
Meta Vens
dd8707b5a2 Cut 2: pin the candidate-port reservation and the rebase guards directly
candidate_ports_in_use is the one reading of which ports admitted, live and
draining transactions hold. Tests pin it, select_candidate_port's routed and
unrouted answers, and the three conditions under which a transaction is not
rebased.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 12:14:46 +02:00
Meta Vens
1953bf233b Cut 2: one per-target lookup, and tests that kill the survivors it exposed
ControlSnapshot::on_target is the one place a transaction is filed under a
target; target_owner, the supervision gates and the handover read it.
Tests: ownership is per target and names only a holder; a draining target is
not restarted until its cleanup ends; the admitted Expected is repaired
beside a building deployment; a live continuity alone holds back a second
mint.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 11:57:31 +02:00
Meta Vens
a7bfbc2296 Cut 2 tests: a launching switch workload, so a real continuity restart runs beside a deployment
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 11:22:58 +02:00
Meta Vens
278cc5c408 Cut 2, commit 4: open the gates; fold in the sustained-reset test reach
Freeze refuses only a second live Deploy of a target, so a profile command
freezes over crash-looping targets. Supervision defers to an owner, a drain
or its own live continuity, never to a deployment that has not taken the
target, and the admitted Expected repair runs beside one. Cut 1's interim
test (no continuity beside a pre-fencing deployment) goes with the state it
asserted.

Fold-in c1-sustained-reset-test-reach: the lower edge to the millisecond,
the newest attempt (not the oldest) deciding the reset, and the mid-wait
crossing recorded in continuity_backoff's doc and pinned.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 11:20:30 +02:00
Meta Vens
9139d7edb8 Cut 2, commit 3: rebase before the handover, wait in Warming, supersede a continuity
settle_before_handover runs after the two abort dispatches and before any
pre-handover step. A Deploy rebases onto the admitted generation when it
differs from the one its evidence was proven against: incumbent_generation_id
is rewritten, warming, route_preflight and isolation are dropped and the
Odin cursor is raised, nothing else. In Warming it waits (a gate note, no
error, so no abort) while another transaction owns or drains the target.
A Continuity is never rebased: when its target is owned or its generation
replaced it ends itself through the ordinary pre-fencing abort.

Tests drive a real continuity restart to Complete beside a deployment and
check the deployment rebases onto it and fences it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 11:16:05 +02:00
Meta Vens
755306d654 Cut 2, commit 2: one phase-entry seam and one handover CAS
Engine::enter is the only writer of a move into the next phase;
transition and the Sealing tail both call it. Entering the phase where a
transaction takes its target (takes_target_at: Fencing, or Starting for
stop-then-start) goes through Engine::take_target, one CAS that expects the
transaction's own envelope, the target's admitted envelope as read (or its
absence) and every other non-terminal transaction of the target, and
writes only the transaction. Of two entrants from one view exactly one
wins; a losing deployment waits with the owner named, a losing continuity
is superseded.

exact_incumbent now says what a mismatch is: a fault, not a race.

Test helper: the brake release is per transaction (a world can hold two
deployments).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 11:13:38 +02:00
Meta Vens
b4bb158707 Cut 2, commit 1: split the ownership predicate and the one-transaction-per-target validation
owns_target_authority and blocks_new_target_mutation answered four
questions with one phase-blind rule. They become is_live, owns_target
(derived from the phase and takes_target_at) and drains_incumbent, each
read by the consumer that asks that question: sibling order, validation,
status, ports, freeze and the supervision gates.

Validation now holds, per target, at most one owner, one live Deploy and
one live Continuity, each refused with its own message, so a continuity
beside a pre-handover deployment is readable. Freeze and the mint gate are
still conservative (any live or draining transaction refuses), so no
intermediate commit lets two transactions coexist unguarded.

seeded_transaction mints a fresh command id when its default is taken, so a
world can hold two of one kind.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 11:11:36 +02:00
Meta Vens
d91ecba759 Cut 2 negative tests, failing at 6138329: restart beside a building deployment, profile freeze over a crash loop
a_dead_incumbent_is_restarted_alongside_a_deployment_that_is_building and
a_profile_deploy_freezes_over_a_crash_looping_target use only base API and
pin the states cut 2 (handover-phase-split) ends. They fail until the
predicate split and the open gates land.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 11:07:13 +02:00
Meta Vens
61383297b2 Reincarnation map: cut 2 phase-split mapped (two slots, one handover CAS)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 10:59:51 +02:00
Meta Vens
9a0a6a2ce9 Body map after reincarnation cut 1; cut 1 installed on Yggdrasil
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 10:36:21 +02:00
Meta Vens
1da150a309 Merge idunn/reincarnation cut 1: continuity never stops, nothing yields before Fencing
Soul passes s1-s3 on cut-c1-never-stop; s3 holds with test-reach follow-ups.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 03:05:36 +02:00
Meta Vens
ffb42936ca Continuity tests: admitted_at that does not make the fixture a sustained run
The clock-step test anchored a target at admitted_at 0, which the sustained-first
rule rightly reads as a sustained run; the unobserved-run test logged restarts
after its generation's admission. Both now describe the cases they name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 02:21:22 +02:00
Meta Vens
da9d246956 Continuity: the sustained-run reset is decided before the anchor; pin the streak guards
continuity_backoff decides the sustained reset first, so a standing anchor
(a run no pass observed) cannot hide it. The running-pass end_backoff stays:
it makes the next death wait from its own discovery, not from a stale anchor.
Behavioural tests: a brief run does not reset the streak, streaks 13..u32::MAX
still mint and store saturating, the unobserved sustained run resets, a running
pass keeps the re-materialization bound, owed_steps admission bound, the v1
lift's inner schema check. The startup message names the supervision schema;
ControlSnapshot::read drops its repeat of the shared reader's key check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 02:19:33 +02:00
Meta Vens
f6d2943fd3 Restore LF line endings in control_plane.rs
The previous commit rewrote the file with CRLF; this one returns it to LF so
the range diff is the real change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 01:28:05 +02:00
Meta Vens
a75e31330a Continuity: the attempt after a re-materialization waits the base step
The re-materialization charges no streak, so a streak of 0 gave Due{0} and
a failed re-materialization was followed at once by a charged attempt. It
is an attempt that failed on the generation: the next one waits the base
step, so a queued deployment gets its gap.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 01:24:09 +02:00
Meta Vens
07a1d41692 Continuity: reset counts the re-materialization, a running pass ends the wait; supervision v2
Fixes Soul pass 1 of cut c1-never-stop:
- the sustained-run reset reads the newest of the paging log and the
  re-materialization, so a failed re-materialization is followed by a gap
- an observed-running pass clears the backoff anchor, so a standing anchor
  cannot suppress the reset on a later death
- TargetSupervision with keys 7-9 is schema v2; the dual-shape decoder is
  deleted and v1 records are lifted and migrated once at store open
  (deletion line named at TARGET_SUPERVISION_SCHEMA_V1)
- tests: continuity mints at every streak 1..=12 with a full or short log,
  the mint stores the reset streak, the schema ids name one shape each
- ROUTE_ACTUATION_CEILING doc no longer says continuity spends restarts

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 01:22:34 +02:00
Meta Vens
32ff879790 Test: a managed-host workload is never claimed lost to a reboot (kills the surviving Ok(true) mutant)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 00:24:48 +02:00
Meta Vens
b1dfe829a1 Remove an orphaned doc line left by the deleted yield control test
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 23:55:47 +02:00
Meta Vens
2fae3af133 Test: a queued deployment may fail on its own account, never to continuity
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 23:55:26 +02:00
Meta Vens
69464b11ef Test: name the abort when the queued deployment does not survive the gap
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 23:54:47 +02:00
Meta Vens
61fc89bbd7 Tests: count only continuity minted over an incumbent; status shows streak and next attempt
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 23:53:40 +02:00
Meta Vens
9a6b4a128c Continuity backoff: capped streak anchored when the target is found free; one uncharged re-materialization
TargetSupervision gains the attempt streak, the backoff anchor and the
re-materialization bound (keys 7-9, same schema; pre-key records decode with
them defaulted). Every charged attempt waits backoff_wait(base, streak - 1,
300 s) from the first dead-and-free pass; a sustained run resets the streak.
WorkloadPort::lost_to_host_reboot lets a reboot-lost unit be re-materialized
once per generation with no step. The streak backoff, reboot and negative
tests land with it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 23:52:13 +02:00
Meta Vens
6eb7931a8c Continuity never stops: delete the yield, the exhaustion stop and the window-derived wait
The paging window now only pages: restarts_page opens the incident and
reports; it ends no pass and aborts no transaction. Deletes next_restart_at,
continuity_is_waiting and the five tests that pinned the stop, the yield and
the mint-anchored spacing. The streak backoff follows in the next commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 23:47:04 +02:00
Meta Vens
e36cad32f0 Negative test: a pre-fencing deployment over a dead paged incumbent is never yielded
Written first against base API; expected to fail at this commit
(deployment aborted 'yielded to continuity' once the window slides).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 23:46:01 +02:00
Meta Vens
f079389be0 Reincarnation: continuity never stops (target r2), cut 1 never-stop mapped
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 23:44:14 +02:00