claude's Bash tool starts every command in a new session, so a signal to
claude's process group never reaches it. claude stops those commands
itself when SIGINT makes it shut down. A SIGKILL leaves them running,
re-parented to init. Per the ruling on #4999, every stop is SIGINT and
nothing escalates.
- Subagent `interrupt` always sends SIGINT. The `force` argument is gone
from the MCP tool and from `session::interrupt`. A caller that still
sends `force: true` gets SIGINT; the argument is ignored.
- `interrupt` used to free the session name before it signalled, so a
`continue` could start a second claude on the session while the first
was still exiting. The `running` map now holds a three-state `Slot`
(starting, running, stopping). An interrupted claude turn is
`Stopping` until the turn task's own `finish_turn` clears it. `status`
says "stopping", and `start`/`continue` on that name are refused.
`interrupt` still returns at once. The ACP arm is unchanged: its name
is freed when `session/cancel` is sent.
- ACP `Connection` drop sends its process group SIGINT, not SIGKILL, and
the spawn no longer sets tokio's `kill_on_drop`, which SIGKILLed the
leader after the `Drop` body. The test fixture's background grandchild
resets SIGINT to default, since `&` starts it ignored.
Tests: a fake claude that records SIGINT, interrupted, fails with
`cancel(true)` (the old `force: true` path). An interrupted fake claude
that keeps running keeps its name claimed and `continue` is refused,
which fails when the slot is freed before the signal. A fake ACP agent
that records SIGINT, dropped, fails with SIGKILL in `Drop`, and also with
SIGINT in `Drop` but `kill_on_drop(true)` left in place.
Not changed: hive-claude's idle watchdog (still SIGKILL, separate
hive-claude change), the units' `KillSignal`, `machinectl kill`, and the
login helper.