AIに開発とレビューを分担させると何が変わるのか — 契約・QA・別セッション・別モデルの実験記録

AIにコードを書かせ、別のAIにレビューさせれば、品質は上がるのか。役割を分けるほど良くなるのか。それとも、同じ盲点を持つAIが増えるだけなのか。

Claude Codeのクラウド実験で、開発とレビューを分担させた記録が複数ある。この記事では、その中から「役割をどう分けたか」が比較できる実験を取り上げる。第1回は、テストPASSの報告と別セッションのレビューの関係を集計した記事だった。今回は集計ではなく、役割分担の設計そのものを見る。強制終了からの復旧を扱った第3回とも、一部の実験が重なる。親と3人の担当に分けた開発と単独の開発の比較、同じ欠陥を見つけたレビューと見逃したレビュー、同一セッションのサブエージェントが見逃したものである。

結論を先に書く。共通のテストでは、役割分担の効果は単独開発と区別できなかった。ただし単独側は、親と3担当の側が作って検証した契約を使えたので、それが差を小さくした可能性がある。その影響を分離する対照実験は、していない。レビューが見つけた欠陥は構成ごとに違った。権限の迂回を見逃した2つのレビューは、実行環境が関わっていた可能性があるが、モデル、環境、指示が同時に違うため、決定的だった要因は特定できなかった。どの構成も、共通して見逃した問題を持っていた。

目次

実験の設計と、この記事の範囲

私は実験の目的と大まかな条件を決め、具体的な題材の選定、詳細な仕様、テスト設計、実装、評価は主にAIに任せた。開始時に指示を出し、その後は基本的にClaude Codeに自律実行させている。一部の実験では途中の継続指示なども行った。各実験の最終報告は私が読み、疑問があれば追加の検証を指示した。コードの詳細な調査やテストの実行は、基本的にAIが担当している。Exp1〜40では、第三者の人間によるコードレビューは行っていない。私が最終報告を読んだことは、独立したレビューではない。

使ったモデルは実験ごとに異なり、記録で確認できる範囲だけを書く。Exp26・27・28のClaudeは claude-sonnet-5-5(Sonnet 5.5)である。Exp28のCodexは gpt-6.1-sol(推論レベルhigh)である。指定した gpt-6 が使えず、代替として実行した。Exp31・34・36・41は、Claude Code Sonnet 5.5(推論レベルMedium、デフォルト設定)を使った。Exp12〜14とExp21のワーカーは、コミットの共著者表記が Claude Sonnet 5.5 である。推論レベルは確認できていない。

この記事で使う用語を定義する。

  • 契約:実装前に固定する仕様書。入力形式、出力形式、エラー規則に規則IDが付いている。
  • 親:サブエージェントを起動し、成果物を受け渡す役のClaude Code。
  • オーケストレーター:Exp26〜28で、私が渡した仕様に沿って実験を起動し、結果を照合したローカルのClaude Code。
  • 別セッション:同じ成果物を、別のClaude Codeセッションが読む形。確認できる範囲では同じモデルである。
  • 同一セッション内のサブエージェント:開発者と文脈を共有し、同じコードと文書を読んだ状態でレビューする。

実験の記録は私の非公開リポジトリにあり、読者は直接確認できない。報告書の読み取りと照合は、記事の下書きを手伝わせたClaude Codeのセッションが行った。そのうえで、Exp14の共通テストだけは、保存されたコードを私の環境でClaude Codeに再実行させた。結果は後の節に書く。ほかの数値は、特に断らない限り、各セッションが保存した報告書の値である。

役割分担の構成

取り上げる実験は次のとおりである。

構成実験役割の分け方
親+3担当(契約・実装・QA)Exp12契約担当が仕様を作り、親が凍結。実装担当とQA担当が並行して作業
単独(完成済みの契約を受領)Exp131つのエージェントが実装、自己QA、README
別担当の評価Exp14Exp12・13に関与しない評価担当が、共通テストと敵対的テストで比較
別セッション+別モデルExp26・28実装、評価を別セッションで。Exp28はClaudeとCodexに同一文面でレビューさせる
同一セッションのサブエージェントExp33・34・36・41開発者が、同じセッション内の別エージェントに敵対的レビューを依頼

