FLARES LLC

Technical document

バグ検出率で実行間隔を変えるAIバグ探索基盤の設計

AIに長時間コードを調べさせる時、必要なのは1台の計算機を動かし続けることではありません。期限、予算、変更範囲、品質ゲートをキャンペーンとして保持し、実行可能な仕事がある時だけ短命なRunnerを起動することです。さらに不具合が見つかる間は短い間隔で回し、検出率が下がれば間隔を広げることで、探索の粘り強さと費用統制を両立できます。
AI開発 / 品質基盤約18分公開日 2026年7月20日更新日 2026年7月20日
不具合の減少に合わせて検査ノードの実行間隔が広がるAIバグ探索基盤の概念図

Summary

この文書の要点

  • 最大24時間は単一VMの連続稼働時間ではなく、中断と再開を含むキャンペーン全体の固定期限として管理します。
  • 不具合やテスト失敗が続く間は5分、静かになれば15分・45分へ間隔を広げ、実行対象がなければSpot VMを作成しません。
  • Batch APIの結果待ちではRunnerを保持せず、結果回収と次工程の起動を別のReconcilerへ分離します。
  • 完了条件は「新しいバグが見つからない」ではなく、同一コミットに対する時間を置いた品質ゲートの2回連続成功です。

24時間動くAIではなく、24時間を上限に再開できるキャンペーン

AIによる不具合探索を長時間続けようとすると、最初に思いつくのは、Runnerを起動して検出、修正、テストを一つのループで回し続ける構成です。しかし、この方法ではAI APIの待ち時間にも計算資源を占有し、Spot VMの中断で長いジョブ全体をやり直し、どこまで進んだかを実行プロセスのメモリに依存してしまいます。

そこで、長時間動くプロセスではなく、期限を持つキャンペーンを永続化します。キャンペーン作成時にdeadlineAtを確定し、実行時間、再試行、Batch待機、Spot中断が発生しても期限は延長しません。各Runnerは1工程または1サイクルだけを処理し、終了後に破棄します。次の工程は、永続化された状態から別のRunnerが再開します。

この分解により、最大24時間という長さを、常時稼働の許可ではなく、探索に与える時間予算として扱えます。品質ゲート合格、期限到達、費用上限、人間判断、進展なしなど、時間以外の停止理由も同じキャンペーン上で明示できます。

  • requestedDurationは1〜24時間とし、作成後のdeadlineAtは延長しない。
  • Runner、Workflow、Batch requestをキャンペーンに関連付け、プロセス終了後も再開できるようにする。
  • Spot中断と容量不足は異常ではなく、待機または再試行へ遷移する正常系として扱う。

操作画面、制御面、実行面、状態保存を分離する

人間の入口にはGitHub IssuesとIssueコメントを使います。開始、状態確認、停止、再開をコメントから指示し、同じIssue上の専用コメントを更新して、進捗、期限、費用、検出件数、Draft PR、停止理由を確認できるようにします。Issueは内部ロックの保存場所ではなく、人が読める操作画面と監査台帳です。

制御面はCloud Run上のControllerが担います。GitHub AppのWebhook署名と操作権限を検証し、delivery IDによる重複排除を行い、Firestoreのキャンペーン状態をトランザクションで更新します。workflow jobが待機状態になった時だけGitHubのJIT設定を発行し、GCE Spot VMを作成します。

実行面はEphemeral Self-hosted Runnerです。リポジトリを取得し、決定的検査、不具合の分類、関連ファイル抽出、パッチ検証、対象テスト、回帰テスト、Draft PR更新のうち、そのジョブに割り当てられた工程だけを処理します。ログ、パッチ、Batch入出力はGCSへ、排他、リース、費用、進行状態はFirestoreへ保存します。遅延再試行と次サイクル起動にはCloud Tasks、定期照合と孤児リソース削除にはCloud Schedulerを使います。

  • GitHub Issues: 人間向けの指示、進捗、停止理由、監査証跡。
  • Cloud Run Controller: 認証、冪等性、状態遷移、JIT設定、Spot VM、Batch、次工程の制御。
  • Ephemeral Runner: 1台1ジョブを原則とする、使い捨ての検出・修正・検証環境。
  • Firestore・GCS・Cloud Tasks: 状態、成果物、遅延実行をプロセス寿命の外に保持する。

工程の状態と実行頻度の状態を、別の状態機械にする

