FLARES LLC

Technical document

Spot VM・Cloud Run・AIで保守を自動化するDevOps制御面の設計

開発者の負担を減らす自動化では、AIに広い権限を渡すことより、証拠、状態、予算、変更範囲、昇格条件を決定的な制御面で管理することが重要です。本稿では、GitHub-hosted runnerの使用を抑えながら、エラー収集から修復、PR検証、本番昇格、定期保守までをGCP上でつなぐ構成と、その限界を整理します。
DevOps / AI運用設計約25分公開日 2026年8月9日更新日 2026年8月9日
エラー検知、証拠保存、AI修復、検証、デプロイ、通知を一つの制御ループとして表したイラスト

Summary

この文書の要点

  • GitHub-hosted runnerの課金対象時間は減らせますが、セルフホステッドランナー、GCP、保存領域、AI APIを含むシステム全体の費用がゼロになるわけではありません。
  • Cloud Storageへ証拠を残し、Firestoreのリースとfencing tokenでSpot VMの突然停止や重複実行から復旧できる制御面を作ります。
  • AIは修正、レビュー、翻訳の候補を作りますが、変更可能範囲、検証コマンド、予算、昇格、ロールバックの決定権は持たせません。
  • 通知を本番状態の変化へ絞る場合も、制御面の停止を見逃さないheartbeatと、後から追える監査記録が必要です。

自動化の目的は、判断を消すことではなく反復作業を減らすことです

小規模な開発では、機能を作る時間より、失敗ログの確認、同じテストの再実行、レビュー指摘の反映、翻訳辞書の同期、依存更新、デプロイ後の監視に多くの時間を取られることがあります。個々の作業は短くても、通知と待ち時間で集中が分断される点が問題です。

この負担は、エラー収集、バッチ修復、PRごとの検証環境、データベース変更の予行演習、多角レビュー、翻訳、定期更新、本番監視を一つのパイプラインにまとめることで減らせます。ただし、自動化の段数を増やすほど、どの処理が正本を持ち、どこで止まり、失敗時に何を戻すかが重要になります。

中心に置くべきものはAIモデルではなく制御面です。AIは原因分類やpatch候補の作成に使い、実行対象、入力証拠、変更範囲、予算、テスト、branch操作、本番traffic、通知状態は通常のプログラムと権限設定で管理します。モデルを入れ替えても同じ安全境界を保てることが、長く運用できる設計の条件です。

  • 人から外す作業: ログ収集、定型分類、限定的な修正候補、繰り返し検証、辞書差分、依存更新候補。
  • 人または制御面に残す判断: 変更境界、データ破壊の許容、秘密情報、費用上限、本番昇格、例外対応。
  • 完了条件: 成功時だけでなく、判断不能時に安全に停止し、再開に必要な証拠が残ること。

小規模チーム向けの前提と、最初に固定する制約

この構成は、複数のWebアプリを少人数で運用し、重いビルドとE2Eを必要な時だけ実行する状況を想定します。アプリケーションはReact Routerなどのフロントエンドを持ち、実行基盤にはCloud Run、証拠保存にはCloud Storage、状態管理にはFirestore、バッチ計算にはCompute EngineのSpot VMを使います。AIモデルはAPI越しに呼び出し、モデル固有の能力へ制御面を依存させません。

GitHub Actionsはイベント受付、branch protection、check結果の表示に残し、重いjobをセルフホステッドランナーへ送ります。GitHub公式ドキュメントでは、セルフホステッドランナーで動くjobにbillable minutesはないと説明されています。ただし、これはGitHub-hosted runnerの実行時間に関する話であり、VM、永続disk、ネットワーク、ログ、artifact、AI APIの費用まで消えるという意味ではありません。

もう一つの前提は、セルフホステッドランナーを使い捨てにすることです。共有runnerへPRの未信頼コードと本番credentialを同居させると、jobが終わった後にも改変や情報が残る可能性があります。PR検証用、AI修復用、本番昇格用を権限とmachine imageで分け、特に外部forkや未信頼PRを特権runnerへ入れません。

  • GitHub Actionsは制御イベントとcheck表示に使い、重い計算だけを外へ出す。
  • GitHubのbillable minutes削減と、システム全体の費用削減を分けて計測する。
  • PR検証、修復、本番昇格でrunner poolとservice accountを分離する。
  • 自動化の対象は、再実行可能で、途中停止から復旧できる処理に限定する。

