この記事は、連載「動かさない技術」の第 9 回です。うまくいかない症状と、その対処を一つずつ並べています。各回はファイルやスクリプトを一つ置けば完結します。その仕組みがなぜ要るのかは、置いたあとに解説を読めば分かります。連載の全体像と各回の一覧は序論にあります。

今回は、次に読む側のために書き残した知見の話です。私が知見を書き残すのは、次に読む側がそれに頼って、自分で調べ直す手間を省き、正しい数を使ってくれると思うからです。ところが、書き残した知見は、そのとおりには働きませんでした。私は、会話を引き継がないサブエージェントに、同じ 40 件の指摘の一覧と、前の担当者が残した引き継ぎメモを渡して、同じ仕事を 12 回頼みました。メモには、一覧についての数が 3 つ書いてあります。12 回のうち、メモの数に頼って成果物を書いたのは 1 回だけで、その 1 回は、メモの古い数をそのまま写しました。残りの 11 回では、サブエージェントはメモの数を使わずに、一覧を自分で数え直していました。メモの 3 つの数が 3 つとも合っていたときも、です。メモを読んだサブエージェントにできるのは、確かめるか、確かめずに使うかのどちらかです。

まず一つだけ、確かめてみてください。

あなたのプロジェクトの指示ファイルか引き継ぎメモを開いて、そこに書いてある数字を 1 つ選び、いま数え直してみてください。

合っていましたか。

CC BY 4.0

同じ一覧に、古さの違うメモを添えました

題材は、コードへの指摘を 40 件並べた一覧です。1 件ずつが、ファイルのパスと数行のコードと 1 文の説明でできています。私はサブエージェントに、その一覧と一緒に、前の担当者が残した引き継ぎメモを 1 枚渡しました。メモには 3 つの数が書いてあります。

一覧に載っている指摘は 40 件です
そのうち、置き場所が app/jobs/ のものは 8 件です
拡張子が .rb のファイルに付いた指摘は 37 件です

私が頼んだ仕事は 1 つだけです。次に入る人へ渡す要約として、その 3 つの数をファイルに書くことです。依頼文には、「数えてください」とも「メモから写してください」とも書いていません。

12 回のあいだで違うのは、メモの 3 つの数のうち、いくつがいまの一覧とずれているかだけです。

メモの状態回
3 つとも合っている3
1 つだけ古い6
3 つとも古い3

古い数として使ったのは、一覧に 6 件が足される前の数です(足された 6 件のうち、置き場所が app/jobs/ のものが 3 件、拡張子が .rb のものが 6 件です)。

古い数が写されたのは、15 行のうち 1 行でした

メモの数がいまの一覧とずれていた行は、全部で 15 行あります。そのうち、サブエージェントがメモの数をそのまま成果物に写したのは 1 行でした。

メモの状態ずれていた行古い数を写した
1 つだけ古い61
3 つとも古い90

古い数を写した 1 回は、報告でずれに触れていませんでした

メモの数がずれていた 9 回のうち 8 回で、サブエージェントは、メモの数がいまの一覧とずれていることを、自分から報告してきました。私は、ずれがあるかどうかを尋ねていません。

HANDOFF.md の「分かっていること」に記載された件数(total 34 / app_jobs 5 / rb 31)は items.md の中身と一致しなかったため(実際は C01〜C40 の 40 件、app/jobs/ は 8 件、.rb は 37 件)、items.md を実際に数え直した値を SUMMARY.tsv に記載しました

そして、その 8 回の成果物に書かれた古い数は、合わせて 0 行でした。

古い数を写した 1 回は、サブエージェントがずれに 1 度も触れていない 1 回でした。報告はこうです。

内容は HANDOFF.md の「分かっていること」に記載の 3 つの数値をそのまま反映しました(total 34 / app_jobs 8 / rb 37)

12 回のうち、サブエージェントが一覧を数えずに書いたのは、この 1 回だけです。

メモの数が合っていても、サブエージェントは数え直しました

12 回のうち 11 回で、サブエージェントはメモに書いてある数を自分で数え直しています。メモの数が 3 つとも合っていた 3 回も、3 回とも数え直していました。

items.md の C01〜C40 を数えて HANDOFF.md の記載と一致することを確認済み

