メインコンテンツへスキップ

AIエージェント開発・運用の事故録 #11

全部をOwner承認に
したら、止まった

LOW/MEDIUM/HIGH/UNKNOWNで権限と証拠を変える

公開日:2026年8月25日 著者:飯田 友広(Tomohiro Iida)

この記事の結論

  • Owner承認を全変更へ一律適用すると、安全性ではなく統合の停止と注意の希薄化が増えます。

  • LOWとMEDIUMは機械ゲートとControllerで自律統合し、HIGHだけexact-SHA Owner認可と独立FINAL_QCを要求します。

  • UNKNOWNはfail-closedにし、分類できなかった差分を低リスク側へ落としません。

  • 承認待ちの件数と待機時間を可視化し、Owner判断を不可逆で損失の上限が読めない境界へ限定します。

AIエージェントへ実装を任せる範囲が広がるほど、運用の中心は「人間がどこで承認するか」へ移ります。

Netsujoでは2026年8月21日まで、mainへの統合条件として、branch名に関わらずすべてのPull Requestに対してOwnerのexact-SHA明示認可を要求していました。安全側へ倒した設計でしたが、実際に起きたのは、CIがGREENで、head同一性もfreezeもcollisionも通過した低リスクの変更まで統合が止まる状態でした。

結論を先に書きます。

承認点は増やすほど安全になるわけではありません。リスク区分ごとに、必要な権限とEvidenceを変えます。

Incident Card

INCIDENT:
main統合の条件として、全Pull RequestへOwnerのexact-SHA明示認可を要求していた

SYMPTOM:
CI GREEN、head同一性、freeze、collisionをすべて通過した低リスク変更まで、
Ownerの入力を待って統合が停止した

FALSE_ASSUMPTION:
承認点を増やすほど安全性は上がり、増やしても運用の質は劣化しない

ROOT_CAUSE:
リスク区分と権限設計が結びついておらず、単一の承認契約を全差分へ一律適用していた

IMMEDIATE_FIX:
exact-SHA認可の契約そのものは維持し、適用範囲をhigh riskへ限定する

SYSTEM_FIX:
LOW / MEDIUM / HIGH / UNKNOWNを機械判定し、区分ごとに統合経路とEvidenceを変える

REMAINING_RISK:
分類パターンの漏れ、リポジトリ構造の変化、承認在庫の不可視化

Ownerが、常にcritical pathへ載った

観測できた事実は単純です。Ownerが承認文字列を書くまで、mergeできるPull Requestが一件も進みませんでした。

当時の承認契約は次の形です。Pull Request本文へ、対象PR番号と40桁のcommit SHAを組にした認可行を残します。

owner_merge_authorized(pr=<PR番号>, sha=<40桁のcommit SHA>)

実際の書式は各リポジトリで決めます。ここで重要なのは書式ではなく、認可がPR単位ではなくSHA単位で効くという性質です。

この契約自体は良い性質を持ちます。PR番号だけでは、あとからcommitが積まれたときに承認対象がずれます。40桁SHAまで書けば、headが動いた瞬間に承認は自動的に失効します。

問題は適用範囲でした。この印を全Pull Requestへ要求すると、次のような変更まで同じ待ち行列へ入ります。

  • ドキュメントの誤字修正
  • テストの追加
  • 記事本文の文言修正
  • READMEの更新

これらはCIで真偽を判定でき、失敗しても本番の顧客影響がありません。それでも、Ownerが手を動かすまで統合されませんでした。

リポジトリの実装には、当時の状況が次のように記録されています。「CI GREEN・exact identity・freeze・collision等をすべて通ったlow / mediumまでOwnerが毎回critical pathになり、統合作業が大量に停止した」。

誤った前提:承認を増やせば、安全性だけが増える

承認点の追加は、導入時のコストがほぼゼロに見えます。設定を一行足すだけで、事故の可能性が一つ減るように見えます。