データ面と制御面を分けて、五つのループをつなぎます

全体は、リアルタイムの観測、1時間ごとの修復、PR検証、本番昇格、日次・週次保守の五つに分けます。各ループは独立して再実行でき、Cloud Storage上の証拠ID、Gitのcommit SHA、PR番号、Cloud Run revision、Firestore上のrun IDで相関できるようにします。

データ面には、Sentryから受け取ったエラー、ビルドログ、E2E結果、匿名化したデータベースsnapshot、生成した翻訳差分などがあります。制御面は、それらの保存先、digest、処理状態、lease、費用、対象branch、昇格revisionを管理します。ログ本文やpatch本文をFirestoreの状態documentへ詰め込まず、大きなartifactはCloud Storageへ置いて参照とdigestだけを状態へ残します。

各ループの出力は次のループへの命令ではなく、検証可能な候補です。たとえばAIがpatchを作ってもpush許可にはならず、E2Eがgreenでも本番昇格の全条件を満たしたことにはなりません。契約を分けることで、一つの誤判定がそのまま本番まで伝播することを防ぎます。

  • 観測: アプリ → Sentry → 受信Cloud Run → 秘匿化 → Cloud Storage。
  • 修復: Cloud Scheduler → Spot VM → 証拠集約 → AI候補 → 決定的検査 → 修復PR。
  • PR検証: ephemeral Cloud Run → 分離したSTGデータ → E2E → integrationへの昇格判定。
  • 本番昇格: 多角レビュー → 翻訳検証 → build → 段階配信 → smoke → revision確定。
  • 定期保守: changelog・文書候補、依存更新PR、長期的な失敗傾向の集計。

Sentryの生ログは、保存前に最小化・秘匿化・重複排除します

未捕獲例外はSentryで検知し、alertまたはwebhookをCloud Runの受信口へ送ります。受信処理はevent ID、release、environment、stack trace、発生時刻、browser情報など、修復に必要な項目だけを正規化します。request body、Cookie、Authorization header、入力値を無条件に『生ログ』として保存してはいけません。

秘匿化はSentryへ送る前のSDK側と、受信Cloud Runの両方で行います。email、token、session ID、query parameter、自由入力欄をdenylistと構造で落とし、秘匿化後のpayloadにschema versionとSHA-256 digestを付けてCloud Storageへ保存します。元payloadを保持する必要がある場合は、修復用bucketと分け、短いretention、限定されたIAM、監査ログを設定します。

同じ障害は短時間に大量発生します。event IDの重複排除に加え、例外型、正規化したmessage、最上位のアプリケーションframe、releaseからfailure fingerprintを作ります。1時間batchではfingerprintごとに件数、最初と最後の発生、影響release、代表例をまとめ、モデルへ全件を投入しません。

  • 保存前: payloadサイズ、content type、schema、共有secretまたは署名相当の検査を行う。
  • 秘匿化: SDK送信前とCloud Run受信後の二段階で行い、自由入力を既定で除く。
  • 証拠: 改変検知用digest、release、event ID、fingerprint、受信時刻を残す。
  • 保持: 修復に必要な期間だけ保存し、Lifecycle Managementで削除する。

Spot VMは突然停止する前提で、一回限りのrunnerとして起動します

Cloud Schedulerは1時間ごとに直接VMを操作するのではなく、認証された小さな起動処理へrun IDを渡します。起動処理は未完了runの有無、同じ時間窓の重複、予算、VM状態を確認し、必要な時だけSpot VMを起動します。エラーがない時間帯はVMを起動しない構成にすると、固定時刻で必ず立ち上げるより無駄を減らせます。

Spot VMは割引率が高い一方、任意の時点で停止または削除され、容量がなく起動できない場合があります。したがって、OS diskやrunnerの作業directoryを正本にしません。起動時にmachine imageからrunnerを登録し、一つのrunだけを処理し、artifactとcheckpointを外部へ保存して登録解除とVM停止まで行います。

