| name | cache-check |
| description | incremental search・メモ化など前回結果を再利用するコードの追加・変更時、または計画レビュー時に使用。述語の単調性と状態遷移の安全性を検証する。 |
| argument-hint | [対象, 例: 'search_with_options: use_incremental 判定' / 'folder cache: prev_filter reuse'] |
| allowed-tools | ["Read","Grep","Glob"] |
$ARGUMENTS のキャッシュ再利用ロジックについて、述語の単調性と状態遷移の安全性を検証する。
$ARGUMENTS が空の場合は、会話の直近の変更内容から対象を推定する。
実装後のコードレビューだけでなく、workspace/plan.md の計画レビューにも使える。計画段階で「このキャッシュ再利用は安全か?」を検証し、見落としがあれば計画を更新してから実装に進む。
背景
キャッシュ再利用(incremental search、メモ化、前回候補の絞り込み等)が安全なのは、今回の結果集合が前回の結果集合の部分集合であるときだけ。これは各述語(フィルタ条件)が前回→今回で「狭まる方向」にのみ変化すること(単調性)を要求する。
典型的なバグパターン:
- 述語の新規出現: 前回は適用されなかった述語が今回有効になり、前回の候補に含まれない要素がヒットするはず → false negative
- 非単調な変換: 入力の伸長に対して述語の内容が非単調に変化する(例: ローマ字→かな変換で "kan"→"かん", "kana"→"かな")
- 閾値の跨ぎ: 入力長が閾値を超えた瞬間に新しい述語が有効化される(例: min_chars)
- キャッシュ状態の更新漏れ: 結果を使った後にキャッシュ状態を更新し忘れ、次回判定が壊れる
Step 1 — 再利用判定の述語列挙
$ARGUMENTS から対象のキャッシュ再利用ロジックを特定し、ソースコードを読む。
再利用を許可する条件(use_incremental / can_reuse 等)を構成する全述語を列挙する:
述語 1: <条件式> — <意味>
述語 2: <条件式> — <意味>
...
各述語が「前回→今回で候補集合を狭める方向にしか変化しない」ことを保証しているか確認する。
Step 2 — 各述語の単調性検証
述語ごとに、入力が変化するパターンを列挙し、単調性を検証する:
述語 1: <条件式>
入力変化パターン A: <前回> → <今回> → 候補: [狭まる/広がる/不変] → [単調/非単調]
入力変化パターン B: <前回> → <今回> → 候補: [狭まる/広がる/不変] → [単調/非単調]
判定: [OK: 常に単調] / [要ガード: パターンBで非単調]
特に以下の変化パターンに注意:
| パターン | 例 | リスク |
|---|
| None → Some | 述語が新たに有効化される | 前回候補に新述語マッチが含まれない |
| Some → None | 述語が無効化される | 候補が広がる可能性(通常は安全だが要確認) |
| 値の非単調変化 | 変換関数の出力が入力伸長で非連続に変わる | starts_with が成り立たない |
| 閾値の跨ぎ | min_chars 未満→以上 | None→Some と同型 |
| prefix 拡張 | "do" → "dok" | 通常は単調(安全)— 候補が狭まる方向 |
| バックスペース | "dok" → "do" | 候補が広がる → full scan 必須 |
| モード切替 | 通常検索 → slash command / instant command | 別モードの候補は無関係 → full scan 必須 |
| ライフサイクルリセット | window-shown / Escape | キャッシュ全クリアが必要 |
Step 3 — 状態遷移マトリクス
キャッシュ判定に使う状態変数の全遷移パターンを列挙する:
今回
前回 None Some(A) Some(B)
None ✅ 安全 ❌ 新規出現 ❌ 新規出現
Some(A) ✅ 消滅 ✅/❌ 比較 ❌ 非単調
Some(B) ✅ 消滅 ❌ 非単調 ✅/❌ 比較
「❌」のセルに対して、コード上でフォールバック(full scan 等)が実装されているか確認する。
Step 4 — キャッシュ状態の更新検証
再利用判定に使うキャッシュ状態(prev_query、prev_mode、prev_kana_query 等)について:
- 更新タイミング: 結果のスコアリング/フィルタリング後に確実に更新されるか
- 全フィールドの同時更新: 一部だけ更新して他を忘れていないか
- early return パス: 結果を返す全パス(正常・エラー・空結果)でキャッシュが整合状態になるか
キャッシュ状態 1: <フィールド名>
更新箇所: <file:line>
全パスで更新: [OK] / [問題: <early return で更新されないパス>]
キャッシュ状態 2: <フィールド名>
...
Step 5 — 境界条件テストの確認
以下の境界条件に対応するテストが存在するか grep で確認する:
| 境界条件 | テストの内容 |
|---|
| None → Some 遷移 | 新述語の有効化で漏れなくヒットするか |
| 非単調遷移 | full scan フォールバックが正しく動作するか |
| 閾値の跨ぎ | 閾値前後で結果が fresh scan と一致するか |
| 単調拡張 | incremental が fresh scan と同一結果を返すか |
| キャッシュクリア後の再構築 | クリア→再検索で結果が正しいか |
推奨テスト手法: incremental result == fresh result の性質テスト。同一入力列に対して「キャッシュありで逐次検索した結果」と「毎回キャッシュなしで検索した結果」が一致することを検証する。非単調遷移・モード切替・バックスペースなど、上記全パターンで一致を確認するのが理想。
テストが不足している場合は、具体的なテストケースを提案する。
出力
根拠の規律: 全判定に根拠(file:line または grep 結果)を付ける。コードを確認せずに下した判定は [OK] とせず [要確認] として報告する。
全述語の単調性判定と状態遷移マトリクスをまとめる。
問題が見つかった場合は修正案(ガード条件の追加 / 状態変数の拡張 / テスト追加)を提示する。
全述語が安全な場合は「全述語で単調性が保証されており、キャッシュ再利用は安全」と明示する。