45395 - シコウサクゴ -

AIメモリの索引は古くなる:「未反映6本」が全部反映済みだった実例と、MEMORY.mdを196行→69行に絞り、保留判断をcheckpointにする記憶設計

2026-04-26
AI駆動開発
AI駆動開発
Claude Code
MEMORY.md
Git
運用設計
Last updated:2026-11-08
15 Minutes
2853 Words

Claude Code の MEMORY.md に「6本の PR が未反映、リリース推奨」と書かれていました。それを信じて cherry-pick を始めたら、6本とも既に反映済みで、30分の作業が無駄になりました。

原因は、MEMORY.md の1行サマリと、実際の状態がずれていたことです。この記事では、この「索引が古くなる」問題の構造と、同じ時期に起きた「索引が膨らんで古い結論が目立つ」問題、そして対策として入れた運用ルールを整理します。


実例:「未反映6本」を信じて作業を始めた

ある日の朝、MEMORY.md に次のエントリがありました。

1
- [PR Backlog](pr_backlog.md) — 53コミット未反映、第1陣6本推奨(#157-#162)

この「第1陣6本推奨」を信じて、6本を1本ずつ pre ブランチに cherry-pick する計画を立てました。

Terminal window
1
git cherry-pick abc1234 # PR#157
2
# → 衝突発生

単純な typo 修正のはずなのに、3箇所も衝突します。違和感があったので調べました。

Terminal window
1
git log pre --grep="(#157)" --oneline # → ヒット
2
git log pre --grep="(#158)" --oneline # → ヒット
3
...
4
git log pre --grep="(#162)" --oneline # → ヒット

6本とも、すでに pre に入っていました。30分間、不要な cherry-pick の衝突を解いていたことになります。


構造:索引と本体は、更新のタイミングが違う

会話ログをさかのぼって、原因を突き止めました。

  • 本体(pr_backlog.md): 最終更新は 2026-04-15 で、「この時点で53コミット未反映」と書かれていました。その後、別のセッションで PR#157〜#162 が cherry-pick されましたが、本体は更新されていませんでした
  • 索引(MEMORY.md): 1行サマリは本体を最後に更新したときのスナップショットで、その後の変化は反映されません

つまり、索引は本体の鮮度を超えられません。本体が古ければ、索引も古いままです。

AI は索引をいちばん強く信じる

Claude Code は、会話の開始時に MEMORY.md を自動でシステムプロンプトに入れます。1行サマリは、AI が最初に読む情報です。

  • AI は索引を読み、「未反映6本」を事実として受け取る
  • 本体ファイルや git の履歴を確かめる前に、作業計画を立てる
  • 誤った前提のまま cherry-pick を始める

索引が間違っていると、AI はいちばん強く誤った方向に導かれます。


もう1つの実例:索引が膨らむと、古い結論が目立つ

同じ時期に、別の形でも索引に引きずられました。新しい取り組みの対象業種を AI に相談したところ、明らかに古い結論にもとづく答えが返ってきました。

1
ユーザー: 新しい取り組みの対象業種を検討し直したい
2
AI: 過去のヒアリング(04-14)から、業種Aが最有力です

実際には、その後の2件目のヒアリング(04-18)で、業種Bのほうが反応がよいと分かっていました。MEMORY.md には両方の記録がありましたが、196行に膨らんだ索引の上のほうに「業種Aが最有力」という1行が残っていて、AI はまずそれを読んでいました。

調べてみると、問題は自動で読み込まれることそのものではなく、索引が膨らんで、古い結論の行が残り続けていることでした。


対策1:着手前に、実際の状態を確かめる

いちばん即効性があるのは、作業を始める前に git log で実際の状態を確かめるルールです。

Terminal window
1
for pr in 157 158 159 160 161 162; do
2
if git log pre --grep="(#$pr)" --oneline | grep -q .; then
3
echo "PR#$pr: 反映済み → スキップ"
4
else
5
echo "PR#$pr: 未反映 → cherry-pick 候補"
6
fi
7
done

これを cherry-pick-audit という skill にして、MEMORY.md の記述より実際の確認を優先するよう、ワークフローに組み込みました。cherry-pick の前に確かめる前提条件と、その判定の仕方は「cherry-pick前の3値判定」に書いています。


対策2:索引のエントリに「最後に確かめた日」を書く

各エントリに、いつ実際の状態を確かめたかを書きます。

1
- [PR Backlog](pr_backlog.md) — 53コミット未反映、第1陣6本推奨 [verified: 2026-04-15]

そして「verified から7日以上たったエントリは、使う前に必ず確かめ直す」というルールを CLAUDE.md に書きます。日付があれば、AI も「この情報は古いかもしれない」と判断できます。


対策3:索引を絞る(196行→69行)

書くもの・書かないもの

  • 書く: 進行中の施策や未解決の問題など、自分で能動的に管理している情報
  • 書かない: 「リリース予定6本」のように、git の履歴など外の状態で決まる情報。これは実行時にコマンドで取得すべきもので、スナップショットを書いた瞬間から古くなり始めます

運用ルール

  1. MEMORY.md は索引だけにする: 1行150文字以内のサマリとリンクだけを書き、本文は別ファイルに置きます
  2. 終わったもの・古いものは退避する: 完了した項目と、8日以上更新のない項目は archive/ に移し、索引からも消します。完了した項目は、その日のうちに消します。残しておくと「進行中」と誤解されるためです
  3. 200行を上限にする: MEMORY.md は、200行を超えた分が読み込まれません。超える前に統合・削除します

8日以上更新のないファイルを探すには、次のようにします。-mtime +7 は「7日を超える(8日以上)」という意味です。

Terminal window
1
find . -maxdepth 1 -name "*.md" ! -name "MEMORY.md" -mtime +7 -exec mv {} archive/ \;

結果

指標BeforeAfter削減率
MEMORY.md の行数1966965%
MEMORY.md のサイズ18.2KB5.0KB73%
索引のリンク数1553975%

絞った後は、「業種Aが最有力」の行は archive に移り、AI は本文のファイルを読みにいって新しい情報も合わせて答えるようになりました。このルールで回し始めてから1週間、古い結論に引きずられたと感じる場面はありませんでした。

CLAUDE.md の側の肥大化と、その圧縮の記録は「CLAUDE.mdの肥大化と圧縮の記録」にまとめています。


対策4:「後でやる」は、トリガー付きの checkpoint として残す

索引を絞ると、「今は決めなくていい、後でやろう」とした判断まで消えてしまう心配があります。この種の判断は、TODO コメントや Issue にしても埋もれがちです。

TODO コメントが「腐っていた」例

リポジトリを整理していて、次の TODO コメントを見つけました。

1
# TODO: もしレスポンス時間が500msを超えるようになったら、
2
# キャッシュ層を入れる検討をする

書いたのは3ヶ月前で、現在のレスポンス時間は800msでした。判断のきっかけはとっくに来ていたのに、誰も気づいていませんでした。このファイルは最近誰も開いておらず、レスポンス時間は別の場所で見ていたからです。判断の条件と、判断する場所が離れていると、条件を満たしても誰も気づきません。

checkpoint の形

そこで、保留した判断は「いつ・何を見たら判断するか」を構造にして、AI の外部記憶に置くことにしました。

1
type: deferred_decision
2
created: 2026-05-17
3
trigger:
4
what: response_time
5
threshold: 500ms
6
source: ダッシュボードのURLまたはクエリ
7
decision: キャッシュ層を入れるか
8
context: |
9
現状 200ms。当面はキャッシュなしで問題ないと判断した。
10
負荷が増えるとレスポンスが悪化する見込みなので、500ms を超えたら再評価する。
11
related_files:
12
- src/api/handler.py

CLAUDE.md には、関係するファイルや領域を触るときは、まず該当する checkpoint のトリガーが満たされていないかを確かめ、満たされていればユーザーに知らせる、と書いておきます。トリガーが数値で取れるものなら、週1回スクリプトで確かめることもできます。

使い分け

状況置き場所
次のコミットで直すTODO コメント
今のスプリント中に対応するIssue
条件が変わったら判断するcheckpoint
とりあえずのメモノート

checkpoint の対象は、「いつ判断するかは今は分からないが、きっかけは定義できる」ものです。

書けない保留は、保留ではない

この運用には副次的な効果がありました。checkpoint を書くには、「何を見たら判断するか」を最初に決める必要があります。

1
書ける保留: 「P99 レイテンシが500msを超えたら、キャッシュを検討する」
2
書けない保留: 「将来的に何かあったら見直す」

書けない保留は、本当は「保留」ではなく「あいまい」だったと気づけます。その場で、今決めるべきことではないかを考え直します。


AI の記憶を設計する4つの原則

  1. 外の状態を索引に書かない: git log やファイル一覧、API の応答のように実行時に取れる情報は、索引に書きません。書いた瞬間から古くなります
  2. 索引は本体の鮮度を超えられない: 本体を更新しないまま索引に追記しても、意味がありません。索引には「最後に確かめた日」を添えます
  3. 索引は「今の話題の見出し」に絞る: 終わったものと古いものは退避し、200行の上限より十分に小さく保ちます
  4. 着手前の確認と、保留のトリガーを仕組みにする: 実際の状態の確認は skill や hook で強制し、保留した判断はトリガー付きで残します

AI の出力や記憶を鵜呑みにせず、実物で裏を取る作法は「AIの報告を鵜呑みにしない」にもまとめています。


まとめ

  • MEMORY.md の「未反映6本」を信じて cherry-pick したら、6本とも反映済みでした。索引は、本体を最後に更新した時点のスナップショットにすぎません
  • 索引が196行に膨らむと、古い結論の行が目立ち、AI がそれに引きずられました。69行に絞り、終わったものと古いものを退避するルールにしました
  • 「後でやる」は、トリガー付きの checkpoint にして残します。トリガーを書けない保留は、その場で考え直します

索引は古くなる前提で運用する。これが、AI の記憶を設計するときの出発点です。

Article title:AIメモリの索引は古くなる:「未反映6本」が全部反映済みだった実例と、MEMORY.mdを196行→69行に絞り、保留判断をcheckpointにする記憶設計
Article author:45395
Release time:2026-04-26

記事へのご質問・ご感想をお聞かせください

フィードバックを送る