この基盤には、性質の違う二つの状態があります。一つはrequested、provisioning、detecting、batch_processing、testing、gate_evaluating、completedのような「いま何の工程にいるか」です。もう一つはACTIVE、COOLING、IDLE_VERIFY、FINAL_VERIFY、COMPLETEDのような「次にいつ実行してよいか」です。

二つを一つのstatusへ詰め込むと、たとえばBatch結果待ちであることと、45分間隔で静観していることを区別できません。工程状態は処理の再開位置を決め、頻度状態は次回の起動可否を決める、と責務を分けます。CampaignにはnextEligibleAt、zeroBugCycles、noProgressCycles、lastVerifiedCommitSha、consecutiveGreenRunsなどを持たせます。

状態遷移はコードで許可リストとして定義し、previousStatus、newStatus、時刻、理由、commit SHA、Runner、Batch、費用差分を記録します。Firestore Transactionと期限付きリースを使い、同じWebhookや再試行が重なっても、同一ジョブを二重に割り当てたり、同じファイルを並行修正したりしないようにします。

  • 工程状態は再開位置を表し、頻度状態は次回起動時刻を表す。
  • イベント、Issueコマンド、Workflow job、Batch request、修正試行ごとに決定的な冪等性キーを持つ。
  • ロックには有効期限を持たせ、Spot中断後に永久ロックを残さない。

検出が続く間は短く、静かになれば実行間隔を広げる

初期状態のACTIVEでは、新しい再現可能不具合、パッチ適用、テスト失敗、品質ゲート未通過、前サイクルからのコード変更があるため、次回を5分後に設定します。直近2サイクルで新規不具合がゼロならCOOLINGへ移り、15分後まで待ちます。直近3サイクルで新規不具合がなく、affected quality gateが成功し、実行可能な高優先度タスクがなければIDLE_VERIFYへ進み、45分後までRunnerを作成しません。

full quality gateが成功し、未解決のP0・P1がなく、コード変更もBatch待機もない場合はFINAL_VERIFYへ移ります。30分以上待って、同じcommit SHAへもう一度full quality gateを実行し、再度成功した時だけCOMPLETEDとします。バグ検出ゼロを即座に完了扱いせず、時間を置いた再検証を状態機械に組み込む点が重要です。

ControllerはVM作成前に、キャンペーン状態、deadlineAt、nextEligibleAt、停止要求、予算残、実行可能ジョブ数、Batch待機数、現在と最終検証済みのcommit SHAを確認します。時刻が早い、仕事がない、Batch待機だけ、追加検証が不要という場合はVMを作らず、正常終了として記録します。

  • ACTIVE: 5分。新しい不具合、変更、失敗があり、探索を密に続ける。
  • COOLING: 15分。2サイクル連続で新規不具合がなく、活動を抑え始める。
  • IDLE_VERIFY: 45分。3サイクル連続で新規不具合がなく、次の確認までVMを起動しない。
  • FINAL_VERIFY: 30分。同じcommit SHAに対する2回目のfull quality gateを待つ。

待機は固定sleepではなく、イベントでいつでも解除できる

実行間隔を広げても、重要な変化への反応を遅らせてはいけません。新しいcommit、対象Issueの更新、CI失敗、Batch完了、Draft PR更新、新しい再現可能不具合が到着した時は、nextEligibleAtを現在時刻へ戻し、必要に応じてACTIVEへ遷移させます。

この仕組みは、15分や45分のsleepをRunner内で行うものではありません。待機はFirestoreのtimestampとして表現し、Cloud TasksまたはSchedulerが再評価します。計算資源は解放されたままなので、待機時間が長くても費用はほとんど増えず、外部イベントがあれば予定時刻を待たずに再開できます。

時間駆動とイベント駆動を組み合わせることで、静かな時は省資源、変化した時は即応という二つの性質を両立します。適応型制御の実体は、Runnerの速度を変えることではなく、次に計算資源を割り当てる判断を状態として保存することです。

Batch APIを待つ時間から、Runnerを切り離す

大量のログ分類、関連ファイル候補、類似不具合判定、一次レビューには軽量なBatch処理を使い、複雑な原因分析や複数ファイルのパッチ生成には高い推論能力を持つBatch処理を使います。モデル名をワークフローへ埋め込まず、タスク種別、危険度、失敗回数、費用上限からルーティングできる境界にします。