GitHub registration token、repositoryへの書き込みcredential、AI API keyを永続imageへ焼き込みません。短命tokenを起動時に取得し、PRの未信頼コードを実行する段階ではpatch push用credentialを渡さず、検証済みdigestを別の小さなpush処理へ引き渡します。runnerが侵害されても到達できる範囲を、時間、repository、branch、操作の四つで狭めます。

  • VMはrunごとに初期化し、作業directory、Docker volume、credentialを再利用しない。
  • checkpointはCloud Storage、所有権と状態はFirestoreへ保存する。
  • preemption通知は最終checkpointの補助に使い、通知が来ることを正常終了の前提にしない。
  • Spot容量不足が続く場合の標準VM fallbackは、費用上限と待機期限を決めてから有効にする。

Firestoreにはロックではなく、期限付きリースと状態遷移を保存します

Spot VMの突然停止へ対応するには、単純なrunningフラグでは足りません。run documentにowner、leaseUntil、fencingToken、attempt、checkpoint、inputDigest、statusを持たせ、transactionで未所有または期限切れを確認してclaimします。heartbeatでleaseを延長し、外部副作用の直前には所有者とtokenを再確認します。

fencing tokenは、古いworkerの復帰を止めるための単調増加値です。worker Aのleaseが切れ、worker Bがtoken 12で引き継いだ後にAが復帰しても、token 11の書き込み、PR作成、通知、本番操作を受け付けません。時刻だけで所有権を判断せず、更新ごとのtokenとversion条件を組み合わせます。

Firestoreのtransactionには競合と再試行があります。transaction関数の中でAI API呼び出しやGit pushを行うと、再試行により副作用が重複します。transactionでは状態の予約だけを行い、外部処理を終えた後にidempotency key付きで結果を確定します。PR、commit、Cloud Run revision、通知にも同じrun IDを付け、再実行が既存結果へ収束するようにします。

  • 許可した状態遷移だけを受け付け、終端状態から実行中へ戻さない。
  • transaction内では外部APIを呼ばず、副作用の予約と結果確定を分ける。
  • lease切れを再実行の合図にし、古いworkerはfencing tokenで拒否する。
  • run IDとinput digestが同じ再要求は、新しいPRを作らず既存結果を返す。
Firestoreに保持するrun状態の例
{
  "runId": "repair-20260809T0100Z",
  "status": "ANALYZING",
  "owner": "runner-ephemeral-id",
  "leaseUntil": "2026-08-09T01:12:00Z",
  "fencingToken": 12,
  "attempt": 2,
  "inputDigest": "sha256:...",
  "checkpoint": "evidence-clustered",
  "pullRequest": null
}

1時間分のエラーは、根本原因ごとに束ねて一つの修復PRへまとめます

同じreleaseで発生した複数エラーは、failure fingerprint、関連frame、時系列、既知の因果関係でcluster化します。すべてのエラーを一つの巨大promptへ入れるのではなく、代表証拠と関連sourceだけを原因候補ごとに渡します。モデルは原因、確信度、変更候補path、patch、必要な検証を構造化形式で返します。

一つのPRへ集約する目的は、デプロイ待ちとreviewの渋滞を減らすことです。ただし、無関係な根本原因を一つのatomicな変更へ混ぜると、失敗時の切り分けとrevertが難しくなります。同じPRの中でも原因clusterごとにcommitを分け、依存関係がないclusterは個別に検証し、一つでも危険領域へ触れる場合はそのclusterだけを自動修正から外します。

モデル出力は提案であり、実行命令ではありません。変更可能path、総変更行数、新規・削除・rename、binary、secretらしい文字列、migration、workflow、認証、権限、本番設定、テスト弱体化を決定的に検査します。検証コマンドもモデルに選ばせず、repository側のallowlistから変更pathに応じて決めます。

GLM-5.2のようなcoding modelを採用する場合も、model ID、prompt version、入力digest、出力digest、token使用量、latency、停止理由を記録します。APIのrate limit、提供条件、model更新は変わり得るため、timeout、最大token、費用予約、retry上限、別modelへ切り替える条件を制御面に置きます。

  • 自動修正に向く: 既存product codeの小さな差分で、再現可能なテストがある失敗。
  • 人へ移す: 認証、権限、secret、migration、infrastructure、workflow、依存契約、テスト基準の変更。
  • 一つのPRでも原因clusterごとにcommitと検証証拠を分け、個別revertを可能にする。
  • 最大attempt、同一fingerprintの反復、token・費用・時間の上限で停止する。

