🧭 本記事は Claude Code実務運用シリーズ の STEP 5「レビュー自動化する」です。
前回のリスク判定に、高リスクのときだけ動く敵対的レビュー3体を足します。
シリーズ全体の地図と読む順は 親記事 にまとめています。
Claude Code の3層コードレビュー構成に、読み取り専用の敵対的レビュアー3体を足しました。高リスク差分のときだけ自動で注入される仕組みです。共通工程ファイル(168行)と単独実行スキル(108行)を全文公開します。
はじめに
Claude Code でコードレビューを自動化するスキルを作り込んでいくと、ある時点で妙な感覚になります。
このレビューの仕組み自体は、誰がレビューするのか。
コード差分は AI がレビューしてくれます。テストも通ります。でも、レビューを実行している側のスキル定義(SKILL.md、frontmatter、判定基準、通知手順)は、書いた本人しか読んでいません。ここにバグがあっても、テストは緑のままです。
前回の記事で、差分のリスクでレビュー方式を振り分ける3層構成を作りました。
差分リスクでレビュー方式を自動振り分け:Claude Codeで作る3層コードレビュー・オーケストレーター【6体AI+テンプレ全公開】
前提として最小限だけ書くと、/review-smart が入口(ルーター)で、差分のリスクを見て単独レビュー /review-and-fix と6体チームの /review-team-and-fix を振り分けます。共通手順は review-shared に置いて全スキルから参照します。修正対象は 🔴重大 / 🟠高 のみで、🟡🟢 はレポート記載にとどめます。詳細は上の記事を参照してください。
この3層は「正しく作れているか」を確認する仕組みです。今回足したのは、その逆側——「どこで壊れるか・どう悪用されるか」だけを探す敵対的レビューです。読み取り専用のサブエージェント3体が、差分を擁護せずに破綻シナリオの構成を試みます。
そして、この仕組みを最初に向けた相手は自分自身でした。レビュー機構を構成するスキル一式を対象に敵対的レビューを回したところ、機構自身に複数の欠陥が出ました。その経験を踏まえて仕上げた定義を、この記事で全文配ります。
なお執筆前に「レビュー機構そのものを自作の敵対的レビューにかける」という角度の記事を探しましたが、日本語の Qiita / Zenn を中心に複数の検索語で探した範囲では見当たりませんでした(悉皆調査ではないので、前例がないと断定はしません)。
この記事のゴール
便利なスキルを紹介すること自体がゴールではありません。
ゴールは、AIコードレビューをこう運用できる状態にすることです。
低リスク差分
→ 通常レビューのみ
中リスク差分
→ 通常レビュー / チームレビューのみ
高リスク差分
→ 選ばれたレビューに敵対的レビュー3体を自動で追加
ルーティング(単独レビューか、チームレビューか)とは別軸で、リスク階層(低・中・高)を判定します。敵対的レビューは高いだけなので、毎回足すものではありません。「高」のときだけ足す構成にします。
逆に、この記事で書けないことも先に明示します。未検証の点は4つです。
- 効果の定量比較は未実施です。 同一差分を「敵対的レビューあり / なし」で回した対照群がないため、敵対的レビューで出てきた指摘は通常レビューとの差ではありません
-
/review-adversarialの単独実行によるフルランは未検証です。 検証済みなのは/review-smart経由の注入パスのみで、単独実行時の Blocking あり経路と Slack / Redmine 送信は確認できていません - 3体という編成は設計上の選択です。 2体でも5体でも試しておらず、3が最適だと示すデータは持っていません
- リスク階層「高」の判定精度は測れていません。 過剰トリガー / 過少トリガーの率は、実運用1件では評価できません
なお、自己改善機能のうち出力ゲート・再試行は未実装で、現在は最小構成での運用です。
前提
Claude Code のバージョンは以下です(2026-07 時点)。
$ claude --version
2.1.220 (Claude Code)
AIエージェント分野は変化が速いので、allowed-tools の挙動やサブエージェントの既定動作は、お手元のバージョンで確認してください。
- Claude Code のスキル(
.claude/skills/<name>/SKILL.md)とサブエージェントを使います - 対象は既存の3層レビュー構成(上記 STEP 5 の記事)。未読でも「レビュー用スキルが複数ファイルに分かれている」状態をイメージできれば読めます
この記事で扱う「敵対的レビュー」は、Claude Code の公式機能ではなく、自分で書いたスキル(review-adversarial / review-shared/adversarial.md)です。仕組みは全文を載せます。
全体構成
敵対的レビューは、単独起動と /review-smart からの注入という2経路から、同じ共通工程ファイルを参照します。
/review-smart が共通工程を直接実行するのではなく、選ばれた主ワークフローの途中に工程として差し込むのがポイントです(点線)。review-and-fix なら Step 2 の後、review-team-and-fix なら Step 5 の後に入ります。
役割はこうです。
| ファイル | 行数 | 役割 |
|---|---|---|
review-shared/adversarial.md |
168 | 新規。敵対的レビューの共通工程。3体の定義・並列実行ルール・統合と選別・Blocking 判定 |
review-adversarial/SKILL.md |
108 | 新規。敵対的レビューの単独実行版スキル |
review-smart/SKILL.md |
318 | 既存のルーター。リスク階層(低・中・高)の判定を追加 |
review-and-fix/SKILL.md |
91 | 既存の単独レビュー。Step 2 の後に共通工程が注入される |
review-team-and-fix/SKILL.md |
315 | 既存のチームレビュー。Step 5 の後に共通工程が注入される |
普段使うコマンドは変わりません。
/review-smart feature/123456
敵対的レビューだけを単独で回したいときは、こちらです。
/review-adversarial feature/123456
1. review-shared/adversarial.md:敵対的レビュー共通工程
この記事の中核です。3体のレビュアー定義、出力形式、統合・除外ルール、Blocking 判定、呼び出し元フローとの連携まで、これ1ファイルに入っています。
構成はこうです。
| 節 | 内容 |
|---|---|
| 前提 | 呼び出し元から引き継ぐ情報(コミット範囲・チケット情報・差分概要・最低サポート OS) |
| 並列実行ルール | 1メッセージでの3体並列起動、読み取り専用の担保、渡す情報の限定 |
| Adversarial Reviewer 1〜3 | 要件・仕様破綻 / 異常系・クラッシュ / セキュリティ・データ破損 |
| 各レビュアーの出力形式 | 指摘表のスキーマと確信度の定義 |
| 敵対的統合 | 重複統合と、除外・格下げルール |
| Blocking 判定 | 既存の修正対象基準(🔴/🟠)をそのまま使う |
| 呼び出し元フローとの連携 | 単独実行 / review-smart 経由それぞれの挿入位置と成果物の扱い |
要点だけ先に抜き出すと、次の3つです。
## 敵対的レビュアー(3体・読み取り専用)
1. 要件・仕様破綻レンズ
要件・受け入れ基準・既存仕様が破綻するシナリオを探す
2. 異常系・クラッシュレンズ
異常系・境界値・非同期処理・クラッシュ条件を探す
3. セキュリティ・データ破損レンズ
セキュリティ・認証・データ破損・機密情報の漏れを探す
## 実行ルール
- 3体は1メッセージで並列起動する。互いの出力は共有しない
- 渡すのは客観的事実のみ(構成・対象ファイル・変更点)。
呼び出し側のリスク判定や結論は渡さない
- レビュアーは読み取り専用。コードを修正しない。修正は既存フローに差し戻す
- 起動前後に `git status --porcelain` を実行し、出力が変化していないことを確認する
- Blocking の定義は既存の修正対象基準と同一(統合・選別後に残った 🔴/🟠)。
敵対的レビュー専用の新しい基準は作らない
「渡すのは客観的事実のみ」が地味に重要だと考えています。呼び出し側のリスク判定や結論を渡すと、3体はその見立てを追認するだけになります。各体は互いの出力も見ていません。
そして「読み取り専用にしてね」とプロンプトで頼むのと、前後で差分が出ていないことを確認するのは別の話です。git status --porcelain の前後比較は、当初の指示文だけの担保に対して後から足した機械的な検証です。
そしてもう1つ、実務に載せるうえでいちばん重要だと考えているのが除外・格下げルールです。敵対的レビューで怖いのは、根拠の弱い指摘が大量に出て信用を失うことです。かといって黙って捨てると、何を落としたのか分からなくなります。
そこで、理由を記録して落とす形にしました。以下は読みやすさのために要点を再構成したものです(原文は下記の全文の「除外・格下げルール(根拠の弱い指摘の選別)」節)。
## 除外・格下げルール(根拠の弱い指摘の選別)
以下に該当する指摘は除外し、「除外・格下げした指摘」に理由つきで記録する
(黙って捨てない)。
- 対象コミット範囲の差分に基づかない指摘(差分と無関係な既存コード全般への指摘)。
ただし「変更によって既存コードの前提が崩れる」型の指摘は差分起因として扱う
- 破綻シナリオが「条件 → 結果」で具体化されていない指摘
- ファイル:行が「未確認」かつ確信度「低」の指摘
以下は除外せず格下げする。
- 確信度「低」のみを根拠とする指摘は 🟡 以下に格下げする(Blocking にしない)
- 差分起因だが影響が限定的な指摘は 🟢 に格下げしてよい
「既存コードへの指摘は一律で除外」にしなかったのがポイントです。単純なルールにすると、変更が既存コードの前提を崩す型の指摘まで落としてしまいます。
以下が実際に運用している共通工程ファイルの全文です(.claude/skills/review-shared/adversarial.md、168行)。長いので折りたたみます。
`review-shared/adversarial.md` 全文(168行)
# adversarial: 敵対的レビュー共通工程
このファイルは敵対的レビュー(Adversarial Review)の共通工程である。単体では起動しない。以下の 2 経路から参照される(同一範囲に対して両経路を重複実行しない)。
- `review-adversarial`(単独実行): 同スキルの SKILL.md の Step 構成に従い、本ファイルの工程を実行する
- `review-smart` 経由(リスク階層「高」): 選択された主ワークフロー(review-and-fix / review-team-and-fix)に本工程を追加する(挿入位置は「呼び出し元フローとの連携」参照)
通常レビューが「正しく作れているか」を確認するのに対し、敵対的レビューは「どこで壊れるか・どう悪用されるか」を探す。レビュアーは差分を擁護せず、破綻シナリオの構成を試みる。
## 前提(呼び出し元から引き継ぐ情報)
- 正規化済みコミット範囲と比較基点
- チケット情報(取得済みの場合。未取得なら「未確認」として続行し、Reviewer 1 は既存仕様との矛盾に集中する)
- 差分概要(変更ファイル一覧・主な変更内容)
- AGENTS.md「現在の実装前提」から確認した最低サポート OS
- Context7 確認結果(ある場合)
## 並列実行ルール
- 3 体の敵対的レビュアーを Agent ツール(サブエージェント)として起動し、**1 つのメッセージで並列に呼び出す**
- 各レビュアーは**読み取り専用**とする。コード修正・ファイル書き込み・git の書き込み系操作を禁止する指示を明示的に含める(使用してよいのは Read / Grep / Glob と、`git diff` / `git log` / `git show` などの読み取り系コマンドのみ)
- Agent ツールが使えない環境では順次のロールプレイで代替してよい。その場合、レビュアー間の独立性が低下している旨を最終レポートに明記する
- 各レビュアーには「前提」の共通情報のみを渡す。主ワークフローのレビュー指摘・統合結果・オーケストレーターのリスク判定は渡さない(独立した攻撃視点を維持する)
- 各レビュアーには他レビュアーの出力を渡さない
- 各レビュアーは、渡された対象コミット範囲に対して自ら `git diff` / `git log` を実行し、差分の実物を確認する
- 各レビュアーはコードを修正しない。レビュー結果のみ返す
- 各レビュアーは、指摘ごとに根拠となるファイル・行・差分内容と、破綻シナリオ(どういう条件で・何が壊れるか)を明記する
- ファイル・行が特定できない場合は「ファイル:行 = 未確認」とする
- オーケストレーターは 3 体の起動前と完了後に `git status --porcelain` を実行し、出力が変化していないこと(レビュアーがファイルを変更していないこと)を確認する。変化があった場合はルール違反として内容を最終レポートに明記する
## Adversarial Reviewer 1: 要件・仕様破綻アタッカー
スタンス: この変更が「チケットの約束」と「既存仕様の暗黙の契約」を破る反例を探す。
観点:
1. チケット要件・受け入れ基準を満たさない入力・状態・操作手順の存在
2. 既存仕様(現行の挙動・データ契約・画面遷移)との矛盾・回帰
3. 仕様の抜け(要件にあるが実装にない / 実装にあるが要件にない)
4. 関連チケット・関連機能との整合性の破綻
5. アップデートユーザー(既存データ保持者)で成立しないシナリオ
特に確認すること:
- 受け入れ基準を「満たせない反例」を最低 1 つ構成できないか試みる
- チケット外の仕様変更が紛れ込んでいないか
- チケット情報が未取得の場合は、既存コードから読み取れる現行仕様との矛盾に集中する
## Adversarial Reviewer 2: 異常系・クラッシュアタッカー
スタンス: この変更を実行時に壊す入力・タイミング・環境を探す。
観点:
1. 異常系(通信断、タイムアウト、権限拒否、ディスクフル、不正レスポンス)での挙動
2. 境界値(空、0、1、上限、nil、空文字、巨大データ、絵文字・異体字)
3. 非同期処理(Task / async/await / DispatchQueue / Combine)の競合・順序逆転・キャンセル・二重実行
4. クラッシュ条件(force unwrap、配列範囲外、nil 参照、メインスレッド違反、fatalError 経路)
5. メモリ(retain cycle、weak/unowned の誤用、解放後アクセス)
6. ライフサイクル(バックグラウンド遷移、プロセス kill、画面破棄中のコールバック)
特に確認すること:
- 「このタイミングでこれが起きたら落ちる」という具体的なシーケンスを構成できないか試みる
- 変更行だけでなく、変更によって前提が崩れる呼び出し元・呼び出し先も攻撃対象にする
## Adversarial Reviewer 3: セキュリティ・データ破損アタッカー
スタンス: この変更を悪用する、またはユーザーデータを壊す経路を探す。
観点:
1. 認証・セッション・トークンの取り扱い(漏えい、失効漏れ、権限昇格)
2. 機密情報(トークン、鍵、個人情報、購入情報)のログ出力・平文保存・外部送信
3. データ破損(書き込み途中の中断、部分更新、同期競合、移行失敗時の不整合)
4. 削除・初期化処理の巻き込み(対象外データの削除、復旧不能な状態)
5. DRM・コンテンツ保護・暗号化の弱体化
6. 入力検証の欠如(外部入力・Deep Link・サーバーレスポンスの信頼しすぎ)
特に確認すること:
- 「この操作列でデータが失われる / 見えてはいけないものが見える」という具体的な経路を構成できないか試みる
- 失敗時のロールバック・リトライでデータ整合性が保たれるか
## 各レビュアーの出力形式
```markdown
## Adversarial Reviewer {n}: {レビュアー名}
### 確認範囲
- 対象ファイル:
- 対象観点:
### 指摘一覧
| # | リスク | 観点カテゴリ | ファイル:行 | 破綻シナリオ(条件 → 結果) | 根拠 | 推奨対応 | 確信度 |
|---|--------|------------|-----------|--------------------------|------|---------|--------|
### 破綻を構成できなかった観点
- (試みたが反例を作れなかった観点と、その理由)
```
- リスク評価基準は review-shared の共通基準(🔴🟠🟡🟢)を使う
- 観点カテゴリは自分の担当観点(上記 1〜6)から記載する
- 確信度:
- 高: 差分・チケット・公式仕様に直接根拠がある
- 中: 差分から合理的に懸念できるが、実行確認が必要
- 低: 可能性の指摘に留まる。必ず「(推測です)」を付ける
- 敵対的レビュアーは読み取り専用でビルドを実行しないため、ビルド結果は確信度の根拠に含めない(review-team-and-fix の確信度定義との意図的な差異)
## 敵対的統合(3 体の指摘の統合と選別)
オーケストレーター(呼び出し元スキルの実行主体)が統合する。
### 統合ルール
- 同一箇所・同一原因の指摘を統合し、「複数指摘あり」と明記する
- 指摘ごとに最終リスク(🔴🟠🟡🟢)を再判定する
### 除外・格下げルール(根拠の弱い指摘の選別)
以下に該当する指摘は除外し、「除外・格下げした指摘」に理由つきで記録する(黙って捨てない)。
- 対象コミット範囲の差分に基づかない指摘(差分と無関係な既存コード全般への指摘)。ただし「変更によって既存コードの前提が崩れる」型の指摘は差分起因として扱う
- 破綻シナリオが「条件 → 結果」で具体化されていない指摘
- ファイル:行が「未確認」かつ確信度「低」の指摘
以下は除外せず格下げする。
- 確信度「低」のみを根拠とする指摘は 🟡 以下に格下げする(Blocking にしない)
- 差分起因だが影響が限定的な指摘は 🟢 に格下げしてよい
### Blocking 判定
- **Blocking = 統合・選別後も残った 🔴 重大 / 🟠 高**(既存スキルの修正対象基準と同一)
- Blocking あり → 呼び出し元の修正フローへ差し戻す。修正は敵対的レビュアーではなく呼び出し元フローが行う(ガードレール対象領域は review-shared「共通の心得」どおり修正案の提示にとどめ、ユーザー承認後に適用する)
- Blocking なし → 修正しない。🟡 中・🟢 低 は残課題・推奨改善として最終レポートに記載する
## 出力形式(敵対的レビュー結果)
```markdown
## 敵対的レビュー結果
- 実施: Adversarial Reviewer 1〜3(並列 / 順次代替)
- Blocking 判定: あり(n 件)/ なし
### 統合結果
| # | 最終リスク | 観点カテゴリ | ファイル:行 | 破綻シナリオ(条件 → 結果) | 指摘元 | 根拠 | 推奨対応 | Blocking |
|---|-----------|------------|-----------|--------------------------|--------|------|---------|----------|
### 除外・格下げした指摘
| # | 指摘元 | 内容(要約) | 除外・格下げ理由 |
|---|--------|-----------|----------------|
```
指摘が 1 件もない場合、統合結果の表は「該当なし」と明記する。
## 呼び出し元フローとの連携
### review-adversarial(単独実行)
`review-adversarial/SKILL.md` の Step 構成に従う(Blocking ありの場合のみ、同 SKILL.md の修正 Step へ差し戻す)。
### review-smart 経由(リスク階層「高」)
- 挿入位置:
- `review-and-fix`: Step 2(コードレビュー)完了後に本工程を実行し、Step 3(コード修正)に進む
- `review-team-and-fix`: Step 5(Self-Critique)完了後に本工程を実行し、Step 6(コード修正)に進む
- Blocking 指摘は主フローの修正対象(🔴🟠)に合流させる。修正・ビルド確認・成果物・publish は主フローの手順・ファイル名のまま実行する(敵対的レビュー用に別のレポートファイルは作らない)
- Blocking 指摘の修正後は、主フローの再点検に加えて、修正差分そのものを 3 つの敵対的観点(要件・仕様破綻 / 異常系・クラッシュ / セキュリティ・データ破損)で再点検する
- 最終レポート: 「敵対的レビュー結果」セクション(上記出力形式)を「Context7利用判定」の後に挿入する。review-team-and-fix の場合はチーム固有 3 セクションのさらに後(「Self-Critique結果」の直後)に挿入する
- 最終レポートの「レビュー結果」表には、敵対的レビュー由来の指摘も含める。その際の観点カテゴリは「要件・仕様破綻」「異常系・クラッシュ」「セキュリティ・データ破損」のいずれかとし、「破綻シナリオ(条件 → 結果)」の内容は「問題内容」列に記載する
- テスト項目には、統合結果に残った破綻シナリオを異常系・回帰テストのケースとして反映する
- publish の `{Slack 追記}` の「レビュー方式」に「• 敵対的レビュー(3体)による追加検証」を 1 行追加する(`{Slack 追記}` が「なし」のスキルでは「レビュー方式:」の見出しとともに新設する)
- 自己改善プロトコル(STATE.md)使用時: Run Meta に `adversarial: applied` を 1 行追記し、本工程を Step Log に記録する
移植するときに読み替えが必要な箇所は3つです。
-
AGENTS.md「現在の実装前提」から確認した最低サポート OS: プロジェクト規約ファイルの参照です。自分のプロジェクトの前提ファイルに読み替えてください - Reviewer 2 の観点3・観点4(
Task/DispatchQueue/Combine/ force unwrap など): iOS / Swift 前提の語彙です。自分のスタックの並行処理プリミティブとクラッシュ要因に置き換えます -
{Slack 追記}/STATE.md: それぞれ通知テンプレートと運用記録ファイルのプレースホルダです。使っていなければ該当行を落としてかまいません
2. /review-adversarial:単独実行版
共通工程を単独で回すためのスキルです。/review-smart を通さず、敵対的レビューだけを差分に当てたいときに使います。
流れはこうです。
1. 共通手順の実行(入力の正規化・チケット確認・Context7 判定)
2. 差分の事前整理(空差分ガードを含む)
3. 敵対的レビュー(3体並列)
4. 統合と Blocking 判定
5. コード修正とビルド確認(Blocking ありの場合のみ)
6. 成果物の作成(テスト項目・受け入れ基準・最終レポート)
7. 保存・Slack 通知・Redmine 添付
8. Retrospective(自己改善の振り返り)
ここで押さえておきたい設計上の判断が3つあります。
-
Step 2 に空差分ガードを置く: ルーター(
/review-smart)側にしかガードがないと、直接起動したときに素通りします。マージ済みブランチを指定すると、空の差分に対してフルパイプラインが完走して、中身のない成果物3点がチケットに自動添付されます。入口が複数あるなら、ガードは本体側に置きます - Blocking なしなら Step 5 を丸ごとスキップする: コードを1行も触らずに Step 6 へ進みます。そのとき「ビルド結果」は ✅ / ❌ ではなく「対象外(修正なしのためスキップ)」と書きます
- description に副作用を書き切る: このスキルは Blocking があればコードを修正しますし、常に Slack 通知とチケット添付を実行します。「読み取り専用」だけを書くと、確認だけのつもりで起動した人の意図から外れます
description を重視するのは、これがスキル選択の判断材料になるからです。
description| Recommended | What the skill does and when to use it. Claude uses this to decide when to apply the skill. …— Skills - Claude Code Docs(2026-07-29 アクセス)
サブエージェント側も同様で、公式ドキュメントは、リクエスト内のタスク記述・サブエージェント設定の description フィールド・現在の文脈に基づいて自動委譲すると説明しています(Subagents - Claude Code Docs、2026-07-29 アクセス)。
つまり description は主要な判断材料です(「唯一の」ではありません。公式の記述は現在の文脈も含めています)。それでも、人間が / で選ぶときも、Claude が自動委譲するときも、まず読まれるのはここです。外部送信・ファイル書き込み・コード変更という副作用は、ここに書いておくべきです。
以下が全文です(.claude/skills/review-adversarial/SKILL.md、108行)。1章と同じく折りたたみます。
`review-adversarial/SKILL.md` 全文(108行)
---
name: review-adversarial
description: 3体の読み取り専用の敵対的レビュアー(要件・仕様破綻 / 異常系・クラッシュ / セキュリティ・データ破損)が iOS 差分の破綻シナリオを探し、Blocking 問題がある場合のみ最小修正・ビルド確認を行い、レポート・テスト項目・受け入れ基準を作成・通知・添付する
argument-hint: "<commit-range | commit-hash | branch-name> [--base <branch>]"
---
あなたは熟練した iOS コードレビュー責任者です。
Swift / Objective-C / SwiftUI / UIKit / Xcode / 署名 / 依存関係管理 / 配布 / App Store 審査まで理解している前提で対応してください。
このスキルは「敵対的レビュー」の単独実行版です。通常レビュー(review-and-fix / review-team-and-fix)が「正しく作れているか」を確認するのに対し、このスキルは「どこで壊れるか・どう悪用されるか」だけを集中的に探します。
- レビュー工程の中核は `.claude/skills/review-shared/adversarial.md`(共通工程)に従う
- review-smart 経由の高リスク差分では、Skill ツールによる本スキルの自動起動は行われず、同じ共通工程が主ワークフローに追加される。同一範囲に両経路を重ねて実行すると成果物・通知が重複するため、通常は併用しない
## Step 1: 共通手順の実行
`.claude/skills/review-shared/SKILL.md` を Read し、以下を実行する。
1. Step 0: プロジェクトルールの読み込み(AGENTS.md の該当セクション)
2. 入力の正規化(`$ARGUMENTS` → コミット範囲)
3. チケット番号の特定と Redmine チケット内容の確認
4. Context7 利用要否判定
5. 自己改善プロトコルの初期化(`.claude/skills/review-shared/self-improvement.md`「実行開始時」節: STATE.md 作成、Phase に応じた承認済みヒント読み込み、以降の各 Step 完了時記録の開始)
共通の心得・リスク評価基準も review-shared に従う。
## Step 2: 差分の事前整理
正規化したコミット範囲について、以下を取得する。
- `git log --oneline <コミット範囲>`
- `git diff --name-status <コミット範囲>`
- `git diff --stat <コミット範囲>`
- `git diff <コミット範囲>`
変更ファイルが 0 件(差分が空)の場合は、「レビュー対象の差分がありません(コミット範囲が空です)」と報告して終了する。
以下を日本語で簡潔にまとめる。
### 差分概要
- 対象ブランチ
- コミット範囲
- 変更ファイル一覧
- 主な変更内容
- 破綻が起きやすそうな領域(攻撃の当たりをつける)
## Step 3: 敵対的レビュー(3 体並列)
`.claude/skills/review-shared/adversarial.md` を Read し、「前提」「並列実行ルール」「Adversarial Reviewer 1〜3」「各レビュアーの出力形式」に従って 3 体の敵対的レビュアーを並列に起動する。
- 各レビュアーは読み取り専用であり、コードを修正しない
- 各レビュアーに渡す情報は adversarial.md「前提」の共通情報のみとする
## Step 4: 統合と Blocking 判定
adversarial.md の「敵対的統合」「Blocking 判定」「出力形式(敵対的レビュー結果)」に従い、3 体の指摘を統合し、重複と根拠の弱い指摘を除外・格下げする。
- Blocking(統合後の 🔴 重大 / 🟠 高)なし → Step 5 をスキップし、コードを変更せずに Step 6 へ進む
- Blocking あり → Step 5 で既存の修正フローへ差し戻す
## Step 5: コード修正とビルド確認(Blocking ありの場合のみ)
既存の修正フローと同じルールで修正する。
- 修正対象は Blocking 指摘(🔴 重大 / 🟠 高)のみとする
- review-shared「共通の心得」に従う: ガードレール対象領域(認証・課金・DRM 等)は修正案の提示にとどめてユーザー承認後に適用する / 元のコード意図を尊重し最小限の変更にする / 🟡 中・🟢 低 は修正しない
- 修正後、修正差分そのものを 3 つの敵対的観点(要件・仕様破綻 / 異常系・クラッシュ / セキュリティ・データ破損)で再点検し、新たな破綻を生んでいないことを確認する
- ビルドは AGENTS.md「検証手順」の標準コマンドで実行する
- ビルドエラーがあれば修正を試み、再度ビルドする。**ビルド試行は最大 3 回まで**。3 回失敗した場合は以下を報告して次の Step に進む:
- 最後のエラーメッセージ全文
- 試した修正内容の履歴
- 推測される原因(「(推測です)」と明記)
- 人間によるデバッグが必要である旨
- 最終的なビルド結果を報告する
## Step 6: 成果物の作成
`.claude/skills/review-shared/deliverables.md` に従い、テスト項目・受け入れ基準・最終レポートを作成する。
- テスト項目には、統合結果に残った破綻シナリオ(🟡🟢 含む)を異常系・回帰テストのケースとして反映する
- 最終レポートには、共通部に加えて adversarial.md の「敵対的レビュー結果」セクションを「Context7利用判定」の後に挿入する
- 「レビュー結果」表の観点カテゴリは「要件・仕様破綻」「異常系・クラッシュ」「セキュリティ・データ破損」のいずれかを記載する
- Blocking なしで修正を行わなかった場合、「実施した修正」は「なし(Blocking 指摘なし)」、「ビルド結果」は「対象外(修正なしのためスキップ)」と明記する
## Step 7: 保存・Slack 通知・Redmine 添付
`.claude/skills/review-shared/publish.md` に従い実行する。
- `{レポートファイル名}` = `{チケット番号}_敵対的レビューレポート.md`
- `{Slack 追記}` = 以下
```text
レビュー方式:
• 3体の敵対的レビュアーによる並列レビュー(要件・仕様破綻 / 異常系・クラッシュ / セキュリティ・データ破損)
• 統合と根拠検証(重複・根拠の弱い指摘を除外)
• Blocking 問題がある場合のみ修正フローへ差し戻し
```
- Slack メッセージの 1 行目は「〜の敵対的レビューが完了しました。」とする
- Redmine 添付コメントの資料名は「敵対的レビューレポート(レビュー結果)」とする
## Step 8: Retrospective(自己改善の振り返り)
`.claude/skills/review-shared/self-improvement.md`「Retrospective」節に従い、サブエージェントで振り返りを実行し、オーケストレーターが結果を STATE.md・学習ファイルに記録する。
- この Step の失敗はレビュー結果・成果物に影響させない(失敗時は理由を報告して終了する)
- 最終報告に Retrospective 要約(学習候補・提案・昇格待ち件数)を含める
移植するときの読み替えは、1章と同じ考え方です。Redmine はお使いの Issue Tracker、AGENTS.md はプロジェクト規約ファイル、self-improvement.md は運用記録の仕組み(使っていなければ Step 8 ごと落とせます)に読み替えてください。
3. /review-smart への組み込み:ルーティングとは別軸のリスク階層判定
/review-smart は元々、単独レビューかチームレビューかを判定していました。ここにもう1軸を足します。
軸1(ルーティング): review-and-fix か review-team-and-fix か
軸2(リスク階層): 低 / 中 / 高。「高」のときだけ敵対的レビュー3体を追加
2軸にしたのは、規模と危険度が別のものだからです。3行の差分でもマイグレーション処理なら危険ですし、700行の文言修正なら危険ではありません。前者にはチームレビューではなく敵対的レビューが効きます。
3-1. 階層の決定
「高」の判定に使うのが判定Hです。文中の判定 A〜E はルーティング側の判定基準を指します(内容は STEP 5 の記事にあります)。内容の改変は1点だけで、同期処理の例示のみプロダクト固有の語を外しています(見出しの階層と文末表現、行の折り返しは記事向けに整えています)。
## 判定H: 高リスク領域
追加・変更行が以下の領域の**挙動を変える**場合は、変更行数が少なくても
「高」と判定する(判定 D と同様、キーワードの単純な出現やコンテキスト行では
判定しない)。
- 認証、ログイン、セッション・トークン管理
- 課金、購入、レシート検証
- DRM、コンテンツ保護、暗号化
- データ削除、初期化、リセット
- 同期処理(クラウド同期など)
- データ移行、マイグレーション、スキーマ変更
- 非同期処理・並行処理の挙動変更(判定 D のうち非同期処理・スレッド境界・
キャンセル処理・メインスレッド制約に関わる変更を含む。force unwrap や
参照保持の変更など、非同期に関わらない D 項目はこの項目の対象外)
- クラッシュ修正、障害対応(判定 E のうち実際に障害・クラッシュ・不具合への
対応である案件を含む。キーワードの出現のみでは判定しない)
- セキュリティ、機密情報(トークン・鍵・個人情報)の取り扱い、ログへの出力内容
階層の決定そのものは、判定H とルーティング側の判定 A〜E の組み合わせです。以下は実運用中の記述です。
#### 階層の決定
- 判定 H に該当 → 高
- 判定 H に非該当で、判定 A〜E のいずれかに該当 → 中
- いずれにも該当しない → 低
判定 H への該当が疑われるが確信が持てない場合は「高(境界判定)」として安全側に倒し、その旨を理由に明記してください。
判定 A〜E は、それぞれ A=変更規模 / B=影響範囲 / C=外部依存・ビルド設定 / D=クラッシュ・非同期・メモリ / E=リリース前・重要チケット です(内容は STEP 5 の記事にあります)。つまり「中」は、危険領域ではないが何らかのリスク要因を持つ差分に付きます。
最後の1行が地味に重要です。判定Hに該当するか迷ったときは「高」に倒します。 これがないと、境界ケースで敵対的レビューが付きません。「付けすぎたときのコスト」と「付け損なったときのコスト」が非対称なので、安全側に倒す既定を明文化してあります。
そして「変更行数が少なくても」が実務では効きます。1行の変更でマイグレーション判定が変わることは普通にあります。
このブロックの2つの言い回しは、意図して冗長にしてあります。括弧書きの参照範囲を書き切ること(非同期の項。「判定 D に該当するもの」とだけ書くと、force unwrap のような非同期に無関係な D 項目まで高リスクに巻き込み、「中」階層がほぼ発火しなくなります)と、キーワードの出現だけでは判定しないこと(前置きとクラッシュ修正の項。部分一致にすると「緊急ではない」という文にも反応してしまうため)です。ここを削ると、階層判定が壊れます。
3-2. 注入位置
「高」と判定したら、/review-smart が共通工程を直接実行するのではなく、選ばれた主ワークフローの途中に工程として差し込みます。
| 主ワークフロー | 注入位置 |
|---|---|
review-and-fix |
Step 2(コードレビュー)完了後 → 敵対的レビュー → Step 3(コード修正) |
review-team-and-fix |
Step 5(Self-Critique)完了後 → 敵対的レビュー → Step 6(コード修正) |
どちらも「レビューが終わって、修正に入る直前」です。この位置なら、敵対的レビューで出た Blocking 指摘を主フローの修正対象(🔴🟠)にそのまま合流させられます。
そして Blocking 指摘を修正したあとは、修正差分そのものを3つの敵対的観点で再点検します。敵対的レビューの修正が新しい破綻を生むのが、いちばん間抜けなパターンです。
配置方法
プロジェクト単位で使う場合は、スキルとして以下に配置します。
.claude/skills/
既存の3層構成に2ファイル足す形です。
.claude/
skills/
review-smart/
SKILL.md ← 判定Hとリスク階層を追記
review-and-fix/
SKILL.md ← 空差分ガードを追記
review-team-and-fix/
SKILL.md ← 空差分ガードを追記
review-adversarial/
SKILL.md ← 新規(2章の全文)
review-shared/
SKILL.md
adversarial.md ← 新規(1章の全文)
deliverables.md
publish.md
self-improvement.md
作成コマンドです。
mkdir -p .claude/skills/review-adversarial
touch .claude/skills/review-adversarial/SKILL.md
mkdir -p .claude/skills/review-shared
touch .claude/skills/review-shared/adversarial.md
新規に足すのはこの2ファイルだけで、既存3スキルは追記のみです。全プロジェクト共通で使いたい場合は ~/.claude/skills/ に置けますが、レビュー観点・ビルドコマンド・Issue Tracker・通知先はプロジェクトごとに違うので、最初はプロジェクト配下のほうが安全です。
配置で意識した設計判断は3つあります。
-
共通工程を1ファイルに一元化する: 単独起動(
/review-adversarial)と、ルーターからの注入(/review-smart)の両方が同じadversarial.mdを参照します。同じプロンプトを2箇所に持つと、片方だけ直して食い違います - Blocking の基準を増やさない: 既存の修正対象基準(🔴/🟠)をそのまま使います。敵対的レビュー専用の新基準を作ると、判定の階層がまた増えます
- 専用レポートを作らない: 成果物ファイルは増やさず、主フローのレポートに「敵対的レビュー結果」セクションとして統合します
なお、同一範囲に対して単独起動とルーター経由を重ねると、成果物と通知が二重になります。併用しない前提で書いてあります。
最後に1点。スキル定義には社名・社内URL・チャンネルID・実チケット番号・個人名・内部実装のクラス名・APIキーやトークンを直書きしないでください。敵対的レビュアーの定義は、そのまま公開資料になりやすいファイルです。{ISSUE_TRACKER_URL} のようなプレースホルダに寄せておくのが安全です。この記事に載せた2ファイルも、この基準で確認したうえで掲載しています。
実行例
普段のレビュー。リスク階層の判定は自動で入ります。
/review-smart feature/123456
コミット範囲指定。
/review-smart abc1234..def5678
判定だけ確認(レビュー本体は走りません)。
/review-smart feature/123456 --dry-run
敵対的レビューだけを単独で回す場合。
/review-adversarial <コミット範囲またはブランチ> [--base <ブランチ>]
/review-adversarial feature/123456
/review-adversarial abc1234..def5678
/review-adversarial feature/123456 --base release/v1.2.0
単独実行のフルランは未検証です。 実出力があるのは /review-smart 経由の注入パスだけです。/review-adversarial の Blocking あり経路(Step 5 の修正・ビルド)と Step 7 の Slack / Redmine 送信は、まだ通しで確認できていません。
Review Routing の実出力
実案件1件で /review-smart を回したときの、レビュー本体着手前に確定するルーティング判定の出力です。実出力(社内情報をマスキング済み) です。
## Review Routing
`/review-smart` によるルーティング判定結果(レビュー本体着手前に確定)。
- 選択: review-team-and-fix
- 理由:
- 判定A(規模大): 生成物・docs・テスト専用ファイルを除外しても、実質的なソース変更は 7 ファイル・757 行(+8/-749)で 300 行を超過
- 判定B(影響範囲大): マイグレーション処理・起動フロー・一覧画面の初期表示という起動処理/共通基盤に関わる変更
- リスク階層: 高
- リスク階層の理由: 判定H該当。本チケットはマイグレーション不可バージョンの引き上げそのものであり、特定バージョン以前のユーザーはアプリ初期化(データ削除・リセット)対象に変わるため「データ移行・マイグレーション・スキーマ変更」「データ削除・初期化・リセット」に直接該当する
- 敵対的レビュー: 追加する(3体)
- 強制指定: なし / dry-run: no
ここで見てほしいのは、ルーティングの理由と、リスク階層の理由が別々に書かれていることです。判定A・判定B(規模と影響範囲)でチームレビューが選ばれ、それとは独立に判定Hで「高」が付き、敵対的レビューの追加が決まっています。2軸にした意味がここに出ます。
敵対的レビュー結果セクションの書式
最終レポートには、以下の書式でセクションが挿入されます(ヘッダ行のみ。実案件の指摘内容は内部実装のファイル名を含むため転記していません)。
## 敵対的レビュー結果
- 実施: Adversarial Reviewer 1〜3(並列 / 順次代替)
- Blocking 判定: あり(n 件)/ なし
### 統合結果
| # | 最終リスク | 観点カテゴリ | ファイル:行 | 破綻シナリオ(条件 → 結果) | 指摘元 | 根拠 | 推奨対応 | Blocking |
|---|-----------|------------|-----------|--------------------------|--------|------|---------|----------|
### 除外・格下げした指摘
| # | 指摘元 | 内容(要約) | 除外・格下げ理由 |
|---|--------|-----------|----------------|
実務での使い分け
基本運用はこれでいいです。
普段は /review-smart(リスク階層は自動判定)
敵対的レビューだけ当てたい → /review-adversarial
判定だけ見たい → /review-smart --dry-run
もう少し実務寄りにすると、こうなります。
| 差分 | リスク階層 | 敵対的レビュー |
|---|---|---|
| 文言修正・コメント修正 | 低 | 追加しない |
| 軽微なUI調整 | 低 | 追加しない |
| 小さなリファクタリング | 低 | 追加しない |
| 広範囲だが領域は安全な一括変更 | 中 | 追加しない |
| SDK更新・Package更新 | 中 | 追加しない |
| 認証・ログイン・セッション管理 | 高 | 追加する |
| 課金・購入・レシート検証 | 高 | 追加する |
| DRM・暗号化 | 高 | 追加する |
| データ削除・初期化・リセット | 高 | 追加する |
| データ移行・マイグレーション | 高 | 追加する |
| 非同期処理の挙動変更 | 高 | 追加する |
| クラッシュ修正・障害対応 | 高 | 追加する |
低・中で足さない理由は、単純にコストです。 3体のサブエージェントを並列で起動すると、時間もトークンも増えます。文言修正にこれを毎回払うのは過剰です。
そして、コスト以上に効くのが指摘の質の問題です。敵対的レビュアーは「破綻シナリオを構成する」ことを目的に動くので、危険な領域でないところに向けると、根拠の弱い可能性の指摘が増えます。除外・格下げルールで受け止められますが、そもそも当てる対象を絞ったほうが安いです。
判定Hに該当する高リスクだけに足す。これが今のところの結論です。
最後に、並列で3体を回すときの運用注意を1つ。サブエージェントは完走しないことがあります。 ストールや API エラーで途中で止まることもあれば、実行自体は終わったのに完了通知に最終出力が含まれないこともあります。どちらの場合も、SendMessage で同じエージェントに再開・再依頼すると、読み込み済みのコンテキストを保ったまま回収できます。新しい Agent を立て直す前に SendMessage を試すのが早いはずです。
なお、これは私の環境での実測であり、公式に説明された挙動や既知の不具合として主張するものではありません。
なぜ敵対的レビューを足すのか
通常レビューとチームレビューがあるのに、なぜもう1種類足すのか。理由は、 通常レビューの当て方では構造的に見えにくい欠陥の型があるからです。以下の3つは、いずれも「壊れている」のではなく 「壊れていないが間違っている」 型で、動かしても表面化しません。なお、レビュー対象がコードではなくプロンプト・設定ファイルになる場合は、攻撃観点も対象に合わせて張り替える必要があります(コード差分向けの境界値・クラッシュ観点をそのまま定義ファイルに当てても噛み合いません)。
理由1: 宣言と実態のズレは、動かしても分からない
スキルやエージェントの定義ファイルは、本文で自分の振る舞いを宣言します。「このスキルは読み取り専用です」「この工程は実行しません」といった記述です。一方で実際の権限や挙動を決めるのは frontmatter や参照先の別ファイルです。この2つは別々に編集されるので、片方だけ更新されて食い違いうる構造になっています。
食い違っても実行は成功します。だからテストは緑のままです。しかも矛盾を見つけたあと、直す先は2つあります。宣言を実態に合わせるか、実態を宣言に合わせるか。どちらが嘘をついているのかを決めるには、両方を突き合わせて読む視点が別に必要です。
理由2: 判定基準を参照で書くと、階層設計が崩れうる
判定基準を複数持つと、片方から他方を「〜に該当するものを含む」と参照したくなります。ところが参照先には、参照元の意図とは無関係な項目も入っています。参照範囲を書き切らないと、意図しない項目まで巻き込んで、設計した階層のうち中間の階層がほぼ発火しなくなる——という壊れ方をします。
これも動作テストでは出ません。判定は毎回何らかの結果を返し、そのまま正常に完走するからです。「判定が返ったか」ではなく「設計した階層すべてが到達可能か」を問う視点が要ります。
理由3: 入口が複数ある構成では、単一経路のレビューで抜けが見えない
入口が複数あるワークフローでは、ガードや前提条件チェックが一部の入口にしか置かれていない、ということが起こります。副作用の開示も同様です。外部送信やファイル書き込みを行うのに、定義の説明文がそれを書いていない場合があります。どちらも、通した1本の経路では正常に動きます。
見えるのは、経路を数えて「この入口から入ったらどうなるか」「この状態で止まったらどうなるか」を構成しに来たときです。正常系を1本通すレビューと、破綻シナリオを構成しに来るレビューは、別の作業だと考えています。
自己点検チェックリスト
上の3つの理由を点検項目に落とすとこうなります。コード差分のレビュー観点ではなく、プロンプト・設定ファイルの品質チェックリストです。3体を移植しなくても、自分のスキル定義に当てるだけで使えます。
## スキル・エージェント定義の自己点検チェックリスト
1. frontmatter の権限宣言と、本文の権限主張が一致しているか
- `Bash(cmd *)` はサブコマンドを区別しない。読み取り専用ならサブコマンド単位で列挙する
- `allowed-tools` は「ターン限定の付与」であって「制限」ではない
2. 判定基準の参照(特に括弧書き)が、意図した範囲に限定されているか
- 「判定 X に該当するもの」ではなく「判定 X のうち〜に関わるもの」まで書く
- 参照によって階層設計が潰れていないか、最も軽い階層が発火するか確認する
3. description に副作用が明記されているか
- 外部送信(Slack / チケット)・ファイル書き込み・コード変更・ビルド
- 「読み取り専用」と書いてあるものが本当に読み取り専用か
4. ガードが入口(ルーター)だけでなく、実行本体側にもあるか
- 空入力ガード・前提条件チェックを、直接起動でも通る位置に置く
- 入口が N 個あるなら、ガードは本体側に 1 つ置く
5. 「承認待ち」など非同期に発生する状態の「その後」が定義されているか
- 承認を待つ間、ランは停止するか続行するか
- 続行する場合、外部通知の文面は「完了」のままでよいか
項目1に挙げた2点——Bash のワイルドカード規則と allowed-tools の位置づけ——は、いずれも公式ドキュメント(Permissions / Skills、2026-07-29 アクセス)に明記されています。
このチェックリストは、自分の定義に当てるだけなら AI に投げてもかまいません。ただし今回効いたのは、判定と結論を渡さずに独立した複数視点に読ませたことだと考えています。自分の見立てを添えて「これで合ってますか」と聞くと、追認が返ってきやすいはずです。
まとめ
今回作ったのは、3層コードレビュー・オーケストレーターに足す4つ目の視点——高リスク差分のときだけ主フローに差し込む敵対的レビューです。層を1つ増やしたのではなく、既存のレビューの途中に工程を差し込みます。
review-shared/adversarial.md(168行)
敵対的レビュー共通工程。3体の定義・並列実行ルール・除外/格下げルール・Blocking判定
/review-adversarial(108行)
単独実行版スキル
/review-smart への追記
ルーティングとは別軸のリスク階層(低・中・高)。判定Hに該当する「高」だけに注入
持ち帰れる成果物は3点です。
- 3体の敵対的レビュアー定義+並列実行ルール+除外・格下げルール(1章の全文168行)
- 単独実行スキルの Step 構成(2章の全文108行)
- リスク階層の判定H+注入位置(3章)と、スキル・エージェント定義の自己点検チェックリスト5項目(「自己点検チェックリスト」)
前回は、レビュー方式を差分のリスクに応じて使い分ける入口を作りました。今回はそこに、方式ではなく視点を足しました。「正しく作れているか」を確認するレビューに、「どこで壊れるか」を探すレビューを重ねる。重ねるのは高リスク差分だけです。
この構成を最初に向けた相手が自分自身だったのは、たまたまではありません。動くコードのレビューより、動くレビュー機構のレビューのほうが後回しになるからです。自己適用で残った教訓は、機構が壊れていたのではなく(実行が破綻する類の欠陥は出ませんでした)、宣言と実態が食い違っていたということでした。
次の一歩として、/review-adversarial の単独実行フルランの検証と、同一差分での「敵対的レビューあり / なし」の対照実験を考えています。後者ができれば、この記事で書けなかった効果の定量比較になるはずです。
移植したら、自分のスキル定義を1つ選んで、チェックリストの1番だけでも当ててみてください。frontmatter と本文が食い違っているスキルは、たぶん1つ目で見つかります。
このシリーズの歩き方
Claude Code実務運用シリーズ ― 暴走させない、から仕組みにするまで。
- ◀ 前の記事: 差分リスクでレビュー方式を自動振り分け:Claude Codeで作る3層コードレビュー・オーケストレーター【6体AI+テンプレ全公開】
- ▶ 次の記事: AIが書いた受け入れ基準を『読者ペルソナレビュー』で外部QA品質にする【Claude Code・テンプレ公開】
- 🔍 あわせて読む: そのスキル、どこにあるか言えますか?:Claude Codeのスキルを4系統まるごと棚卸しして、GitHub Pagesでカタログ化する ― 棚卸ししたスキル定義に、この記事のチェックリストを当てる
- 🗺 シリーズ全記事の地図(親記事)
