Stop hook exit-2 verdict silently discarded (no stop_hook_summary logged) when turn ends on a tool result with a pending ScheduleWakeup
Environment
- Claude Code v2.1.220 (also inspected the v2.1.221 changelog — no related fix listed)
- Linux (WSL2), CLI, interactive tmux sessions
Setup
A Stop hook (registered in ~/.claude/settings.json) enforces \"the final assistant output of a turn must be user-visible prose, not a tool call\". It scans the transcript tail and exits 2 with stderr when the last assistant output is a tool_use block. This works as documented on normal turn ends.
Expected
On every turn end, exit 2 from the Stop hook blocks the stop, the stderr is fed back to the model, and a stop_hook_summary system entry is written to the transcript — as happens on ordinary turn ends.
Actual
When the turn ends on a ScheduleWakeup tool result (the model stops right after arming a wakeup — the result text \"Nothing more to do this turn — the harness re-invokes you\" invites exactly this), the Stop hook is invoked and awaited, but its outcome is then silently discarded:
- exit 2 does not block the stop (no re-invocation, no stderr fed back)
- no
stop_hook_summaryentry is written — the hook execution is unlogged - the
turn_durationsystem entry lands directly after, delayed by exactly the hook's runtime
Evidence (transcript forensics across 10 sessions on one machine)
- Normal turn ends: 97/97 have a
stop_hook_summary(durationMs≈540,preventedContinuation:false) and the verdict is honored. - Wakeup-armed, tool-result-last turn ends: 0/76 have a summary; none were blocked. The gap between the last transcript entry and
turn_durationis ~1.07–1.24s, matching the hook's internal retry sleeps (2×0.5s) and scaling with transcript size exactly as its whole-file scans predict — i.e. the hook ran to completion and was then ignored. - Wakeup-armed turn ends where prose WAS last (compliant): summaries present and honored (14/14, 4/4 in two sessions) — so the discard is specific to the tool-result-last + wakeup-pending shape, not the wakeup path generally.
Impact
Any policy Stop hook (e.g. \"always end the turn with a user-visible message\") silently fails on exactly the turn shape it most needs to catch in scheduled-wakeup/loop workflows. Because no summary is logged, the failure is invisible — the hook appears healthy.
Related history
The v1.0.45 changelog notes \"Stop Hooks: … fixed triggering when loop ends with tool call\" — this looks like a sibling of that bug on the ScheduleWakeup park path.
Suggested fix
Run the Stop hook's decision through the same honor-and-log path on the wakeup-park turn end, or (if blocking is intentionally unsupported there) log the summary with an explicit \"verdict ignored: wakeup pending\" marker so hook authors can detect it.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