Previous behavior:
- McpClient.__exit__() in scripts/benchmark-incremental-speed.py:807-822 closed stdin and waited for the server but did not join stdout_thread or stderr_thread, close the output streams, or clear retained process/thread references.
Changes:
- Join both reader threads after process exit, close stdout and stderr, clear proc/stdout_thread/stderr_thread, and raise MCP reader thread did not stop after process exit when a normal teardown cannot reap a reader.
- Preserve the existing wait, terminate, then kill escalation sequence.
- Add test_mcp_client_exit_reaps_process_streams_and_reader_threads in tests/test_benchmark_incremental_speed.py:15-60.
Resource lifecycle:
- Repeated benchmark cells now synchronously release the subprocess pipes and reader-thread references before the next cell starts.
- The bounded second join runs only when a reader remains alive after the initial five-second join.
Verification:
- Red: the focused unit test failed because process.stdout.closed was false.
- Green: focused unit test passed; benchmark, campaign, and summarizer suites passed 70/70.
- uv run ruff check passed for scripts/benchmark-incremental-speed.py and tests/test_benchmark_incremental_speed.py.
Signed-off-by: Andrew Hundt <ATHundt@gmail.com>