docs(tickets): add memory-extract-occupancy-cap ticket

This commit is contained in:
Keisuke Hirata 2026-05-11 01:14:59 +09:00
parent 248e3d7aa2
commit eec33aba98
No known key found for this signature in database
2 changed files with 58 additions and 0 deletions

View File

@ -24,9 +24,12 @@
- セッションコンテキスト長 / ウィンドウ占有率の常時表示 → [tickets/tui-context-usage-indicator.md](tickets/tui-context-usage-indicator.md)
- Manifest: Tool Output / File Upload 上限の分離とデフォルト緩和 → [tickets/manifest-output-upload-limits.md](tickets/manifest-output-upload-limits.md)
- Prune: 保護境界を turn 数から末尾 token budget に置き換え → [tickets/prune-token-budget.md](tickets/prune-token-budget.md)
- Compact worker サーキットブレーカーを占有量ベースに統一 → [tickets/compact-worker-occupancy-cap.md](tickets/compact-worker-occupancy-cap.md)
- メモリ機構
- 使用頻度メトリクス + Knowledge 化候補レポート → [tickets/memory-usage-metrics.md](tickets/memory-usage-metrics.md)
- Phase 1/2 呼称を extract/consolidation に統一 → [tickets/memory-phase-naming.md](tickets/memory-phase-naming.md)
- extract / consolidation 監査ログ → [tickets/memory-audit-log.md](tickets/memory-audit-log.md)
- extract worker サーキットブレーカーを占有量ベースに統一 → [tickets/memory-extract-occupancy-cap.md](tickets/memory-extract-occupancy-cap.md)
- セッション内 Task ツールの注意機構(無アクティビティで `<system-reminder>` ナッジ) → [tickets/session-todo-reminder.md](tickets/session-todo-reminder.md)
- ワークスペースのメモリーをLintするヘッドレスCLI
- system-reminder 注入機構の汎用化2件目の利用者が出た時に検討。タグ形式 `<system-reminder>...</system-reminder>` の規約は session-todo-reminder で先行確立。注入された Item は worker.history に append する方針)

View File

