「Issue を渡したら、あとは PR まで全自動」——聞こえはいいけれど、それ、実際どうなの?
Issue 番号をひとつ渡すと、要件分析から PR 作成まで人が触らずに進む。その段取りを JavaScript の if 文と定数で決定論的に組む方法は、Issue 番号ひとつで PR まで自動化する記事に書きました。フェーズ遷移もループ上限もコードで固定してあるので、エージェントが気分でゲートを飛ばすことはありません。
「じゃあ、本当に全部任せていいのか?」——段取りが固まると、この問いが顔を出します(ここで急に手が止まるのが人情です)。答えは、任せていい。ただし任せてはいけない場所が、あらかじめ決まっている。そして肝心なのは——その場所を人間が覚えていて手動で覗きにいくのではなく、機械のほうから人間へ差し戻してくる設計になっていることです。
覚えておく運用は、いつか忘れます。だから「戻すべきところは向こうから戻ってくる」ようにしておく。この記事では、無人で進むパイプラインの終盤で必ず人間に戻している3点を、実装の裏付けとともに紹介します。
この記事で学べること
- 品質の高低と「誰が責任を負うか」を、なぜ別の軸で扱うのか
- LLM が自分では緩められない「床」を決定論で敷くやり方
- 自動修正が空回りしていることを検出して人間へ渡す出口の作り方
先に3点を早見表でまとめておきます。以降の章はそれぞれの実装の裏付けです。
| 差し戻す3点 | 何を見るか | 実装での担保 |
|---|---|---|
| ① 当事者性 | 正しさではなく、結果責任・好み・訓練分布外性が論点か | 品質は重大度、当事者性は escalate フラグと軸を分ける |
| ② 床(floor) | 越えてはいけない境界がなし崩しに緩んでいないか | critical の格下げを封じ、危険カテゴリは自動で床フラグ |
| ③ 行き詰まり | 同じ指摘が刺さらない・修正不能・CI が非緑でないか | 決定論カウンタで stuck 検出し、緩めず人間へ |
1. 「正しさ」ではなく「誰が責任を負うか」で止める
品質評価フェーズでは、独立した評価者エージェントが diff・計画・テスト結果だけを見て採点します。ここで押さえたいのは、指摘が2系統に分かれていることです。
ひとつは品質の高低。コードが良いか悪いかは重大度 critical / major / minor で表します。もうひとつが escalate フラグで、これは品質とはまったく別の軸に立っています。評価者が「これは正しさの問題ではなく、当事者性・好み・訓練分布外性が論点だ」と判断したときだけ立てるフラグです。理由は次の4クラスに限定してあります。
- accountability(結果責任): 外部公開 API の命名や課金挙動の変更など、結果の責任を人間が負うべき決定
- preference(好み): 技術的に複数解が同等で、Issue にも指定がなく、好みでしかないもの
- novelty(訓練分布外): 前例のないドメイン固有仕様の解釈など、モデルが自信を持って判定できないもの
- blast-radius(影響範囲): 誤っていた場合の影響が PR のスコープを超えるもの(データ移行の方針など)
このフラグが立つと、後段のマージ判定が HOLD になり、人間が読まないとマージできません。おもしろいのは、評価が「合格」でも escalate は立てられる点です。コードは正しい。でも、この命名を最終決定するのは人間の仕事だ——そういう状態を、機械が明示的に切り分けて差し戻してくる。
品質が低いから止めるのではなく、当事者性が人間側にあるから止める。「良い / 悪い」の物差しと「誰の判断か」の物差しは、混ぜてしまうと片方が片方に飲まれます(だいたい飲まれるのは後者のほうです)。この線引きを評価者の出力スキーマそのものに埋め込んでおくのが、1点目です。
2. LLM が自分では緩められない「床」を置く
自動化で一番こわいのは、ゲートをすり抜けられることではありません。ゲート自身が、なし崩しに緩むことです。「critical だと収束しないから、まあ major でいいか」——エージェントがそう妥協した瞬間、既知の重大問題がそのまま出荷されます。本人は丸く収めたつもりでも、現実は爆弾を抱えたまま出荷ボタンを押しているだけです。妥協は、たいてい締め切りの匂いがするときに起きます(つまり、いちばん緩めてはいけない瞬間に限って緩む)。
そこで判定には、LLM が下げられない床(floor)を決定論で敷いています。実装上のルールはこうです。
criticalは妥協でmajorへ格下げできない。重大度を下げる操作そのものを封じてあり、criticalが残るかぎりループは収束しません。- 危険度検査が決定論の床を注入する。認証・暗号・設定・データ移行・公開 API といった危険カテゴリに変更が触れたら、その項目は自動で
criticalへ引き上げられ、床フラグが立ちます。床フラグの立った項目は、以降 LLM が重大度を下げられません。 - 「安全だ」の主張には具体的な evidence が要る。評価者が「この危険箇所はクリアした」と返すとき、ファイル名・行・テスト名といった根拠が伴わない主張は無視され、その項目はブロックのまま残ります。既出の
criticalを「解消した」と言うにも、同じく file:line やテスト名が要ります。根拠なしの「直しました」は通りません(人間のレビューでも同じですよね)。
さらに、危険度検査を走らせるスクリプト自体が失敗したときは、全項目を未確認へ巻き戻す「fail-closed」で倒します。ツールが動かなかったのか、検査してクリーンだったのかを取り違えないためです。「エラーで検査できなかった」を「問題なし」と読んでしまうのが、この手の自動化で一番静かに事故る場所です。
これらは信頼度ポリシーをどう設定しても緩まない不変条件として置いてあり、「今日は急ぎだから床を下げよう」ができない構造になっています。判定は LLM に委ねつつ、越えてはいけない境界だけを決定論の床で固定する。これが2点目です。
3. 「同じ指摘が刺さらない」を検出して人間へ渡す
PR を作ったあとは、レビューと修正を繰り返して LGTM を目指すループが回ります(この反復は別の workflow に部品として切り出してあります)。ここに、自動修正が空回りしていることを検出する仕組みが要ります。
レビューアが指摘を返し、修正エージェントが直し、また再レビューする。うまくいけば指摘は消えます。問題は、同じ指摘が何度も戻ってくるとき。修正が本質を捉えていない証拠です。そこで各指摘には安定した topic 文字列を振り、同じ topic が2回連続で出たら「stuck(行き詰まり)」と判定してループを止め、人間のレビューへ渡します。
ここで絶対にやらないのが、ゲートを緩めることです。「2回回っても消えないなら、もう major のまま承認でいいか」という relax は入れていません。それをやると、既知の major を出荷する運びになるからです。行き詰まったら緩めるのではなく、止めて人間に渡す(正直、機械に「もういいよ」と言わせるほうが実装は楽なのですが、そこは我慢どころです)。この一線だけは自動側で判断させない。
人間へ渡す出口は stuck だけではありません。
修正エージェントが「適用できなかった(applied:false)」と返したら、黙って再レビューを繰り返さず、その場で人間へエスカレーションします。CI がまだ回っている途中なら、緑を待たずに承認することはありません。CI の取得そのものが認証やネットワークで失敗したときも、CI 落ちと取り違えず人間へ回します。反復上限に達した場合も、major を残したまま承認はしません。
大事なのは、これらを例外で死んで止めるのではなく、構造化した終了ステータスで返していることです。行き止まりに来たとき、人間が次に何をすべきか分かる形で手渡す。ログを掘らないと状況が読めない停止は、結局また人間の時間を溶かします。「なぜ止まったか」を出口が語る、が3点目です。
まとめ
段取りをスクリプトへ移すと、自動化は退屈で信頼できるものになります。でも、退屈にしてはいけない場所が3つ残ります。
- 当事者性: 正しさではなく、結果責任・好み・訓練分布外性が論点なら人間へ回す(品質は重大度、当事者性は
escalate、と軸を分ける) - 床: 越えてはいけない境界を決定論の床で固定し、LLM が重大度を下げられなくする。「安全だ」の主張には根拠を必須にする
- 行き詰まり: 同じ指摘が刺さらない・修正が適用できない・CI が緑でない状態を検出し、ゲートを緩めず人間へ渡す
自動化の完成度は「どれだけ人間を外せたか」ではなく、「人間に戻すべき場所を、機械のほうから正しく戻せるか」で決まります。無人で進むフローほど、この3つの出口が設計されているかを確かめてから任せてください。任せるのは怖くない。戻ってこないことが怖いのです。



