Skip to content

fix: reclaim posix harness trees orphaned by a crashed meshloop - #39

Merged
smota merged 2 commits into
mainfrom
work/posix-orphan-reconcile
Oct 7, 2026
Merged

smota merged 2 commits into
mainfrom
work/posix-orphan-reconcile

Conversation

@smota

@smota smota commented Oct 7, 2026

Copy link
Copy Markdown
Owner

Implements #30
Closes #30

Problem

On POSIX, a harness process group outlives an aborted Meshloop, because a group has no equivalent of the Job Object's kill-on-close. On restart, recovery saw the attempt as untracked, recorded HarnessCrashedOrTimeout and retried, while the old tree kept running against the worktree.

Change (option 1: recovery reconciliation, safe Rust)

  • RunLoop::reattach_running: a Running attempt the harness no longer tracks is cancelled before the crash is recorded.
  • CliHarness::cancel: for an untracked attempt with a recorded pid, calls the new process::kill_orphaned_tree.
  • kill_orphaned_tree guards against pid reuse. It kills only when the pid is alive and runs the harness executable (image name on Windows; comm on POSIX, which Linux truncates to 15 bytes), and on POSIX only when the pid still leads its own process group.
  • ADR 0025 amendment records the decision, the rejected alternatives and the residual risks. The verification note for grandchild_dies_on_parent_abort now says it is Windows-only.

Known limits

  • Orphans are reclaimed at the next resume or status of that graph, not immediately.
  • A harness launched through a shim whose process image differs from the configured executable is not matched, so it is left running rather than risk killing an unrelated process.
  • There is no engine-level reattach test with fakes; the engine change is a single cancel call covered by the adapter tests and the end-to-end suites.

Merge note

#38 also appends an amendment to ADR 0025. Whichever merges second needs a trivial rebase; I will handle it.

Validation

  • cancel_kills_an_orphaned_tree_left_by_a_previous_process fails without the untracked-pid branch ("orphaned leader 36968 survived cancel") and passes with it.
  • cancel_leaves_an_unrelated_process_with_a_recorded_pid_alone covers the pid-reuse guard.
  • Windows: xtask check (17 suites) and smoke pass.
  • Linux (WSL2 Ubuntu 24.04, native clone at 3da9a42): xtask check (17 suites) and smoke pass, with 0 leftover fixture processes.

🤖 Generated with Claude Code

On POSIX a harness process group outlives an aborted Meshloop. Recovery
then marked the attempt crashed and retried while the old tree kept
running against the worktree.

Per the accepted option 1 (recovery reconciliation, ADR 0025 amendment):
RunLoop cancels an untracked Running attempt before recording the crash,
and CliHarness::cancel kills an untracked attempt's recorded pid via
process::kill_orphaned_tree, only when the pid is alive, runs the harness
executable, and (POSIX) leads its own process group.

Implements #30
Closes #30

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@smota smota added bug Something isn't working drafted-by:claude Issue, plan, or spec drafted by Claude in the current session labels Oct 7, 2026
@smota
smota merged commit 85c06a7 into main Oct 7, 2026
3 of 4 checks passed
@smota
smota deleted the work/posix-orphan-reconcile branch October 8, 2026 08:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working drafted-by:claude Issue, plan, or spec drafted by Claude in the current session

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: contain harness descendants on posix when meshloop aborts

1 participant