実際には、承認点は二つのコストを同時に生みます。

  1. 待ち時間 — 承認者が確認するまで、後続のすべてが止まります。
  2. 注意の希薄化 — 承認対象が増えるほど、一件あたりに割ける確認時間は減ります。

二つ目のほうが危険です。1日に30件の承認要求が届き、そのうち28件が誤字修正なら、残り2件の本当に危険な変更へ向ける注意も同じ粒度になります。承認が形式化した状態は、承認が無い状態より危険な場合があります。承認済みという記録だけが残るためです。

「安全側に倒した」という言い方は、コストが片側にしか存在しないときだけ正しくなります。承認設計はその条件を満たしません。

根本原因:リスク区分と権限設計が結びついていなかった

事故の原因は、Ownerが遅かったことでも、AIエージェントが信用できなかったことでもありません。変更のリスクを判定する仕組みと、誰が何を認可するかを決める仕組みが、別々に存在していたことです。

リポジトリにはリスク分類器が既にありました。にもかかわらず、統合の可否はその分類結果を参照せず、単一の承認契約だけを見ていました。分類はレポート用の情報で終わり、権限へ接続されていませんでした。

同じ構造は、AIエージェントを使わない開発でも起こります。CODEOWNERSを全ディレクトリへ設定した状態が近い例です。

その場の対処:契約は維持し、適用範囲だけを狭める

最初に行った修正は、承認契約を弱めることではありません。契約はそのまま残し、適用範囲をhigh riskへ限定することです。

その場の対処:契約は維持し、適用範囲だけを狭める
変更前変更後
全Pull Requestへexact-SHA認可を要求high riskのPull Requestだけへ要求
low / mediumも人間の入力待ちlow / mediumは既存の機械ゲートで自律統合
判定できない差分の扱いが未定義判定できない差分はhigh側へ倒す

現在の実装では、Owner FINAL_QCの要否は次の一行で決まります。lowとmedium以外はすべて必要、という書き方です。

requiresOwnerFinalQc(risk):
    return risk != 'low' and risk != 'medium'

否定形で書いてあることには意味があります。新しい区分が増えたとき、既定でOwner承認が必要な側へ落ちます。「highのときだけ必要」と書くと、未知の値がOwner承認なしで通ります。

仕組みへの変換:4区分で権限とEvidenceを変える

現在の設計は次のとおりです。

仕組みへの変換:4区分で権限とEvidenceを変える
区分統合経路必要なEvidence
LOWControllerによる自律統合CI GREEN、head同一性、freeze、collision不在
MEDIUMControllerによる自律統合LOWと同じ機械ゲート一式
HIGH自動統合の対象外exact-SHA Owner認可+独立FINAL_QC review
UNKNOWN統合しない分類が成立するまで進めない

HIGHの判定は、パスのパターンで機械的に決めています。実装に列挙されているのは、workflow定義、エージェント運用契約、governance、品質ゲート設定、package定義、デプロイ設定、DBマイグレーション、認証・認可・課金・セッション・顧客データアクセスの各モジュールです。

LOWは逆に、ドキュメント、README、markdown、テストファイルのように、変更しても本番の顧客挙動が変わらないパスだけを列挙しています。

そして、どちらのパターンにも当てはまらない差分はMEDIUMになります。分類できないものをLOWへ落とさない設計です。

UNKNOWNをfail-closedにする

最も重要なのは、判定に失敗したときの既定値です。現在の実装は、次のすべてをhigh扱いにします。

  • 変更ファイル一覧が空で返ってきた
  • APIの応答が想定と異なる形だった
  • PR番号やリポジトリ名の入力が不正だった
  • 例外で分類処理が終わらなかった

いずれも OWNER_FINAL_QC_POLICY_UNVERIFIED のようなコードを付けて、requiredをtrueで返します。観測できなかったことを、安全だったことと同じに扱いません。

