subagent daemon: report a killed session as killed, not idle
A subagent whose claude process died on a signal — the kernel's OOM
killer, a stopped unit, an `interrupt` — was indistinguishable from one
that finished its turn: its entry left the `running` map, `status` fell
through to "a session exists on disk" and answered `idle`, and the
end-of-turn todo said the subagent had "finished". The usual next move
on that reading is `continue`, which resumes work that was cut mid-turn
with nothing having recorded that it was cut.
The driver already preserves how the child ended — `RunningClaude::wait`
returns `Error::Exit` carrying the `ExitStatus`, whose `signal()` is the
whole answer — so this reads it rather than having to recover it:
`classify_end` turns the outcome into `Complete` / `Killed { signal }` /
`Failed`, and `State::finish_turn` remembers a kill against the name
(cleared by the next confirmed spawn under it).
What an agent sees as a result:
- `status` reports the session killed, naming the signal, instead of idle;
- the todo the daemon pushes without being asked says the subagent was
KILLED mid-turn rather than that it finished;
- `continue` still resumes such a session, but its reply says the
previous turn was killed, so no caller carries on from cut-off work
believing it was complete.
Refs #4326
This commit is contained in:
parent
fde4a36b93
commit
f817e27d4c
5 changed files with 383 additions and 29 deletions
|
|
@ -33,6 +33,26 @@ claude's own on-disk session (`hive_claude::SessionStore`), which
|
|||
`continue` reattaches to independent of the daemon's own lifetime — a
|
||||
restart loses the _in-flight turn_, not the subagent's history.
|
||||
|
||||
## A killed turn
|
||||
|
||||
A subagent whose `claude` process dies on a signal — the kernel's OOM
|
||||
killer under memory pressure, a stopped unit, an `interrupt` from the
|
||||
owning agent — did not finish its turn, and the daemon says so rather
|
||||
than letting it settle back into `idle`:
|
||||
|
||||
- `status` reports the session **killed**, naming the signal, instead of
|
||||
the `idle` it reports for a turn that ended on its own;
|
||||
- the end-of-turn todo the daemon pushes without being asked says the
|
||||
subagent was killed mid-turn, not that it finished;
|
||||
- `continue` still resumes such a session — often what you want — but
|
||||
its reply says the previous turn was killed, so nobody carries on from
|
||||
cut-off work believing it was complete.
|
||||
|
||||
The record is per-name, in memory with the rest of this daemon's state,
|
||||
and the next confirmed spawn under that name clears it. A daemon restart
|
||||
loses it along with everything else — the daemon has to outlive the kill
|
||||
to report it, which is what `OOMPolicy=continue` on the unit is for.
|
||||
|
||||
## Compaction trade-off
|
||||
|
||||
Built on `hive_claude::Claude::spawn` + `RunningClaude::wait` directly
|
||||
|
|
|
|||
Loading…
Reference in a new issue