PRごとのCloud Run環境では、アプリだけでなくデータも分離します

PR作成時にpr-123のようなCloud Run revision tagまたは専用serviceを作ると、共有STGを上書きせずに画面とAPIを確認できます。PR close時にはservice、tag、service account binding、一時secret、データ領域をrun IDから特定して削除します。削除jobが失敗する可能性もあるため、期限ラベルを付けた日次のgarbage collectionを別に用意します。

共有STGデータベースへ単に接続するだけでは、環境はephemeralでもデータは共有されたままです。tenant ID、schema、databaseのいずれかでPR単位に分離し、connection先をservice identityから決定します。application queryだけで分離する方式は、条件漏れ一つで他PRのデータを読めるため、可能ならschemaまたはdatabase境界も使います。

本番の匿名化snapshotを一時DBコンテナへ復元する検証では、匿名化処理そのものをテスト対象にします。行数、外部キー、代表的な分布を保ちながら、氏名、連絡先、token、自由記述、添付物、監査ログを不可逆に置換します。snapshotは短い保持期限と暗号化を設定し、runner終了後にvolumeと一緒に破棄します。

migration検証は、applyできることだけでは不十分です。実行前後のrow count、NULL率、一意制約、外部キー、代表query、実行時間、lock時間、disk増加、rollbackまたはrestore時間を確認します。破壊的変更はexpand、backfill、switch、contractへ分け、旧revisionと新revisionが同じDBを使う移行期間を検証します。

  • PR URLの作成とclose時削除に加え、期限超過resourceを回収するsweeperを持つ。
  • service名、revision数、artifact、IP、database connectionなどのquotaを事前に計測する。
  • 匿名化snapshotは匿名化品質、保持期限、アクセス主体、削除証跡まで検証する。
  • migrationは新revision単体ではなく、旧新revisionの共存期間を含めて確認する。

多角レビューと翻訳は、mainへ入る前の昇格候補に対して行います

mainへのmergeを本番デプロイの起点にするなら、セキュリティ、性能、UI・UX、保守性のAIレビューはmainへmergeした後では遅くなります。integrationからrelease PRを作り、固定したhead SHAに対して四つの観点を並列評価し、修正が入るたびに全checkを再実行してからmainへmergeします。mainへ入ったcommitは、レビュー済みの昇格artifactとして扱います。

四つのAIレビューを独立に自動修正させると、同じ行を上書きしたり、一方の最適化が別の制約を壊したりします。reviewerは指摘、根拠、影響path、severityを構造化して返し、coordinatorが重複と矛盾を整理します。修正は一つのpatchとして作り、型検査、unit test、E2E、accessibility、bundle size、依存脆弱性などの決定的なgateで確認します。

多言語化では、日本語sourceから翻訳を生成するだけでなく、key集合、placeholder、ICU message、HTML tag、改行、リンク、数値単位を機械的に照合します。翻訳済み文字列をsourceとして再翻訳せず、日本語keyとtranslation memoryのversionを正本にします。削除key、未翻訳key、同一keyの意味変更をdiffとして残します。

UI文言の翻訳はE2Eだけでは品質を保証できません。長い言語でのlayout崩れ、右から左へ書く言語、日付・通貨・複数形、検索用metadata、画面reader向け文言を別に確認します。AIの訳文は候補であり、法務、料金、個人情報、障害通知など意味の誤差が許されない文言は自動公開の対象から外します。

  • release PRのhead SHAを固定し、レビューと翻訳の入力を途中で差し替えない。
  • AI reviewerは直接pushせず、coordinatorが指摘を統合して一つの候補差分を作る。
  • 翻訳はkey、placeholder、tag、locale format、layout、検索metadataを検証する。
  • mainを本番起点にする場合、mainへ入った後のAI修正は別の緊急PRとして扱う。

本番は新revisionへ一度に切り替えず、smokeの証拠で昇格します

mainの固定commitからcontainer imageを一度だけbuildし、digestで指定してCloud Runへdeployします。同じsourceからSTG用と本番用を別々にbuildすると、依存取得時刻やbuild環境の差が入り得ます。検証済みimageを環境ごとの設定とservice identityで昇格させる方が、何を配ったかを追いやすくなります。

