Orchestrata Ultimate › Plans › briefs › qwen › Q8-continuation

Q8 continuation — the leaking live_run_tree fixture, then finish

Source: plans/briefs/qwen/Q8-continuation.md at 8a2cb42ad · last changed 2026-10-12 · first committed 2026-10-12 · 73 lines.

Prose pending.

Plan text

Q8 continuation — the leaking live_run_tree fixture, then finish

Same worktree, same branch, same rules as plans/briefs/qwen/Q8-hook-process-matching.md. Do not commit. Every scripts/run_tests.py run goes through bash .run_exclusive.sh .... Every measured step goes through bash .hostlock.sh ..., if your worktree has it. A guard denial is reported, never worked around.

1. The defect (orchestrator, measured)

tests/claude/test_test_run_context.py, fixture live_run_tree (lines 74-111 on master):

Evidence:

Anything that scans /proc sees these as pytest processes:

2. Fix, red first

  1. Factor, do not replace.
    • Move the fixture's body into a module-level context manager, _live_run_tree() (contextlib.contextmanager). It yields the same object the fixture yields today, plus a way to read the child's pid; add that only if it is not already exposed.
    • The fixture keeps its name, scope and yield value, and becomes with _live_run_tree() as tree: yield tree.
    • No existing test changes, and no assertion changes.
  2. Red test first. Add a test that uses the context manager directly:
    def test_live_run_tree_leaves_no_child_behind() -> None:
        with _live_run_tree() as tree:
            child = <the child pid>
            assert Path(f"/proc/{child}").exists(), "precondition: the child is running inside the block"
        deadline = time.monotonic() + 5
        while Path(f"/proc/{child}").exists() and time.monotonic() < deadline:
            time.sleep(0.1)
        assert not Path(f"/proc/{child}").exists(), f"child {child} outlived the fixture"
    
    • Run the module through the wrapper before the fix. Quote the red output: the child outlives the block.
    • A zombie (State: Z in /proc/<child>/status) still has a /proc entry. If the red result depends on that, say so and quote /proc/<child>/status.
  3. The fix, inside _live_run_tree():
    • start the parent with start_new_session=True;
    • at teardown, os.killpg(parent.pid, signal.SIGKILL) (tolerate ProcessLookupError), then parent.wait(timeout=...);
    • then poll /proc/<child_pid> for up to 5s and raise AssertionError if it remains. A leak becomes a red result instead of a silent one.
  4. Same treatment for any other fixture in the files you touch that spawns grandchildren. Check foreign_run. Report each fixture you checked, and what you found.
  5. Run the module again. It must be green; quote the totals.

3. Verification additions

4. Finish

Complete your brief's done-when and write plans/briefs/qwen/Q8-report.md. Include this item with its red/green evidence and the orphan check output. Do not commit.