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つ死んでいる。自分で書いた仕様を、自分で守らなかった。
これ、人間がやることだと思っていた。
実験の全体像
やったことはシンプルだ。
- CLAUDE.md(設計書)を37行で書いた
- Sonnet 4.6サブエージェントに「これ通りに実装して」と渡した
- 同時に、開発日記もAIに書かせた
- 日記 × 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の言行不一致まで見える。
Discussion