fix-exited-worker-finish-convergence-deadlock

Eliminate exited-worker finish deadlock

Metadata

Statusdone
Agent identityfbb2d89fe44d6b761bcb4b67748ab3d417f29df70a65f8d9403308f5bb2bab78
Created2026-08-01T12:43:55.933329053+00:00
Started2026-08-02T05:27:39.750280082+00:00
Completed2026-08-03T09:42:51.413168926+00:00
Tokens14909997 in / 26649 out

Description

The task-owned finish simplification still deadlocks across process epoch, task lifecycle, and finish-transaction state. Exact production incident on fix-candidate-wg-control-plane-destruction generation 0 attempt attempt-0-1: the Pi worker completed substantial validated WIP and emitted agent_settled; its task wrapper then failed stale_process_identity: terminal caller is not descended from current epoch 1 PID 3913691; cleanup next failed finish transaction missing; ProcessObserver classified the task NeedsFinalization with reason needs_finalization_settled; the service left it there for ~1h47m with zero live agents; wg why-blocked misleadingly said “has no blockers.” A human had to run wg retry --preserve-session, which correctly released the dead owner and resumed the exact session/worktree. This violates completed-means-cleaned, deterministic post-lifecycle convergence, and the simplified task-owned finish contract.

Remove the state dance rather than adding another state. Establish one durable completion handoff before/at child exit that is authenticated by the attempt fence and wrapper/process identity without requiring the wrapper to be a descendant of the native Pi child it owns. If an exact owner exits after settlement with WIP and no finish transaction, service convergence must deterministically either (a) finish the already-receipted completion, or (b) release the proven-dead owner exactly once and resume the same session/worktree/intent automatically. It must never sit indefinitely in NeedsFinalization, never infer semantic success from silence, never discard WIP, and never weaken stale-writer fencing. wg why-blocked/status must report the concrete pending convergence action and deadline. Expected terminal-wrapper/epoch topology must be modeled explicitly, not rejected as stale ancestry.

Validation

  • Candidate-binary regression reproduces the exact topology: wrapper owns native Pi child; child settles/exits; wrapper terminal call occurs after process-epoch observation; no finish transaction exists initially. Assert automatic bounded convergence to a live same-session continuation or completed Land transaction with no operator command.
  • Assert one session ID, one worktree, monotonically fenced generations/epochs, no competitor, no WIP loss, no duplicate promotion, and zero breaker charges.
  • Kill/crash at every handoff boundary (before settlement receipt, after receipt/before tx, after tx/before promotion, after promotion/before cleanup); restart service and converge exactly once.
  • A genuinely stale unrelated process remains rejected and cannot terminalize or write.
  • NeedsFinalization cannot persist with a proven-dead owner and no scheduled action/deadline; wg why-blocked must never say unblocked for this condition.
  • cargo fmt --check, focused lifecycle/watchdog/finalization tests, cargo check, cargo clippy, owned smoke.

Depends on

Required by

Messages 10 messages (10 unread)

  1. #1user2026-08-01T12:46:44.720273638+00:00read
    A parallel formalization task, formalize-lifecycle-finish-lean4, now models your exact production deadlock trace. Please keep the runtime repair's transition semantics small/pure and document the wrapper/native-child capability and convergence rank so Lean/Rust conformance can bind to it; do not wait for the proof task before fixing the urgent production bug.
  2. #2formalize-lifecycle-finish-lean42026-08-01T13:33:38.486921878+00:00read
    Formal model constraints: please expose a versioned pure reducer where exact wrapper capability = (task, generation, attempt_id, fence, wrapper_epoch, child_epoch/owned-child link). Wrapper handoff is authorized by wrapper identity owning current native child, NOT descendant-of-child ancestry; unrelated/stale tuple rejects inertly. Convergence state should carry explicit pending action+deadline and rank (receipt/no-tx -> tx -> promoted -> cleanup), with contention breaker-neutral. Please send final event/field names; I will mirror byte-for-byte fixtures without blocking your repair.
  3. #3formalize-lifecycle-finish-lean42026-08-02T05:29:51.309731570+00:00read
    Formal WIP currently uses schema_version=1 and ProcessCapability fields task_id, attempt_id, generation, fence, wrapper_epoch, child_epoch; events child_settled, wrapper_handoff{candidate,base,disposition}, owner_proven_dead, continue_same_session, begin_finish, promote, commit_cleanup, message, ownership_contention. Please send final runtime names/semantics when stable; I will update fixtures byte-for-byte, without blocking your repair.
  4. #4formalize-lifecycle-finish-lean42026-08-02T05:45:29.901455938+00:00read
    Please list both owners = ["fix-exited-worker-finish-convergence-deadlock", "formalize-lifecycle-finish-lean4"] on your candidate-binary incident restart smoke. Formal fixtures now include finish_lease plus rank cuts; I will not duplicate your urgent OS/runtime scenario.
  5. #5formalize-lifecycle-finish-lean42026-08-02T05:45:42.183073232+00:00read
    Received. I will mirror those final constants/types/field names exactly in the incident fixture/conformance once confirmed. Please message when tests stabilize; current formal broader state can retain its abstract rank while embedding your runtime capability/action wire byte-for-byte.
  6. #6formalize-lifecycle-finish-lean42026-08-02T05:55:38.866616268+00:00read
    I mirrored your exact capability fields and reducer version/rank/action names in Lean, plus formal/fixtures/runtime/v1/exited_worker_finish.json with all cuts. Once your branch lands I will make Rust conformance deserialize that fixture into your production FinishConvergenceSnapshot and call reduce_exited_worker_finish directly.
  7. #7formalize-lifecycle-finish-lean42026-08-02T05:56:33.429720788+00:00read
    Acknowledged final correction: I will use  (not attempt_fence) byte-for-byte in the runtime capability fixture. Please send final decision JSON/commit when landed.
  8. #8formalize-lifecycle-finish-lean42026-08-02T05:56:44.311597019+00:00read
    Correction: acknowledged. I will use fence, not attempt_fence, byte-for-byte. Please send the final decision JSON/commit when landed.
  9. #9formalize-lifecycle-finish-lean42026-08-02T06:09:05.892437940+00:00read
    I see your native child exited after full validation with WIP uncommitted. Please preserve WIP and commit/push when your wrapper resumes; formal conformance is ready to bind immediately.
  10. #10formalize-lifecycle-finish-lean42026-08-02T06:27:18.249112405+00:00sent
    Integrated your landed runtime reducer. Production conformance now deserializes formal/fixtures/runtime/v1/exited_worker_finish.json into the real WrapperChildCapability/FinalizationPhase, invokes reduce_exited_worker_finish for all crash cuts, and byte-compares decisions; 5/5 focused tests pass.

Log