@ -0,0 +1,55 @@
# Memory: extract worker のサーキットブレーカーを占有量ベースに統一
## 背景
`compact-worker-occupancy-cap` で compact worker のサーキットブレーカーを `UsageTracker` + `llm_worker::token_counter::total_tokens` ベースに切り替えたが、同じ設計上のバグを抱えた `MemoryExtractWorkerInterceptor``crates/pod/src/pod.rs:2180-2199` に残っている。実装コメントには `Mirror of compact::worker::CompactWorkerInterceptor;` と書かれており、compact 側が直った今、コメントも事実と乖離している。
具体的には:
- `MemoryExtractWorkerInterceptor``input_so_far: AtomicU64``UsageEvent.input_tokens``fetch_add` し、`pre_llm_request` で累積値が `max_input_tokens` を超えたら `Cancel` する (`pod.rs:1930-1942` で配線、`pod.rs:2186-2198` で判定)。
- `UsageEvent.input_tokens` は cache hit を含む prompt prefix 全体の占有量 (`crates/llm-worker/src/llm_client/event.rs:76-94`)。同じ prefix を毎ターンフルカウントするため、cache が 99% ヒットしても累積値は context size × ターン数で増える。
- 結果は compact と同じcap が「現在占有量」ではなく「累積(≒ context × turns」を測っており、設計と整合しない。
extract worker は compact ほどツールループが深くない(`extract.write_extracted_tool` のみ、ファイル探索なし)ため誤発火頻度は compact より低いものの、構造的な誤りは同じであり、放置すると今後ツールが増えた瞬間に再発する。
メイン Pod のしきい値群と compact worker (修正済み) はどちらも `Pod::total_tokens()` (`pod.rs:146-149`) 経由で「現在の占有量」を見ており、extract worker だけ別ロジックという歪みも残っている。
## 方針
`MemoryExtractWorkerInterceptor` を、compact 側と同じ `UsageTracker` + `llm_worker::token_counter::total_tokens` 機構に乗せ替える。累積メトリックは廃止する。compact と対称に `extract_worker_max_turns` を新設し、`Worker::set_max_turns` 経由で extract worker に伝える。
## 要件
- `MemoryExtractWorkerInterceptor``pre_llm_request``llm_worker::token_counter::total_tokens(context, &records).tokens > max_input_tokens` ベースに置き換える。`input_so_far: AtomicU64` の累積パスは廃止。
- Extract worker にも `UsageTracker` を持たせ、`pre_llm_request` で `note_request(context.len())`、`on_usage` で `record_usage(event)` する。compact worker (`pod.rs:1535-1547` 周辺) と同じ配線パターン。
- `extract_worker_max_input_tokens` の意味を「extract worker 側の現在占有量しきい値」に変更し、ドキュメント (`crates/manifest/src/lib.rs:111-115`, `crates/manifest/src/defaults.rs:54-56`, 関連 `docs/`) を更新する。デフォルト値 30000 は新セマンティクスで再評価可能だが、変更必須ではない。
- `MemoryConfig``extract_worker_max_turns: Option<u32>` を追加し、cascade (`crates/manifest/src/config.rs`) に通したうえで extract worker 構築箇所 (`pod.rs:1924-1942`) で `extract_worker.set_max_turns` に渡す。デフォルトは要検討(仮: `Some(8)` — extract は本来 1-2 ターンで終わる軽量 worker のため compact より小さく)。
- compact 側で消した「Mirror of `CompactWorkerInterceptor`」というコメントを削除し、独立した interceptor として doc を整える(実体はほぼ同じだが、ロジック共有のための共通化はやらない: subsystem ごとにメッセージとしきい値が異なる前提を維持)。
- 後方互換 shim は入れない。`extract_worker_max_input_tokens` はフィールド名を維持しつつセマンティクスだけ差し替える。
## 完了条件
- 通常の extract 実行で、cache hit 込みの prefix がフルカウントされなくなり、現実的な extract 入力 (compaction 区間の skeleton) で cap に当たらない。
- extract worker のループが暴走するケースで、`extract_worker_max_turns` により打ち切られる。
- `Pod::total_tokens()` / `CompactWorkerInterceptor` / `MemoryExtractWorkerInterceptor` の 3 者が同じ算出経路 (`llm_worker::token_counter::total_tokens`) を使っている。
- `MemoryExtractWorkerInterceptor` のユニットテストで「累積では落ちる量でも occupancy では通る」「占有量が cap を超えたら cancel」の 2 パターンが covered されている。
## 範囲外
- `extract_threshold`extract 発火条件)のセマンティクス変更。これは「ポインタ以降の cumulative input tokens」で別概念。
- Consolidation 側の同等変更consolidation worker は別の lock + iteration 機構で動いており、interceptor 設計が異なる。必要なら別チケット)。
- `compact_threshold` / `compact_request_threshold` 自体のセマンティクス変更。
- 共通 `OccupancyInterceptor` を新設して compact / extract で共有する抽象化。サブシステム個別のメッセージ・cap・将来の挙動分岐を残せるよう、現状の重複構造を維持。
## 影響範囲
- `crates/pod/src/pod.rs`:
- `MemoryExtractWorkerInterceptor` 定義 (`pod.rs:2180-2199`) を occupancy ベースに書き換え、`input_so_far` フィールドを `usage_tracker: Arc<UsageTracker>` に置換。
- extract worker 構築箇所 (`pod.rs:1924-1942`) で `UsageTracker` 配線、`set_max_turns` 呼び出し追加。
- `crates/manifest/src/lib.rs`:
- `MemoryConfig::extract_worker_max_input_tokens` の doc を新セマンティクスに更新。
- `extract_worker_max_turns: Option<u32>` フィールド追加 + デフォルト値関数。
- `crates/manifest/src/config.rs`: `MemoryConfigPartial` への追加と cascade 解決。
- `crates/manifest/src/defaults.rs`: `MEMORY_EXTRACT_WORKER_MAX_INPUT_TOKENS` の doc 更新、`MEMORY_EXTRACT_WORKER_MAX_TURNS` 定数の追加。
- `docs/manifest.toml` 等の memory 設定例: 新フィールドと意味の更新。
- `crates/pod/src/pod.rs` 周辺もしくは新規モジュールでのユニットテストcompact 側で追加した 2 パターンを extract 用に)。