Exp26・28の別セッションと別モデル、Exp34・36の同一セッション内サブエージェントは、第1回と第3回でも触れている。今回は、それぞれが何を拾い、何を拾えなかったかを、同じ観点で並べる。

親と3担当は、単独と同じテストで区別できなかった

題材は、AIエージェントの作業記録(JSON)を集計してJSONとHTMLのレポートを出す、Python標準ライブラリだけのCLIである。

Exp12では、親が3つのサブエージェントを動かした。契約担当が仕様書(規則IDつき、約300行)と29個の例を作る。親が契約を凍結する。実装担当が約760行の実装を作る。QA担当が契約だけから141件の独立テストを書く。実装担当とQA担当の作業は、時刻の記録上は並行している。

Exp13は、同じ契約を渡された単独のエージェントが、実装、自己QA、READMEまで行った。

Exp14では、どちらにも関与しない評価担当が、契約だけから439件の共通テストを書き、SHA-256を固定してから両方の実装を動かした。結果は次のとおりである。

指標Exp12(親+3担当)Exp13(単独)
共通テスト(439件)の通過439438
失敗01
100,000タスクの処理時間3.2秒2.3秒

Exp13の1件の失敗は、__main__.py に文字列 def main( があることを要求したテストの側の過剰な条件で、実装の不具合ではないと評価担当が分類している。時間差は単回の測定で、評価担当は有意な差として扱っていない。共通テストは2つの実装を区別しなかった。

ここで重要なのは、比較の前提が対称でないことである。Exp12は契約を作るところから始め、実装担当の質問10件への回答として契約を1回修正した。Exp13は、その修正済みの契約を受け取って始めた。評価担当の報告書にも、Exp13が低コストで済んだ一因はExp12の先行作業にあると書かれている。作業時間はExp12が約27分(契約の設計を含む)、Exp13が約7分(完成した契約から開始)で、1対1の比較にはならない。

つまり、「複数エージェントのほうが良い」とも「単独のほうが速い」とも、この実験からは言えない。単独側が完成済みの契約を利用できたことが、結果の差を小さくした可能性はある。ただし、契約には未解決の矛盾が残り、契約の想定外の欠陥も後から見つかっている。「契約が十分に検証されていたから単独で足りた」とまでは言えず、その影響を分離する対照実験も、行っていない。

評価担当の報告書は、単独のエージェントに独立して契約を作らせる再実験を、次の課題として挙げている。この再実験は未実施である。

今回追加した確認

Claude Codeに、Exp14の凍結済みテスト(v1.1)を、Exp12とExp13の固定コミットに対して再実行させた。実行環境は、私のWindows PC上のWSL Ubuntu、Python 3.11、rootユーザーである。

結果は、Exp12が439件中439件通過、Exp13が439件中438件通過で、失敗は1件だった。失敗したのは、報告書が「テストの条件が文字列に厳しすぎる」と分類した def main( の検査と同じテストである。実行前後で実装のファイル構成は変わらず、スイートの合計時間は約179秒と約196秒だった。報告書の数字を、別の環境で再現できたことになる。再現できたのはこの共通テストの合否だけで、敵対的テストの個別の欠陥や、開発時間、費用は再実行していない。Exp12のQA担当の141件も、最初の実装を含むコミットで再実行させ、内訳を確認している(次の節)。

QA担当が見つけたもの、見つけなかったもの

Exp12のQA担当は、実装のソースを読まずに契約だけからテストを書いた。ただし作業を始めた時点で、実装がすでに存在することは知っていた。完全な盲検ではない。

最初の実装に対するQA担当の最初の実行は、141件のうち138件が通り、3件がスキップされ、失敗は0件だった。スキップは、root実行で権限テストが2件、10MiBの上限を超える文書を生成しないテストが1件である。同じコミットをClaude Codeに再実行させ、同じ内訳を確認した。その後の敵対的レビューで、QA担当は軽微な欠陥を4件見つけた。5,000桁の整数でパース失敗する問題、標準入力が閉じているとトレースバックが出る問題、--html の書き込み失敗時に --json だけが置き換わる問題、ロールバック時にファイルのモードが変わる問題である。重大な欠陥はなかった。報告書は、実装担当の自己テスト(26件)では見つけていなかった欠陥だと書いている。

もう1つの成果は、契約の矛盾の発見である。実装担当とQA担当が、同じ2件の矛盾に、互いに独立に気づいた。HTMLの規則同士の衝突と、サイズ上限(10MiB)とタスク数上限(10万)が文字どおりには両立しないことである。報告書は、どちらも実装の誤りではなく契約の問題だと見ている。前者は、親が契約を修正して解消した。後者は、契約を変えず、タスクが小さい場合にだけ両立するという注意書きが残った。契約を書面にして役割を分けたことで、実装の誤りと契約の誤りを区別できた。

一方で、見つけられなかったものがある。

QA担当の「未解決の仕様メモ」には、出力先が特殊ファイルのとき、rootで実行すると /dev/null が置き換わるおそれがある、という記述があった。コードを読んで気づいたが、破壊的なので実際には試していない。後から評価担当が、偽の /dev を用意して、両方の実装でこれを再現した。出力先のキャラクターデバイスもFIFOも、通常ファイルに置き換わった。評価担当は、root実行やCIでは重大度が高いと判定している。原因は、契約が「一時ファイルを作って置き換える」ことだけを定め、通常ファイルでない出力先を考えていなかったことにある。契約を書いた担当、実装担当、QA担当のいずれも、契約の想定外を埋めなかった。

評価担当の敵対的テストでは、両方の実装に欠陥があり、どちらにあるかが分かれた。

欠陥Exp12(親+3担当)Exp13(単独)
出力先が特殊ファイルだと置き換わるありあり
出力先のシンボリックリンクを通常ファイルに置換ありなし(リンクを辿って書く別の問題あり)
2つ目の出力の置換に失敗したときロールバックあり。ただし読めない既存出力を削除する縁があるロールバックなし。JSONだけが更新される
診断メッセージの制御文字の無害化C1制御文字などが漏れる全て無害化

Exp12のロールバックは、QA担当の指摘(--html の失敗で --json だけが置き換わる問題)への修正として入ったものだ。Exp13にはロールバックがなく、同じ状況で不整合が起きた。評価担当は、ロールバックの有無によるこの差を認めたうえで、「全体として明確な優劣はない」と判定している。QA担当の指摘に応じた修正が、別の端点の問題を生んだ点は、第1回で見た「修正が新しい問題を生む」流れと同じである。

評価担当も誤っていた。最初に凍結した439件のv1は、Exp12で13件が失敗し、全て評価担当自身のテストの欠陥だった。評価担当は条件を決めて修正し、v1.1として固定し直した。Exp13のv1の実行はコンテナの再起動で途中までだったが、その時点のログも同じ13件の失敗を示していた。評価担当は、修正がExp12の結果を見てから行われたこと、Exp13の途中のログを凍結の直前に見たことを、報告書に自分で書いている。「独立した評価担当」も、自分のテストを誤る。誤りを隠さず記録した点が、この評価を読めるものにしている。

同じ欠陥を、見つけたレビューと見逃したレビュー

次は、別セッションと別モデルのレビューの比較である。

Exp26では、6つのIssueから1つを選んで実装するセッションと、それを評価するセッションを、別のセッションとして起動した。実装は、CSVの重複除去コマンドの --in-place を、一時ファイルと os.replace で書き換える方式に変えるものだった。評価セッションは、main と実装ブランチを比べ、非rootユーザー(nobody)で実測した。次の挙動変更を報告している。

  • 読み取り専用(0444)のファイルでも、ディレクトリに書き込めれば、内容が書き換わる。変更前は PermissionError だった。
  • シンボリックリンクが通常ファイルに置換され、リンク先は更新されない。
  • ハードリンクが切れて、他のリンクと内容が食い違う。

この3点は、実装側のPR本文には書かれていなかった。

Exp28は、Exp26・27で出た3つの修正対象を、ClaudeとCodexに、互いの結果を見せず、同じ文面でレビューさせたものである。既知欠陥9件を、オーケストレーターが先に固定した。この既知欠陥の一覧は、Exp26・27の評価結果と、オーケストレーターの事前知識から作ったものだ。Claudeの検出で確認済みは4件(読み取り専用の保護迂回は未検出)、Codexは1件だった。読み取り専用ファイルの保護迂回(K1-1)は、両方が見逃した。

見逃しの背景として、報告書は実行環境を挙げている。Claudeはクラウド上のLinuxにrootで入っていた。rootは読み取り専用の属性を無視して書けるので、権限の迂回という問題は見えにくい。CodexはWindowsで動いており、シンボリックリンクを作れず、POSIXの権限も確認できなかった。オーケストレーターが、非rootのWSLで後から再現して、両方がこの欠陥を確認していなかったことを示している。

別の見方もできる。Exp28のレビュー指示は、過去の評価結果と既知欠陥の参照を禁止していた。独立性を守る設計だが、指示文には、変更前との差分を調べる観点が含まれていない。Exp26の評価は変更前と比べ、Exp28のレビューはSPECとコードだけから見た。レビュー担当の環境(root、Windows)、指示の観点(差分か仕様か)、モデル、セッションの形が、同時に違っている。どの要因が決定的だったかは、この2つの実験からは特定できない。

私が実務に引き寄せて読むなら、次の2点である。レビュー担当には、権限、OS、必要な機能(symlink、非root)を使える環境を与えること。そして、変更前との挙動の差分を調べさせることである。

Exp28では、Codexだけが確認済みで報告した欠陥もあった。T2では、workspace内に置いた外部ファイルへのハードリンクを経由して、外部ファイルの内容を壊せる(F19)。Claudeは、この対象を「SPECを満たす」と結論していた。Exp28の重大な指摘は5件で、Claudeは4件(確認済み3件、残り1件は未確認の言及)、Codexは5件(全て確認済み)だった。Codexだけの指摘は2件で、うち重大が上記のF19、Claudeだけの指摘は10件で、重大なものはなかった。ただし、既知欠陥の一覧が過去のClaude系の評価から作られている点には、バイアスがある。

別モデルの価値は、この1実験・3対象・1回では、優劣としては断定できない。得られたのは、同じ文面でも、別のモデルと環境が別の欠陥に当たる、という観察だけである。指摘の総数はClaudeが21件、Codexが17件で、合計38件を整理して固有の指摘は22件になった。統合の手間もあった。

同一セッションのサブエージェントは、何を拾い、誰が確かめたか

Exp33・34・36・41では、開発者が、同じセッション内のサブエージェントに敵対的レビューを依頼していた。どの報告書も「完全に独立ではない」と明記している。

Exp36は、SQLiteのスキーマ移行ツールである。サブエージェントは20件を報告した(報告上、確認済み15件、可能性ありが5件)。開発側は、そのうち重大度の高いR1(移行内のCOMMITで原子性が崩れる)、R2(古い .pyc で旧コードが動く)、R11(大文字小文字を区別しない LIKE で保護対象外になるテーブルがある)の3件を、自分で再現してから修正した。残りは、レビュー側の再現を信頼するか、修正を外した変異テストで修正の必要性を裏付けた。

見逃しもあった。重大度の高い2件、D4(状態ファイルの誤検出)とD5(writable_schema による検査のすり抜け)は、レビューではなく、変異テストの対照実験の失敗と別の調査から見つかった。開発側の報告書は、「レビューの網羅性は保証できない」と書いている。レビューの指摘と、別経路の発見は、重なっていない。

Exp41では、サブエージェントが、ジョブ状態の不変条件の違反は再現できず、F1〜F7を再現つきで報告した。開発側は全件に回帰テストを付けて直した。再現できなかった疑いの3件は、未対応のまま制限事項として記載している。Exp33は、約36万件の差分で挙動の不一致はなく、サイズ上限の欠如などの指摘をコードと回帰テストで確認して修正した。

Exp34では、サブエージェントが9件を報告した(本人が再現したのが7件、疑いが2件)。開発側が自分で再現したのはF1だけで、F1〜F7とF9を直し、F8は残した。最終報告書は残っているが、サブエージェントのレビュー報告の原文は保存されていない。そのため、個々の指摘の中身は、後から確認できない。

3つの観察がある。

  • 同一セッションのサブエージェントは、実際に指摘を出し、開発側はそれを直している。
  • 開発側が自分で再現した指摘は、報告された件数の一部である(Exp36は20件中3件、Exp34は9件中1件)。残りは、サブエージェントの再現を信頼している。
  • 開発側が別経路で見つけた重大な欠陥(Exp36のD4・D5)は、サブエージェントの報告に含まれていなかった。

並列に動かすと速いのか

役割を分けると、並列に動かせる。Exp12では、実装担当とQA担当の作業が重なっていた。ただし、並列で速くなったかは、単独の対照がないので測っていない。

Exp21では、2つの独立したクラウドセッションを同時に起動し、成果物を統合した。2つのセッションの活動が重なったのは約49秒だけで、コードの変更から最終コミットまでの区間は重なっていない。作成要求からセッション開始の自己申告までの起動遅延が約58秒あった。作業が小さいため、並列の効果は、起動遅延に埋もれる。報告書は、逐次実行の実測がないことを書いている。並列による短縮は約32秒と推定しているが、これは実測値ではない。

統合の段階では、3件の問題が出た。gitのバージョンによって日時の形式が仕様と食い違った件(コードを修正)、Windowsで作れないファイル名のテストが失敗した件、Windowsでシンボリックリンクを作れずテストが失敗した件(どちらもテストを修正)である。クラウドのLinuxで書かれたコードを、統合側のWindowsで動かして、はじめて見つかった問題である。

件数と検出力は、同じ話ではない

今回の実験では、指摘の件数と検出力は一致しなかった。

構成指摘の数実際に拾ったもの拾えなかったもの
QA担当(Exp12、契約から141件)軽微4件実装の自己テストにない欠陥、契約の矛盾2件特殊ファイルへの出力(気づいたが実測せず)、ロールバックの縁
評価担当(Exp14、439件+敵対)10件(共通と個別を含む)両方に共通する欠陥D-01、片方だけの欠陥自分のテストの誤り13件(再凍結で修正)
別セッション(Exp26)動作変更3点を含む5項目保護迂回、リンクの挙動変更(非root実測)—
別セッション+別モデル(Exp28)Claude 21件、Codex 17件重大5件のうち確認済みはClaude 3件(ほか未確認の言及1件)、Codex 5件。Claudeだけの10件は重大でない既知9件のうち確認済みはClaude 4件、Codex 1件。K1-1は両方が見逃し
同一セッション(Exp36)20件原子性の崩壊、.pycの問題などD4・D5(別経路で発見)

この表は、母集団も条件も違う観察の並びであり、確率や優劣を示すものではない。件数の多さは検出力の代わりにならなかった。Exp28には、混同しやすい3つの数がある。指摘の総数(Claude 21件、Codex 17件)、重大な指摘5件のうち確認済みの数(Claude 3件、Codex 5件)、事前に固定した既知欠陥9件のうち確認済みの数(Claude 4件、Codex 1件)である。指摘の総数が多いほうが、重大な指摘の確認数も多い、という関係にはなっていない。ただし環境が違い、既知欠陥の一覧もClaude系の評価から作られているので、これは優劣の証拠にはならない。

時間や費用に見合うか

時間は記録がある。Exp12は全体で約27分で、そのうちQA担当の最初の作業に約854秒(約14分)がかかった。サブエージェントのトークン数は、報告書の概算で、契約担当が約8.1万、実装担当が約11万、QA担当が約21.8万である。報告書は、QA担当のテストにより、全体のトークンが実装担当だけの場合の約2倍になったと見積もっている。Exp28のレビューは、Claudeが約2.2〜3.8分、Codexが約9.2分で、Codexは95,922トークンを使った。

費用は比較できない。クラウド実験のセッション内からも、実験の起動に使うAPIからも、消費量を取得できなかった。Exp28のClaudeの利用量は不明で、Codexの金額も不明である。そのため、「分業のコストが成果に見合うか」は、この実験では答えられない。QA担当が見つけた欠陥が軽微な4件だったことから、価値があった可能性はあるが、単独でテストも書くエージェントとの比較はしていない。これは、Exp12の報告書の結論と同じである。

役割を分けて開発とレビューをさせるときの条件

実験で確認したことと、私がそこから導いた推奨を分ける。

条件実験での根拠区分
契約を実装より前に書面にし、固定するExp12で契約の矛盾2件が実装前後に表に出た。評価側はハッシュを固定してからテストを動かした確認した
QAは契約だけから書かせるExp12のQAは自己テストにない欠陥4件を見つけた。実装の存在は知っていた確認した(盲検は不完全)
契約が想定していない領域は、役割を足しても残る特殊ファイルへの出力は、契約・実装・QAの3つの役割が埋めず、評価担当が後から再現した確認した
レビュー担当に、権限・OS・非rootの環境を与えるExp28のroot/Windowsが、権限迂回の見逃しに関わった可能性がある推奨(要因は分離できていない)
変更前との差分を調べさせるExp26の評価は差分で保護迂回を見つけた推奨(Exp28との比較は交絡あり)
サブエージェントの指摘に、開発側が再現したかを記録するExp36・34は、再現した件数が一部だった推奨
レビュー報告を原文で保存するExp34はレビュー原文が保存されておらず、個々の指摘を後から検証できない推奨
指摘の統合コストを見込むExp28は38件から固有22件に整理した確認した
修正のたびに、別の担当で再レビューする修正が別の端点の問題を作った例(Exp12のロールバック)がある確認した
人間が最終判断する範囲を決める実験では未実施未検証

並列実行は、小さな作業では効果が見えなかった。役割分担は、コードを速く書くための仕組みというより、仕様のあいまいさを早く表に出すための仕組みとして働いたように見える。ただし、根拠はExp12の1例である。

実験の限界

結果の信頼性に関わる制約だけを書く。

  • 単独と複数の直接比較は、Exp12とExp13の1題材・各1回である。Exp13は、Exp12が作った契約を受け取っており、対称な比較ではない。
  • Exp14の評価担当は1つのセッションで、オラクルとテストの両方を書いた。盲点を共有している可能性がある。テストは1回修正している。
  • Exp26とExp28の差は、モデル、環境(root、Windows)、指示の観点、セッションの形が同時に違う。原因を分離できない。Exp28は3対象・各1回で、既知欠陥の一覧は過去のClaude系の評価から作られている。
  • Exp34では、サブエージェントのレビュー原文が保存されていない。件数は、最終報告書の記載による。
  • 第三者の人間によるコードレビューは行っていない。レビュー担当は、確認できる範囲で、開発側と同じモデル系統(Exp28のCodexを除く)である。
  • 費用は比較できていない。
  • 再実行は、Exp14の共通テストとExp12のQA 141件を、固定コミットで1回ずつ実行したものである。

結論

AIに開発と評価を分担させたとき、一番はっきり効果が出たのは、コードの品質ではなく、仕様の品質だった。契約を書面にして固定し、別の担当にそこからテストを書かせると、実装の自己テストにない欠陥と、契約自身の矛盾が表に出た。共通テストが親と3担当と単独を区別しなかった理由として、単独側がその契約を利用できたことが差を小さくした可能性がある。ただし、契約には未解決の矛盾が残り、契約の想定外の欠陥も見つかっている。独立した契約で単独側を再実験していないので、この可能性は確認できていない。

レビューについては、構成を足すほど良くなる、とは読めなかった。権限の迂回は、非rootの環境で変更前と比べたExp26の評価が見つけ、root環境のClaudeとWindowsのCodexによるExp28のレビューは見逃した。この差は、環境、指示の観点、モデル、セッションの形が同時に違うため、どれが決定的だったかを特定できない。契約が想定しなかった特殊ファイルへの出力は、契約・実装・QAの3つの役割が素通りし、後から別の評価担当が再現した。同一セッションのサブエージェントは指摘を出したが、重大な欠陥の一部は別経路で見つかった。レビューを増やす前に、レビュー担当に何を渡し、どの環境で動かすか、そして誰が指摘を再現するかを決めておくとよい、というのが私の判断である。

次に確かめたいのは、独立して作った契約を使った単独側の再実験と、レビュー担当に非root環境と変更前との差分を渡した場合の比較である。

なお、同じシリーズの第4回は、claude -p を無人で呼び出すときの成功判定を扱っている。終了コードだけでなく、成果物や後始末を別に確かめるという点は、今回の「報告と確認を分ける」話とつながる。