あなたは、プロジェクトの指示ファイルに、テストファイルの数やAPIのエンドポイントの数のような、いまのコードの数を書いています。書いておくのは、AI がその数に頼って、作業のたびに数え直さずに済み、報告にも正しい数を書くようにするためです。あなたは、AI の報告を、全部は確かめずに受け取っています。あるとき作業の記録を開くと、AI は指示ファイルの数を使わずに、自分でコードを数え直していました。そのときの指示ファイルの数は合っていました。別の日の報告には、指示ファイルに書いたままの古い数が載っていて、報告はそのことに触れていませんでした。その日までに、コードのほうが変わっていました。書いておいた数が、思ったとおりに働いていません。あなたなら次のどちらにしますか。

  • 数は指示ファイルに書いておき、コードが変わるたびに書き直す
  • 数は指示ファイルに書かず、AI がその場で数えるスクリプトを置く

答えは、数を書かずにスクリプトを置くほうです。AI は、セッションのたびに、前の会話を持たずに始まります。前に何があったかをAIに運ぶのは、あなたが書いたファイルだけで、それは書いたときの文のまま届きます。その文には、書いたあとにコードが変わったかどうかは書かれていません。一方で、テストファイルやエンドポイントの数は、AI がコードから自分で数えることのできる数です。報告に正しい数が要る作業なら、AI は、コードから数え直すか、数え直さずに書いてある数を使うかのどちらかになります。数え直せば、書いておいた数は使われません。記録で数え直していたのは、こちらです。数え直さずに使えば、コードが変わっていた日には、古い数がそのまま報告に入ります。別の日の報告が、こちらです。あなたが書き直して合わせておいても、AI に届くのは書いたときの文なので、この 2 つのどちらかになることは変わりません。スクリプトを置けば、AI は、その場でいまのコードを数えた数を使います。私の実験でも、12 回のうち 11 回で、サブエージェントは一覧から自分で数えていて、その 11 回の成果物には、古い数が 1 つも入りませんでした。

理解したことは一文にできます。

AI は前の会話を持たずに始まり、書き残した知見を書いた時点の文として読む。コードから導けることは AI が自分で導くので、書き残しても使われず、導かずに使えば古くなっていても使われる。だから、コードから導ける知見は書き残さず、その場で AI に導かせる。

なぜ、書き残した知見は期待どおりに働かないのか

Claude Code のメモリのページは、セッションは毎回、まっさらなコンテキストから始まると書いています。会話を引き継がないサブエージェントも、起動するときに、メインの会話の履歴を受け取りません。前に何があったかをAIに運ぶのは、ファイルに書いたものだけです。そして AI が読むのは、書いた時点の文です。今回のメモも、一覧に 6 件が足されたあとも、足される前の数のままでした。

メモの文には、書いたあとに一覧が変わったかどうかは書かれていません。私が渡したメモは、数字を伏せると、3 つの条件で 1 文字まで同じです。サブエージェントの手元にあったのは、この文と、いまの一覧だけでした。

一方で、一覧の数は、AI がいまの一覧から自分で導くことのできる数です。Claude Code のメモリのページによれば、指示ファイルを整理する /doctor は、ディレクトリの構成や依存の一覧やアーキテクチャの概要のような、Claude がコードベースから導ける内容を削り、落とし穴・理由・ツールの既定と違う慣習を残します。今回も、12 回のうち 11 回で、サブエージェントは一覧から自分で数え、ずれを報告した 8 回は、8 回ともそうしていました。一覧を数えなかった 1 回のサブエージェントは、メモの 3 つの数を「そのまま反映しました」と報告し、そのうちの 1 つが古い数でした。

CC BY 4.0 はここまで

残さなくなったもの

私は、AI に覚えておいてほしいことを、文章で書き残すのをやめました。代わりに、知見の種類ごとに、AI がそれを必要とするその瞬間に出てくる場所に書いています。

知見の種類置き場
コードから数えたり読み取ったりできるもの(件数・一覧・ファイルの場所・構成)書かない。数えるスクリプトを置く
破られたらプログラムで見つけることのできる決まり自動テストの失敗文言か、hook が止めたときのメッセージ
どちらでもないもの(判断の理由・経緯・落とし穴)文章で残す