品質ゲートの設定ファイルにも、同じ思想が明文化されています。分類や機械検査のPASSは、実行の許可ではないという規則です。観測できないtelemetryは推測で埋めず、UNKNOWNのまま記録します。

HIGHの承認は、自己申告では成立しない

HIGHへ落ちた変更は、Owner認可があるだけでは統合されません。独立したFINAL_QC reviewを別に要求します。

review本文には次の2つが必要です。

REVIEW_STATUS: PASS
(レビュー本文へ、対象の40桁commit SHAを示すmarkerを添える)

判定は、この40桁がGitHub側のreview.commit_idと一致するかどうかで行います。SHAは実装者が自由に書ける文字列ではなく、GitHubが記録する不変値と突合されます。新しいcommitを積めば、古い認可は自動的にstaleになります。

Netsujoの運用では、この判定を通ったあとも、実装・merge・deploy・本番検証を別々の状態として報告します。deploy成功だけでは完了としません。

承認の在庫を可視化する

リスク区分を導入しても、HIGHの件数がゼロにはなりません。むしろ、本当に危険な変更だけがOwnerの手元へ集まります。

そこで必要になるのは、いま何件がOwner待ちなのかを一覧で見られる状態です。Netsujoの現在の実装では、Controllerが1回の実行で最大1件だけを統合し、GitHub上のsingle writerとして直列化します。統合可能性が変わったイベントでのみ起動し、6時間ごとのscheduleは取りこぼしの回復に限定しています。

一方、承認待ちを一覧化する専用のinventoryは未実装です。現時点で運用が把握しているのは、Controllerの実行ログとPull Request一覧までです。次の項目を定期的に出力する設計を検討しています。

  • HIGH判定で承認待ちのPull Request件数と待機時間
  • 承認済みだが、そのあとheadが動いて失効した件数
  • UNKNOWNで停止した件数と、その分類失敗コード
  • LOW / MEDIUMで自律統合された件数

承認在庫が見えないと、「Ownerがボトルネックになっている」という状態を、体感でしか検知できません。件数と待機時間を出さない限り、区分の閾値が妥当かどうかも評価できません。

再利用できるチェックリスト

承認設計を見直すとき、次の順序で確認します。

  1. その変更が失敗したとき、不可逆か。取り消せるなら人間の事前承認は必須ではありません。
  2. 失敗したときの損失の大きさはどれくらいか。顧客データ・課金・認証は上限が読めません。
  3. その判定は機械で決定的に行えるか。行えるなら人間ではなく検査へ渡します。
  4. 判定に失敗したとき、既定でどちらへ倒れるか。倒れる先が安全側でなければ設計が未完成です。
  5. 承認対象は、承認者が実際に読める件数に収まっているか。
  6. 承認は、承認した瞬間の状態に束縛されているか。SHAへ束縛されていない承認は、あとから対象がずれます。
  7. 承認待ちの件数と待機時間を、あとから数えられるか。

3番目で人間を外せる項目が残っている限り、承認点を増やしても安全性は上がりにくくなります。

Evidence

