CTS-KB

Red テストは verifier 家族の資産 — テスト改ざんガード・レビュー漏れの機械クローズ・自己評価遮蔽【クロスファミリー検証 第4回】

⏱ 約 8 分で読めます
#クロスファミリーレビュー#TDD#ハーネスエンジニアリング#Claude Code#Codex#hooks#コードレビュー#認知バイアス

📖 はじめに — 「Codex 実装 → Claude レビュー」だけでは半分

クロスファミリー検証の記事は、たいてい「どちらが書き、どちらがレビューするか」で終わる。だが実際に運用してみると、効果を底上げしているのはその周辺のハーネスとステアリングだった。

  • TDD で Test は Claude、実装は Codex という家族配置
  • テストを実装役から守る機械ガード
  • レビューを「やらずに済ませる逃げ道」を塞ぐ三層ゲート
  • レビュアーの独立性を守る自己評価遮蔽

本記事はこの「見落とされがちな層」を詳解する。ここが甘いと、+18.1pt のパイプラインは絵に描いた餅になる。

🧬 テスト層の家族配置 — なぜテストを Codex に書かせないか

TDD フローに家族を割り当てると、こうなる。

TDD フェーズ担当家族理由
Phase 1: Red(失敗するテストを書く)Claudeverifier 家族テスト=実装が満たすべき契約。契約は検証側の資産
Phase 2: Green(実装してテストを通す)Codexfinder 家族high-recall な実装役
Phase 3: レビュー・採否確定Claudeverifier 家族精密な採否確定(+18.1pt 方向)

導入時、オーナーから当然の疑問が出た。「Test: Claude、実装: Codex は、『Codex 実装 → Claude レビューが最良』と矛盾しないか?」 — 精査の結論は「矛盾しない。むしろ必須」だった。

理由は防御の独立性にある。設計編のとおり、防御は二層 — ①決定論ゲート(テスト)と ②クロスファミリー AI 検証。ここでテストも Codex に書かせると、第一の網(テスト)が実装と同一家族相関になる。Codex が誤解した仕様は、Codex が書くテストも同じように誤解する。実装者が自分の受入基準を自分で書く構図は、人間のチームでも避けるのと同じだ。

Red テストを Claude 側に置くことで、「Codex は自分が書いていない契約の充足を機械強制される」状態になる。二層の網が両方とも実装と非相関 — これがクロスファミリー TDD の核心である。

🔒 テストを機械で守る — checksum ガードと exit 3

家族配置を決めても、実装役がテストを書き換えたら無意味だ。「テストが通らないので、テストの方を直しました」は AI 実装役の定番の逃げである。CTS-EC の実装ハンドオフスクリプトは、R1 PASS 済み(レビュー済み確定)テストを二重に保護する。

  1. プロンプト制約: Codex への実装プロンプトに「これらのテストは変更禁止・すべて緑にする実装のみを行う」を注入
  2. 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 した。これらを人の規律ではなく機械で塞ぐ。

🚪 レビュー漏れの機械クローズ — 「消す」行為をゲートにする

自動生成

Yes

検証 OK のみ

未解消のまま push

implement.sh 成功(作業ツリーに変更あり)

review-pending マーカー.git/ 配下・コミット不可

Claude verifier全ゲート PASS?

証跡ファイル作成run-id / verdict / reviewed-files

resolve-review.sh が機械検証run-id 突合 + テストスタンプ

マーカー解消 → push 可

三層ゲートが block

目玉は「解消のゲート化」

マーカーは専用スクリプト経由でしか消せない。解消には、証跡ファイルの run-id 一致・verdict PASS・must-findings 0・テストスタンプ(pass かつマーカーより新しい) の機械検証をすべて通す必要がある。つまり「レビュー済みマーカーを消す」という行為そのものがゲートだ。レビューの起動でなく完了の証明を強制する発想は、既製の自動化にはまず見られない。

push は三層でブロック

実体捕捉範囲迂回可能性
① 早期警告PreToolUse hookClaude 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 を実際に動かす実装編。

📚 シリーズ記事(ステアリング駆動開発・実践編)

序章

  1. AI 駆動開発が積み上げる技術的負債

第I部: 技術的負債ドメイン別の実録(総点検ガイド + 8 ドメイン・全 9 回)

  1. リファクタリング総点検ガイド — 7 つの観点と進め方
  2. DDD/SOLID/BC 編 — god class 一掃と境界の機械ガード
  3. SAGA 編 — 新アーキテクチャ挑戦と再発ゲート
  4. Atomic Design リファクタ編 — 47 page 新規移植
  5. Storybook × a11y 実機編
  6. テスト品質・網羅性編
  7. Python ジョブ群編
  8. パフォーマンス編
  9. セキュリティ編

第II部: 検証エンジン(クロスファミリー検証・全 6 回)

  1. 総論 — マルチ LLM の 2 系統と見取り図
  2. 裏取り編 — +18.1pt 論文の検証
  3. 設計編 — finder/verifier 分業と逆順禁止
  4. TDD×ハーネス編(本記事)
  5. 実装編 — Claude Code の中から Codex を動かす
  6. モデル戦略編 — ティア割当と「買うか組むか」

終章

  1. クロスファミリー検証の最終型 —「正しく作る」から「自分で正しさを測り直す」へ — 検証エンジンに「計測」の層をはめ、自己修正ループを閉じる

番外編

  1. CI テスト 29 分 → 5.6 分 — 検証エンジンの平時運用実録 — 実測が有力仮説を殺し、退行前より速くなった 1 日
  2. GPT-5.6 sol 切替の当日実録 — もう一つのデフォルト追従 — CLI 更新が黙って替える finder と、当日中の再計測
  3. 遊休 90% の枠に仕事を振る — Codex 上流調査と verifier バッチ化 — 逆順禁止の境界を ADR で確定し、読む仕事を遊休枠へ移した 1 日
  4. ハーネスが単一プロジェクトを卒業する — プラグイン化と二層配布 — 4 プロジェクト展開への切り出しと、version + SHA ピンによる非強制追従
  5. 69分で5リリース — Opus 5 当日対応が暴いた共通ハーネスの死角 — 新モデル対応を起点に、配布・文書・CI の回帰を二消費者で検出した 69 分

関連記事