Version / branch / commit
Audited on main at 903e3d13 (2026-08-23).
Problem
Five process-launching packages use exec.CommandContext without Cmd.WaitDelay or process-tree termination. Cancellation kills only the root PID. A surviving grandchild can retain stdout or stderr, leaving the os/exec copy goroutines waiting for EOF and Wait blocked indefinitely after the intended timeout.
Affected paths
internal/verify/verify.go:301-307
internal/agenteval/agent_command.go:63-70
internal/agenteval/run.go:141-147
internal/agenteval/materialize.go:190-201
internal/perfbench/turn_bench.go:639-648
internal/perfbench/taskbench.go:330-393
internal/perfbench/perfbench.go:287-321
internal/hooks/dispatch.go:299-323
internal/dictation/runner.go:105-128
Expected behavior
A context deadline terminates the complete spawned process tree and returns within a bounded cleanup interval.
Actual behavior
Only the direct child is killed. Descendants can survive while holding inherited pipes, making the caller wait forever.
Existing pattern
internal/config, internal/execution, internal/specialist, internal/tools/bash*, and internal/worktrees already use WaitDelay and/or the shared process-group/tree-kill helpers.
Suggested fix
Set a bounded WaitDelay on every affected command and reuse execution.ConfigureProcessGroup plus execution.KillProcessTree where process trees are possible. Add a focused regression test that starts a child which leaves a grandchild holding stdout, cancels the context, and asserts bounded return. Run affected concurrent tests under -race.
Version / branch / commit
Audited on
mainat903e3d13(2026-08-23).Problem
Five process-launching packages use
exec.CommandContextwithoutCmd.WaitDelayor process-tree termination. Cancellation kills only the root PID. A surviving grandchild can retain stdout or stderr, leaving theos/execcopy goroutines waiting for EOF andWaitblocked indefinitely after the intended timeout.Affected paths
internal/verify/verify.go:301-307internal/agenteval/agent_command.go:63-70internal/agenteval/run.go:141-147internal/agenteval/materialize.go:190-201internal/perfbench/turn_bench.go:639-648internal/perfbench/taskbench.go:330-393internal/perfbench/perfbench.go:287-321internal/hooks/dispatch.go:299-323internal/dictation/runner.go:105-128Expected behavior
A context deadline terminates the complete spawned process tree and returns within a bounded cleanup interval.
Actual behavior
Only the direct child is killed. Descendants can survive while holding inherited pipes, making the caller wait forever.
Existing pattern
internal/config,internal/execution,internal/specialist,internal/tools/bash*, andinternal/worktreesalready useWaitDelayand/or the shared process-group/tree-kill helpers.Suggested fix
Set a bounded
WaitDelayon every affected command and reuseexecution.ConfigureProcessGroupplusexecution.KillProcessTreewhere process trees are possible. Add a focused regression test that starts a child which leaves a grandchild holding stdout, cancels the context, and asserts bounded return. Run affected concurrent tests under-race.