* fix: clean up zombie parallel workers stuck in error state
refreshWorkerStatuses() set worker.state = "error" for dead workers but
never removed them or deactivated the orchestrator, leaving zombies in
memory forever. restoreRuntimeState() short-circuited on state?.active
without verifying any workers were actually alive.
Two fixes:
1. refreshWorkerStatuses() now checks if all workers are terminal after
the status sweep — if so, deactivates the orchestrator and removes
the persisted state file.
2. restoreRuntimeState() now verifies at least one worker is in a
non-terminal state before returning true. If all workers are dead,
it clears the stale cached state and falls through to restoreState()
which handles proper cleanup.
Closes#2736
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* test: add regression tests for zombie worker cleanup
Covers #2736: verifies refreshWorkerStatuses() deactivates orchestrator
when all workers reach terminal states, and restoreRuntimeState() clears
stale cached state instead of returning true with only dead workers.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>