Repository navigation
fix(land): settle a speculation the lease abandoned, not just one main outran - #381
Conversation
A backgrounded task's exit already re-invokes the session with its status, so a wait built to detect that exit duplicates a guaranteed event — it cannot fire earlier and cannot carry more information. Measured 2026-08-12: one session had nine such waiters live at once, four shadowing `verify`, two `land`, one a merge, one `bats`, each a hand-rolled re-implementation of a notification the harness was already going to deliver. `mise run alive` (CLOUD-425) is the answer for "is it still going, and where is it", and it beats `pgrep -f` on correctness rather than manners: `pgrep -f` matches a command-line substring, so in a container with sibling sessions it answers "some process matches this string", which is not the question. A registered task whose process is gone reports `crashed`, which no `pgrep` can express. Lands in the section that already names the two habits which destroy the supervised-process interface and fail green, because this is the third and it fails the same way — plausibly, with a green exit. Refs: CLOUD-489, CLOUD-490
CLOUD-495 An admitted successor publishes the holder's unlanded commits, and cannot rewind when that base never lands
WhyA waiter pre-warms by linearizing onto the lease holder's branch tip, and the admitted successor then readies and pushes with no lease ( Speculation is justified as free because local execution costs nothing. Publishing it is not free: it makes one branch's published history depend on another branch's unlanded work, and nothing undoes that coupling. The severe case is a bet that stays pending forever. So when the holder abandons while That is a correctness hazard for trunk, not a coupling annoyance. The header comment at The conflict case is already handled and is not this: a speculation that fails to apply resets to the Measured
A setup failure on the holder propagated into a sibling's published history. Neither branch can now land independently without rewriting the other's published base, and the fleet-wide bound of holder-plus-one-successor is silently exceeded whenever this repeats. Two supporting factsNo remote-side unwind exists. After the push at The base taken is not the base advertised. MechanismThe successor needs a rewind, decided before it readies:
Two smaller defects surfaced by the same instance, recorded here rather than filed separately:
Refinement — Ready (a summary)
Done
|
…n outran A bet was resolved by asking whether `main` had moved: won when the base became an ancestor of it, lost when it moved elsewhere, pending otherwise. A holder that goes away while `main` stays put is none of those, so it read as pending — and pending returned 0 forever. The waiter kept the borrowed tree, later won the lease over an unmoved `main`, and the re-confirmation inside the hold asked only the question that had already been answered. What the fast-forward then landed was another branch's unmerged commits. Pending is now a positive claim: a bet is live only while the branch the lease names now is somebody else's and still carries the base. Lease freed, lease passed on, lease won by us, lease unreadable — all stale, all unwound before anything can be readied, pushed or merged. A published bet is re-drafted before its remote is rewound, so the correction buys no matrix and no stop leaves origin holding commits that are not landing. Refs: CLOUD-495
17809e8 to
795847b
Compare
|
|
/fast-forward |



Closes CLOUD-495.
Why
A speculative bet was resolved only by asking whether
mainhad moved: wonwhen the base became an ancestor of it, lost when it moved elsewhere,
pending otherwise. A holder that goes away while
mainstays put is none ofthose, so it read as pending — and pending returned 0 forever.
The waiter kept the borrowed tree, later won the lease over an unmoved
main,and the re-confirmation inside the hold asked only the question that had already
been answered. What the fast-forward then landed was another branch's unmerged
commits. Measured on this loop: a holder whose CI died in a provider incident
held the lease going nowhere, a sibling linearized onto its published head, and
the two branches ended at the identical SHA with neither able to land.
What changed
bet_is_livere-reads the lease: a bet islive only while the branch it names now is somebody else's and still carries
the base. Lease freed, lease passed on, lease won by us, lease unreadable — all
stale, all unwound. Fails closed everywhere.
before its branch is rewound, so the correction buys no matrix and no stop
leaves origin holding commits that are not landing.
the ready, the push and the fast-forward comment — the last computable moment.
An unwind there moves HEAD, so the lap ends rather than pushing a commit the
branch no longer has.
A successor readying a live borrowed tree is unchanged; that is the mechanism's
whole economy. What changed is that the bet must be fresh, not absent.
Tests
Six new cases in
tests/land.bats, plus three stub levers (rc.spec_live,rc.fetch_live,lease_abandons). Five of them fail against the previouslandand pass against this one; the sixth is the negative that stops the unwind firing
on every lap. The lap-count sensor caught the new
continueand is updated.🤖 Generated with Claude Code
https://claude.ai/code/session_01QHmaY5qiHMntdm2A2d6vTW