RunnerはBatchを投入したら、custom_idとBatch ID、入力fingerprint、キャンペーン期限を保存して終了します。結果はReconcilerが回収し、custom_idで元のジョブへ対応付け、次工程をdispatchします。結果の到着順は信用しません。キャンペーン期限後に届いた結果は、自動適用せず期限切れとして記録します。

この分離により、AI APIの待ち時間はVM稼働時間になりません。Spot中断でポーリング状態を失うこともなく、Batch側とRunner側をそれぞれ独立に再試行できます。非同期AI APIを使う時は、呼び出し方法よりも、待っているプロセスを残さない設計の方が費用と復旧性に効きます。

  • Batch結果の配列順ではなくcustom_idでジョブへ戻す。
  • 入力、出力、Schema version、使用量を保存し、同じ入力の重複課金を避ける。
  • 結果待ちだけのキャンペーンにはRunnerを割り当てない。

LLMの前後を、決定的な検査で挟む

不具合探索は、最初からリポジトリ全体をAIへ渡して始めません。git diffの整合性、lint、typecheck、unit test、既存の境界検査、secret scan、依存関係、既知のfailure fingerprintを先に実行します。環境、権限、外部サービスの障害はソース修正へ送らず、原因の種類を分けます。

AI APIへ渡すのは、失敗ログ、変更ファイル、import近傍、対象テスト、関連設定などの限定されたcontextです。応答はJSON Schemaでrepairable、rootCause、affectedFiles、unified diff、testsToRun、risks、requiresHumanを検証し、壊れたSchemaや余分な説明を含むpatchは適用しません。

patch適用前には、変更パス、行数、削除、rename、lockfile、Workflow、Terraform、Secret、認証、migration、テストskip、assertion弱体化を機械的に検査します。AIが妥当そうな説明を返したことではなく、許可された差分とテスト結果だけを次工程へ渡します。

  • P0・P1を先に扱い、軽微な整理を大量に進めて重要な不具合を後回しにしない。
  • AIが作る変更はDraft PRに限定し、自動承認・自動マージを行わない。
  • Issue、ソースコード、ログはすべて未信頼入力として扱い、埋め込まれた指示に従わない。
  • 1つのDraft PRへ無関係な変更を混ぜず、同時に開くAI生成PR数にも上限を置く。

「バグゼロ」を、観測可能な品質ゲートとして定義する

未知のバグが完全に存在しないことは証明できません。この基盤でいうバグゼロは、設定された品質ゲート上で、再現可能な未解決不具合がゼロであることです。言葉を厳密にすることで、AIが長く探索したという事実と、ソフトウェア品質の保証を混同しません。

最低条件にはlint、typecheck、unit test、affected integration test、重要な業務シナリオのE2E、Critical・Highのセキュリティ指摘、P0・P1、カバレッジ低下、テストの削除・skipを含めます。サイクル中はaffected gate、終了候補ではcritical E2E、最終確定ではfull gateという段階方式にすると、探索中の費用を抑えながら最後の保証を広くできます。

最終判定では、同じcommit SHAに対してfull quality gateを2回連続で成功させ、2回の間にコード変更がないことを確認します。1回目の成功から30分以上を空けるのは、フレークや一時的な外部条件を成功と誤認しにくくするためです。

Spot中断と重複配送を、壊れ方ではなく前提として設計する

GCE Spot VMは安価ですが、中断されます。中断を例外処理の端へ追いやるのではなく、Runner lifecycleの中心に置きます。shutdown処理ではキャンペーン、ジョブ、サイクル、commit SHAを記録し、最終ログと未コミットpatchをGCSへ退避し、リースを解放してinterruptedへ遷移します。重い回復処理は次のRunnerに任せます。

RunnerはJIT設定を一度だけ受け取り、原則1ジョブを処理したらGitHubから登録解除されます。VM削除はRunner自身とControllerの両方から試みても、既に削除済みなら成功として扱います。起動から一定時間を超えたVM、ディスク、Runner登録は、Schedulerが孤児リソースとして定期削除します。

Webhook、Cloud Tasks、GitHub APIは少なくとも1回届く前提で考えます。副作用を一度しか起こさないことを配送保証に期待せず、delivery ID、comment ID、workflow job ID、入力fingerprintを使って、同じ要求を何度処理しても同じ状態に収束させます。

停止条件と費用台帳を、実行前の判定にする

