## Task 8 Report

**Status:** DONE

**Commit SHA:** fb99114

**Test result:** `1 passed in 1.22s` — post-fix `test_timeout_kills_child_process_tree` passes quickly. Pre-fix behavior note: on macOS, the test also returned quickly pre-fix because `proc.kill()` kills the shell and the function returns immediately (without waiting for the orphaned child), satisfying `elapsed < 5.0` and `"timed out" in out`. The real-world bug is the orphaned `sleep 30` child remaining alive and holding file handles — the fix correctly kills the whole process group via `os.killpg` + `start_new_session=True` and reaps with `await proc.wait()`.

**Concerns:** None. The `start_new_session=True` change doesn't affect the happy (non-timeout) path — `proc.communicate()` still works normally. Full orchestrator suite: 78 passed, 0 failures. Lint: clean.

---

## Task 8 Follow-up: Genuine Behavioral Test

**Status:** DONE

**Problem with original test:** The old `test_timeout_kills_child_process_tree` (spawning `"sleep 30 & wait"` with timeout=1.0 and asserting `elapsed < 5.0` and `"timed out" in out`) was a false red-green test — it passed both BEFORE and AFTER the `os.killpg` fix because `run_test_command` returns immediately after killing the shell wrapper regardless. The orphaned `sleep 30` child survived but went unobserved.

**New test:** `test_timeout_reaps_child_process_group` in `tests/orchestrator/test_acceptance_killpg.py`

Strategy: marker-file side effect observable only if the child is orphaned.
- Command: `(sleep 3; touch <marker>) & wait` — background child sleeps 3s then touches a file; timeout fires at 1s.
- After the timeout, wait 3.5s to let the child's sleep finish.
- Assert the marker file does NOT exist — if os.killpg killed the whole process group, the child never ran `touch`.

**Red run (fix reverted — `proc.kill()` + no `start_new_session`):**
```
FAILED tests/orchestrator/test_acceptance_killpg.py::test_timeout_reaps_child_process_group
AssertionError: orphaned child survived the timeout — process group was not killed
```

**Green run (fix restored — `os.killpg` + `start_new_session=True`):**
```
PASSED (1 passed in 4.83s)
```

**Full orchestrator suite (fixed state):** `78 passed, 1 warning in 6.00s`

**Lint:** All checks passed.

**Commands run:**
```bash
uv run pytest tests/orchestrator/test_acceptance_killpg.py -v   # GREEN (fixed)
# [reverted fix: proc.kill() + removed start_new_session=True]
uv run pytest tests/orchestrator/test_acceptance_killpg.py -v   # RED (reverted)
# [restored fix: os.killpg + start_new_session=True]
uv run pytest tests/orchestrator/ -q                             # 78 passed
uv run ruff check claw_forge/ tests/                             # All checks passed
```