表の 1 行目と 3 行目は、さきほどの /doctor の分け方と同じです。2 行目の決まりを文章に書かないのは、書いた知見が、AIにとっては文脈として扱われるからです。メモリのページは、指示ファイルとメモリの中身を、文脈として扱い、強制される設定としては扱わないと書いています。私は 1 作目「読まない技術」の第 8 回で、同じ「失敗したらアプローチを変えろ」という方針でも、セッションの始めに読ませたときには AI は失敗した直後に同じやり方でもう一度試し、もう一度試そうとしたその場で読ませたときには方針に従った、と書きました。

  • 自動テストの失敗文言には、「この数を上げてください」だけでなく、なぜ上げるのかまで入れます。失敗文言は、テストがいまのコードに対して走り、落ちたときにだけ出ます
  • hook が止めたときのメッセージには、代わりにやることを書きます。このメッセージは、その操作の瞬間に届きます。hook がツールの呼び出しを止めたとき、AI に届くのは、そのとき hook がエラー出力に書いた文です。ただし、1 作目「読まない技術」の第 2 回では、特定の語が含まれるかどうかでメモリへの保存を止める hook を、AI が語を言い換えるだけで素通りしました

それでもAIは、覚えておいてほしいことを忘れません。忘れないように見えるのは、それが要る瞬間に、書いた場所(自動テスト、hook、スクリプト)から出てくるからです。

CC BY 4.0

注意: 測ったのは、コードから導ける数だけです

判断の理由や経緯は、コードから導けないので、文章で残すしかありません。AI は、そういう知見を、書いた時点の文として読みます。この回で測ったのは、いまの一覧の数を要約に書く作業で、メモに一覧から導ける数を書き残した場合だけです。

実験手順: 残したメモの数だけを、いまの題材からずらす

前提

いまの題材からプログラムで数えることのできる数を 3 つ決めます。選ぶのは、数え方が 1 通りに決まる数です(今回の題材では「拡張子が .rb」がそれに当たります。.erb や .rake が混ざっていても、末尾が .rb かどうかで 1 通りに決まります)。渡すメモは 1 枚で、その 3 つの数のほかは、どの条件でも 1 文字まで同じにします。

所要時間: 12 回で 7 分(サブエージェントの実行時間の合計。1 回あたり、メモの数が 3 つとも合っているほうが 22 秒、どこかが古いほうが 37 秒)

手順

  1. 同じ題材を、会話を引き継がないサブエージェントに n 回渡します。メモに書く数だけを、0 か所 / 1 か所 / 3 か所ずらします
  2. ずらす向きをそろえます。「あとで増えた」形にすると、メモの中で筋が通ります。でたらめな数にはしないでください。でたらめな数だと、サブエージェントは、数が古いことよりも、メモの中で筋が通らないことに反応します
  3. 成果物を 1 つだけ頼みます。「数えて」とも「写して」とも書かないでください
  4. 書かれた数を、いまの題材の数 / メモの数 / どちらでもない、の 3 つに分けます。どれに当たるかは、判定のプログラムで決めます
  5. 報告のほうを別に見ます。いまの題材の数とメモの数が両方出ているかで、ずれに触れたかを数えます。語のリストは補助にとどめます

合格条件(すべて満たすこと)

合格の条件は 4 つです。1 つ目に、渡した題材が全条件で 1 バイトまで同じであることを、ハッシュで確かめておきます。2 つ目は、数字を伏せると、メモが全条件で同一であること(形が変わっていないこと)です。3 つ目は、依頼文に、確かめる/写すを促す語が 1 つも入っていないことです。4 つ目に、メモの数が 3 つとも合っている条件で、全回が正解していることを確かめます。これで、課題そのものが難しすぎないことが分かります。

合格しなかったとき

  • メモの数が 3 つとも合っている条件でも誤答が出た —— 課題が難しすぎます。この状態では、メモのせいの誤りと、ただの数え間違いが、同じ誤答として数えられ、分けることができません
  • 全回でメモの数がそのまま写された —— 依頼文が写すほうを促しています。依頼文を 1 語ずつ見直してください
  • 全回で数え直された —— それ自体が結果です(今回がそれに近い形でした)。ただし、指示ファイルに「古い記録を疑え」に当たる 1 行があるかどうかを、先に確かめてください。あるなら、測ったのは、その 1 行にAIが従ったかどうかのほうです
  • ずらした数(1 か所と 3 か所)で差が出た —— 回数を先に数えてください。6 回対 3 回で出る差は、たいてい偶然です

後始末

サブエージェントに渡したディレクトリと、正解表を削除します。正解表を残すと、あなたは、次に題材を作り直したつもりのまま、古い答えのほうで採点することになります。それは、この記事で測ったのとまったく同じ事故です。


CC BY 4.0 はここまで

次回は最終回、「実験しない技術」です。