📋 PR #97 設計ドラフト(Issue #74 / Phase 1)
ブランチ: chief/74-context-recovery-design / ステータス: OPEN・CI ✅・レビュー待ち
未確定論点 5 件は本文末尾「未確定の論点」セクションを参照。

M層 文脈復元設計(Push + Pull ハイブリッド)

関連 Issue: #74 関連 PR/Issue: #88(compact_summary バグ修正、CLOSED), #87(token threshold 引き上げ、OPEN)

目的

M層 のプロセス再起動・コンテキストロストに対し、議論連続性を保つための文脈復元機構を整備する。

スコープ

対応する再起動ケース(B カテゴリ):

区分 ケース 検知方法
B-1 トークン上限ローテーション再起動 bot/persistent_session.py 内 token カウント閾値
B-2 bot.py 再起動(launchd / 手動) プロセス起動時
B-3 プロセスクラッシュ → 自動 restart subprocess の returncode 検知
B-4 アカウント切替再起動 account_pool ローテーション通知

非スコープ(別 Issue 管轄): - A カテゴリ(履歴自動注入、#430 系) - セッション間の長期記憶(GitHub Issue / Slack thread が SoT)

設計原則

  1. 二重防御: Push(強制注入)と Pull(能動取得)の両方を持つ。どちらか欠けても致命傷にならない
  2. 層の独立性: L1/L2/L3 は並行生成・並行注入。1つの層が欠けても他の層は機能する
  3. モデル割当の責任分担:
  4. Haiku は routing 専任(CEO 方針)
  5. サマリ生成は Sonnet / Opus が担当
  6. 既存資産の活用: bot/session_log.py の作業ログを活用し、追加のストア層は作らない

アーキテクチャ概要

┌──────────────────────────────────────────────────────┐
│             M層 再起動契機 (B-1〜B-4)                  │
└────────────────────┬─────────────────────────────────┘
                     │
                     ▼
        ┌──────────────────────────┐
        │  Push: bot 側で強制注入   │
        │  ┌────────────────────┐  │
        │  │ L1: 直近10ラウンド  │  │  ← Sonnet 生成
        │  │     の素データサマリ│  │
        │  ├────────────────────┤  │
        │  │ L2: 全体サマリ      │  │  ← Sonnet 生成
        │  ├────────────────────┤  │
        │  │ L3: 確定事項リスト  │  │  ← Opus 生成
        │  │  (CEO 承認決定)    │  │
        │  └────────────────────┘  │
        └──────────────┬───────────┘
                       │ 起動時の最初のプロンプトに連結
                       ▼
              ┌──────────────┐
              │  M層 (Opus)   │
              └──────┬───────┘
                     │
                     │  必要時に発動
                     ▼
        ┌─────────────────────────────┐
        │  Pull: M層 が能動的に取得    │
        │  <<FETCH>>thread_history<</>>│
        │  ↓                          │
        │  bot が Slack API で取得     │
        │  → M層 に再注入              │
        └─────────────────────────────┘

Push 層: 3層構造

L1: 直近の素データサマリ(Sonnet 4.6)

目的: 最直近の活動コンテキスト復元。前回 invocation の流れを保つ。

生成タイミング: Soft 閾値到達時にバックグラウンドで生成(既存の _generate_compact_summary() の発展形)。

入力: bot/session_log.py の直近 10 entries(prompt + response + delegations)。

出力フォーマット:

Goal: <division 責務>
Recent Actions: <時系列で直近の主要アクション 5-7項目>
Open Loops: <CEO 返答待ち・W層 結果待ち等の未解決事項>

モデル: claude-sonnet-4-6 - 直近データの正確な要約が必要。Haiku は捏造リスクあり(#88 で露呈) - 頻度高め(再起動毎)なのでフルパワー Opus はオーバー

保存場所: logs/m-sessions/<route>-compact.jsonl(既存)

L2: 全体サマリ(Sonnet 4.6)

目的: スレッド全体・タスク全体のマクロ視点復元。

生成タイミング: 1日 1 回(cron 等)+ Hard 閾値到達時。

入力: 当日のセッションログ全件 + 直前の L2 サマリ(漸進的更新)。

出力フォーマット:

Daily Goal: <その日の目的>
Threads Engaged: <扱った Slack thread と主題のリスト>
Decisions Made: <その日の意思決定>
Pending Tasks: <翌日に持ち越し>

モデル: claude-sonnet-4-6 - L1 と同じ理由。全体俯瞰だが、Opus を割く必要はない

保存場所: logs/m-sessions/<route>-daily.jsonl(新設)

L3: 確定事項リスト(Opus 4.7)

目的: CEO が明示承認した決定を忘れない。最も漏らしてはいけない情報。

生成タイミング: CEO 発言中に「承認」「OK」「決定」等のキーワード検出時、または DONE status タグ付き応答後。

入力: 該当の Slack thread 全体 + 既存の L3 リスト(追記方式)。

出力フォーマット:

- [<YYYY-MM-DD>] <decision summary> (thread: <thread_ts>)
- ...

モデル: claude-opus-4-7 - 抽出ミスが致命的。Opus を割く価値あり - 頻度低い(CEO 承認は1日数回程度)のでコスト許容

保存場所: logs/m-sessions/<route>-decisions.jsonl(新設、append only)

Pull 層: M層 能動取得

発動条件

M層 が以下を検知したら能動取得を試みる:

  1. CEO 発言に指示語(「あれ」「さっきの」「前話した」)が含まれる
  2. 自分の記憶と CEO 発言の食い違いを感じる(自信なし応答が出そうな時)
  3. 「直前の議論」「履歴」を CEO が要求している

タグ書式

M層 応答内に以下を出力:

<<FETCH>>
{"target": "thread_history", "thread_ts": "1778246185.616809", "depth": 50}
<</FETCH>>
target 取得対象 取得経路
thread_history Slack thread の全 reply Slack conversations.replies API
session_log 自 M層 の直近ログ bot/session_log.py
issue_body GitHub Issue 本文 + コメント gh issue view --comments

bot 側ハンドラ

bot/router.py<<FETCH>>...<</FETCH>> タグを検出し、指定リソースを取得して M層 に再注入する(CONTINUE ラウンド扱い)。

4ケース別の発動経路

ケース Push 注入経路 Pull 発動
B-1 トークン上限ロテ bot/persistent_session.py の rotation 直後、起動プロンプトに L1+L2+L3 連結 M層 が違和感検知時
B-2 bot.py 再起動 初回タスク到来時、L1+L2+L3 連結 同上
B-3 クラッシュ自動 restart subprocess returncode 異常時、build_context_summary() 経由で L1+L2+L3 注入 同上
B-4 アカウント切替 account_pool ローテーション通知時、新セッションの初回プロンプトに L1+L2+L3 注入 同上

既存コードとの整合

影響範囲

ファイル 変更内容
bot/router.py _generate_compact_summary() のモデルを claude-haiku-4-5-20251001claude-sonnet-4-6 に変更。<<FETCH>> タグハンドラ追加
bot/session_log.py build_context_summary() に L2/L3 統合。-daily.jsonl / -decisions.jsonl 新設対応
bot/persistent_session.py rotation 時に L1+L2+L3 注入する処理を追加
bot/account_pool.py account 切替通知 → context_summary 注入トリガー
新規 L2 daily summary 生成スクリプト(cron 起動)
新規 L3 decision extraction(DONE status hook)

非互換性

実装計画

Phase 内容 担当 依存
P1 本設計 doc レビュー & 承認 CEO
P2 L1 (Sonnet 化) 実装 + 単体テスト github_claude P1
P3 L2 (daily summary, Sonnet) 実装 + cron 配線 github_claude P2
P4 L3 (decision extraction, Opus) 実装 github_claude P2
P5 Pull タグ機構(<<FETCH>>)実装 github_claude P2
P6 B-1〜B-4 注入経路の配線 github_claude P2-P4
P7 4ケースの実機検証 chief P6

各 Phase は別 Issue として分割し、claude-code-action に委譲する。

受け入れ条件(Issue #74 既定)

未確定の論点

レビュー時に CEO と詰めるべき点:

  1. L3 抽出のトリガー語: 「承認」「OK」だけで十分か、「決定」「進めて」も拾うべきか
  2. L3 リストの剪定: 無限に append しないために、古い decision を自動 archive する期間(30日?90日?)
  3. Pull タグの max depth: thread_history で 50 entries 取得は spam 防止の上限値で良いか
  4. L2 daily summary の生成時刻: 0:00 JST がブロード時間と被ると bot.py が止まる → 6:00 JST 等の安全時刻?
  5. コスト見積: L1 (Sonnet, 50回/日) + L2 (Sonnet, 1回/日, 大入力) + L3 (Opus, ~10回/日) の月額試算

最終更新: 2026-05-13 作成: chief(参謀) レビュー待ち: CEO