Evidence
内容分類根拠
全PRへexact-SHA認可を要求した結果、low / mediumの統合が大量に停止したOBSERVEDリポジトリの scripts/agent-os/integration-controller.mjs の実装コメント
exact-SHA認可の適用範囲をhigh riskへ限定したIMPLEMENTEDscripts/agent-os/integration-controller.mjsownerMergeAuthorization
low / medium以外はOwner FINAL_QCを必須にするIMPLEMENTEDscripts/agent-os/owner-final-qc-policy.mjs
分類・観測に失敗した場合はhigh扱いでfail-closedにするIMPLEMENTEDscripts/agent-os/owner-final-qc-policy.mjs の各失敗コード
ファイルパスでLOW / MEDIUM / HIGHを機械判定するIMPLEMENTEDscripts/agent-os/integration-controller.mjsclassifyRisk
分類も機械検査のPASSも実行の許可ではないIMPLEMENTED.quality/codex-review-policy.jsonexecutionAuthorization
ルールに一致しない差分はLOWへ落とさずMEDIUMにするIMPLEMENTEDscripts/quality/classify-change-risk.mjs
FINAL_QC認可はGitHubのreview.commit_idと突合し、自己認可を許さないIMPLEMENTEDscripts/agent-os/final-qc-authorization.mjs
Controllerは1回の実行で最大1件だけ統合するIMPLEMENTED.github/workflows/agent-integration-controller.yml
Workerはmergeを実行せず、統合はControllerへ集約するIMPLEMENTEDリポジトリの AGENTS.md
本番反映はworkflow_dispatchと確認文字列の入力を要求するIMPLEMENTED.github/workflows/deploy-signal-production.yml
Git連携による自動デプロイは全branchで無効IMPLEMENTEDvercel.jsongit.deploymentEnabled
承認待ち件数・待機時間を一覧化するinventoryPROPOSED未実装
区分導入によるリードタイム短縮の定量効果INFERRED待機時間の継続計測が未実施

適用限界

この設計は、次の条件を満たす環境を前提にしています。

  • 変更差分がファイルパスで観測でき、リスクとパスに一定の対応がある
  • CI・型検査・テストが、LOW / MEDIUM区分の変更について実質的な検出力を持つ
  • 統合を担う単一のwriterが存在し、直列化できる
  • 承認者が、HIGH区分の内容を実際に読んで判断できる

パスとリスクの対応が弱いリポジトリでは、分類器のパターン列挙が機能しません。その場合はMEDIUM以上へ倒す範囲を広げます。

また、Netsujoが列挙しているHIGHのパスは当社のリポジトリ構造に依存します。当社の運用目安であり、普遍的な正解ではありません。

数値についても限界があります。区分導入の前後で統合リードタイムがどれだけ変わったかは、現時点で計測していません。停止していた状態が解消したことは観測できますが、削減幅は未計測です。

残るリスク

区分を分けても、次は残ります。

  • 新しいディレクトリが追加され、HIGHのパターンに載らないまま高リスクの変更が入る
  • LOWに列挙したパスへ、実際には挙動を変えるコードが置かれる
  • 分類器のパターン変更自体が、レビューを受けずに入る
  • HIGHの件数が増え、Ownerの確認が形式化する
  • 承認済みSHAのあとにcommitが積まれ、失効に気づかないまま待ち続ける
  • 自律統合された変更に、CIが検出できない欠陥が含まれる

最後の項目は特に重要です。LOW / MEDIUMの自律統合は、機械検査の検出力を信頼する設計です。検出力が落ちれば、区分の安全性も落ちます。テストが主張どおりの検出力を持つかどうかは、テストの数ではなく、変異を入れて落ちるかどうかで確かめます。

まとめ

Ownerの承認は、開発を安全にする道具であって、開発を止める道具ではありません。

LOW / MEDIUM
  → 機械ゲート + Controller自律統合

HIGH
  → exact-SHA Owner認可 + 独立FINAL_QC

UNKNOWN
  → 統合しない(fail-closed)

この3行を先に決めてから、どのパスがどの区分へ入るかを列挙します。順序を逆にすると、承認点だけが増えて、判断の質は上がりません。

Owner判断は、不可逆で、損失の上限が読めない境界へ限定します。それ以外は検査とControllerへ渡します。

シリーズの他の回はAIエージェント開発・運用の事故録にまとめています。

よくある質問

リスク区分を分けると、監査で説明できなくなりませんか

区分ごとの経路と必要Evidenceを事前に定義し、判定をコードに置けば、どの変更がどの経路で統合されたかを機械的に再現できます。全件を人間が承認した記録より、区分と判定根拠が残るほうが説明しやすい場合があります。