新revisionは最初にtraffic 0のtagへ配置し、認証、主要read、主要write、外部連携、静的asset、database互換性をtag URLで確認します。その後、少量traffic、監視時間、全量trafficの順に進めます。smokeはHTTP 200だけでなく、期待したbody、書き込み結果、ログ中のrequest ID、依存先の応答を確認します。

失敗した場合は、直前に記録したhealthy revisionへtrafficを戻します。rollbackはsourceの再buildではなくCloud Runのtraffic変更で行い、database migrationが後方互換かを昇格前に保証します。非互換migrationを同時に適用すると、application revisionだけ戻しても復旧しないためです。

traffic変更は瞬時ではなく、移行中のrequestは新旧revisionのどちらにも届き得ます。statefulな処理、session affinity、queue consumer、重複実行に影響するため、新旧共存を前提にidempotencyとschema互換性を設計します。

  • build once: commit SHA、image digest、SBOM、検証結果を一つのrelease manifestへまとめる。
  • traffic 0 tag → smoke → 少量traffic → 観測 → 全量trafficの順で昇格する。
  • 直前healthy revisionとtraffic設定を保存し、再buildせずに戻せるようにする。
  • DB変更はapplication rollbackと独立して戻せるか、旧revisionと互換にする。

通知は本番状態の変化へ絞り、無通知の失敗は監査可能にします

CIの途中失敗、AIが修正を見送ったこと、依存更新PRの失敗を都度Google Chatへ送ると、重要な本番障害が埋もれます。paging相当の通知は、Firestore上の本番状態がHEALTHYからUNHEALTHYへ変わった時と、UNHEALTHYからHEALTHYへ戻った時だけに限定できます。同じ状態でsmokeが繰り返し失敗しても、同じincident IDでは再通知しません。

ただし、完全な無通知には『監視処理自体が止まった』ことを見逃す危険があります。lastSmokeAt、lastSchedulerAt、lastEvidenceAt、lastRunnerHeartbeatを持ち、一定時間更新されない場合は制御面をUNHEALTHYとして扱います。アプリが正常でも監視不能なら、HEALTHYを証明できないためです。

自動rollbackが成功して利用者影響が短時間で解消しても、HEALTHYからUNHEALTHYへの遷移は一度通知します。復旧通知にはincident ID、影響時間、失敗revision、復旧revision、smoke証拠への参照を含めます。通知本文に生ログ、secret、利用者データを含めません。

通知しない内部失敗も捨てず、状態、停止理由、attempt、費用、artifact参照を検索可能にします。通知ノイズを減らすことと、問題を見えなくすることは別です。週次に成功率、見送り理由、平均復旧時間、重複排除数を確認すると、自動化が静かに劣化していないか判断できます。

  • 通知の正本はChat履歴ではなく、Firestoreのincident状態と遷移versionに置く。
  • 通知送信もidempotency keyを持ち、送信結果が不明な時の二重通知を抑える。
  • 監視heartbeatの欠落を本番の不健康状態へ含め、沈黙を正常と誤認しない。
  • 内部失敗は通知しなくても、検索、集計、再実行、監査ができる形で残す。
通知を発生させる本番状態遷移
HEALTHY   -> UNHEALTHY : rollbackを試行し、障害を1回通知
UNHEALTHY -> UNHEALTHY : 証拠を追記し、同じincidentでは通知しない
UNHEALTHY -> HEALTHY   : smoke成功を確定し、復旧を1回通知
HEALTHY   -> HEALTHY   : 状態とheartbeatだけを更新し、通知しない

日次文書化と週次依存更新は、公開物ではなく検証可能な差分を作ります

commit logからchangelogや文書を生成する日次batchは、最初から公開せずdraft PRを作ります。commit messageだけでは利用者への影響、非互換変更、移行手順を判断できないため、変更diff、release label、既存文書、明示したfront matterを入力にします。根拠となるcommitを各項目へ関連付け、根拠のない説明は採用しません。

複数言語の文書は日本語draftを確定してから翻訳し、source digestを持たせます。日本語が変わったページだけを再生成し、翻訳者やAIモデルが変わっても未変更ページを無用に書き換えません。リンク、heading ID、code block、製品名、数値、日付を機械的に照合します。

