Skip to content

A silently-resumed session with outstanding work (an open PR, a claimed hook-* assignment) never re-engages #548

Description

@defangdevs

Incident

This box's own hook session for #535/#546 (this repo's fix for a different
flavor of the same problem) got a live demonstration of it: a sibling
session ran sudo systemctl reboot at 16:40:39 while this session was
mid-task, waiting on CI and a CodeRabbit review for PR #546. The reboot
killed every tmux session with no epilogue, the supervisor silently
respawned this one via --resume (confirmed: AGENT_BOX_RESTART_NOTICE is
off, per #507/#512's default), and it then sat fully idle for 2.5 hours
— CI had failed and CodeRabbit had requested changes in the meantime, and
nothing happened until the user noticed and asked why.

This isn't quite the case #507/#512 reasoned about

PR #512's decision was specifically about the canned interruption text:
"--resume restores the transcript on its own, so a respawn ... hands the
agent no injected prompt at all rather than this notice." That's a good
call for the verbose "You were interrupted and automatically restarted..."
message being unnecessary noise when the agent can just read its own
transcript.

But "no injected prompt" doesn't mean "the agent reads its transcript and
decides what to do" — it means no new turn is triggered at all. A
resumed Claude Code process sits at the prompt exactly as claude --resume
outside agent-box would: correctly caught up, and doing nothing until
someone or something starts a turn. For an ordinary interactive session
that's fine — a human will type something eventually. For a session with
an outstanding external commitment (an open PR it authored, a claimed
webhook topic, anything hook-* by definition), there's nobody to type
anything, and it can sit there indefinitely with no signal to anyone that
it needs to.

Options

  1. Turn restartNotice back on globally. Simple, but reintroduces the
    noise feat(sessions): make the claude restart notice opt-in, off by default #512 was avoiding for the common case (an interactive session
    whose work is already done or who doesn't need a nudge).
  2. Make the nudge conditional, not global: only inject a minimal
    "you were interrupted, check whether your prior work is still needed"
    prompt when the respawned session has something to check — e.g. a
    non-stopped boxSessionId/transcript that has real work AND (new,
    via feat(sessions): durable lease for a hook session's accepted assignment #546) an unresolved lease (outcome: died:<status> or
    vanished) for that session name. That's a much narrower trigger than
    "every respawn," and it reuses state feat(sessions): durable lease for a hook session's accepted assignment #546 already maintains — a
    lease_mark_outcome write on respawn is exactly the moment to also
    decide whether to nudge.
  3. Do nothing here, treat it as covered by Decide: auto-requeue and/or GitHub notification for a stranded hook-* assignment (#535 follow-up) #547 (this repo's own
    follow-up on auto-requeue/notification for a stranded hook-*
    assignment) — except Decide: auto-requeue and/or GitHub notification for a stranded hook-* assignment (#535 follow-up) #547 is scoped to a hook session's worker dying;
    this incident is about a session that's very much alive again after a
    respawn, just silent. Worth keeping the two issues distinct even if a
    shared mechanism ends up serving both.

No recommendation forced here between (1) and (2) — (2) is more surgical
and ties into #546's own lease state, but is more code; (1) is one config
flip whose cost is a message the agent can trivially answer "already
handled" and stop. Lio's call.

Also worth confirming from the incident itself

Independent of the reboot: CodeRabbit's review (16:21:29) and CI's failure
(16:27:16) both landed on PR #546 before the reboot, while the session's
own webhook subscription should have still been live (subscribed ~16:15,
2h TTL) — and neither reached the session either. That gap is not explained
by this issue and wasn't root-caused (no access to the prior boot's
local-webhook receiver logs from here); flagging it here since it compounds
the same symptom, but it may be a distinct bug in the delivery path itself.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    • Status
      Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions