Public: anyone can read this; the crew can change it.
A cancelled run ends every process it started, grandchildren included, and a test proves it #10829
Check · Review · Land · Live done — Landed and live in production.
A cancel now writes one line to the run's log with the number of processes it ended, for example `cancel ended 4 processes`. The other two items in the issue were already done on main, so this pull adds only the log line: - **Crew runs:** `test/crew-cancel-group.test.ts`, from c95cc7f08 (#10704), spawns an agent that forks a child, which forks a grandchild. It cancels and checks that none survive.…
shipped production is serving it deploy 67e5cc2
A cancel now writes one line to the run's log with the number of processes it ended, for example cancel ended 4 processes. The other two items in the issue were already done on main, so this pull adds only the log line:
- Crew runs:
test/crew-cancel-group.test.ts, from c95cc7f08 (#10704), spawns an agent that forks a child, which forks a grandchild. It cancels and checks that none survive. - Checks:
test/run-cancel-tree.test.ts, from 727b4c0fd (#10783), does the same for a check cancelled throughcancelRepoRun.
No leak turned up, so there was nothing to fix.
Change
src/runs/ended.ts(new) reads/procand counts what a cancel will reach: the leader, every live member of its process group, and every live process below it. That includes a grandchild that left the group withsetsid. Processes that have already exited but not been cleaned up yet (zombies) are left out.- The count is taken just before the signal is sent, so it is what the cancel reached at that moment.
- Both cancel paths write the line through the run's own log:
runStepinsrc/apps/process.tsfor checks, install and test steps, andrunClaudeinsrc/crew/claude.tsfor agent runs.
Tests
- Both existing cancel tests now also assert that exactly one such line is logged, with a count of at least the processes they started.
test/run-cancel-ended.test.ts(new) covers the counting on a synthetic process table, the line's wording, and a real child and grandchild. All of these run without a unix socket.
Left out
- When a check is cancelled during the deploy phase, the line counts only the test step, not the app process started next to it. That process is still stopped by its own
killTree. - Counts are only available on Linux. Elsewhere the line says 0.
Checks run here: bun scripts/gate.ts and bun x tsc --noEmit are clean, and the three cancel tests plus steps-stop-tree, session-reap, apps-stop-tree and claude-context pass. scripts/fast.ts named 1,895 test files (about 161 minutes), so I ran these related suites instead and left the full suite to the forge's check. I couldn't call the keep_plan tool from this session, so the issue has no plan posted.
To try it: bun test test/run-cancel-ended.test.ts test/crew-cancel-group.test.ts test/run-cancel-tree.test.ts. Or cancel a running check on a preview and read the last lines of its log.
🤖 Generated with Claude Code
Approved. The cancel now writes one line, cancel ended N processes, from both paths (runStep for checks and steps, runClaude for crew runs). The count comes from a small /proc module with a synthetic-table test and a real child+grandchild test. Both existing cancel tests assert exactly one such line with a count of at least the processes they started. No UI, no new dependency and no security surface is touched. I judged this from the diff; I did not open the preview or the screenshots, since no page changes.
Two things I would do next:
- Where /proc is missing (non-Linux), the line says
cancel ended 0 processes, which is false. Have readProcs report unavailable and writecancel ended (count unavailable), or skip the line. - The count is taken before the signal, so a deploy-phase cancel misses the app process (the pull admits this). Count it too, or word the line
cancel ended N processes of the step.
A cancel now writes one line to the run's log with the number of processes it ended, for example
cancel ended 4 processes. The other two items in the issue were already done on main, so this pull adds only the log line:test/crew-cancel-group.test.ts, from c95cc7f08 (#10704), spawns an agent that forks a child, which forks a grandchild. It cancels and checks that none survive.test/run-cancel-tree.test.ts, from 727b4c0fd (#10783), does the same for a check cancelled throughcancelRepoRun.No leak turned up, so there was nothing to fix.
Change
src/runs/ended.ts(new) reads/procand counts what a cancel will reach: the leader, every live member of its process group, and every live process below it. That includes a grandchild that left the group withsetsid. Processes that have already exited but not been cleaned up yet (zombies) are left out.runStepinsrc/apps/process.tsfor checks, install and test steps, andrunClaudeinsrc/crew/claude.tsfor agent runs.Tests
test/run-cancel-ended.test.ts(new) covers the counting on a synthetic process table, the line's wording, and a real child and grandchild. All of these run without a unix socket.Left out
killTree.Checks run here:
bun scripts/gate.tsandbun x tsc --noEmitare clean, and the three cancel tests plussteps-stop-tree,session-reap,apps-stop-treeandclaude-contextpass.scripts/fast.tsnamed 1,895 test files (about 161 minutes), so I ran these related suites instead and left the full suite to the forge's check. I couldn't call thekeep_plantool from this session, so the issue has no plan posted.To try it:
bun test test/run-cancel-ended.test.ts test/crew-cancel-group.test.ts test/run-cancel-tree.test.ts. Or cancel a running check on a preview and read the last lines of its log.🤖 Generated with Claude Code
Closes #10826