週次のnpm updateは、patchとminor、major、runtime、build tool、test toolを分けます。すべてを一度に上げてgreenならmergeする方式は、隠れた挙動差の原因を追いにくくします。lockfileの差分、install script、license、既知の脆弱性、bundle size、unit test、E2Eを確認し、major更新とsecurity境界に触れる更新は人の判断へ残します。

integrationへの自動mergeを許す場合も、同じgroupの更新が一定期間greenで、flaky testの再実行で通っただけではなく、固定回数の再現性を満たすことを条件にします。本番へ直接mergeせず、通常のrelease候補として多角レビューと本番昇格を通します。

  • 生成結果はdraft PRにし、根拠commit、source digest、model versionを残す。
  • 文書と翻訳は変更ページだけを更新し、機械的な構造検査を先に通す。
  • 依存更新は変更種類と影響範囲でgroup化し、原因を切り分けられる大きさにする。
  • E2Eの一度のgreenではなく、flaky test率と再現性を昇格条件に含める。

最小権限、未信頼入力、供給網の三つを別々に守ります

この構成では、Sentry payload、Gitのsourceとdiff、dependency、test出力、AI出力がすべて未信頼入力です。ログ中の命令文をpromptとして扱わず、source内の指示で許可path、検証コマンド、credential、予算を変更できないようにします。モデルへ送る入力はschemaで区切り、secret scanとサイズ上限を通します。

service accountは受信、証拠読取、runner起動、AI呼び出し、PR作成、STG deploy、本番deploy、通知で分けます。runnerのdefault service accountへ広いEditor権限を与えません。本番deploy主体はPR sourceを直接実行せず、release manifestで許可されたimage digestと設定だけを昇格させます。

actions、container base image、npm package、runner binaryも供給網の一部です。versionまたはdigestを固定し、SBOM、脆弱性scan、署名またはprovenance、更新期限を記録します。週次更新の自動化が、未確認のinstall scriptを特権runnerで実行する経路にならないようにします。

AI APIへsourceやログを送る場合は、利用規約、保存、学習利用、region、削除、監査、subprocessorを確認します。機密度の高いrepositoryや利用者データでは、送信しないpath、ローカルmodel、要約だけを送る方式を選ぶ判断も必要です。

  • 未信頼入力の内容で、権限、予算、変更範囲、実行コマンドを拡張しない。
  • 受信、計算、Git書き込み、STG、本番、通知のcredentialを分離する。
  • 外部fork、未信頼PR、依存installを本番権限のあるrunnerで実行しない。
  • model providerへ送る情報分類と保持条件を、実装前に決める。

『GitHub Actions 0円』ではなく、処理単価と待機費用で評価します

セルフホステッドランナーへ重いjobを移すと、GitHub-hosted runnerのbillable minutesを使わずに済みます。一方で、Spot VMの起動時間、永続disk、snapshot、Cloud Storage、Firestore read・write、Cloud Run、Cloud Scheduler、logging、network egress、AI API、artifact保持が費用になります。費用の場所が移るため、Actionsの請求だけを見てゼロと判断しません。

一時間batchは、同じ根本原因をまとめてmodel呼び出しとPR数を減らせる利点があります。ただし、緊急度の高い障害まで最大一時間待たせる設計にはできません。利用者影響があるproduction errorは即時rollback経路へ送り、修復候補の作成だけをbatchへ回します。安全確保と原因修正の時間軸を分けます。

費用は、受信event一件、fingerprint一件、修復attempt一回、PR一件、release一回あたりで計測します。AIには日次・月次の上限だけでなく、一runの最大input、output、retry、wall clockを設定します。budget ledgerが読めない時は、残額を推測せず新しい呼び出しを止めます。

最安の構成が最良とは限りません。Spot容量不足で修復が何時間も遅れる、複雑な制御面の保守に時間がかかる、共有STGの分離が不十分になるなら、Cloud Run Jobs、GitHub-hosted runner、管理されたCIを部分的に使う方が総コストを下げる場合があります。

  • GitHub minutes、GCP、AI API、保存、監視、保守時間を同じ月次表で比較する。
  • production保護は即時、原因修正はbatchとして、応答時間の要件を分ける。
  • 一runのtoken、retry、wall clock、VM時間、artifact量へ上限を置く。
  • 制御面の複雑さと復旧時間を、インフラ料金と同じコストとして扱う。