自律的な修正ループでは、失敗後に費用を集計するだけでは遅すぎます。Runner起動前とAI API呼び出し前に最大想定費用を予約し、完了時に実使用量へ精算します。期限、停止要求、同一failureの連続、同じファイルへの修正回数、進展なし、Schema違反、patch検証失敗、危険領域への変更要求を確認し、一つでも上限へ達したら新しい処理を始めません。

監視では、Runner起動回数だけでなく、起動しなかった判定回数、ACTIVE・COOLING・IDLE_VERIFYの滞在時間、新規バグ検出率、1件あたりのRunner費用、1修正あたりのAI API費用、前サイクルからの改善量を記録します。適応型スケジューラの価値は、VMが減った印象ではなく、検出率と費用の関係で評価します。

5分、15分、45分という値は普遍的な正解ではなく初期設定です。プロジェクトのテスト時間、変更頻度、Spot容量、AI APIの完了時間に応じて設定可能にし、観測値を基に調整します。頻度を下げすぎて検出が遅れる場合と、上げすぎて同じ結果を再確認し続ける場合の両方を監視する必要があります。

検証は短いキャンペーンから段階的に広げる

最初から24時間動かすと、失敗した時にController、Runner、Batch、権限、状態遷移のどこが原因か分かりません。まずWebhook署名、コマンド解析、期限計算、状態遷移、冪等性、予算予約、patch guardをUnit Testで固定します。次にWebhookからキャンペーン作成、workflow jobからVM要求、Runner callbackからJIT発行、Batch完了から次工程起動までをIntegration Testでつなぎます。

インフラはTerraformのformat、validate、plan、Workflowは権限、timeout、concurrency、オンデマンドVMへのfallbackがないことを検査します。Smoke TestはControllerのhealth check、1台の小さなSpot Runner、echoジョブ、自動削除、15分のanalysis-only、30分のaffected、Spot中断、2時間キャンペーンの順に広げます。

適応型制御には、2・3サイクル連続で不具合ゼロになった時の遷移、nextEligibleAt以前にVMが作られないこと、イベント到着で即時再開すること、同じSHAで2回検証すること、期限を越えたBatch結果を適用しないことをテストします。これは機能テストというより、無駄な起動と早すぎる完了を防ぐ制御系のテストです。

この設計の限界と、採用しない方がよい条件

短命なSpot Runnerは待機費用を減らし、中断からの復旧性を高めますが、起動時間と環境構築の費用が増えます。テストが数十秒で終わる小さなリポジトリでは、Runnerを毎回作る方が非効率になる場合があります。カスタムイメージやキャッシュを用意しても、常駐Runnerより単純になるわけではありません。

Batch APIは大量処理の単価を抑えやすい一方、結果到着までの遅延が読めません。緊急の障害対応や数分以内の修正が必要な場面には向きません。また、AIが見つけられるのは、与えられたテスト、ログ、context、探索手段から観測できる不具合だけです。品質ゲートが弱ければ、2回連続成功しても弱い基準を2回通っただけです。

この基盤の導入前に整えるべきものは、再現可能なテスト、重要シナリオ、protected path、ブランチ保護、責任分界、費用上限です。これらが曖昧な状態で自律実行だけを足すと、探索速度ではなく曖昧さを増幅します。

AI時代に変わるのは、作業量より実行ループの設計

この仕組みが変えるのは、AIにコードを書かせる速度だけではありません。人間が退勤前に長い処理を開始し、翌朝に一つの成否を見る運用から、複数の短い工程が中断可能な状態機械として進み、必要な時だけ計算資源を割り当て、判断が必要な差分だけをDraft PRとして受け取る運用へ変わります。

開発者の役割も、すべての試行を手で回すことから、品質ゲート、変更可能範囲、停止条件、検証シナリオを設計することへ重心が移ります。これは人間を品質管理から外す設計ではありません。機械が得意な反復を期限と予算の中へ閉じ込め、人間の判断を設計変更とレビューに集中させるための設計です。

長時間のAI処理を安全にする要点は、強いモデルを一つ選ぶことではありません。プロセスの外に状態を残すこと、待機中の計算資源を解放すること、変化へはイベントで即応すること、静かになれば頻度を下げること、同じコードを時間を置いて再検証することです。この五つを揃えると、AIによる探索を、実験的な一回の実行から継続運用できる品質基盤へ変えられます。

Technical documents

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

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

技術文書一覧へ