
実装が AI に移ったあと、レビューで人間に残る判断は何か - 読む対象をコードから AI の判断へ移した記録
はじめに
LINE/アプリ DevOps チームの及川です。
実装の多くが AI に移りつつあり、人間に残るのは要件を決め、設計し、判断する部分になってきました。レビューはその判断が実際に行われる場です。
PR のレビューが長引くのは、「これで見終わってよいのか」を自分で決められないときでした。経緯(なぜ必要になり、どこまで話がついているか)が分からず手が止まると、念のための仕様探しが終わりません。AI に任せても同じで、鋭い指摘ほど真偽の確認に手間がかかります。レビュー対象の差分も実装側が AI エージェント(Claude Code など)で書いたものです。
戻る矢印 2 つは、どちらも「これ以上探さなくてよい」と言える条件が無く回り続けます。抜ける矢印が、後述するスキルの終了条件です。「4 つの問い」は探索の打ち切り条件、「変更のすぐ外側」は変更箇所が参照する / される先と、同じ設定を共有するものです。分からなかったのは次の点です。
- 経緯が分からないとき、どこまで調べれば終わりにしてよいのか
- 「他に影響がないか」を、どこで止めてよいのか
- AI の指摘が正しいかを、どう確かめるか
- 案件(特定の顧客プロジェクト)専用の前作スキルを他へ持ち出すには、何を外すか
そこで、ある案件専用の PR レビュースキルを他案件でも使える形に作り直しました。前者を「案件専用版」、後者を「汎用版」と呼びます。どちらも Claude Code Skill(判断基準をマークダウンで書いて呼び出す仕組み)です。
変えたのは 2 点、出力を「指摘の列挙」から救急の手当てのような優先度づけ(トリアージ)にしたことと、案件固有の前提を自動で見つけることです。案件専用版は「どこを見るか」、汎用版は「何をもって見終わりにするか」を書きます。作り直しは Claude Code に任せました。
Skills 機能そのものは、以前ライブラリアップデートを題材に書いた記事をご参照ください(今回とは別のスキルです)。
この記事で紹介すること
- 指摘の列挙をやめ、仕分けにすると出力はどう変わるのか
- 「見なくてよい」と書いてよいのはどんなときか(根拠の 5 種類)
- 案件専用に書いた前提を、リポジトリからどう見つけるか
- 経緯を渡す / 渡さない、実行を許す / 許さないで、出力はどう違ったのか
- 実行を禁じる安全ルールは、何を出せなくしたのか
先に 3 つお断りします。
1 つ目は向き不向きです。手元のレビュー記録を直近 20 件ほど見て、クリティカル(障害や手戻りになるもの)0 件が半分以上あるなら、この記事の形が効くと思います。0 件でも根拠を書く手間は残るためです(後述)。逆に毎回大量に出るなら、レビューの前段で潰せていない可能性があり、この形より先に手を打つところがあると思います。
2 つ目は配布物です。スキルは 3 ファイルで、分量があるため本体は末尾に折りたたみで載せました。
3 つ目は数値の出どころです。スキル本文とレビュー文書の生成、本記事の集計は Claude Code に行わせ、設計の判断、出力の検証と修正、掲載の可否は私が担いました。件数・字数は出力ファイルから数え直した実測値です(AI の自己申告は使いません)。
先に結論
スキルが無くても、レビュー依頼のプロンプトに次の 3 行を足せば形は再現できると思います(3 行だけの出力は取っていません)。以降はこの 3 行の出どころの記録です。
根拠は「実行された結果を見た / 全部数えた / 資料に書いてある / 構造上そうなる / 読んでそう思っただけ」のどれかを必ず名乗ってください。
ファイル名と行番号を書けない根拠は「見なくてよい」に入れず、「未確認」として何を確認すれば決着するかを書いてください。
経緯の調査は「何を / なぜ今 / 採らなかった案 / 過去の方針」の 4 つに出典付きで答えられた時点で打ち切ってください。
作ったのは、PR 番号を渡すとレビューのマークダウンと図解 HTML を出す Claude Code Skill です。1 リポジトリ・2 本の PR で分かったことを挙げます。レビューの所要時間は測っていません。測ったのは人間に回ってきた件数と出力の中身だけです。読み比べは経緯を渡さない(A)/渡す(B)/渡して実環境を読むコマンドも許す(C)の 3 通りです。
- 仕分けにすると、人が最初に読むのは「人間の判断が要る」に入ったものだけです。1 本目の PR は条件によって 4・3・2 件、2 本目は 2 件でした
- 経緯の一次情報(PR 本文・レビューコメント・後続コミット)を渡すかどうかで出力は別物になりました。ただし後述のとおり、この 2 条件は経緯以外も同時に動いており、経緯だけの効果とは読めません
- 渡した情報が誤っていると、誤りごと引き継ぐことがありました。PR 本文の記載を正として論点を取り下げた 1 件があり、その記載自体が実環境と食い違っていました
- 実環境を測らないと分からない食い違いもありました。PR 本文の数と実環境の数が違っていた件と、クォータ(アカウントごとの、確保できるリソース数の上限)を問い合わせる API の戻り値が実際に使えている数と食い違って見えた件です。実行を禁じた条件ではどちらも出ず、これを受けて一律禁止をやめ、許可リスト方式に変えています
設計原則は、スキル本文の「レビュアーの時間が溶けるのは『調べること』ではなく、『調べ終わっていいと判断できないこと』である」です。「指摘を増やすほど人間の検証工数が増える」という仮説も置いています(測定した関係ではなく、設計判断の根拠)。以下、「出力より」はスキルが出したレビューです。
設計 ― 人間が読む対象を「AI の判断」に変える
「見なくてよい根拠」を先に置く理由
作り直す前に、手元のレビュー記録を Claude Code に数え直させました(採否は私が決め、記録の一部は案件専用版の下書きを検証・修正して投稿したものです)。
| 項目 | 値 |
|---|---|
| 数え直した PR レビュー記録 | 69 件(約 4 か月分。同じ PR の複数回分を含み、対象 PR は 64 本) |
| クリティカル 0 件で終わった記録 | 36 件(52%) / 合計 98,546 字 |
| その 36 件の 1 件あたり | 平均 2,737 字 |
半数以上がクリティカル 0 件で終わり、その判断を書くのに 1 件平均 2,737 字でした。「見なくてよい根拠」を先に置くのはそのためです。
ただし 1 案件の傾向なので、まず同じ集計を取るとよいと思います。記録が 1 PR 1 ファイルなら、その置き場所で定型句(私の場合は「クリティカルな指摘はございません」)を grep -rl して wc -l で数えると、この 52% に当たる値が出ます。
出力を 3 つの仕分けにする
方針は、人間が読む対象を「コード」から「AI の判断」に変えることです。スキルは差分から問題かもしれない箇所(以下、気になった点)を書き出し、出力はそれを次の 3 つに振り分けます。
- 人間の判断が要るもの ― なぜ判断が要るかを書く
- 人間が見なくてよいもの ― なぜ見なくてよいかの根拠を書く
- 未確認 ― 根拠が推論どまりのもの。何を確認すれば決着するかを書く
「人間の判断が要るもの」は、そのまま出ると障害や手戻りになるもの(クリティカル)と、許容してよいかを人が決めるものです。後続コミットで直ったものや合意済みは「対応済み」として見なくてよい側です。
従来は末尾の付録だった「確認して問題なしと判断した点」が本体になります。最初に知りたいのはそこだと考え、仕分け結果と「経緯としてどこまで確認したか」を先頭にしました。
仕分け結果の形
例は、通信の宛先を旧経路から新経路へ移し、同時に受け口(通信を受け付ける側の許可設定)を新経路ぶんへ狭めるインフラ変更の PR です。顧客名と PR 番号は伏せ、環境が読み取れる箇所は一般名や架空の例にしましたが、件数と構造は元のままです。
出力より:
## トリアージ結果
### 人間の判断が要るもの: 4 件
1. **切り替えのデプロイ中に、特定の接続元からの通信が通らない時間帯ができます。**
なぜ人間の判断が要るか: 停止時間を許容するかは利用時間帯と業務影響で決まり、コードからは決められません。
AI の見解: 受け口を狭める変更と宛先を新経路へ切り替える変更が 1 回のデプロイにまとめられており、前者は新経路の完成を待たないため、**新経路ができる前に受け口だけ先に閉じられます。** 根拠は `network-construct.ts:120-123` と `network-construct.ts:340`。
判断してほしいこと: (a) 停止時間帯を確保して 1 回で切り替える / (b) 受け口を閉じる変更を次回デプロイに分ける / (c) 停止調整済みで対応不要。
この 3 点セットは全件で揃えさせ、読み手は選択肢を選ぶだけです。
「見なくてよい」と書いてよい根拠の 5 種類
「見なくてよい」と書けるのは、根拠が次の 5 種類の上位 4 つに当てはまり、その所在(path:line、または CI のどの実行か)を書けるときだけです。表は強い順です。
| 根拠の種類 | 意味 | 「見なくてよい」に入れてよいか |
|---|---|---|
| 実行された結果を見た | CI(変更のたび自動で走るテスト・ビルド)の結果を見た | 可(どの実行のログか示せるときだけ) |
| 全部数えた | 参照を全走査し、N 件すべてを確認した(N を書く) | 可 |
| 資料に書いてある | 仕様書・リポジトリ内の公式ドキュメント・規約(CLAUDE.md などの決めごと)の該当文を引用できる |
可 |
| 構造上そうなる | 呼び出し側が値を渡さず変更後も同じ値になる / データが書き換わらない / その経路は実行されない / 型の上で不正な状態を作れない | 可(下の問いに通るときだけ) |
| 読んでそう思っただけ | 読んで、たぶん問題ないと考えた | 不可。「未確認」へ落とす |
「読んでそう思っただけ」は「構造上そうなる」に見せかけられるため、判定の問いを「変更後のコードのどこを見れば確認できるか。path:line で示せるか」に固定しました。示せれば「構造上そうなる」、示せなければ「読んでそう思っただけ」です。経緯なしの出力(後述の条件 A)では、後者を根拠にした「見なくてよい」は 0 件でルールは守られていました。
種類が強くても入れられないものはあります。5 種類が答えるのは「その事実を確かめたか」だけで、「許容してよいか」は別の問いです。テストが無いことは確かめられても、リリースしてよいかは人間が決めます。
スキルの構成
本体は SKILL.md(ワークフロー・判定基準・出力フォーマット)、ほかに図解 HTML 用の 2 ファイルの計 3 ファイルです。--no-visual なら図解は作らず、Python 3.9 以上が要るのも図解のときだけです。
.claude/skills/pr-critical-review/ に置き、/pr-critical-review 123 と呼びます。初対面のリポジトリを汚さないよう、出力は既定でリポジトリ外(~/.local/state/pr-review/)です。必要なのは gh(GitHub 公式 CLI。PR 取得にのみ使用)と git です。
動作確認は Claude Code 2.1.251・gh 2.83.1・Python 3.9.18 です(既定のモデルは版で変わるため厳密な再現条件ではありません)。工程は次のとおりです。
取得の終了条件は、次の 4 問に出典付きで答えられたかです。
- この PR は何を達成しようとしているか(1 文)
- なぜ今それが必要になったか(障害 / 要望 / 期限 / 仕様変更)
- 採用しなかった選択肢とその理由(あれば)
- この領域で過去に決まっている方針・前例(あれば)
探索の上限も置きますが 4 問を優先し、埋まらない問いは作成者への 1 問に変えます。
案件固有の前提を自動で見つける
案件専用版では規約や課題管理の置き場所を直書きしていました。作り直しでは固有名詞を追い出し、規約・構成・仕様の置き場所・検証コマンドをリポジトリから探させます。「有れば見る、無ければ観点を落とす」だけで、推測もエラーもしません。落とした観点は本文に書かせます。経緯の質を左右するのは PR 本文・課題チケット・課題ミラー(課題をリポジトリ内に写した文書)の 3 つだと見ています。後ろ 2 つが無い環境では材料が PR 本文と git 履歴だけになり、4 問は埋まりにくいはずです(未検証)。
見つけた前提は冒頭 5 行以内に出させます。間違っていれば読み手が棄却できます。一般論で埋めさせないよう 一般的には〜が推奨されます という言い回しも禁じました。
| 自動発見で見つからなかったもの | そのときの振る舞い |
|---|---|
| 文書化された規約 | 命名や可読性など軽微な指摘を出さない。探したパスを列挙して本文に書く |
| 検証コマンド | 任せる先が無いため lint 相当の指摘(フォーマット・命名・未使用変数・スペル)を出さない。AI の一般論が規約と誤解されるため |
| 課題ミラー | 経緯探索を PR 本文・リンクされた課題チケット・git 履歴に限定する |
実行してよいコマンドを許可リストで決める
CI 定義から拾った検証コマンドは、検出しても実行しません。run: 行に cdk deploy のような課金される・環境を壊すコマンドも混ざるためです。
実行してよいコマンドは別立てで、安全かどうかは get- や describe- のような接頭辞では決まりません。aws ce get-cost-and-usage(利用料金の照会)は読み取りに見えて課金されます。そこでコマンド名を列挙しました(全文は末尾)。リストに無いものは実行せず、必要なコマンドを添えて未確認へ出します。実環境を読んだときは、いつ・どこで・どのコマンドで測ったかも書かせます。無いと読み直しで結論が変わります。
なお、この許可リスト方式は次の読み比べのあとで入れた変更です。以降の A・B は一律禁止版の出力で取り直していません。いま配布しているスキルでの追試で再現できるのは出力の形までで、件数と字数はリポジトリと PR に依存します。
同じ PR に 3 通りの出力を並べて眺めた記録
厳密な比較にはなっていません。A と B は経緯の有無とコミット範囲が同時に変わり、C は別のスキル(案件専用版)の出力に私の手も入っています。どの条件による違いかは言えません。3 通りを並べ、何が消えて何が残ったかの記録です。
| 条件 | 呼び方 | 使ったスキル | PR 本文・レビューコメント・後続コミットを渡したか | 実環境を読むコマンドの実行 |
|---|---|---|---|---|
| A | 経緯なし | 汎用版(作り直し後) | 渡していない(gh 未認証) |
しない |
| B | 経緯あり | 汎用版(作り直し後) | 渡した | しない |
| C | 経緯あり・実環境も見た | 案件専用版(作り直す前) | 渡した | する |
A と B の違いは gh の認証だけのつもりでしたが、認証が無いと PR 番号から差分を取れません。A には手元の git の 1 コミット目、B には PR 全体を読ませたため、経緯に加えて読んだ範囲も変わりました。A は認証前の出力で、意図した条件ではありません。
C は今回走らせたものではなく、案件専用版が同じ PR に出したレビューを私が確認・修正して投稿したものです。読んだ範囲は A と同じです。この版には実行を禁じるルールが無く、クォータと使用中の数を読んで実環境を測っています。私の手が入るため、A と C は AI 同士の比較になりません。
対象は同じインフラ変更の PR(全体で 6 ファイル / 198 行の追加と 18 行の削除)です。数え直した件数は次のとおりです。
| 指標 | A(経緯なし) | B(経緯あり) | C(経緯あり・実環境も見た) |
|---|---|---|---|
| 「人間の判断が要る」件数 | 4 | 3 | 2 |
| うち対応済みだったもの | 1 | 0 | 1 |
| 未確認 | 5 | 2 | 0(該当節なし) |
| 「見なくてよい」掲載(実数) | 27 | 20 | 17 |
| コマンドを実行して測った根拠 | 0 | 0 | 6 |
C の未確認 0 件は、出力フォーマットにこの節が無いためです。
次は A が出した 9 件(判断が要る 4 + 未確認 5)が B でどうなったかです。「別の形で残った」は同じ懸念が別の粒度で出たものです。
| A が出した 9 件の行方 | 件数 |
|---|---|
| B で消えた | 7 |
| うち PR 本文やレビューコメントが直接効いた | 4 |
| うち読ませたコミット範囲の効果 | 1 |
| うちどちらの条件でもできた確認 | 2 |
| 別の形で残った | 2 |
| そのまま残った | 0 |
指摘が外れていたのか、もう終わっていた話なのか
問題にしているのは技術的な誤りではなく、すでに直っている、または合意済みの話を、決着していないものとして持ち出すことです。
A がクリティカルとした 2 件(判断が要る 4 件の内数)は、どちらも B で外れました。理由は別々で、1 件は A が見た時点ですでに決着(表の「対応済み 1 件」)、もう 1 件は A が見たあとのコミットで直されたものです。後者は A の見落としではありません。
| 経過 | 出来事 |
|---|---|
| 1 日目 | 該当のコミットが積まれる(A と C が見たのはここまで) |
| 2 日目 | 私が検証・修正して投稿したレビュー(条件 C)が設定の不備を指摘 |
| 3 日目 | その内容どおりの修正コミットが入る(B が見たのはここまで) |
A と C は同じコミットを見ており、なぜ問題になるかの説明まで一致していました。A の指摘は当たっていて、見えていなかったのは「その後どうなったか」だけです。決着済みの 1 件は、受け入れ済みと知らず持ち出したものでした。
一次情報を正として論点を取り下げた 1 件
一方、経緯を渡した B は A に無かった誤りを起こしました。リソース数がクォータに収まるかを、PR 本文の記載を正として取り下げています。
C は同じ件で実環境を測っており、B が取り下げの根拠にした記載そのものが実環境と合っていません。クォータを問い合わせる API の数値も、実際に使えている数と合わないように見えます。A も実環境を測らず食い違いに気づいていませんが、B が取り下げたのに対し A は判断が要るものとして残しました。
逆に B だけの発見もありました。PR 本文の復旧手順を読み、その記載では「切り替え先から戻す手順」の有無を判断できないと気づいています。一次情報は誤りを引き継がせるだけでなく、欠落も見つけさせます(1 本での 1 件)。
実行を許したときにしか出せなかった根拠
コマンドを実行して測った根拠は A・B とも 0 件、C が 6 件でした。禁じた以上 0 件は当然で、意味があるのは中身です。その中に前節の 2 つの食い違いが含まれ、どちらもコードと文書だけでは出てきません。0 件は経緯の一次情報を足しても変わりません。増えるのは情報の量で、実行できる範囲ではないからです。一律禁止をやめた理由がこれです。ただし C は私が確認・修正を加えたもので、6 件のうち何件がスキル自身の実行かは数えていません。許可リスト版での件数も測っていません。
未確認と「変更のすぐ外側」をどう書かせるか
推論どまりの点も捨てず、決着に必要なことを書かせます。A は 5 件、B は 2 件です。
影響範囲は変更点の列挙ではなく「すぐ外側に何があって、なぜ触れていないと言えるか」で書かせますすぐ外側(出力では「隣接物」)とは、変更したファイルが参照する / される先と、同じ設定を共有するものです。A の出力では 8 項目で、次はそのうち 3 項目です。
出力より:
| 隣接物 | 触っていない根拠 | 根拠の型 |
| --- | --- | --- |
| 同じ設定を読む別サービス | 新しい値を渡しているのは 1 か所のみ。リポジトリ全体を検索した全ヒットを確認 | 全部数えた |
| 呼び出し元のバッチ | 未指定時は変更前と同一の値が使われる(`config-loader.ts:64`) | 構造上そうなる(呼び出し側が値を渡していない) |
| デプロイの順序 | ワークフロー定義が前段の完了を待つ指定になっている | 構造上そうなる |
うまくいかなかったこと
1. すでに合意済みの論点を、未解決の重大事項として先頭に出した: A でのことで、中身は正しくても経緯が欠けたため優先順位が狂いました。対策は、各件が PR 本文と既存コメントに出ていないか先に見ることです。「経緯として確認した範囲」に PR 本文が無ければ、この誤りを疑って読みます。
2. 「見なくてよい」に落としてはいけないものを 1 件落とした: A は「変更を担保するテストが存在しない」をそこに置きました。事実確認は完結していますが、テスト無しでマージするかは人間の判断です。対策は「存在しない / 無い」で終わる項目を目視し、あれば人間側へ戻すことです。
3. 「◯ 件掲載」の自己申告が、汎用版では実数と合っていなかった: 汎用版の出力 3 件すべてで、末尾の「見なくてよい ◯ 件を掲載」が実数と食い違います。C の総数の自己申告は検算できません。件数を信頼の担保にする以上、自己申告は引用前に数え直すのが確実です。
まだ確かめられていないことも書いておきます。読み比べの数値はすべて 1 リポジトリ・2 本の PR・各条件 1 試行です。
- 検証に使った 2 本は、どちらも他のメンバーが AI エージェントで実装し、私がレビューを担当して内容を把握していた PR です。前提を知り資料も残っていた点は有利に働いており、資料が無い PR では経緯の節が成立しないかもしれません。ここが一番大きい制約です
- 条件の差が 1 つに絞れていません。A と B は経緯の有無とコミット範囲を同時に変えており、分けるには「経緯なし・PR 全体」の 4 つ目が要ります(未実行)。C はスキルが違ううえ私の手も入っています。件数の差が条件の効果かばらつきかも区別できません
- 誤りか正しいかの判定は C と PR 本文に頼り、C 自体は検証していません。C の見落としがあれば、A・B の誤りとして数えられているかもしれません
- 文書が長い点は、測定した時点では直っていません。結論までに読む量は全文の一部で済む一方、全文は B でも C の 1.6 倍ほどあります
- リポジトリ外の公式ドキュメントには当たれません。「資料に書いてある」で扱えるのは取り込まれている仕様書・規約までです。この設計のため、C が公式ドキュメントの原文で決着させた論点は A・B では人へ回ります
- 同じリポジトリの別 PR(23 ファイル / 546 行の追加と 52 行の削除。ファイル数で約 4 倍・変更行数で約 2.8 倍)でも条件 B で取りましたが、総字数は 5% 増にとどまりました。人間の判断が要るのは 2 件、見なくてよい側の対応済みが 11 件です。出力量は差分量より判断が要る件数に近く動くという観察ですが、2 本での話です
この記事のあと、実際のレビューで使いながら 2 点直しました。Critical と判定する前に、その問題に他の仕組みで先に気づけないかを探す手順を足したこと。マークダウンは PR に貼れる長さ(4,000 字以内)に収め、検証用の詳細は図解 HTML へ寄せたことです。
ここまでの数値は変更前のスキルで取ったものです。末尾のスキル全文は最新版です。
コストについて
追加で呼ぶのは gh の読み取りと、課金されるものを除いて選んだ許可リストのコマンドだけです。Claude Code 自体の利用料は別にかかります。金額は改定もあり、ワークロードで変わるため扱いません。実額は参考資料のリンク先でご確認ください。
効果は「人間が読む対象の件数」で見ています。最初に読むのは 2〜4 件です。残りは疑ったときだけ path:line を開けば足りる形ですが、実際にそう運用できるか、時間がどう変わるかは測っていません。
スキル全文
.claude/skills/pr-critical-review/SKILL.md に置けば /pr-critical-review として呼び出せます。案件に依存する記述は含めていません。図解 HTML 用の 2 ファイルは割愛します。
SKILL.md 全文
---
name: pr-critical-review
description: 指定された PR を `gh`(読み取り専用)で取得し、レビューを「指摘の列挙」ではなく「トリアージ」として出力する。人間の判断が要るものと、人間が見なくてよいもの(+なぜ見なくてよいかの根拠)に仕分け、経緯としてどこまで探したかを明示して探索を終わらせる。クリティカル指摘が 0 件のときだけ、リポジトリ内の明文規約に照らした微修正指摘を最大 3 件出す。規約・仕様・パッケージ構成・検証コマンドはリポジトリを見て自動発見するため、案件を問わず動く。成果物はレビュー マークダウンと、変更内容を前提知識ゼロで掴める図解 HTML。「PR #123 をクリティカルレビューして」「#456 の致命的な問題だけ確認して」「この PR、他に影響ないか見て」「PR レビューコメント下書き作って」「PR の変更内容を図解して」といった依頼で発動する。
---
# PR Critical Review — トリアージ型 PR レビュー
このスキルの成果物は **指摘ではなくトリアージ** である。PR の変更点を次の 2 つに仕分け、それぞれに根拠を付けて出す。
- **人間の判断が要るもの** — なぜ人間の判断が要るかを書く
- **人間が見なくてよいもの** — **なぜ見なくてよいかの根拠を書く**
## なぜ指摘ではなくトリアージなのか
元になった案件のレビュー記録 69 件を数えると、**36 件(52%)がクリティカル 0 件**で終わっている。その 36 件は合計 98,546 字あり、そのすべてが「指摘が無い」という結論を支えるために書かれている。**レビューの主成果物は、指摘ではなく「見なくていい根拠」だった。**
レビュアーの時間が溶けるのは「調べること」ではない。**「調べ終わっていいと判断できないこと」** である。終わりが決まらない探索が続く。だから指摘を増やすほど工数は増える。AI が高度な指摘を出しても、人間がその真偽を検証させられるなら時間は減らない。
したがってこのスキルは 3 つを設計原則にする。
1. **探索に終端を与える。** どこまで探したかを書く。「探しました」ではなく「この範囲を探し、無かった」と書く
2. **根拠のない安心を出さない。** 根拠を書けないものは「見なくてよい」に入れず、人間に上げる
3. **読み手が咀嚼できる粒度で出す。** 理解に前提知識が要る指摘には、前提を先に書く。書けないなら、それはまだ理解されていない
## 成果物
| # | 成果物 | 置き場所 | 用途 |
| --- | --------------------- | ------------------------------------- | ------------------------------------------ |
| 1 | レビュー マークダウン | `{出力先}/pr-{番号}-critical.md` | PR にそのまま貼れる指摘の下書き |
| 2 | 図解 HTML(Artifact) | `Artifact` ツールで公開 | ブラウザで共有・コメント可能なレビュー解説 |
| 3 | 単体 HTML ファイル | `{出力先}/pr-{番号}-explainer.html` | ダブルクリックで開ける/添付して配れる |
成果物 2・3 は同一の HTML から生成する。`--no-visual` 指定時は 1 のみ生成する。
`{出力先}` は後述の手順で 1 度だけ決め、`VISUAL.md` にも同じ値を渡す。
## 前提条件
### 必須
- `gh` が認証済みであること(**読み取りのみ使用する**)
- `git`(`build-html.py --ref` が `git show {ref}:{path}` で PR ブランチのコードを読む)
- `python3` 3.9 以上(`scripts/build-html.py`)
### 任意(無ければその参照をスキップして続行する)
- Claude Code の `Artifact` ツール。使えない環境では `--no-visual` で運用するか、Artifact 公開を飛ばして単体 HTML の書き出しだけ行う
- `jq`(あれば使う。無ければ `gh --jq` と `grep` で代替する)
- 兄弟スキル。**存在を確認してから案内する**(`ls .claude/skills/ 2>/dev/null`)。無ければその行ごと出さない
## 入力
$ARGUMENTS
形式: `{PR番号} [保存先パス] [フラグ]`
例: `#123`、`456 .issues/pr-456.md`、`789 --no-visual`
| フラグ | 意味 |
| ---------------- | ---------------------------------------------------------------- |
| `--out {path}` | 保存先を明示する(第 2 引数と同義)。**末尾が `.md` ならファイル名、そうでなければディレクトリ**として扱う |
| `--no-visual` | Phase 3(図解 HTML)をスキップし、マークダウンのみ生成する |
| `--visual-only` | 既存のレビュー マークダウンを読み、Phase 3 のみ実行する |
| `--profile-only` | Phase -1(リポジトリプロファイル)だけ実行して結果を表示し終了する |
| (`--run-checks` は廃止)| 検証コマンドは**検出するだけで、実行しない**。理由は「安全性ルール」を参照 |
| `--tone {ja\|en}` | 出力言語・文体を明示する(既定は自動判定) |
## 安全性ルール
gh コマンドは読み取り専用のみ使用すること。PR への書き込み・投稿は絶対に行わない(下書きはファイルに保存するだけ)。
許可するコマンド:
- `gh pr view` / `gh pr diff` / `gh pr checks` / `gh pr list` / `gh issue view` / `gh repo view`
- `gh api`(GET リクエストのみ)
禁止するコマンド(絶対に実行しないこと):
- `gh pr create` / `edit` / `close` / `merge` / `comment` / `review` / `reopen` / `ready`
- `gh api` での POST / PATCH / PUT / DELETE
- その他 PR を変更・作成するコマンド
Artifact は既定で非公開に発行される。公開範囲を広げる操作はユーザーに委ねること。
**レビュー対象のリポジトリに書き込むのは、`{出力先}` 配下のファイルだけ**とする。`.gitignore` の書き換え・設定ファイルの追加は、提案するだけで勝手に行わない。
### 実行してよいコマンド・いけないコマンド
Phase -1 で検出する「検証コマンド」は、**何が自動で検査されるか(=指摘してはいけない領域)を知るため**に集める。**検出したコマンドをそのまま実行してはいけない。**
CI 定義の `run:` 行には `cdk deploy` / `terraform apply` / `npm publish` のような、**課金される、あるいは環境を壊す**コマンドが混ざる。収集は無選別なので、実行を許すと「レビューしただけのつもりがデプロイしていた」が起きる。
#### 判定は接頭辞でしない
`describe-*` / `get-*` なら安全、は**成り立たない**。
| 見た目 | 実際 |
| --- | --- |
| `aws ce get-cost-and-usage` | リクエストごとに課金される |
| `aws logs start-query`(Logs Insights) | スキャンしたデータ量で課金される |
| `aws s3api list-objects-v2` / `aws s3 ls` | LIST リクエストが課金対象 |
| `aws dynamodb scan` / `query` | 読み込みキャパシティを消費する |
| `cdk diff` / `terraform plan` | クラウド API を呼ぶ。`terraform plan` は state ロックという書き込みを伴う |
したがって**コマンド名の明示リストで判定する**。
#### 実行してよいもの
1. **リポジトリ内のファイルを読む操作** — `cat` / `grep` / `find` / `ls` / `git show` / `git diff` / `git log`
2. **`gh` の読み取り** — `gh pr view` / `gh pr diff` / `gh pr checks` / `gh api` の GET
3. **クラウドの読み取り専用 API のうち、下の許可リストに載っているものだけ**
許可リスト(課金されず、状態を変えないもの)。
```
aws sts get-caller-identity
aws ec2 describe-addresses / describe-instances / describe-security-groups
aws ec2 describe-vpcs / describe-subnets / describe-nat-gateways / describe-route-tables
aws elbv2 describe-load-balancers / describe-target-groups / describe-listeners
aws service-quotas get-service-quota / list-service-quotas
aws iam get-role / get-policy / list-attached-role-policies
aws cloudformation describe-stacks / list-stack-resources
```
**このリストに無いクラウドコマンドは実行しない。** 迷ったら実行しない。
#### 実行しないもの
- 許可リストに無いクラウドコマンド全般(`aws` / `gcloud` / `az` / `cdk` / `terraform` / `pulumi`)
- データベースへ接続するもの(読み取り専用クエリであっても)
- ネットワークへ出るもの(`gh` の読み取りを除く)
- パッケージのインストール(`npm install` / `pip install` など)
#### クラウドを読んだときに必ず書くこと
実環境の値を根拠にすると、**同じ PR を後で読み直したときに結論が変わる**。
再現できない根拠は根拠にならないので、次の 3 点を根拠の隣に必ず書く。
- **いつ測ったか**(日付)
- **どのアカウント・どのプロファイルか**(実行前に `aws sts get-caller-identity` で確認する)
- **実行したコマンドそのもの**
この 3 点が揃ったものだけが `R1` になる。揃わないなら `R1` を名乗らない。
#### 実行できないときは、コマンドを添えて「未確認」に出す
許可リストに無い、認証情報が無い、対象アカウントが分からない — いずれの場合も**黙って諦めない**。
> この値はコードからは決まりません。確認するには次を実行してください。
> `aws service-quotas get-service-quota --service-code ec2 --quota-code L-0263D0A3 --profile <対象>`
読み手が 30 秒で確かめられる形にして「未確認」へ入れる。
**確認できなかったことを書かずに済ませるのが、いちばんまずい。**
---
## 絶対ルール 1: 読み手は「経緯を一切知らない新規参加者」
**マークダウン・図解 HTML のすべての文について、この PR に至る経緯・過去の議論・社内の暗黙知を一切知らない人が読んで意味が通るか**を確認する。通らない文は残さない。
読み手が持っている前提は「このリポジトリの一般的な知識」だけと仮定する。
守ること:
- **固有名詞は初出で 1 行説明する**。外部ベンダー名・システム名・バッチ名・社内略語はすべて対象(例:「◯◯連携バッチ(毎晩、外部システムへ差分を送る処理)」)
- **参照だけの表現を禁止する**。「例の」「前回の」「既存の議論のとおり」「〜の件」は使わない
- **Issue 番号・コミットハッシュ・PR 番号を根拠にする場合は、その内容を 1 文で要約して併記する**。「#1234 参照」だけで終わらせない
- **PR 本文の文言をそのまま引き写さない**。PR 本文は作成者が経緯を知っている前提で書かれている。読み手向けに書き直す
- **数字には単位と意味を添える**。「486 件」ではなく「移行対象の全 486 件」
- **レビュー対象の PR で初めて出てくる概念は、指摘より先に説明する**。指摘の中で概念を初出させない
チェック方法: 書き終えたあと、各セクションを単独で読み返し、直前のセクションを読んでいない人に通じるかを確認する。
## 絶対ルール 2: 読み手は「その技術の内部挙動を知らない」
絶対ルール 1 が**経緯**についてのルールであるのに対し、これは**技術的前提**についての同種のルールである。
高度な指摘は、読み手が咀嚼できなければレビュー時間を**増やす**。「言っている意味が分からないので、意味を理解するところから始まる」状態を作らない。
### すべての指摘に「ひとことで言うと」を前置する
30〜60 字。次の 3 条件をすべて満たすこと。
1. 固有名詞・製品名・API 名を含まない
2. 実装がどうなっているかではなく、**相手に何が起きるか**を述べる
3. それ単独で読んで意味が通る
満たす一文が書けない指摘は、**まだ自分が理解しきれていない**。その指摘は出さず「未確認」へ降格させる。
> 例: 「書き込んだ直後に、まだ内容が届いていないかもしれない別サーバーへ『重複ありますか?』と聞きに行っています。参照先を 1 語変えるだけで確実になります」
### 難易度タグが付く指摘には「理解に必要な前提」を置く
指摘が次のいずれかに該当したら、本文の**前**に「この指摘を読むのに必要な前提」を 2〜4 行で置く。「X を知っている必要があります。X とは〜」の形で書く。
| 型 | 例 |
| ------------------------------ | ------------------------------------------------------------------------ |
| クラウド SDK / IaC の合成時挙動 | IaC の記述が実際に生成するリソース定義が、記述の見た目と一致しない |
| ランタイム内部挙動 | コネクションプールの再利用、実行環境の凍結と再開、GC・タイマーの扱い |
| SQL の三値論理・実行計画 | `NOT IN` と NULL、ORDER BY なし LIMIT の順序不定、インデックスの効き方 |
| 分散データの時間差 | レプリカラグ、キャッシュ反映待ち、デプロイ順序による一時的な不整合 |
| 型システムのセンチネル設計 | 「未指定」を表す特別値(最大日時・0・負の最小値)が実データと衝突する |
前提が書けない場合、その指摘は「未確認」へ降格させる。**前提を説明できないものを指摘として出すと、真偽の検証がまるごと人間に降ってくる。** それはレビュー工数を削るのではなく、付け替えているだけである。
## 絶対ルール 3: 根拠を書けないものを「見なくてよい」に入れない
「見なくてよい」は**免責の宣言**である。根拠のない「たぶん大丈夫」を書くと、読み手はそれを信じて探索をやめ、しかし根拠は存在しない。図解でも文章でも同じで、**曖昧に閉じた結論が最も害が大きい。**
根拠の型は次の 5 つに限る。上ほど強い。`R5` は「見なくてよい」に入れられない。
| 強度 | 根拠の型 | 意味 | 境界図の外箱ラベル | 「見なくてよい」に入れてよいか |
| ---- | ---------------- | -------------------------------------------------------------- | ------------------------ | ------------------------------ |
| R1 | 実行済みの証跡 | **CI で実際に走った**テスト・ビルドの結果を確認した(`gh pr checks` の合否、ワークフローのログ)。自分ではコマンドを実行しない | テストで担保 | 可(**実行された証跡の所在を書けるときだけ**) |
| R2 | 全数確認 | 参照を全走査し、N 件すべてを確認した(N を書く) | 全数確認 | 可 |
| R3 | 一次資料の原文 | 仕様書・公式ドキュメント・明文規約の該当文を引用できる | 一次資料の原文で確認 | 可 |
| R4 | 構造上の不変 | 呼び出しが不変/データが不変/そもそも通らない/型で不正な状態を作れない | 呼び出しが不変 ほか | 可(**下の判定に通るときだけ**) |
| R5 | 推論のみ | コードを読んでそう思った | — | **不可 → 未確認へ** |
この外箱ラベルは `VISUAL.md` 第 4 章「影響範囲の境界図」と共通の語彙にしてある。ヘッダの内訳は**本文に付けたラベルから数える**(手で書かない)。Phase 1 でこの型を選んでおけば、Phase 3 は図にするだけで済む。
**根拠には必ず所在を書く。** `path:line`、参照件数、規約ファイルの行と原文引用、CI の実行結果のいずれか。所在のない根拠は R5 と同じ扱いにする。
### R1 を名乗る条件
「テストで担保」と書けるのは、**そのテストが実際に走って通った証跡があり、その所在を示せる**ときだけ。走る場所を示せても、走った結果を見ていないなら R1 を名乗らない。
- `gh pr checks {番号}` で該当ジョブが success である
- **かつ**、そのテストが CI のどのワークフローで走るかを `path:line` で示せる
**ジョブが success でも、そのテストが実際に走っているとは限らない。** CI 定義にテスト実行のステップが無ければ R1 にならない。走る場所を示せるだけでも R1 にならない。
**テストファイルが存在するだけでは R1 にならない。** 存在するが走っていないテスト、
存在するが今回の変更を通らないテストは、担保になっていない。示せないなら R4 か「未確認」へ落とす。
### 「未確認」は抜粋しない
**未確認は全件挙げる。** 掲載件数を絞ってよいのは「見なくてよい(`閉`)」だけである。
「見なくてよい」は根拠があるので、代表例を挙げて残りを件数で示せば読み手は納得できる。
一方「未確認」は**人間が見なければならないもの**なので、抜粋すると見るべきものが消える。
指摘に件数上限を設けないのと同じ理由。
母数を書くときは 3 つの数字を分けて書く。
```
立てた疑い {N} 件 / うち指摘 {N} 件 / 未確認 {N} 件(全件掲載)/ 見なくてよい {N} 件(うち掲載 {N} 件)
```
### R4 と R5 を分ける判定
この 2 つは書き方が似ているので、次の問いで切り分ける。
> **その「不変」は、変更後のコードのどこを見れば確認できるか。`path:line` で示せるか。**
示せるなら R4。示せず「読んだ限りそう見える」なら R5。
| 例 | 判定 |
| --- | --- |
| 「この関数の呼び出しは 2 箇所のみ(`a.ts:31` / `b.ts:88`)で、どちらも引数が変わっていない」 | R4 |
| 「型が Discriminated Union なので不正な状態を作れない(`types.ts:12-20`)」 | R4 |
| 「この分岐はそもそも通らないと思われる」 | **R5** |
| 「既存の実装と同じ書き方なので問題ない」(同型性の所在を示していない) | **R5** |
**R5 を R4 に言い換えない。** 迷ったら R5 に倒して「未確認」へ入れる。
未確認に入れて人間が 30 秒見て済むほうが、根拠のない「見なくてよい」より安い。
### 根拠が強くても「見なくてよい」に入れられないもの
根拠の型(`R1`〜`R4`)が答えるのは **「その事実を確かめたか」** だけである。
**「確かめた結果を許容してよいか」は別の問い**で、そちらは人間が決める。
この 2 つを同じ軸で扱うと、事実確認が完結しているという理由だけで、
本来は人間が決めるべきものが「見なくてよい」に落ちる。
判定はこの問いで行う。
> 事実を確かめた結果、**「だから何もしなくてよい」**と言い切れるか。
> **「だから誰かが決める必要がある」**なら、根拠が `R1` でも「人間の判断が要る」に入れる。
根拠の強さにかかわらず「人間の判断が要る」に入れるもの。
| 類型 | 例 | なぜ人間か |
| --- | --- | --- |
| 安全網の不在 | 変更を担保するテストが無い / 監視・アラートが無い / 切り戻し手順が無い | 無いことは確かめられるが、無いままリリースするかは判断 |
| 停止・断・劣化 | デプロイ中に通信が止まる / 一時的に性能が落ちる | 許容できるかは業務時間帯と影響範囲で決まる |
| 公開範囲・権限の拡大 | 通信の許可範囲を広げる / 権限を追加する | 妥当かは運用ポリシーで決まる |
| 取り消せない変更 | データ移行 / 破壊的なスキーマ変更 / 既存データの書き換え | 失敗したときの回復手段の有無を人間が確認する |
| 継続的に増える費用 | 常時起動のリソースを追加する / 保持期間を延ばす | 費用を負担するかは予算の話 |
これらを「見なくてよい」に入れてはならない。
「テストが無いことを `path` 付きで確認した」は、**確認が終わった証拠であって、許容の根拠ではない。**
---
## ワークフロー
### Phase -1. リポジトリプロファイル
**このスキル本文には固有名詞を一切書かない。** 規約の場所・パッケージ構成・仕様の置き場所・検証コマンドは、リポジトリを見て発見し、`profile` として保持する。以降の Phase はすべて `profile` を参照する。
なぜここに集約するか。発見処理が本文に散っていると、案件を移したときに壊れる箇所が特定できない。1 箇所に集めておけば、**誤認識を人間が 5 秒で棄却できる**(後述の -1-3)。
#### -1-1. 上書き設定を先に読む(あれば自動発見より優先)
```bash
cat .pr-review.json 2>/dev/null \
|| cat "$(dirname "$0")/pr-review.json" 2>/dev/null \
|| cat .claude/pr-review.local.json 2>/dev/null
```
このファイルがあれば、書かれている項目については自動発見を行わない。スキーマは末尾の「プロジェクト側の上書き設定」を参照。
**スキルと同じ場所に置いた場合、他の案件へ持ち出すときは必ず外す。** 中身は案件固有の事故履歴で、別の案件では根拠のない観点になる。
#### -1-2. 自動発見
すべて **「ファイルが有れば見る、無ければその観点を落とす」** で判定する。推測しない。エラーにもしない。
| 項目 | 発見手順 |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ベースブランチ | `gh pr view {番号} --json baseRefName -q .baseRefName`。**`main` と決め打ちしない** |
| 言語 | `git ls-files \| sed -n 's/.*\.\([a-zA-Z0-9]*\)$/\1/p' \| sort \| uniq -c \| sort -rn \| head -15` |
| パッケージ管理 | ロックファイルで判定(`pnpm-lock.yaml` / `package-lock.json` / `yarn.lock` / `bun.lock*` / `uv.lock` / `poetry.lock` / `requirements*.txt` / `go.mod` / `pom.xml` / `build.gradle*` / `Cargo.toml` / `Gemfile` / `composer.json` / `*.csproj`) |
| パッケージ一覧 | この順で最初に当たったものを採用: `pnpm-workspace.yaml` の `packages:` → `package.json` の `workspaces` → `turbo.json`/`nx.json`/`lerna.json` → `go.work` の `use` → `settings.gradle*` の `include` → `Cargo.toml` の `[workspace] members` → `pyproject.toml` の workspace 定義 → `find . -maxdepth 2 \( -name package.json -o -name go.mod -o -name pom.xml -o -name pyproject.toml -o -name Cargo.toml \) -not -path './node_modules/*'` の件数で判定。**2 個以上ならモノレポ / 1 個または 0 個なら単一パッケージ**(0 個は言語標準のレイアウトとみなし、リポジトリ全体を 1 パッケージとして扱う)。ワークスペース定義がグロブ(`packages/*` など)のときは、**実ディレクトリへ展開してから件数を数える**(`ls -d packages/*/ 2>/dev/null \| wc -l`)。展開せずにグロブのまま件数を書かない |
| 明文規約 | `find . -maxdepth 3 \( -name node_modules -o -name .git -o -name vendor -o -name dist -o -name target -o -name .venv -o -name build \) -prune -o -type f \( -iname 'AGENTS.md' -o -iname 'CLAUDE.md' -o -iname 'CONTRIBUTING*' -o -iname '.cursorrules' -o -iname 'STYLEGUIDE*' -o -iname 'ARCHITECTURE*' -o -iname 'copilot-instructions.md' -o -iname '.windsurfrules' -o -iname '.clinerules' \) -print` に加え `find .cursor/rules .github/instructions docs/adr docs/decisions -type f \( -name '*.mdc' -o -name '*.md' \) 2>/dev/null` |
| 自動チェック(委譲先) | `find . -maxdepth 2 -type f \( -name 'eslint.config.*' -o -name '.eslintrc*' -o -name 'biome.json*' -o -name '.prettierrc*' -o -name '.editorconfig' -o -name 'ruff.toml' -o -name '.flake8' -o -name 'setup.cfg' -o -name '.golangci.y*ml' -o -name '.rubocop.yml' -o -name 'checkstyle.xml' -o -name '.pre-commit-config.yaml' -o -name 'cspell.json' \) 2>/dev/null`(**`ls` にグロブを並べない。**zsh は最初のグロブが不一致だと `no matches found` でコマンド全体が止まり、出力ゼロになる) |
| 検証コマンド | **収集の目的は「何が自動で検査されるか」を知ること。実行はしない。** `grep -hE '^[[:space:]]*-?[[:space:]]*(run\|uses):' .github/workflows/*.y*ml 2>/dev/null \| sort -u`。**`run: \|` の複数行ブロックと `uses:` のアクションは grep では中身が見えない。**該当したワークフローはファイルを開いて読む(他 CI: `.gitlab-ci.yml` / `.circleci/config.yml` / `Jenkinsfile` / `azure-pipelines.yml` / `.buildkite/`)→ タスクランナー(`Makefile` / `Taskfile.y*ml` / `justfile` / `mise.toml`)→ `package.json` scripts のうち `^(lint\|format\|fmt\|test\|typecheck\|tsc\|check\|validate\|verify\|ci\|build)` → 言語標準(設定ファイルがある場合のみ) |
| API 契約 | `find . -maxdepth 4 \( -iname '*openapi*.y*ml' -o -iname '*openapi*.json' -o -iname '*swagger*' -o -name '*.graphql' -o -name '*.proto' \) -not -path './node_modules/*'`。**1 本だけを名指ししない。全件を候補にする** |
| DB スキーマ | `find . -maxdepth 4 \( -name '*.prisma' -o -name 'drizzle.config.*' -o -name 'alembic.ini' -o -name 'sqlc.yaml' -o -name 'schema.rb' -o -name '*.sql' \) -not -path './node_modules/*'` と `find . -type d -name migrations -maxdepth 4` |
| IaC | `cdk.json`→CDK / `*.tf`→Terraform / `serverless.yml` / `Pulumi.yaml` / `*.bicep` / `template.y*ml` に `AWSTemplateFormatVersion` or `Transform: AWS::Serverless` / `Chart.yaml`・`kustomization.yaml`→k8s |
| 環境の集合 E | `find . -maxdepth 3 -type f -name 'config.*' -not -path './node_modules/*' 2>/dev/null` と `find . -maxdepth 3 -type d \( -name envs -o -name environments \) 2>/dev/null`、`find . -name '*.tfvars'`、`grep -hoE '(environment\|env):\s*\S+' .github/workflows/*.y*ml \| sort -u`。ここから環境トークン集合を作る(`dev` / `stg` / `prd` など) |
| 課題ミラー | PR 本文から抽出した課題キーで `grep -rl --exclude-dir={node_modules,.git,dist,build,target,.venv,vendor} -F '{キー}' . \| head -20` し、ヒットしたパスの共通接頭辞を採用。ヒット無しなら「直下に `issues/` `wiki/` `documents/` のうち 2 つ以上を持つディレクトリ」を探す |
| owner / repo | `gh repo view --json owner,name --jq '.owner.login + "/" + .name'`。`gh` が使えないときは `git remote get-url origin` から抽出する |
| PR テンプレート | `cat .github/PULL_REQUEST_TEMPLATE.md 2>/dev/null`(節構成が分かると、PR 本文のどの節が空欄かで経緯の欠落箇所が分かる) |
| 文体 | PR 本文・issue・既存レビューコメント中の日本語文字(かな・漢字)比率が 30% を超えれば敬体日本語、そうでなければ中立英語。`--tone` で上書き可 |
規約の**読み込み量は合計 2000 行まで**。超える場合は絞る。frontmatter に `alwaysApply: true` があるものは常に読み、`globs:` を持つものは **diff のファイルパスが glob に一致するものだけ**読む。それでも超える場合は見出しだけ読み、diff から立った疑いのキーワードに一致する節だけ本文を開く。
規約は **git 管理外でも読む**。`CLAUDE.md` 等が `.git/info/exclude` に入っている構成は実在するため、`git ls-files` ベースではなく**ファイルシステム上の存在**で判定する。
適用順は「対象パスに近いもの > リポジトリ全体のもの」。変更ファイルごとに最も近い祖先ディレクトリの規約を先に当て、ルートのものを後段に置く。
#### -1-3. プロファイルを人間に提示する(必須)
**レビュー本文の冒頭に 5 行以内で必ず出す。**
```
検出: {N} パッケージのモノレポ({パッケージ管理})/ 明文規約 {n} 本 / API 契約 {n} 本 / 環境 {E をすべて列挙}
委譲: format・lint・spell は {検出したツール} に委譲(指摘しない)
検証: {取得元} から取得(`{コマンド}` / `{コマンド}`)
仕様: 課題ミラー `{パス}` を検出
```
**件数は必ず書く**(「10 パッケージ」)。数が出ていれば、影響範囲の grep でその全数を対象にしたことが読み手に伝わる。「複数パッケージ」では伝わらない。
理由は 1 つ。**誤った前提のまま出されたレビューを人間が検証させられるのが、最も時間を溶かす。** 前提を先頭に晒しておけば、間違っていれば人間は 5 秒で棄却できる。
#### -1-4. 見つからなかったときの振る舞い
**黙って一般論で代替しない。** 一般論に基づく指摘は「このリポジトリでは違う」という反論可能性が常に残り、レビュアーは指摘の妥当性そのものを審査させられる。さらに PR 作成者との無益な往復を生む。ROI がマイナスに振れる。
| 自動発見で見つからなかったもの | そのときの振る舞い |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| 明文規約 | **微修正指摘を出さない。** 本文に「明文規約を検出できなかったため微修正指摘は無効化しました(探索したパス: …)」と**探した場所を列挙して**書く |
| 検証コマンド | 委譲リストを空にし、**lint 相当の指摘(フォーマット・命名・未使用変数・スペル)を出さない。** 自動チェックが無い=そのレイヤーを重視していない |
| API 契約 | 「契約ファイル無し → 要件照合は PR 本文と課題チケットのみ」と本文に書く |
| 課題ミラー | 経緯探索を PR 本文・linked issue・git 履歴に限定する(Phase 0-2 の探索順で自然にそうなる) |
| 環境の集合 E | 「環境別設定の追随もれ」観点を落とす。落としたことを本文に書く |
落とした観点は profile に `N/A` として記録し、**レビュー本文にも「本リポジトリには該当なし」と出す**。「見ていない」と「該当が無い」を人間が区別できないと、結局その人が自分で確認しに行く。
**`一般的には〜が推奨されます` という文言を出力に含めることを禁止する。**
#### -1-5. 出力先を決める
この順で 1 度だけ決め、以降(`VISUAL.md` の `{出力先}` を含む)すべてでこの値を使う。
1. `--out` / 第 2 引数の明示指定
2. `.pr-review.json` の `outputDir`
3. 既存の慣習ディレクトリ: `ls -d .issues .reviews .notes docs/reviews 2>/dev/null` で見つかり、かつ追跡外のもの
4. どれも無ければ **リポジトリ外**: `${XDG_STATE_HOME:-$HOME/.local/state}/pr-review/{owner}__{repo}/`
**初対面のリポジトリに勝手にファイルを作らない**ため、既定はリポジトリ外にする。リポジトリ内に置く場合は追跡状態を確認する。
```bash
git check-ignore -v {出力先}
```
- 由来が `.gitignore` → そのまま使う(チーム全員で無視される)
- 由来が **`.git/info/exclude` → 警告する**。「このパスはあなたの手元でのみ無視されています。`.git/info/exclude` はコミットされないため、他メンバーの環境ではコミット対象になります」
- 無視されていない → `.gitignore` への追記を**提案するだけ**にし、承認が無ければ 4 のリポジトリ外へフォールバックする
書き込みに失敗したら `${TMPDIR:-/tmp}` へフォールバックする。いずれの場合も**絶対パスを標準出力に必ず表示する**(見つけられなければ無いのと同じ)。
---
### Phase 0. 取得
```bash
BASE=$(gh pr view {番号} --json baseRefName -q .baseRefName)
gh pr view {番号} --json number,title,body,author,headRefName,baseRefName,state,additions,deletions,files
gh pr diff {番号}
```
diff が巨大(概ね 1000 行超)な場合は先に対象ファイルを絞る。
```bash
gh pr diff {番号} --name-only
```
**行番号を引用する場合は、ブランチの実ファイルから取得すること**(diff のハンク行番号を手写ししない)。
```bash
git fetch origin "$BASE" {headRefName} --quiet
git diff $(git merge-base origin/$BASE origin/{headRefName})...origin/{headRefName} -- {path}
```
作業コピーが読み取り専用だったりして **`fetch` が通らない場面は普通にある。** その順で試す。
1. ローカルにある ref を使う(`git rev-parse --verify origin/{headRefName}` が通れば `fetch` は不要)。
**ただしその ref が PR の head と同じかを確認する**(`gh pr view {番号} --json headRefOid` と突き合わせる)。
古ければ次へ進む
1.5. `gh api repos/{owner}/{repo}/contents/{path}?ref={head}` で変更後のファイルを取得し、行番号を数える
2. 無ければ `gh pr diff {番号}` のハンクから算出し、**ヘッダにこう書く**
> 変更後の行番号は diff のハンクから算出した推定値です(`fetch` できなかったため)。
黙って推定値を実ファイル由来のように見せない。読み手は `path:line` を実在の所在として読む。
#### 0-1. 既存レビューコメントの取得(必須)
**既に指摘され、方針が決まっている事項を再提起しないため**、レビュー前に必ず既存コメントを確認する。
```bash
gh api --paginate 'repos/{owner}/{repo}/pulls/{番号}/comments' \
--jq '.[] | "\(.id)\t\(.in_reply_to_id // "ROOT")\t\(.user.login)\t\(.path):\(.line // .original_line)"'
gh api repos/{owner}/{repo}/pulls/comments/{id} --jq '.body'
gh api --paginate 'repos/{owner}/{repo}/issues/{番号}/comments' --jq '.[] | "\(.user.login): \(.body)"'
```
得られた各スレッドを次の 3 分類に仕分ける。
| 分類 | 扱い |
| ---------------------------- | ------------------------------------------------------------------------------------ |
| 対応済み | 現在のブランチのコードで**実際に反映されているかを確認**したうえで、同じ指摘をしない |
| 「このままで」等の見送り方針 | 同一の指摘は**取り下げる**(認識済みの判断のため) |
| 未対応・部分対応 | 自分の判定と突き合わせ、**続きの論点があれば出す**(重複ではないことを明記する) |
既存コメントの主張が事実として誤っている場合は、**根拠を示して補正する**。誤った前提のまま「対応不要」と扱われるのを防ぐため。
#### 0-2. 経緯カード — 探索の終わりを決める
経緯調査に終わりが無いのが、レビューで最も時間を溶かす。だから終了条件を **「調べ尽くしたか」ではなく「4 つの問いに出典付きで答えられたか」** で定義する。
| # | 問い |
| -- | ------------------------------------------ |
| Q1 | この PR は何を達成しようとしているか(1 文) |
| Q2 | なぜ今それが必要になったか(障害/要望/期限/仕様変更のどれか) |
| Q3 | 採用しなかった選択肢と、その理由(あれば) |
| Q4 | この領域で過去に決まっている方針・前例(あれば) |
**各回答には必ず出典を添える**(`gh pr view` / `{ファイル}:{行}` / `{PR番号}: {内容の 1 文要約}`)。番号だけの参照は絶対ルール 1 違反として扱う。
**4 問すべてが埋まった時点で、予算が残っていても即座に探索を終了する。**
探索手順(安い順。埋まった時点で打ち切る):
| 段階 | 内容 |
| ---- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| S0 | PR 本文・ブランチ名・コミットメッセージから参照を抽出する。正規表現: `#[0-9]+` / `(?:close[sd]?\|fix(?:e[sd])?\|resolve[sd]?)\s+#[0-9]+` / `https://github\.com/[^/]+/[^/]+/(issues\|pull)/[0-9]+` / 課題キー `\b[A-Z][A-Z0-9_]{1,15}-[0-9]+\b` / 課題管理 SaaS の URL。`git log --format='%s%n%b' $(git merge-base origin/$BASE origin/{head})..origin/{head}`。PR テンプレートがあれば、**どの節が空欄のまま残っているか**を見る(空欄の節がそのまま Q2/Q3 の欠落を指す) |
| S1 | 抽出した課題キーでリポジトリ内を grep し、課題ミラーの在り処を学習する(Phase -1 参照)。`ls docs/` と `find docs -maxdepth 2 -name '*.md' \| head -30` |
| S2 | linked issue 本体 `gh issue view {N} --json title,body,comments`。変更ファイルの履歴から過去 PR を辿る `git log --format=%s -n 20 -- {path} \| grep -oE '#[0-9]+'` → 上位 3 件を `gh pr view {n} --json title,body`(**本文だけ。diff は読まない**)。同領域の過去 PR `gh pr list --search '{キーワード} in:title' --state merged --limit 5` |
| S3 | 変更対象ファイル内の**コメントに書かれた設計理由**を読む。制約の出所がコード内コメントに書かれていることは多く、最も安い経緯の出典になる |
**打ち切り基準(ハード数値)**
- 検索・取得コマンドは S0〜S3 通算 **12 回まで**
- 新規に開くドキュメントは **8 本まで、各 400 行まで**(超える分は見出し一覧+キーワード周辺 ±40 行のみ)
- 過去 PR は **5 本まで、本文のみ**
- **Slack・メール・会議メモ・人に聞く は探索範囲外**とする。境界を引くこと自体が価値
**打ち切ったら黙って終わらない。** 埋まらなかった問いを、**PR 作成者への 1 問**に変換して出す。探索の続きを人間に押し付けるのではなく、1 回のやり取りで解決する形に落とす。
```
Q2 なぜ今必要になったか — 不明。
探索範囲: PR 本文 / linked issue #1234 / docs/ 配下 2 件 / 同ファイルの過去 PR 3 件
PR 作成者への確認事項: 「この変更のきっかけは障害対応でしょうか、それとも仕様変更でしょうか」
```
---
### Phase 1. トリアージ
#### 1-1. 疑いを立てる
**出力単位は「指摘」ではなく「疑い」である。** 1 つの PR で数十件の疑いを立てても、指摘として残るのは数件にとどまる。指摘を主・確認を従にした構造は、この実態と逆になっている。
疑いは次の形で列挙する。**指摘は、この表で `指摘` と判定されたものの射影として生成する。** こうすれば Critical 0 件でも成果物が空にならない。
| id | 疑ったこと | 判定 | 根拠の強度 | 根拠の所在 |
| -- | ---------- | ---- | ---------- | ---------- |
| S1 | 削除のスコープが想定より広くないか | 閉 | R2 全数確認 | `where` 句の条件 3 件を列挙、`repo.ts:88` |
| S2 | 呼び出し元がすべて更新されているか | 閉 | R2 全数確認 | `createOrder(` 参照 7 件すべて確認 |
| S3 | フリーズ中の接続再利用で失敗しないか | 指摘 | R3 一次資料 | 公式ドキュメントの該当文 |
| S4 | 別環境の設定に追随もれがないか | 未確認 | R5 | 推論のみ。閉じるには `config.stg` の実値が要る |
判定は 3 値。`閉`(見なくてよい)/`指摘`(人間の判断が要る)/`未確認`。
**R5 止まりのものを `閉` にしてはいけない。** 必ず `未確認` に落とす。曖昧なものを曖昧なまま可視化するほうが、無理に断定するより人間の判断コストは下がる。
最低限、次の観点で疑いを立てる(該当する差分があるときだけ)。
- 削除・更新の**スコープ**が変わっていないか(どの範囲が消えるか)
- 一意制約・外部キー・カスケードに抵触しないか(profile の DB スキーマで確認)
- 同じデータを読む**他パッケージ**への波及。**profile のパッケージ一覧の全 N 件を対象にする**。個数を思い込みで決めると取りこぼす
- 既存の呼び出し元がすべて更新されているか(シグネチャ変更時)
- エラー時・0 件時・NULL 時の分岐
- **二重管理の片側もれ**(後述のクリティカル判定基準)
- インフラ変更では、既存リソースの**置換/再作成**が発生しないか、切替時の**ダウンタイム**、ロールバック可否
diff が広い場合は調査をサブエージェント(`Explore` / `general-purpose`)に分割して投げ、**疑いの表の形で**結論を受け取ってよい。
#### 1-2. 母数と網羅根拠を出す
疑いの表ができたら、次の 4 つの数字を出す。**図解 HTML を作る場合は HTML の冒頭に、`--no-visual` のときはマークダウンのヘッダ表の下に置く。**
```
立てた疑い {N} 件 / うち指摘 {N} 件 / 未確認 {N} 件(全件掲載)/ 見なくてよい {N} 件(うち掲載 {N} 件)
```
**「指摘」は Critical・要検討・参考・微修正の合計である。**4 段階は指摘の中の重み付けであり、
母数の分類とは別の軸。母数は 4 つの数字が足して疑いの総数になること。
掲載件数が母数より少ないのは正しい。そのときは **「全 {母数} 項目のうち、判断に影響の大きいものを抜粋しています」** と明記する。母数と掲載数を分離して書くことが、「調べ終わっていい」と言える形の本体である。
あわせて **どの観点リストを使って疑いを立てたか** を書く。網羅の根拠がそこにしか無い。
#### 1-3. 指摘への昇格(件数上限なし)
後述の **クリティカル判定基準** に明確に該当するものだけを指摘にする。該当なしなら 0 件で正しい。該当するものは件数を絞らずすべて挙げ、深刻度の高い順に並べる(`C1` が最も深刻)。**件数合わせで軽微な指摘をクリティカルへ昇格させない。** 同一原因・同一箇所に起因する指摘は 1 件にまとめる。
各指摘について、絶対ルール 2 を適用する。「ひとことで言うと」が書けなければ出さない。難易度タグに該当すれば「理解に必要な前提」を前置する。
#### 1-4. 微修正フォールバック(Critical・要検討がともに 0 件のときのみ)
後述の **微修正判定基準** に照らして最大 3 件まで。**Critical または要検討が 1 件以上あればスキップする**(判断が要るものが残っているのに細かい指摘を足すと、そちらへ注意が逸れる)(PR 作成者をクリティカル修正に集中させるため)。件数合わせで無理に埋めない。
**周囲のコードが既に同じ書き方をしている場合は指摘しない。** 指摘前に同一ファイル・同一ディレクトリの既存コードを確認し、そのスタイルがベースブランチ側に既存であれば取り下げる。
**取り下げた微修正は件数として残す。** 「1 件検討し、周囲のコードが同じ書き方だったため取り下げました」と書く。取り下げの記録そのものが、レビューの信頼の根拠になる。
---
### Phase 2. マークダウン生成 → 保存
`{出力先}/pr-{番号}-critical.md` に後述のフォーマットで保存する。親ディレクトリが無ければ作成する。
疑いの表は、**Phase 3 の境界図の材料でもある**。ここで根拠の型・対象 `path:line`・全数確認した参照件数を構造化して残しておくこと。Phase 3 で調べ直すと同じ探索を 2 回することになる。
### Phase 3. 図解 HTML 生成
`--no-visual` 指定時はスキップ。**手順は `VISUAL.md` に従うこと**(このファイルを最後まで読んでから着手する)。
概要:
1. `artifact-design` スキルを読む(必須)。図を描くので `artifact-diagramming` も読む。**ただし Web フォントは使わない**(`VISUAL.md` 第 7 章の自己完結が優先。Artifact プラットフォームは Google Fonts を許可するが、このスキルの生成物はネットワーク無しで読める必要がある)
2. デザイン計画(色・書体・レイアウト)を立てる
3. HTML を書く。**影響範囲の境界図(`VISUAL.md` 第 4 章)を必ず入れる。** Phase 1 の疑いの表をそのまま図にする
4. 解説の要所に `<!--SRC path start end hi=a-b-->` プレースホルダを置く
5. `python3 {SKILL_DIR}/scripts/build-html.py expand {fragment.html} --ref origin/{PRのブランチ}` で展開する(**行番号の手打ちは禁止**。`--ref` を忘れるとベースブランチ側のコードが載る)
6. `python3 {SKILL_DIR}/scripts/build-html.py validate {fragment.html} --strict` を通す(**exit 1 なら公開しない**)
7. `Artifact` ツールで公開する
8. `python3 {SKILL_DIR}/scripts/build-html.py standalone {fragment.html} {出力先}/pr-{番号}-explainer.html`
**`validate` には既定で `--strict` を付ける。** `--strict` は境界図の欠落をエラーに昇格させる。境界図の無い図解は、体裁だけ整って「どこで探索を終えてよいか」が解決されないため、中途半端に出すより出さないほうがよい。図解が不要な PR は `--no-visual` で Phase 3 ごと飛ばす。
### Phase 4. 結果サマリ
標準出力に短く表示する。
- PR #番号・タイトル
- 検出したプロファイル(1 行)
- **立てた疑い N 件 / 指摘 M 件 / 未確認 J 件**
- 既存レビューコメントとの突き合わせ結果(重複・取り下げた件数)
- 各指摘の「ひとことで言うと」
- PR 作成者への確認事項(あれば)
- 成果物の**絶対パス**/URL
---
## クリティカル判定基準
以下に **明確に該当** するもののみ Critical として扱う。
### Critical に上げる前に、気づける経路を探す
**「誰も気づけない」「検知できない」と書く前に、気づける経路を必ず探すこと。** 設計上の穴が別の経路で埋まっていることは多い。探さずに Critical にすると、レビュイーから「運用でカバーできている」と返り、指摘全体の信用が落ちる。
探すもの(見つかったら所在を `path:line` か設定名で示す)。
- 別系統の通知(別のトピック・チャンネル・メール・監視ツール)
- 下流の処理が止まることで表に出る症状
- 定期的に人が見る画面・レポート・突合
- 失敗が続いたときに別の形で現れる現象(件数が増えない、キューが溜まる など)
**経路が 1 つでも見つかったら Critical にしない。** 「要検討」に落とし、その経路が実運用で機能しているかを人間に確認してもらう。探して見つからなかったときだけ Critical にし、**どこを探したかを本文に書く**。
- **要件未達**: 仕様書・API 契約・PR 本文に記載された挙動と実装が明確に乖離している
- **致命的バグ**: null/undefined による例外、無限ループ、データ破損・喪失、レスポンス形式崩壊
- **セキュリティ**: 認証・認可の欠落、SQL インジェクション、秘密情報のログ出力
- **整合性破壊**: トランザクション境界の誤り、書き込み直後に反映前の複製から読む、キャッシュと実体の乖離
- **契約違反**: 実行時に初めて分かる結線もれ、レイヤー責務の崩壊、ドメイン変換を経ない生データの露出
- **運用事故の誘発**: 一度きりのデータ移行が自動適用対象のディレクトリに置かれている、環境固有 ID の直書きにガードがない、破壊的操作の検査が空振りし得る
- **インフラの破壊的変更**: 既存リソースの置換・削除、切替時の想定外のダウンタイム、ロールバック不能な構成
### 汎用の構造的観点(言語非依存)
案件固有に見える事故の多くは、次の 2 型に還元できる。どちらも根拠を `path:line` と件数で示せるため、人間が数十秒で検証できる。
#### 二重管理の片側もれ
**同じ関心事を複数箇所に書かねばならない構造への追加で、片方だけが更新される。** 対象になる構造は、依存注入の登録表・ルーティング表・バレルファイル・環境別設定・翻訳リソース・テストのクリーンアップ一覧・バンドルの外部依存宣言など。
検出手順(登録もれ):
1. diff で新規追加された export / クラス / 関数の識別子を抽出する
2. `git grep -F '{識別子}' -- . | grep -v '{定義ファイル}' | wc -l`
3. 参照が 0 なら「定義されたが、どこからも参照・登録されていない可能性」
4. 同ディレクトリの兄弟が平均 K 箇所から参照されているのに新規分だけ 1 箇所なら、追随もれの強い候補
検出手順(環境追随もれ): profile の環境集合 E に対し、diff が触れた設定ファイルの環境トークンを抽出し、`E − 触れた環境` が空でなければ「{未更新の環境} の設定が更新されていない可能性」として出す。E が発見できていなければこの観点は落とす(落としたことを本文に書く)。
#### リリース順序に依存する一時的破壊
スキーマ変更・カラム削除・NOT NULL 化・API の破壊的変更を、それを参照するコードの撤去と同一リリースに載せると、デプロイの前後関係次第で一時的に本番が壊れる。**どちらが先に出ても壊れないか**を確認する。
### 言語・スタック固有の観点
**profile の判定に一致したときだけ有効化する。** 一致しなければブロックごと落とす。
| 一致条件 | 疑うこと |
| ------------------ | ---------------------------------------------------------------------------------- |
| バンドラ設定を検出 | 外部依存の宣言もれ。宣言と実際の依存が一致していないと、ビルドも型チェックも通るのに**起動時にクラッシュする**。静的検査では拾えない |
| ORM / マイグレーション を検出 | 制約・カスケード・一意キー、テスト用データ削除処理の追随、seed の更新 |
| IaC を検出 | 記述の見た目と生成物の差、既存リソースの置換、切替順序、環境別設定の追随 |
| フロントエンドを検出 | 描画から導出できる値の state 同期、配列インデックスの key、状態の重複、非同期失敗の握り潰し |
**個々のリポジトリで過去に本番影響を出した経路は、このスキル本文ではなく `.pr-review.json` の `extraCriticalChecks` に置く。** そこが案件知見の置き場所である(末尾参照)。
### 経緯が不明なときの制約
Phase 0-2 で経緯・仕様が確認できなかった領域については、**「要件未達」「仕様と乖離」系の指摘を出してはいけない。** 仕様を確認できていないのに乖離を主張すると、その真偽検証がまるごと人間に降ってくる。
代わりに、トリアージ結果の **「未確認」** に入れ、`PR 作成者への確認事項` として疑問文の形で出す。
> 「〜の場合に 404 ではなく 200 が返る実装となっておりますが、これは意図された挙動でしょうか」
一方、**コード内で完結して根拠を示せるクリティカル指摘(null 例外・無限ループ・トランザクション境界・破壊的変更)は、経緯が不明でも通常どおり出してよい。** 根拠が diff の中で閉じており、人間が数十秒で検証できるため。
## 微修正判定基準(クリティカル 0 件時のフォールバック)
次のいずれかの根拠を**必ず持てるもの**だけを指摘する。「違和感がある」「もっと綺麗に書ける」では指摘しない。
- **(A) 明文規約の条文引用**: `{規約ファイル}:{行} 「{原文引用}」` の形で書ける
- **(B) は設けない。**明文規約のみを根拠とする**(コードベースから帰納した「流儀」は、レビュイーが条文で真偽を確かめられないため根拠にしない。元 Skill の方針を維持する)
**(A) を書けないなら出さない。** 規約が 1 本も見つからなかった場合は、Phase -1-4 のとおり微修正指摘そのものを無効化し、探索したパスを本文に列挙する。
観点の型は次のとおり(**該当する規約条文が実在する場合に限り**有効)。
- マジックナンバー: 数値リテラルが定数化されていない。同一ファイル内の他の値が定数化されているのに特定値だけ直書き、という一貫性の欠如も含む
- 関数長・引数の個数が規約の上限を超えている
- 命名規約違反(大文字小文字の規則、boolean の接頭辞、レイヤーごとの命名パターン)
- 型システム違反(規約が禁止している構文・キャスト・生 SQL)
- コメント規則違反(実装詳細を書いている、コメントアウトコードの放置、**変更に追随していない陳腐化したコメント**)
- import の書式規約違反
- テスト命名規約違反
### あえて指摘しない(対象外)
- 既存コード(他モジュール・同一ファイルの既存行)と同じパターンを踏襲している箇所。**指摘前にベースブランチ側を必ず確認する**
- 既存レビューコメントで方針が決まっている事項
- profile の**委譲リスト**にあるツールが自動検出する種類のもの(フォーマット・import 順・未使用変数・スペル・設定に現れている lint ルール)
- 網羅的なセキュリティ観点(組み込みの `security-review` に委ねる)
- 「よりエレガントに書ける」系のリファクタ提案(規約違反ではない)
- テスト観点の追加要望(網羅性)
---
## 出力フォーマット
### 2 つの成果物は役割が違う
- **マークダウン = PR にそのまま貼れる下書き。** 指摘とその根拠、確認したいことだけを書く。
**目安 4,000 字以内。** 貼れない長さは成果物として失敗である。
- **図解 HTML = 「その指摘は本当か」を確かめるための資料。** トリアージの全体像、
見なくてよいと判断した根拠の一覧、経緯の探索範囲、影響範囲の境界図はこちらへ置く。
**判断の材料はマークダウン、検証の材料は HTML。** マークダウンに検証用の情報まで詰めると、貼れない長さになり、どちらも読まれない。
### マークダウンの構成
指摘があるとき。
```markdown
# PR #{番号} クリティカルレビュー: {PR タイトル}
| 項目 | 値 |
| -------- | --------------------- |
| 作成者 | {author} |
| ブランチ | {head} → {base} |
| 指摘件数 | Critical: {N} 件 |
## クリティカル指摘 {N} 件
### 指摘 C1: {一文サマリ(30 字以内・敬体)}
> {相対パス}:{行番号}
>
> ```
> {該当コード 1〜10 行。長ければ前後を … で省略}
> ```
{敬語の本文・200 字程度。問題 → 影響 → 確認や修正の依頼の順。}
```
**クリティカルが 0 件なら、要検討や参考が何件あっても、必ず `## クリティカルな指摘はございません` を
指摘本体の先頭に置く。** 読み手が最初に知りたいのは「止めるべき問題があるか」であり、
その答えを探させない。要検討・参考はその宣言のあとに続ける。
クリティカルが 0 件のとき。
```markdown
# PR #{番号} レビュー: {PR タイトル}
{ヘッダ表・指摘件数は「Critical: 0 件」}
## クリティカルな指摘はございません
{根拠を 2〜4 行。何を確認して 0 件と判断したか}
{要検討・参考がある場合は、ここに「## {番号}. 要検討: …」を続ける}
## 微修正指摘{もございません / {N} 件}
## 補足(指摘ではございません)
### 確認済みの観点
- {観点}: {根拠。`path:line` または全数確認の件数}
### ご確認いただけますと安心な点(任意)
- {未確認の点}: {決着させるために何を見ればよいか}
```
**`--no-visual` のときは HTML が無いので、「確認済みの観点」に見なくてよいものを全件書く。**
図解 HTML を作る場合は代表 3 件までに留め、残りは HTML へ置く。
**全件書くと 4,000 字に収まらない場合は、字数より母数の明示を優先する。** 代表を掲載し「全 {N} 件のうち {M} 件を掲載」と書く。**絞ってよいのは「見なくてよい」だけで、未確認は常に全件掲載する。**
### 書かないもの
- Phase 1-1 の疑いの表そのもの(作業用の構造であり、読み手の負荷になる)
- 経緯の探索過程の詳細(HTML 側の役目)
- 前提の長い解説(HTML 側の役目。マークダウンでは指摘本文に必要な分だけ)
### 図解 HTML に載せる内容
次はマークダウンではなく **図解 HTML 側**に置く。`--no-visual` のときは、
「確認済みの観点」に圧縮して書く。
```markdown
## トリアージ結果
**人間の判断が要るもの: {M} 件**
1. {ひとことで言うと(30〜60字・専門用語ゼロ)}
なぜ人間の判断が要るか: {AI が決めてよい範囲を超える理由}
AI の見解: {根拠つき・1〜2 文}
判断してほしいこと: {選択肢の形で}
**人間が見なくてよいもの: {K} 件**
なぜ見なくてよいか(根拠):
- {X} 件 全数確認(参照 N 件をすべて確認)
- {Y} 件 テストで担保
- {Z} 件 呼び出しが不変 / データが不変 / そもそも通らない
- {W} 件 一次資料の原文で確認
**未確認: {J} 件** — 根拠が推論に留まったため、判断を保留しています。
- {疑ったこと} → 閉じるには {何を確認すればよいか}
## 経緯として確認した範囲
- PR 本文、linked issue #{番号}(内容: {1 文要約})
- 同じファイルを触った過去 PR {n} 件(#…, #…, #…)
- docs/ 配下の関連ドキュメント {n} 件
この範囲に、本 PR の判断を変える情報はありませんでした。
{埋まらなかった問いがあれば}
**PR 作成者への確認事項**: 「{1 問}」
## 0. このPRの前提(背景を知らない読み手向けの整理)
```
### 「0. このPRの前提」の書き方(必須ゲート)
**これは図解 HTML 側の節である。埋め終わるまで、指摘本体を書き始めない。** 経緯を遡る時間を直接置き換える唯一の項目であり、後回しにすると必ず書かれずに終わる。
6〜8 個の箇条書き、700〜830 字。次の型で埋める。
1. 対象システムが何をするものか(誰から呼ばれ、何を処理するか)
2. 外部制約は何か
3. その制約から現在の設計がどう決まったか
4. 過去の合意(**Issue / PR 番号は必ず決定内容の 1 文要約を併記する。番号だけの参照は書き直す**)
5. 影響が及ぶ共有物の範囲
6. 本 PR は結局その中の何を変えるのか
### 既存レビューコメントがある場合(該当時のみ)
```markdown
## レビュー状況({日付}時点)
| 既存コメントの指摘 | 返信 | 現在のブランチでの状態 |
| ------------------ | ---- | ---------------------------- |
| … | … | 対応済み / 部分対応 / 未対応 |
{重複した指摘があれば、取り下げる旨と理由を明記する。}
```
### 指摘本体
````markdown
## {番号}. {Critical / 要検討 / 参考 / 微修正}: {一文サマリ(30字以内)}
**ひとことで言うと**: {30〜60字・専門用語ゼロ・日常語のみ}
{難易度タグに該当する場合のみ}
**この指摘を読むのに必要な前提**: {2〜4 行。「X を知っている必要があります。X とは〜」}
> {相対ファイルパス}:{行番号}
>
> ```
> {該当コード抜粋(1〜10行、長ければ前後を `…` で省略)}
> ```
{敬語コメント本文・200字程度。問題 → 影響 → 具体的な修正方針の順で簡潔に。}
**判断してほしいこと**: {選択肢の形で}
````
### 「人間が見なくてよいもの」の詳細(必須・主役)
```markdown
## 確認してクリティカル該当なしと判断した点
返信は不要です。レビュー時に懸念として挙がったものの、確認の結果問題なしと判断した内容です。
全 {N} 項目のうち、判断に影響の大きいものを抜粋しています。
### 間違っていれば全断していた{n}点
1. {疑問文の見出し。例: 実クライアントの IP は、本当に後段まで届くのか}
→ {根拠の型}: {根拠(path:line / 件数 / 原文引用)}
### {観点のまとまり}
- {疑ったこと}
→ {根拠の型}: {根拠(path:line 付き)}
```
このセクションは**必ず入れる**。「何を見たか」が伝わらないと、0 件という結論の信頼性が担保できない。
見出しは**肯定形にする**。「確認して問題なしと判断した点」という否定形の付録ではなく、**「間違っていれば全断していた 3 点」** という主役として書く。影響度の上位 3 件を疑問文の見出しで並べ、「もし外していたら何が起きていたか」を伝える。0 件という結論の価値は、そう書いたときにだけ読み手に届く。
**根拠の書き方は「疑い → 反証手段 → 結論」を 1 行で閉じる形**にする。
> 「未指定時に他 6 スタックの生成物が変わらないか → 変わりません。ベース側と本ブランチを併置し、同一入力の 3 パターンで生成結果を厳密比較したところ、3 パターンとも完全一致しました」
「〜と判断いたしました」だけで、疑いの内容も検証手段も書かれていない形は弱い。書き直す。
---
## コメント文体ガイド
profile の文体判定が **敬体日本語** のときに適用する。中立英語のときはこの節を飛ばし、簡潔・中立・提案調で書く。
- 常体禁止。常に敬体で記述する
- 断定ではなく提案調:「〜いただけますでしょうか」「〜のご検討をお願いできますと幸いです」
- 冒頭にクッション:「恐れ入りますが」「ご確認のお願いです」「1 点確認させてください」
- 直接的な否定表現を避ける:
- 「バグです」→「〜の可能性がございます」
- 「誤りです」→「仕様と差異がございます」
- 「間違っています」→「意図と異なる挙動となる恐れがございます」
- 1 指摘あたり本文は 200 字前後(引用・見出し・「ひとことで言うと」・前提は別カウント)。冗長な前置きや言い訳は入れない
- 微修正指摘ではさらにトーンを柔らかく:「お手すきの際にご検討いただけますと幸いです」「必須ではございませんが」等
- **個人名・役職名を文面に出さない**。役割ベースの中立表現にする
- **リリースを急いでいる状況では、最小コストの代替案を併記する**。「置き場所を変える」が重い場合に「コメント 1 行の追記でも危険度は下がる」を添える等
### コメント例(クリティカル)
```
ご確認のお願いです。`user` が `undefined` の場合でも 200 ステータスで空レスポンスが返る状態となっており、
仕様上 404 を返す想定と差異がございます。`NotFoundError` を throw する形にご修正いただけますでしょうか。
```
### コメント例(微修正)
```
お手すきの際にご検討いただけますと幸いです。`max: 50` が直書きになっており、同ファイルの他のタイムアウト値
(`DB_CONNECTION_TIMEOUT_MS` 等)と定数化の粒度が揃っておりません。`DB_POOL_MAX` のような定数名で冒頭に切り出し
いただくと可読性が揃うかと存じます(参照: `{規約ファイル}:{行}`「マジックナンバーは定数として定義」)。
```
---
## プロジェクト側の上書き設定
自動発見は「初対面のリポジトリでも動く」ためのものであり、**その案件で過去に本番影響を出した経路のような知見は自動発見では出てこない。** それはリポジトリ側に置く。自動発見より常に優先される。
置き場所は `.pr-review.json`(リポジトリ直下)/スキルと同じディレクトリの `pr-review.json`(**持ち出すときは外す**)/`.claude/pr-review.local.json` の順に探す。
```json
{
"conventions": ["docs/coding-standards.md"],
"specSources": ["docs/spec/"],
"packages": ["<自動発見が取りこぼす場合のみ列挙>"],
"environments": ["dev", "stg", "prd"],
"validateCommands": ["<CI が実際に流しているコマンド>"],
"outputDir": "<既定を上書きする場合のみ>",
"tone": "ja-keigo",
"extraCriticalChecks": [
{
"when": "**/build.ts",
"check": "バンドルの external 宣言と実際の依存が一致しているか",
"why": "宣言もれがあると、ビルドも型チェックも通るのに起動時にクラッシュする。過去に本番停止を出した"
}
]
}
```
**`extraCriticalChecks[].why` は必須**とする。根拠のない観点が溜まると、観点リストそのものが信用できなくなるため。「過去に何が起きたか」を 1 文で書けない観点は追加しない。
## 参照
- `VISUAL.md` — Phase 3(図解 HTML)の詳細手順。**Phase 3 に入る前に必ず読む**。第 4 章「影響範囲の境界図」は Phase 1 の疑いの表をそのまま図にしたもの
- `scripts/build-html.py` — コード抜粋の展開(`expand`)・公開前チェック(`validate`)・単体 HTML 書き出し(`standalone`)
- profile が検出した明文規約 — 微修正判定の根拠。**このスキル本文にファイル名を書かない**
- `.pr-review.json` — 案件固有の知見の置き場所
まとめ
最初に挙げた疑問に、ここまでの記録をもとに答えます。今日試せる形は、冒頭の 3 行のプロンプトです。
| 当時の疑問 | 整理した答え |
|---|---|
| 経緯が分からないとき、どこまで調べれば終わりにしてよいのか | 4 つの問いに出典付きで答えられたら終わりにします。埋まらなかった問いは PR 作成者への質問に変えます |
| 「他に影響がないか」を、どこで止めてよいのか | 変更点の列挙ではなく「すぐ外側に何があって、なぜ触れていないと言えるか」で書きます。隣接物 8 項目に根拠の型を付け、決着しないものは確認事項を添えました |
| AI の指摘が正しいかを、どう確かめるか | 指摘ではなく、根拠の種類とファイル名と行番号を検査します。それを書けない根拠は「未確認」へ落とします |
| 案件専用のものを他へ持ち出すには、何を外せばよいのか | 固有名詞を本文から追い出し、自動発見に置き換えます。見つからない観点は落とし、落としたことを書きます |
検証を通して、当時は挙げていなかった問いが増えました。「経緯の一次情報を渡せば足りるのか」です。足りません。その一次情報が誤っていた 1 件で、AI は誤りごと結論を取り下げました。
経緯の一次情報を渡すことと、それが正しいかを確かめることは、別の作業として残ります。確かめる手段を持っていたのは、実行を許した条件だけでした。AI に何を実行させないかを決めるときは、禁止で何が出せなくなるかを、実行を許した出力と並べて見ておくのがよいと思います。
このスキルは、まだ発展途上のものです。実はこの記事を書いている間にも 2 点ほど手を入れており、今後も実際の案件や PR に当てながら、少しずつ調整と検証を重ねていきたいと考えています。
そのため、掲載した内容はあくまで一例として、参考程度にご覧いただければ幸いです。レビューで重視すべき観点は、案件の性質やチームの状況によって変わってくるものだと思います。ぜひご自身の環境と照らし合わせながら、役立ちそうな部分だけを取り出してお使いください。
この記事が誰かのお役に立てば幸いです。
参考資料
クラスメソッドオペレーションズ株式会社について
クラスメソッドグループのオペレーション企業です。
運用・保守開発・サポート・情シス・バックオフィスの専門チームが、IT・AI をフル活用した「しくみ」を通じて、お客様の業務代行から課題解決や高付加価値サービスまでを提供するエキスパート集団です。
当社は様々な職種でメンバーを募集しています。
「オペレーション・エクセレンス」と「らしく働く、らしく生きる」を共に実現するカルチャー・しくみ・働き方にご興味がある方は、クラスメソッドオペレーションズ株式会社 コーポレートサイト をぜひご覧ください。※2026 年 1 月 アノテーション㈱から社名変更しました