observe、suggest、repair、promoteの順に自動化範囲を広げます

最初から修正、merge、翻訳、依存更新、本番rollbackをすべて自動化すると、どの境界が効いたかを検証できません。第一段階ではobserveだけを行い、fingerprint、証拠、状態遷移、費用、通知の正確さを測ります。第二段階でAIがPR draftを作るsuggestへ進み、人の修正との差を記録します。

第三段階では、保護path外の小さな修正だけをintegrationへ自動mergeするrepairを有効にします。第四段階で、検証済みimageの段階配信と自動rollbackを行うpromoteへ進みます。各段階には、誤修正率、再発率、平均修復時間、rollback成功率、stale runner回収率、通知重複率、月額費用の停止基準を置きます。

障害訓練では、Spot VMを処理中に停止する、Firestore leaseを期限切れにする、同じwebhookを重複配送する、AI APIをrate limitにする、runnerのpush直前にheadを更新する、migrationを途中で失敗させる、Cloud Run smokeを失敗させる、通知送信の結果を不明にする状況を再現します。正常系のE2Eだけでは、この基盤の価値を検証できません。

運用の完成度は、人が一度も画面を見ないことでは測れません。何も起きていない時に静かであり、異常時には正確な状態と証拠が一つのincidentへまとまり、安全に止まるか戻ることが重要です。

  • observe: 収集と状態記録だけを行い、修正しない。
  • suggest: AIがdraft PRを作り、人が採否と差分を確認する。
  • repair: 許可範囲の小さな修正だけをintegrationへ自動昇格する。
  • promote: 検証済みartifactを段階配信し、smoke失敗時に自動rollbackする。

この構成が向かない条件と、残る人間の仕事

少人数でも運用できるようにする構成ですが、制御面そのものは分散システムです。lease、重複実行、eventual consistency、credential、quota、rollback、監査を保守する必要があります。変更頻度が低いサービスやE2Eが短いrepositoryでは、管理されたCIの無料枠や従量課金を使う方が単純で安い場合があります。

テストが弱い、仕様が暗黙、再現しない障害が多い、migrationに後方互換性がない環境では、AI修復の自動merge範囲を広げられません。まず失敗を再現できるfixture、health check、smoke、branch protection、release manifestを整える必要があります。自動化は品質の土台を置き換えません。

また、セキュリティ、性能、UI・UX、保守性の判断は互いに独立ではありません。AIによる四つの評価は見落としを減らす補助であり、契約、法令、利用者への重大な影響、不可逆なデータ変更を承認する主体にはできません。出動回数を減らしても、例外時の最終判断と定期的な境界の見直しは人に残ります。

  • 変更が少ない、小規模、短時間CIなら、管理されたrunnerの方が総コストを抑えやすい。
  • 再現可能なテストと後方互換migrationがない段階では、自動mergeを有効にしない。
  • 不可逆なデータ変更、権限、法務、料金、重大な利用者影響は人の承認へ残す。

完全自動化の中心は、AIではなく安全に止まれる制御面です

エラー収集、Spot VM、セルフホステッドランナー、AI修復、ephemeral STG、migration検証、多角レビュー、翻訳、依存更新、段階配信、自動rollbackを一つにつなぐと、人間の反復作業は大きく減らせます。その効果は、モデルの賢さより、証拠と状態を外部へ残し、再実行が同じ結果へ収束する設計によって支えられます。

実務で持ち帰る判断軸は三つです。AIへ渡す前に入力を最小化して秘匿化すること、AIの前後を差分・権限・予算・テストの決定的なgateで囲むこと、Spot停止や通知失敗を含む異常系から再開またはrollbackできることです。

通知が鳴るまで人が介入しない運用を目指す場合も、沈黙そのものを正常の証拠にはできません。heartbeat、監査記録、定期的な障害訓練によって、制御面が現在も期待どおり働いていることを確かめます。自動化の完成とは、人を排除することではなく、人が判断すべき場面だけを正確に残すことです。

Technical documents

技術文書を増やしていきます。

AI、クラウド、業務アプリ開発、要件定義、運用設計に関する考え方を、今後も文書として整理します。

技術文書一覧へ