2026-09-04 · ai · claudecode · コードレビュー · githubactions
AIに書かせたコードのレビューが、形だけになっていないか
AIにコードを書かせている人に聞きたいことがあります。
そのレビュー、何を根拠に「OK」と言っていますか。
差分が40ファイルあって、全部読む時間はない。テストは通っている。 見た感じ悪くない。だからマージする。——これはレビューではなく、承認の儀式です。
3ヶ月で個人アプリを10本作る過程で、この状態に何度もなりました。 抜け出すために変えたのは、レビュアーの能力ではなく判定の根拠でした。
なぜ形だけになるのか
理由は2つあります。
1. 判定できる基準が無い
Issueに「ログイン機能を作る」としか書いていなければ、レビュアーは 「ログイン機能ができているか」で判定するしかありません。これは判定できません。 できているように見えれば通ります。
2. 書いた本人がレビューしている
AIに書かせて、同じ会話の続きで「レビューして」と頼む。これが一番危ない形です。
レビュアーは実装過程の文脈を全部持っています。「なぜこう書いたか」を知っているので、 書かれていないことまで補って読みます。 人間が自分のコードをレビューできないのと 同じ理由です。
変えたこと
判定可能な受け入れ条件を、実装前に書く
これが一番効きました。
| 書き方 | 判定 |
|---|---|
| 「ログイン機能が正しく動くこと」 | 判定不能 |
「未登録メールでログインすると 401 と USER_NOT_FOUND を返す」 |
判定可能 |
| 「パフォーマンスを改善すること」 | 判定不能 |
| 「一覧の初期表示が200件で500ms以内(ローカル計測)」 | 判定可能 |
実装より先に書くことが重要です。あとから書くと、実装に合わせた条件になります。
レビュアーに文脈を渡さない
レビューは別のセッション、別の人格として実行します。渡す入力は2つだけです。
- Issueの受け入れ条件
- PRのdiff
実装過程の会話は渡しません。持っていないほうが、書かれていないことに気づけます。
「この PR は認証まわりを整理する意図で……」という説明を足したくなりますが、 足さないでください。説明が要るなら、それはIssueかPR本文に書かれているべきです。
安いチェックから先にやる
判定には順序があります。
- 担当範囲の違反 — 変更ファイル一覧を見るだけで判定できる
- テスト・lint — 機械が判定済み
- 受け入れ条件 — コードを読む必要がある
前の段で差し戻しが決まったら、後ろは見ません。全部指摘してから返しても、 1つ直せば他も変わるので手戻りが増えるだけです。
そして1は本当に安い。
gh pr diff <番号> --name-only
これだけで、Issueに書いた担当範囲の外を触っていないかが分かります。 40ファイルの diff でも、一覧を見れば「なぜ認証のIssueでルーティングが変わっているのか」 がすぐ分かります。
「条件に無い機能」も差し戻す
見落とされがちですが、これが効きます。
「ついでに便利にしておきました」は、レビューされていない変更がmainに入る ということです。受け入れ条件に無い機能は、判定する根拠がありません。
対処は、その部分を別Issueに切り出させることです。捨てるわけではありません。
差し戻しの書き方
差し戻すときは3つ書きます。
- 何が問題か — 該当ファイルと行
- なぜ問題か — どの受け入れ条件・どの担当範囲に反するか
- どうなれば通るか — 判定可能な形で
「もう少し整理してください」は差し戻しになりません。何をすれば通るのか 判定できないので、次も通らないものが返ってきます。
状態管理は機械に寄せる
レビューの判定に集中させるため、ラベルの付け替えはGitHub Actionsに任せています。
on:
pull_request:
types: [opened, reopened, ready_for_review, closed]
pull_request_review:
types: [submitted]
PR本文の Closes #<番号> からIssueを特定し、PRの動きに応じて
status:review / status:changes-requested / status:done を張り替えます。
人格にラベル操作を任せると、付け忘れが必ず起きます。 状態は機械が持ち、人格は「何をしたか」だけに集中させるほうが安定しました。
限界も書いておきます
レビュアーは実装者と同じモデルです。
文脈を分離しても、根本的には同じモデルです。モデルが体系的に持っている誤りは、 レビュアーも見抜けません。 あるライブラリのAPIを一貫して間違えて覚えていれば、 実装者が間違え、レビュアーも正しいと判定します。
これは構成では解けません。対処は、受け入れ条件に実行可能な検証を入れることです。
- [ ] 未登録メールでログインすると 401 と USER_NOT_FOUND を返す
→ これを検証するテストがあること
「テストが通ること」は、モデルの思い込みを外部から検証できる数少ない手段です。 だから受け入れ条件は、できるだけテストに落とせる形で書きます。
まとめ
- 判定可能な受け入れ条件を、実装より先に書く
- レビュアーに実装過程の文脈を渡さない
- 担当範囲の違反から先に見る。一覧を見るだけで判定できて安い
- 条件に無い機能も差し戻す。別Issueに切り出す
- 状態管理は機械に寄せ、判定に集中させる
- モデル共通の誤りは見抜けない。受け入れ条件を実行可能な検証に落とす
この判定手順をレビュアー人格の定義として明文化し、実装者・設計者と組み合わせた構成を 配布しています。4人格の無料版はMITで公開しています。
Claude Code に設計・実装・レビューを別々の人格として分担させ、GitHub Issue と
ブランチを軸に並列開発を回すための設定一式を MIT で公開しています。
コピーして ./setup.sh を叩けば動きます。技術スタックには依存しません。
https://github.com/quintetkit/quartet
このワークフローだけで実際にツールを 1 つ作りました。Issue の分割から PR、 レビュー、マージまで記録が全部残っています。うまくいかなかった箇所も消していません。
https://github.com/quintetkit/mdlinkcheck
UI 設計人格・レビュー基準・Issue 単位の並列実行スクリプト・実践ガイド 10 章を 足したものは製品ページにあります。