LOWと判定された変更にも、人間のレビューは必要ですか

必要かどうかは目的で変わります。Netsujoの運用では、LOW / MEDIUMもCI・型検査・テスト・各種checkを通します。人間のレビューを必須の統合条件から外しているだけで、レビュー自体を禁止していません。

承認をSHAへ束縛すると、修正のたびに再承認が必要になりませんか

必要になります。それが意図した挙動です。承認したコードと統合するコードを一致させるため、headが動いた時点で古い認可は失効します。再承認の頻度を下げたい場合は、HIGH区分の変更を小さく分けます。

UNKNOWNをfail-closedにすると、作業が止まりませんか

止まります。ただし止まった件数と理由が記録に残るため、分類のパターン不足として修正できます。UNKNOWNをLOWへ倒すと、止まらない代わりに、何が通過したかを後から特定できなくなります。

この設計はAIエージェントを使わない開発にも使えますか

考え方は共通です。判定を機械で行えるものを人間の承認から外し、不可逆で損失の大きい境界へ人間を集中させる、という構造は開発体制の種類に依存しません。ただしHIGHのパス列挙は、リポジトリごとに作り直す必要があります。

この記事の著者

飯田 友広

飯田 友広

代表取締役

Netsujo株式会社 代表取締役。京都発のWeb3・AI実装スタートアップを2023年6月に創業。Webサイトを営業基盤として捉え、経営・営業・検索・生成AI・コンバージョン・計測を横断して課題と改善優先順位を整理する「Netsujo SIGNAL」を設計・運営。京都ビッグデータ活用プラットフォーム参画(小規模企業会員・ベンチャー)、同プラットフォーム発のワーキンググループ「Chain Up KYOTO」参画(2026-03-10)、IVS2026サイドイベント「なぜ京都でWeb3.0ビジネスなのか」を京都府庁旧議場で開催(2026-07-02・Netsujoとして主催、企画・登壇・運営/京都府デジタル政策推進課は共催)。京都美術工芸大学での講義・龍谷大学でのセミナー実績、ITコミュニティ「みやこでIT」(connpassメンバー614名・イベント167件・2019年2月から運営)運営。NPO法人NEMTUS理事、BAR KRYPTO運営。ソーシャル企業認証「S認証」認証企業(2026年2月認証・2026年4月公表)。技術領域はWeb3/ブロックチェーン/DID/NFT/生成AI/コミュニティ運営。

プロフィールを見る

この記事が向いている方

  • AIエージェントを開発へ組み込み、mainへの統合条件を設計している事業責任者・開発責任者

  • 承認点を増やした結果、リリースが滞っているチーム

  • どの変更を人間が承認し、どの変更を機械検査へ任せるかを決めたいITエンジニア

— 壁打ち相談

読者のよくある相談

記事を読んだ後に「自分の状況だとどう判断すべきか」を整理するための壁打ち相談を受け付けています。下記のような相談例が当てはまる方は、お気軽にご連絡ください。

Q. 承認を増やしたのに、安全になった実感がない

リスク区分ごとに承認の要否を分け、機械で判定できる項目を人間の承認から外します。

Q. 低リスクの変更まで人間の入力待ちで止まっている

exact-SHA認可の契約は維持したまま、適用範囲をhigh riskへ限定します。

Q. 分類できない差分をどちらへ倒すか決まっていない

UNKNOWNをfail-closedにし、観測できなかった状態を安全と同じに扱いません。

上記いずれかが該当する場合、初回30分の壁打ち相談で論点整理に対応します。記事に書ききれない個別事情を踏まえた判断材料が必要な段階こそ、壁打ちが活きやすいフェーズです。

AI導入・開発運用設計のご相談

Owner判断を、本当に必要な境界へ限定する

リスク分類、統合権限、CI、品質ゲート、本番Evidenceを一つの運用として設計します。

AI導入について相談する