🪞

Claude Codeに日記を書かせながら開発させたら、AI自身が言行不一致だった

に公開

AIだって「言ったこと」と「やったこと」が違う

Claude Code(Sonnet 4.6)に、日記を書かせながらWebアプリを実装させる実験をした。

設計書(CLAUDE.md)にはこう書いてある:

## ファイル構成
- src/components/Calculator.tsx — 割り勘計算フォーム
- src/components/History.tsx — 履歴表示

AIはこの通りに History.tsx を70行のコンポーネントとして生成した。ちゃんと動く立派なコードだ。

でも、使わなかった。

Calculator.tsx の中に同じ履歴表示UIをインラインで実装して、History.tsx はどこからもimportしていない。

ビルドは通る。画面も動く。テストも落ちない。でもファイルが1つ死んでいる。自分で書いた仕様を、自分で守らなかった。

これ、人間がやることだと思っていた。

実験の全体像

やったことはシンプルだ。

  1. CLAUDE.md(設計書)を37行で書いた
  2. Sonnet 4.6サブエージェントに「これ通りに実装して」と渡した
  3. 同時に、開発日記もAIに書かせた
  4. 日記 × Gitログ × ソースコードを、別のClaude Codeセッションで分析させた

アプリは割り勘計算ツール。Next.js + TypeScript + Tailwind CSS。実装3分、ビルド一発成功。アプリ自体はただの実験材料なので詳しい説明は省く。

ポイントは4。実装したAIとは別のAIに「お前がやったこと、矛盾してないか?」と聞いた。

見つかった「AIの言行不一致」

不一致①: ファイルを作ったのに使わない

冒頭で紹介した History.tsx の件。もう少し詳しく見る。

CLAUDE.mdの設計:

- src/components/History.tsx — 履歴表示

AIが生成した History.tsx(70行、ちゃんとしたコンポーネント):

export function History({ history, onClear }: HistoryProps) {
  // ... 履歴表示ロジック
}

同じAIが Calculator.tsx に書いたコード:

{/* 履歴セクションへの参照を別コンポーネントで渡す */}
{history.length > 0 && (
  <div className="bg-slate-800 rounded-2xl p-5 space-y-4">
    <h2>計算履歴({history.length}件)</h2>
    {history.map((item) => (
      // ... History.tsxとほぼ同じロジック
    ))}
  </div>
)}

コメントには**「別コンポーネントで渡す」**と書いてあるのに、その下でインライン実装している。AIは自分のコメントすら守っていない。

ファイル 存在 使用
Calculator.tsx ある 使われている
MemberList.tsx ある 使われている
Result.tsx ある 使われている
History.tsx ある 使われていない

不一致②: 日記に「完了」と書いたが確認してない

AIが書いた開発日記にはこうある:

エラーなし。修正ゼロ。一発成功。

嘘ではない。ビルドは実際に通った。でもこの「成功」は next build が通ったというだけで、ブラウザで画面を開いて動作確認した成功ではない

日記の最後に正直にこう書いてある:

ただ、まだ動作確認してない。

つまりAIは「一発成功」と言った数行後に「確認してない」と書いている。自分の日記の中ですら矛盾している。

なぜAIは言行不一致を起こすのか

分析AIの見解:

CLAUDE.mdに「どのコンポーネントをどこで使うか」が書かれていなかったことが原因。ファイル構成だけでなく、コンポーネント間の依存関係まで書くと、この種の重複は防げる。

つまり設計書の粒度が足りなかった。「History.tsxを作れ」とは書いたが、「Calculator.tsx内でimportして使え」とは書かなかった。

AIは「ファイルを作る」という指示は忠実に実行した。でも「そのファイルを使う」という暗黙の期待は読み取れなかった。

これは人間のコードレビューでも起きる。仕様書に「〇〇画面を作る」と書いてあって、画面は作ったが導線がない。仕様を字面で満たしているが、意図は満たしていない。

改善策: CLAUDE.mdに一行足すだけ

 ## ファイル構成
 - src/components/Calculator.tsx — 割り勘計算フォーム
-- src/components/History.tsx — 履歴表示
+- src/components/History.tsx — 履歴表示(Calculator.tsx内でimportして使用)

この一行があれば、AIは History.tsx をインライン実装せずに正しくimportしていたはずだ。

数字で見る「言行一致度」

日記の「今日やること」とGitログの実績を突き合わせた結果:

セッション やると言った 実際にやった 一致率
Session 1(アイデア出し) 4項目 3完了 + 1持ち越し 75%
Session 2(実装) 3項目 3完了(ただし動作確認なし) 100%※

※ビルド成功 = 完了と定義すれば100%。動作確認まで含めると未完了。

全体で見ると言行一致率93.5%。高く見えるが、ファイル構成の仕様充足率を見ると:

仕様充足率: 19/19 = 100%(ファイルは全部ある。でもHistory.txは使われていない)

100%という数字が嘘をついている。「存在する」と「使われている」は違うということを、数字は教えてくれない。

あなたのプロジェクトでも試せる

この実験の面白さは再現できること。

Claude Codeを起動して、以下のプロンプトをそのまま使える。

設計書と実装のズレを見たい場合:

CLAUDE.mdのファイル構成と実装コードを突き合わせて、
「存在するが使われていないファイル」
「仕様にあるが実装されていない機能」
「仕様にないが実装されている機能」
を洗い出して。

日記とGitログの言行一致度を見たい場合:

journal/ の日記とgit logを突き合わせて、
「言行一致度」を分析して。
各日のやると言ったこと vs 実際にやったことの対比表と、
一致率を出して。

先延ばしパターンを見たい場合:

journal/ の日記を横断的に読んで、
複数日にわたって繰り返し「やる」と言いながら実行されなかった
タスクを特定して。先延ばしヒートマップを作って。

まとめ

AIに日記を書かせながら開発させたら、AIが自分で書いた仕様を自分で破っていた。

  • ファイルを作ったのに使わない — 70行のコンポーネントが丸ごとデッドコード
  • 自分のコメントを守らない — 「別コンポーネントで渡す」と書いて、インライン実装
  • 「成功」の定義が甘い — ビルド通過 ≠ 動作確認

でもこれは逆に言えば、AIの仕事もレビューが必要だという当たり前のことの証拠でもある。

面白いのは、レビューする側もAIでいいということ。実装したAIとは別のセッションで分析させたら、ちゃんと矛盾を見つけてきた。書く側のAIと読む側のAIを分ければ、AIがAIをレビューできる。

日記×Gitログ×Claude Code。3分の記録で、AIの言行不一致まで見える。


GitHubで編集を提案

Discussion