📖 はじめに — 「Codex 実装 → Claude レビュー」だけでは半分
クロスファミリー検証の記事は、たいてい「どちらが書き、どちらがレビューするか」で終わる。だが実際に運用してみると、効果を底上げしているのはその周辺のハーネスとステアリングだった。
- TDD で Test は Claude、実装は Codex という家族配置
- テストを実装役から守る機械ガード
- レビューを「やらずに済ませる逃げ道」を塞ぐ三層ゲート
- レビュアーの独立性を守る自己評価遮蔽
本記事はこの「見落とされがちな層」を詳解する。ここが甘いと、+18.1pt のパイプラインは絵に描いた餅になる。
🧬 テスト層の家族配置 — なぜテストを Codex に書かせないか
TDD フローに家族を割り当てると、こうなる。
| TDD フェーズ | 担当 | 家族 | 理由 |
|---|---|---|---|
| Phase 1: Red(失敗するテストを書く) | Claude | verifier 家族 | テスト=実装が満たすべき契約。契約は検証側の資産 |
| Phase 2: Green(実装してテストを通す) | Codex | finder 家族 | high-recall な実装役 |
| Phase 3: レビュー・採否確定 | Claude | verifier 家族 | 精密な採否確定(+18.1pt 方向) |
導入時、オーナーから当然の疑問が出た。「Test: Claude、実装: Codex は、『Codex 実装 → Claude レビューが最良』と矛盾しないか?」 — 精査の結論は「矛盾しない。むしろ必須」だった。
理由は防御の独立性にある。設計編のとおり、防御は二層 — ①決定論ゲート(テスト)と ②クロスファミリー AI 検証。ここでテストも Codex に書かせると、第一の網(テスト)が実装と同一家族相関になる。Codex が誤解した仕様は、Codex が書くテストも同じように誤解する。実装者が自分の受入基準を自分で書く構図は、人間のチームでも避けるのと同じだ。
Red テストを Claude 側に置くことで、「Codex は自分が書いていない契約の充足を機械強制される」状態になる。二層の網が両方とも実装と非相関 — これがクロスファミリー TDD の核心である。
🔒 テストを機械で守る — checksum ガードと exit 3
家族配置を決めても、実装役がテストを書き換えたら無意味だ。「テストが通らないので、テストの方を直しました」は AI 実装役の定番の逃げである。CTS-EC の実装ハンドオフスクリプトは、R1 PASS 済み(レビュー済み確定)テストを二重に保護する。
- プロンプト制約: Codex への実装プロンプトに「これらのテストは変更禁止・すべて緑にする実装のみを行う」を注入
- checksum 検査: 実行前後で対象テストファイルの checksum を比較し、変更・削除を検出したら exit 3 で差し戻し
# --tests の checksum スナップショット(1 行 = 1 ファイル・改ざん/削除検査用)。
# git diff でなく checksum 比較とする理由: Red フェーズ直後のテストは
# untracked の可能性があり、git diff では改ざんが盲点になる。
snapshot_tests() {
for t in $TESTS; do
[ -f "$t" ] && sha1sum "$t" | awk '{print $1}' || echo "MISSING"
done
}
細部に 2 つの設計判断が埋まっている。
- git diff でなく checksum — TDD の Phase 1 で書かれたばかりのテストは untracked のことがあり、git diff ベースの検査では「新規ファイルの書き換え」が盲点になる
- exit 3 は fallback しない — 環境障害(exit 1)なら Claude 実装への fallback が正しいが、テスト改ざんは契約違反であり障害ではない。revert して修正ブリーフとともに Codex に差し戻す。「テストは verifier 家族の資産だから、実装役を替えても Codex レビューには切り替えない」という判断が exit code の意味論に埋まっている(意味論の全体は第5回)
🚪 レビュー漏れの機械クローズ — 「消す」行為をゲートにする
多くの自動化は「レビューを起動する」までしか作らない。しかし本当の事故経路は逆側 — レビューせずに済ませてしまう逃げ道だ。セッションが死んだ、handoff を忘れた、急ぎで push した。これらを人の規律ではなく機械で塞ぐ。
目玉は「解消のゲート化」
マーカーは専用スクリプト経由でしか消せない。解消には、証跡ファイルの run-id 一致・verdict PASS・must-findings 0・テストスタンプ(pass かつマーカーより新しい) の機械検証をすべて通す必要がある。つまり「レビュー済みマーカーを消す」という行為そのものがゲートだ。レビューの起動でなく完了の証明を強制する発想は、既製の自動化にはまず見られない。
push は三層でブロック
| 層 | 実体 | 捕捉範囲 | 迂回可能性 |
|---|---|---|---|
| ① 早期警告 | PreToolUse hook | Claude Code 経由の push | ターミナルからの push |
| ② 最終ローカル | git native pre-push hook | 全ローカル push | --no-verify・マーカー直接削除 |
| ③ 最終強制 | CI ジョブ | ①②の全迂回 | なし(サーバー側) |
③の CI は、コード変更を含む全 MR に verifier 証跡(run-id・verdict・レビュー対象ファイルの列挙)の同梱を要求する。証跡のカバレッジ(変更ファイルが全部レビューされたか)までスキーマ検証するので、--no-verify でも rm でも逃げられない。
この三層を設計する過程で、副産物として自プロジェクトの既存弱点が発覚した — 従来の pre-push ガード群は Claude Code の hook のみで、素のターミナルからの push は --no-verify すら不要で素通りだった。防御を設計すると、既存の防御の穴が見つかる。
到達限界も明記する
この仕組みでも「AI レビューが真に行われたか」の真正性は証跡の自己申告であり、機械検証できない。ローカルのマーカーを rm で直接消されることも防げない。だから位置づけを「ローカル=機械検出+監査痕跡/CI=機械強制」と分けて文書化した。「全経路を機械的に塞いだ」とは言わない。できないことをできると言わない記述が、運用ドキュメントの信頼を守る。
🙈 handoff の自己評価遮蔽 — framing バイアスを構造で断つ
裏取り編で見たとおり、実装者の自己評価(「全テスト合格しました」)を含む handoff は、Claude・Codex 双方のレビューを実測で劣化させる(Claude の Critical 判定率 90%→60-70%、Codex の指摘数 9.4→2.4-4.0 件)。せっかくファミリーを分離しても、handoff がフレーミングを運んだら独立性は壊れる。
対策は「事実だけを機械が組み立てる」こと。Claude verifier に渡すレビューブリーフはスクリプトが生成し、内容をタスク・diffstat・テスト一覧・チェックリストのみに固定する。Codex の「完璧に完了しました」的な自己申告は転記しない。報告値(テスト結果など)は verifier が独立再実行で突合する。さらに、自己評価マーカーがブリーフに混入しないことをテストで検証するところまで機械化した。
verifier チェックリスト — 機械の網の外を毎回注入する
ブリーフには、決定論ゲート(アーキテクチャテスト)が構造的に拾えないと特定済みの残余経路を、必須確認項目として毎回注入する。CTS-EC の場合は 3 経路 — ①helper 経由の間接的な DB セッション到達(テナント分離の罠)、②非ジェネリックな session.Store(object)(実行時型で静的検出不能・楽観的並行性制御の迂回)、③将来追加される SAGA 状態型の並行性制御の要否判断。
ポイントは、これが抽象論の「二層防御」ではなく、別の ADR(機械ガード設計)が「機械では拾えない」と明示した具体経路を、こちらの ADR の verifier に配線していることだ。第一の網が自分の網の穴を申告し、第二の網がその穴を毎回見る。ADR をまたいだこの連携が、二層防御を実装レベルで成立させる。
🧾 まとめ
- Red テストは Claude(verifier 家族)が書く。テストも Codex に書かせると第一の網が実装と同一家族相関になり、二層防御が壊れる
- テストは checksum 前後比較で機械保護し、改ざんは exit 3 で差し戻す(fallback しない)
- レビュー漏れは「マーカー生成 → 解消のゲート化 → push 三層ブロック」で構造的に塞ぐ。目玉は「消す」行為のゲート化
- handoff から実装者の自己評価を遮蔽し、verifier の独立性をスクリプトとテストで保証する
次回は、この仕組みを支える一番泥臭い層 — Claude Code の中から Codex を実際に動かす実装編。
📚 シリーズ記事(ステアリング駆動開発・実践編)
序章
第I部: 技術的負債ドメイン別の実録(総点検ガイド + 8 ドメイン・全 9 回)
- リファクタリング総点検ガイド — 7 つの観点と進め方
- DDD/SOLID/BC 編 — god class 一掃と境界の機械ガード
- SAGA 編 — 新アーキテクチャ挑戦と再発ゲート
- Atomic Design リファクタ編 — 47 page 新規移植
- Storybook × a11y 実機編
- テスト品質・網羅性編
- Python ジョブ群編
- パフォーマンス編
- セキュリティ編
第II部: 検証エンジン(クロスファミリー検証・全 6 回)
- 総論 — マルチ LLM の 2 系統と見取り図
- 裏取り編 — +18.1pt 論文の検証
- 設計編 — finder/verifier 分業と逆順禁止
- TDD×ハーネス編(本記事)
- 実装編 — Claude Code の中から Codex を動かす
- モデル戦略編 — ティア割当と「買うか組むか」
終章
- クロスファミリー検証の最終型 —「正しく作る」から「自分で正しさを測り直す」へ — 検証エンジンに「計測」の層をはめ、自己修正ループを閉じる
番外編
- CI テスト 29 分 → 5.6 分 — 検証エンジンの平時運用実録 — 実測が有力仮説を殺し、退行前より速くなった 1 日
- GPT-5.6 sol 切替の当日実録 — もう一つのデフォルト追従 — CLI 更新が黙って替える finder と、当日中の再計測
- 遊休 90% の枠に仕事を振る — Codex 上流調査と verifier バッチ化 — 逆順禁止の境界を ADR で確定し、読む仕事を遊休枠へ移した 1 日
- ハーネスが単一プロジェクトを卒業する — プラグイン化と二層配布 — 4 プロジェクト展開への切り出しと、version + SHA ピンによる非強制追従
- 69分で5リリース — Opus 5 当日対応が暴いた共通ハーネスの死角 — 新モデル対応を起点に、配布・文書・CI の回帰を二消費者で検出した 69 分
関連記事
- TDD(テスト駆動開発) — Red / Green / Refactor の基礎
- Claude Code 7層ハーネスエンジニアリング — hook 設計の全体像
- What I Found When Claude Reviewed Codex’s Work(Todd Orr) — framing バイアスの実測(外部)