← 一覧に戻る

Telegram メッセージ取りこぼし対策 v2 設計書

2026年4月7日 22:50 更新
MD から自動変換されたページです。内容について質問があれば右下の ? ボタンからどうぞ。

問題

秘書セッションがツール実行中(dispatch-job.sh等の長時間Bash)にTelegramメッセージが来ると、 Claude Codeが処理しない場合がある。message_id=2604が完全にロストした実例あり。

Phase 2A の失敗分析

設計: 3スクリプト構成

根本原因1: UserPromptSubmitはMCP notificationで発火しない

Telegramメッセージは以下の経路でClaudeに届く:

Telegram → grammY long-polling → server.ts handleInbound()
  → mcp.notification('notifications/claude/channel', ...) → Claude Codeがsystem-reminderとして注入

mcp.notification() はUserPromptSubmitのパイプラインを完全にバイパスする。 これは patch-telegram-plugin.sh のコメント(4行目)にも明記されている。

→ intent-hook.shは構造的に動作不可能

根本原因2: パッチ方式は存在するが本番で稼働していなかった

patch-telegram-plugin.sh がserver.tsに直接record-intent.sh呼び出しを注入する方式は 設計として正しいが、初適用が2026-04-07 07:50と最近。それまでの本番セッションでは未適用。

結果

新設計: 5層防御アーキテクチャ

Layer 1: 確実な記録 (Recording) — 既存修正

場所: server.ts パッチ (patch-telegram-plugin.sh) 仕組み: handleInbound() 内で mcp.notification() の直前に record-intent.sh を fire-and-forget で実行 状態: パッチ自体は堅牢(構文検証・配置検証・ntfyアラート付き)。run-claude.shで毎回適用。 修正点: なし(既に動作確認済み。今後はrun-claude.sh経由で常に適用される)

Layer 2: 処理追跡 (Processing Tracking) — 新規

場所: PostToolUse hook(secretary/settings.json) 対象ツール: mcp__plugin_telegram_telegram__reply のみ 仕組み:

【Codex指摘反映】

Layer 3: セッション内リマインド (In-Session Reminder) — 新規

場所: PostToolUse hook(secretary/settings.json) 対象ツール: Bash(長時間実行の主要因) 仕組み:

Layer 4: 外部ウォッチドッグ (Orphan Watchdog) — 既存

場所: launchctl cron(com.aiharataketo.intents-timer、5分間隔) 仕組み: pending状態で10分以上経過したintentを検知→秘書セッションにtmux.py sendで通知 状態: 既に動作中。Layer 1が安定すればそのまま機能する。

Layer 5: セッション開始時チェック (Bootstrap Check) — 新規

場所: SessionStart hook(secretary/settings.json) 仕組み:

スキーマ変更

intentsテーブルに last_reminded_at カラムを追加(Layer 3のスロットリング用): ALTER TABLE intents ADD COLUMN last_reminded_at TEXT;

【Codex指摘反映】record-intent.sh の CREATE TABLE / MIGRATE セクションに last_reminded_at を追加する(「変更不要」→「migration追加が必要」に訂正)。 新規DBでも既存DBでもカラム存在を保証する。check-pending-intents.sh は カラム不在時に fail-closed する(silent fallthrough禁止)。

フック設定(secretary/settings.json)

PostToolUse:

SessionStart:

UserPromptSubmit:

メッセージフロー(取りこぼし発生時)

  1. ユーザーがTelegramでメッセージ送信 (message_id=2604)
  2. server.ts handleInbound() が受信
  3. [Layer 1] record-intent.sh → intents INSERT (status=pending)
  4. mcp.notification() → Claude Codeにsystem-reminder注入
  5. Claudeは長時間Bash実行中 → メッセージを処理しない
  6. Bash完了 → [Layer 3] check-pending-intents.sh が 3分超のpending検知 → additionalContext で注入
  7. Claudeがメッセージを処理し reply → [Layer 2] で closed

もし Layer 3 でも処理されなかった場合: 8. [Layer 4] intents-timer.sh (cron 5分) が 10分超のpending検知 → tmux.py send で通知

もしセッション間で残った場合: 9. [Layer 5] 次回SessionStart時にpending intentsを提示

replyツールのパラメータ(server.ts確認済み)

reply tool:

react tool:

PostToolUseフックの出力仕様(公式ドキュメント確認済み)

PostToolUse hookはstdoutにJSONを出力することでClaudeのコンテキストに注入できる: { "hookSpecificOutput": { "hookEventName": "PostToolUse", "additionalContext": "ここに書いた文字列がClaudeのコンテキストに追加される" } }

実装ファイル一覧

ファイル 操作 説明
~/.claude/scripts/close-intent.sh 新規 Layer 2: reply時にintent閉じる(reply_to明示一致のみ)
~/.claude/scripts/check-pending-intents.sh 新規 Layer 3: Bash後にpending intent確認
~/.claude/scripts/bootstrap-pending-intents.sh 新規 Layer 5: セッション開始時チェック
~/.claude/secretary/settings.json 修正 フック設定更新
~/.claude/scripts/intent-hook.sh 削除 UserPromptSubmitでは動作しないため

既存で修正が必要:

既存で変更不要:

テスト戦略

各Layerを独立してテスト可能にする:

  1. close-intent.sh: テスト用intentをINSERT → close-intent.shにモックJSON入力 → status確認
  2. check-pending-intents.sh: テスト用ancient intentをINSERT → スクリプト実行 → stdout JSON確認
  3. bootstrap-pending-intents.sh: テスト用intentをINSERT → スクリプト実行 → stdout確認
  4. 統合テスト: record-intent.sh → (時刻操作) → check-pending-intents.sh → close-intent.sh のフロー
  5. 誤閉鎖防止テスト: 同一chatに複数pending → reply(reply_to=特定ID) → 指定IDのみclosed、他はpending維持
  6. react非close検証: react後もintentがpending維持されることを確認
  7. schema migration テスト: last_reminded_at なしDBでrecord-intent.sh実行 → カラム追加確認
  8. cross-chat衝突テスト: 異なるchat_idで同じmessage_idのintent2件 → reply(chat_id=A, reply_to=X) → Aのみclosed、Bはpending維持

Codex Adversarial Review 指摘事項と対応

# 指摘 深刻度 対応
1 react を close 条件にすると未返信メッセージがロストする high react を Layer 2 対象から除外
2 reply_to 欠落時のヒューリスティック close は誤閉鎖を起こす high 明示一致のみに限定、曖昧ケースは pending 維持
3 last_reminded_at カラムが record-intent.sh の migration に含まれていない high record-intent.sh に migration 追加

第2回レビュー指摘(修正後の再検証)

# 指摘 深刻度 対応
4 last_reminded_at migration は設計のみで未実装 high 実装フェーズで record-intent.sh に追加(TDD で検証)
5 close 条件が reply_to 単独 → chat 間の message_id 衝突で誤閉鎖 high 複合キー (chat_id, reply_to) で完全一致に修正 + cross-chat テスト追加
📝 質問モード — テキストを選択してね
✓ 質問を送信しました