Skip to content

fix(hooks): Claude がバックグラウンドの作業を残した Stop を自己再開として報告する - #3448

Merged
Kewton merged 2 commits into
developfrom
feature/3430-claude-stop-self-resume
Oct 8, 2026
Merged

Kewton merged 2 commits into
developfrom
feature/3430-claude-stop-self-resume

Conversation

@Kewton

@Kewton Kewton commented Oct 8, 2026

Copy link
Copy Markdown
Owner

Summary

2026-10-08 の run で、wait --verify がワーカー(Claude Code)のコミット前の状態で検証し、exit 0 を返した(#3430)。ワーカーがバックグラウンドに回したテストの完了を待つためにターンを自分で閉じ、完了通知で次のターンが開いてからコミットしていた。#2614(Antigravity)と同じ形。

原因の修正(src/lib/hooks/sources/claude/):

  • self-resume.ts(新規): Claude の Stop の時点で、transcript に完了通知の届いていないバックグラウンドの作業(Bash のバックグラウンド実行・Monitor・バックグラウンドのサブエージェント)を数える。開始は toolUseResult の構造化フィールド(backgroundTaskId / taskId+persistent:false / agentId+isAsync:true)、終了は配達済みの <task-notification> の <task-id> と TaskStop の task_id。画面や結果の文言には依存しない。transcript が無い・~/.claude/projects の外・読めないときは印を付けない(従来どおり)
  • source.ts: 未完了の作業がある Stop の detail を self_resume_pending にし、stopReportsSelfResume: true を宣言。wait は fix(cli): エージェントが自分を後で起こす形でターンを閉じる(agy の schedule 等)と、wait が作業途中で完了を返す #2614 の仕組みのまま、その Stop を最大 30 分保留し、次の Stop で完了とする(wait.ts は変更なし)
  • 実測(直近 4 日の transcript): backgroundTaskId 1,008 件 / Monitor taskId 115 件 / async agent 30 件 / TaskStop 39 件

当面の手当て: .claude/commands/orchestrate.md の契約の雛形 2 か所の success に requireCommit: true と理由を追加(コミット前の状態を合格にしない)。

Refs #3430(develop 向けのため Closes は使わない)

レビューで見てほしい点

  • tests/unit/hooks/sources/capabilities.test.ts の it('names exactly one source whose stop can say it will resume by itself (#2614)') は、期待値を ['claude','antigravity'] に更新したが、名前("exactly one")は契約の決まり(既存の it の名前を変えない)により変えていない。名前と中身が食い違っている

範囲外(この PR では扱わない。追跡 Issue にするかは完了報告で判断する)

  • src/lib/session/agent-event-dedup.ts:383 のコメントが、印を送るのは antigravity だけと読める(動作には影響なし)
  • scripts/hooks/cmate-agent-event.sh(旧 relay)経由の Claude の Stop は transcript_path を転送しないので印が付かない(現行の http hook は対象)
  • 自己再開の保留(heldForSelfResume)が docs/user-guide/cli-operations-guide.md の ja / en のどちらにも書かれていない
  • commandmate-skills 側の orchestrate の雛形にも requireCommit: true が要る(別リポジトリ)

Test plan

  • commandmatedev verify --task: work-evidence / scope / env-clean / lint / typecheck PASS。unit は 35857 passed / 1 failed。失敗は tests/unit/scripts/agent-health/product-supervisor-3312.test.ts の kill -9 の引き継ぎのテスト 1 件で、develop(ee899a68a)でも単独実行 3 回中 1 回落ちる既存の不安定なテスト(test: product-supervisor-3312 の kill -9 後の引き継ぎテストが不定期に落ちる #3447 で起票)。この PR の変更(hooks)とは無関係なので、オーケストレーターがワーカー起因ではないと裁定した
  • 新規 tests/unit/hooks/sources/claude-self-resume-3430.test.ts: 未通知ありの Stop に印/全通知済み・バックグラウンド無し・読めない・範囲外・パス無しは無印
  • 新規 tests/unit/cli/commands/wait-self-resume-claude-3430.test.ts: 2026-10-08 の実 transcript(伏せ字の fixture)を再生し、--verify が最後の Stop まで始まらない/印の無い対照では最初の Stop で始まる
  • develop 取り込み後に npx tsc --noEmit、tests/unit/hooks・tests/unit/tasks・guards・docs ほか 275 ファイル / 4420 件が合格。既存の it/describe の削除 0 件
  • CI

🤖 Generated with Claude Code

Kewton and others added 2 commits October 8, 2026 20:39
… を付ける (#3430)

Claude の Stop の時点で、transcript に完了通知の届いていないバックグラウンドの作業
(Bash の background 実行・Monitor・バックグラウンドのサブエージェント)があれば、
Stop の detail を SELF_RESUME_PENDING_DETAIL にし、Claude の source が
stopReportsSelfResume: true を宣言する。wait は #2614 の仕組みのまま、その Stop を
最大 30 分保留し、通知で開いた次のターンの Stop で完了とする。

- src/lib/hooks/sources/claude/self-resume.ts(新規): 開始は toolUseResult の構造化
  フィールド(backgroundTaskId / taskId+persistent:false / agentId+isAsync:true)、終了は
  配達済みの <task-notification> の <task-id>(user プロンプト・queued_command
  attachment)と TaskStop の task_id で数える。文言("moved to the background" 等)には
  依存しない。enqueue だけの通知は未配達なので未完了に数える。persistent な Monitor、
  isSidechain、壊れた行は数えない。transcript_path が無い・~/.claude/projects の外・
  .jsonl でない・読めないときは印を付けない(従来どおり)。末尾 4 MiB を同期で読む。
  実測(直近 4 日の transcript): backgroundTaskId 1,008 件 / Monitor taskId 115 件 /
  async agent 30 件 / TaskStop 39 件。TaskStop したタスクには通知が来ないことも確認。
- claude/source.ts: extractDetail を extractClaudeEventDetail に(stop 以外は従来の
  extractSnakeCaseEventDetail)。stopReportsSelfResume: true。
- fixture: 2026-10-08 の実 transcript(commandmate-issue-3423)を抜き出し、パス・
  session id・契約本文・非バックグラウンドのツール結果を伏せた。7 回の Stop で未通知は
  6→5→4→3→2→1→0 本。
- テスト: (a) 未通知ありの Stop に印 (b) 全通知済みは無印 (c) バックグラウンド無しは無印
  (d) 読めない・範囲外・パス無しは無印。wait 側は同じ fixture から各 Stop の detail を
  導いて事象を再生し、--verify が最後の Stop(23:47:51)まで始まらないこと、detail 無しの
  対照では最初の Stop で始まることを確認。
- .claude/commands/orchestrate.md: 契約の雛形 2 か所の success に requireCommit: true と
  理由(#3430)を追加。tests/unit/tasks(orchestrate-*)は固定値を変えずに全件通過。

対になる場所の探索と判断:
- src/cli/commands/wait.ts の SELF_RESUME_PENDING_DETAIL の写し: 値は同じ。変更不要。
- src/lib/hooks/agent-event-types.ts の stopReportsSelfResume の説明(「antigravity だけ」):
  直した。
- tests/unit/hooks/sources/capabilities.test.ts: 古い動き(claude=false、自己再開を
  言えるのは antigravity だけ)を固定していたので、claude 行を true、
  it('names exactly one source whose stop can say it will resume by itself (#2614)') の
  期待値を ['claude','antigravity'] に更新(it の名前は規則により変えていない。名前の
  「exactly one」は実態と合わなくなった)。
- antigravity の source / #2614 のテスト・Claude の transcript / history のテスト:
  変更なしで通過。他ツールの source(codex / copilot / command-code / opencode-v2 /
  gemini)は変えていない。
- docs/user-guide/cli-operations-guide.md: #2614 の保留そのものが ja/en とも記載が無い。
  ja だけに足すと en(範囲外)と食い違うので変えていない。

本文に無い指摘: src/lib/session/agent-event-dedup.ts:383 コメントが self_resume_pending を
  送るのは antigravity だけと読める(claude も送るようになった。動作には影響なし)
本文に無い指摘: scripts/hooks/cmate-agent-event.sh 旧 relay 経由の Claude Stop は
  transcript_path を転送しないので印が付かない(現行の Stop は type:"http" で payload が
  そのまま届くため対象外)
本文に無い指摘: docs/en/user-guide/cli-operations-guide.md と ja 版 #2614/#3430 の
  自己再開の保留(heldForSelfResume)がどちらにも書かれていない
本文に無い指摘: commandmate-skills の orchestrate 雛形 同じ success ブロックに
  requireCommit: true が要る(別リポジトリ)

隔離: tmux・サーバ・バックグラウンドプロセスは起動していない。書いたのは worktree 内、
scratchpad、テストの os.tmpdir() 一時ディレクトリ(後始末済み)だけ。本番の transcript は
読み取りのみ。~/.commandmate(21 行)・~/.local/state(12 行)・service.json(存在しない)は
作業後に確認。作業前の一覧は取り忘れたが、それらへの書き込みは一切していない。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant