Skip to content

Claude primary supervision goes dark after an asyncRewake handling turn ends in StopFailure #2940

Description

@stanzhang

Summary

A Claude-primary Firstmate home can remain silently unsupervised indefinitely when an actionable watcher close successfully rewakes the session but that handling turn ends in an API error.

Claude runs StopFailure instead of Stop for API-error turn ends.
Firstmate's primary supervision guard and auto-arm are registered only under Stop, and the Claude continuity design starts the successor at the next Stop after handling.
No next Stop means no rearm, no guard, and no alarm.

This happened with three tasks in flight and remained invisible for 3h52m until the captain returned.

Observed

Installed harness:

2.1.241 (Claude Code)

Final pre-gap watcher lifecycle:

arm_pid=41542 watcher_pid=41556 origin=started
started_at=1787546697 ended_at=1787547749
exit_code=0 signal=none reason=actionable-signal
beacon_age=49 successor=none

Delivery ledger:

watcher_pid=41556
signal: deckhand-crawler-v1.status deckhand-crawler-v1.turn-ended alienware-ml.status

The Claude transcript then shows:

2026-08-24T05:02:29.597Z  Stop hook feedback enqueued
2026-08-24T05:02:29.604Z  feedback dequeued
2026-08-24T05:02:29.618Z  synthetic handling turn created
2026-08-24T05:05:53.707Z  API Error: 529 Overloaded (isApiErrorMessage=true)

There is no stop_hook_summary after the API error.
No further transcript event occurs until the captain returns.

Morning drain:

1787547749  102/103/104  signal  ...
WATCHER DOWN - SUPERVISION IS OFF
3 task(s) in flight, but no watcher has a fresh beacon
(last beat: 13980s ago, grace 300s).

The next ordinary Stop immediately starts another watcher at 1787561825, which rules out a poisoned lock, bad eligibility, or persistent home misconfiguration.

Mechanism

  1. The watcher is intentionally one-shot and exits 0 after an actionable reason.
  2. Claude ordering intentionally does not start a successor before notification; docs/watcher-continuity.md assigns that to the next Stop after handling.
  3. fm-claude-stop-autoarm.sh exits 2 and successfully creates the handling turn.
  4. The handling turn ends through Claude's StopFailure event because the API returns 529.
  5. Tracked .claude/settings.json registers supervision only for Stop.
  6. Therefore no guard or successor arm runs.
  7. With no watcher there is no wake; with no wake there is no turn; with no normal turn end there is no Stop.

Claude's hook reference says StopFailure runs instead of Stop on API errors and that its output/exit code do not control continuation, so copying the current exit-2 Stop handler is not sufficient.

Not the retained SIGTERM artifacts

Two older .claude-autoarm-output.* files contain Terminated: 15, but their watcher PIDs map exactly to lifecycle rows with reason=arm-interrupted during explicit Claude session restarts.
The final overnight cycle is exit_code=0 signal=none reason=actionable-signal.

Impact

Durable queue custody prevents data loss, but blocked work is neither retried nor reported until a human supplies another turn.
A transient vendor overload can therefore disable all supervision for an unbounded unattended interval.

Suggested fix

Register a dedicated primary StopFailure supervision handler.
At minimum it must, without another model turn, publish a typed degraded episode and emit one rate-limited pane-independent active alert through the existing wedge-alarm channels.

Acceptance criterion: within FM_GUARD_GRACE after an eligible StopFailure, either a live identity-matched watcher with an independently viable owner exists or the captain receives the active alert.

Do not reuse the current Stop exit-2 protocol without isolated live verification because Claude documents StopFailure output and exit status as ignored.

Add a live isolated regression that induces an API-error handling turn and sends no later user message.

Workaround

There is no reliable normal-mode unattended workaround in the current Claude-primary design.
Keeping the optional away daemon active could provide an independent owner only when its injection target is valid, but that is a different operating mode and should not be required to uphold normal Stop-owned continuity.


Metadata

Metadata

Assignees

No one assigned

    Labels

    ready-for-prTriage: real bug or VISION-aligned feature, open for a PR

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions