「覚えたルール」がバグにも都合よく当てはまるとき——エージェントワークフローのメタトラップ

Dev.to / 2026/5/4

💬 オピニオンDeveloper Stack & InfrastructureIdeas & Deep AnalysisModels & Research

要点

  • Claude Code のエージェントにある「バージョン管理されたメモリ」が、過去に覚えたルールを症状に“それっぽく”当てはめてしまい、検証を途中で止めてしまう副作用があると述べています。
  • 著者は、エージェントが提示した「1件の登録=N席」というルールに基づく説明を信じかけ、そのルールが実際には確認しているカウントの元データには適用されないため、SQL調査に約20分を費やした体験を紹介しています。
  • /crm/eleves 画面で「Enrolled」と「スタジオ」タブの合計が77ずれていたケースでは、最終的に基盤となるビュー(v_eleves)が contact_id で重複排除しており、席数ではなく人数を数えていたことが原因だと分かります。
  • 教訓は、メモリに保存された“それっぽいルール”が一致して見える場合でも、必ずカウンタの正確なデータソースとクエリの仕様で裏取りすべきで、検証の規律を強める必要があるという点です。
  • 著者は、エージェント自身のフィードバックファイルを信じ始めるほど、この「見かけは正しいが一般化に失敗して黙って外す」リスクが起きやすいと警告しています。

マンガ — ミシェルは、ルールの壁に新しいピンクのポストイットを貼る。隣のルールが互いに矛盾していることに気づかない。ポーリーヌはそれを見て、冷淡にツッコミます:「

もし30秒あるなら。 Claude Code のワークフローで行われる「バージョン管理された記憶(versioned memory)」には、誰も教えてくれない副作用があります。それっぽく症状に当てはまると、検証が短絡されてしまう“覚え込んだルール”があるのです。たとえ、それが今まさに見ている特定のカウンターには当てはまらない場合でも。先週、SQL の探索に20分を自分で浪費しました。バグの形をしたルール(ただしバグそのものではない)が、数値を生み出したビューを読まずに済ませてしまったからです。自分のフィードバックファイルを信じ始めているなら役に立ちます。

77の差

2026年4月22日、午前11:14。私は /crm/eleves ページで、管理アシスタントとの同期前にタブ数を確認しています。「Enrolled」は 785。タブ「Alesia studio」は 312、「Republic」は 278、「Villiers」は 272。この3つを足します:862。Enrolledカウントが主張するより、あるスタジオにおける登録数が77件多い。画面上で、数値同士が並んでいます。まるで、朝の気分を台無しにする寸前の数字のように。

私の最初の反射はSQLを開くことではありません。エージェントに聞くことです。スクリーンショットを貼り、差異を説明し、あまりにも素早く 「たぶん『1つの登録=N席』のルールのせいだよね?2つのスタジオにいる人はスタジオのタブで2回カウントされるはず」 と付け加えます。エージェントは同意します。説明はもっともらしい。ルールは存在します。さらに、そのためのメモリファイルまであります:feedback_modele_inscription_places.md。それでも私は規律としてSQLエディタを開きます。そして inscriptions を自分自身に結合して、同時に2つのスタジオに存在している連絡先(contacts)を探し続けます。20分かかりました。

それらは11件でした。11件では何も説明できません。差は77。

私はSQLを閉じ、スタジオのタブを実際に供給しているビューを読みます — v_eleves — そして3行目に DISTINCT contact_id 条項と、ateliers_effectifs[] という配列列があるのを見つけます。このビューは contact によって重複排除されています。座席を数えるのではなく、人を数えています。テーブル inscriptions では成り立つ「1登録=N席」のルールは、このカウンターには適用されません。そもそもこのカウンターは inscriptions を直接見ていないからです。座席をすでに人へと潰し込んだビューを読んでいます。

本当のバグは別の場所にありました:「Enrolled」タブは statut = 'inscrit' でフィルタしている一方、スタジオのタブは statut IN ('inscrit', 'ancien_eleve') でフィルタしているのです。スタジオのタブには ancien_eleve が77件表示されているのに、Enrolledタブには表示されていない。ステータス・フィルタの不一致。正しいコードパスに入ってから5分で見つかりました。

バグは5分で見つかりました。バグに至るまでは25分かかりました。そのうち20分は、適用されない“覚え込んだルール”を確認することに費やしたものです。

何が起きたのか

私はこの罠にまた戻ってきます。エージェントは嘘をついていません。私が提示した仮説を確認しただけです。メモリファイルは間違っていません。データモデルの“実在する不変条件”を説明しています。誤りはもっと前にありました — 問題をルールで切り取ったその瞬間、つまり、数値を生成したコードを読む前に。

記憶されたルールがエージェントのワークフローで持つ固有のリスクがあります。それは、呼び出してもコストがかからない、もっともらしい説明を提供してしまうこと。ルールはそこにあります。名前もあります。検証済みです。そして症状の形にもそれとなく一致しています。SQLビューを開くという認知的摩擦はゼロではありません。一方で「ルールがXと言っているから、バグはXの現れに違いない」という認知的摩擦はゼロです。あなたは安い道を選びます。ルールが売り込んでくるのです。

これは、メモリに関する前回の記事で私が述べたものとは別の失敗モードです。そこでの失敗は、コードの中でドリフトしてしまった事実について、エージェントが取り繕って(confabulateして)いたことでした。今回は失敗はです。安定していて正しいルールを、検証の代わりとして使ってしまいました。ルールはバグの輪郭(シルエット)に合っていたからです。トレース装置(trace device)は同じです。有用にしている規律は違います。

私は、エージェント向けではなく自分自身向けにフィードバックを書く必要がありました。

今私が適用するルール

その日の午後に ~/.claude/agent-memory/feedback_memoire_court_circuite_verification_code.md に追加したフィードバックは短いです:

なぜ: 記憶されたルールは、モデルの中の“正確な位置(precise location)”に適用されます。関連するデータを表示するすべてのカウンターに自動的に適用されるわけではありません。ルールが「バグっぽく見える」からといって検証を飛ばした結果、2026年4月22日にSQL探索20分を失いました。

どう適用する: UI上の数値が不整合に見え、記憶されたルールが差分(delta)を説明してくれそうだと思ったら、まずルールを呼び出す前に、その数値を生成するコードを開いてください。数値を生むSQLクエリ、または使用しているビューを読んでください。ビューが DISTINCT を行っていたり、重複排除されたソースを経由していたりする場合、「N席/人」のルールはその特定のカウンターには適用されません。読んでから呼び出す。

これはルールに関するルールです。エラーを直接減らすタイプのフィードバックではありません — 減らすのは、二種類目のエラーです。つまり、症状がもっともらしい形をしているために、正しいルールが誤って適用されてしまうタイプのエラーです。

コピペできるもの

私が今、規律として手元に置いている3つの具体要素:

  1. ルールを呼び出す前に“作り手(producer)”を読む。 あなたが調べているのがどんなカウンター、残高、集計(aggregate)であっても、それを生成するSQLビュー、APIハンドラ、またはReactのセレクタを開いてください。そうしないなら、あなたは検証していません。シルエットをシルエットに当てはめているだけです。
  2. エージェントへの質問を監査する。 「たぶんこれはXのせいだ」として調査を組み立てたとき、エージェントがどう同意するか見てください。仮説が、エージェントのメモリにある“ルール”を指し示しているなら、同意は安く済みます。仮説が仕事をしている。エージェントはゴム印(rubber-stamping)しているだけです。それはコラボレーションではありません。フレンドリーなインターフェースを通じた“確認バイアスの洗浄”です。
  3. メタ・フィードバックを書く。 ルールがだいたい正しい形だったために検証をスキップしてしまったと気づいたら、それは書く価値のあるフィードバックです。特定のケースよりも広く適用できます。私のものは、それ以来少なくとも2回は私を捕まえました。1回は couple と doublon のルールに見えた重複検出がそうではなかったケース。もう1回は tarif-applique-snapshot のドリフトに見えたカウントが、古い REFRESH から来ていたケースです。

より深い規律は、記憶されたルールは仮説であって、判決ではないということです。生成コードがそれを裏付けたときにだけ、その地位(rank)を獲得します。同僚からのスタックトレースのように扱ってください — 有用な指し示しではあるが、再現(reproduction)が必要です。

追記(コーダ)

返却形式: {"translated": "翻訳されたHTML"}

Claude CodeでRembrandtを構築していた4週間を振り返って気づくのは、適用を検証するための規律よりも、ルールが積み上がる速度のほうが速いということです。私のメモリディレクトリには、いま57個のフィードバックファイルがあります。どれも対向可能です。どれも日付が付いています。どれもどこかでは正しい。それらのすべての場所では正しくありません。そして、それらが正しい領域は、彼らが覆っているように見える症状空間よりも、より限定的です。

この非対称性がメタ・トラップです。ルールの数に比例して増幅します。メモリが豊かになればなるほど、実際には説明していないバグの形に、そのルールが合致してしまう頻度が高くなります。対処はルールを減らすことではありません——ルールを減らすと、ズレが増えます。対処は、法を引用する前に作り手(プロデューサー)を読む習慣をつけることです。

その朝、実際のバグを見つけるのに費やした5分間は落ち着いていました。25分前までの時間は、私がひとりで書いていた探偵小説で、エージェントがアリバイを供給してくれていました。私はそのエージェントに対して敵意はありません。ただ、少し冷めた認識があります。口を利き返してくるどんなツールでも、あなたが持ち込んだものを教えてくれる。そして、あなた自身からあなたを守っているのは、ツールが書かなかったファイルなのだと。

コンパニオンコード: rembrandt-samples/claude-md/feedback-template.mdfeedback_*ファイルの構造。この記事のメタフィードバックを作例として反映しており、MITで、コピペ可能です。