Does not build-verified yet; tests follow. drivers.rs: holder-side lease read, one lease-binding rule shared with grant.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
If the boot lift returned Err, boot logged and served with nothing held, so
every pending continuity abort ran and stopped a running candidate. Boot now
sets lift_unsettled; retry_held_lift runs the lift for each continuity abort
until one succeeds, and no abort step runs before. Boot's call moves into
Engine::boot_lift so the failure is testable.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The lift kept an abort running for any awaits_handover Deploy, so a braked
Deploy released a held record to an abort that stopped the only copy of the
body. One predicate, deploy_the_continuity_yields_to (candidate unproven, a
waiting Deploy that deploy_can_move), is now what both the deadline's yield
and the lift ask (rulings c2d-yield-only-unproven-to-movable,
c2c-lift-defers-on-observe-error).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Two tests, from Soul's h2 attacks: a running candidate at boot beside a braked
stop-then-start Deploy at its Sealing tail, and a held (unobservable)
candidate when such a Deploy appears. Both must leave the candidate unstopped.
They fail here: the lift treats any awaits_handover Deploy as a reason to keep
aborting.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
serving_proven (Committing, or routing evidence recorded) ends the yield:
yields_to_a_deploy replaces retries_forward, and wait_for_owner reads it, so
a Deploy no longer waits on an owner that will keep serving. deploy_can_move
asks the deployment brake live for a Deploy at its Sealing tail, so a braked
Deploy draws no yield and the yield happens once the brake releases. The
tests of 04389e6 are repaired to reach their worlds (the failures they
showed at 1beca61 were the right ones). Rulings
c2d-yield-only-unproven-to-movable.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fail at 1beca61 (the c2d logic is 81bfb03's): a Committing continuity past
its deadline yields to a waiting Deploy and stops serving; a stop-then-start
Deploy at its Sealing tail with the deployment brake unreleased draws the
yield. The second test releases the brake and pins that the yield then
happens and closes the continuity's operator-required incident Recovered.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An abort over a candidate the boot lift could not observe is held in
process memory: resume_candidate runs no step of it and retries the lift
each pass (retry_held_lift) until observation answers Ok (lifted) or the
driver proves the candidate dead (the abort proceeds). The predicate and
write move into consider_lifting_continuity_abort, which boot and the
retry share. Ruling c2c-lift-defers-on-observe-error.
The page and the expire refusal name the manual exit from the plan's
workload binding: a unit to stop for systemd, a process to kill for a
host actuator.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fails at 81bfb03: an observe error leaves the abort running and its first
step stops the candidate. Also pins the lease_withdrawal==Complete conjunct
(case LeaseWithdrawalRecordedComplete) and makes the refusal table's
dead-candidate case provably dead (SwitchWorkload::bury).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
resume_candidate removes the transaction's backoff when the resolver
moved its record, so a yield abort is not held behind the forward retry's
backoff (ruling c2d-yield-mechanics). return_wedged_continuity_aborts_forward
skips an abort whose target holds a Deploy awaiting the handover. Tests:
the yield table, the unit rows, the c2b waiter-still-ends row, the
backoff spend, and lift case (vii).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A continuity past its deadline at or past Fencing begins its own
post-fencing abort when a Deploy on its target awaits the handover; the
waiter keeps waiting on an owner that retries forward. Adds
retries_forward and awaits_handover, both derived.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Red at e529858: the waiter ends FailedBeforeFencing owner-left-to-operator.
The yield (ruling continuity-yields-to-deploy) lands in the next commit.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Conflict in begin_post_fencing_abort: kept c2's now_millis binding and
the hotfix's bounded_detail in place of truncate. The owner-wait note
written by wait_for_owner now goes through bounded_detail too; every
other c2/c2b/c2c detail writer already did.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
- 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>
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>
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>