一覧に戻る
    影響範囲調査をCIに組み込む──CARE設計の思考ログ

    影響範囲調査をCIに組み込む──CARE設計の思考ログ

    15 分で読める

    前回の記事では、1四半期に発生した9件のインシデントを分析し、「暗黙的な依存の見落とし」が根本原因だという結論を出した。

    そこで提唱したアプローチは3つ。

    • 案 A(リアクティブ型): 変更時に都度調べる
    • 案 B(プロアクティブ型): 常に依存マップを維持する
    • 案 C(自動化型): CI で自動検知する

    でも、「アプローチの方向性」を書いただけで、「どうやって実現するか」まで踏み込めていなかった。今回はその続き。実際にどう設計を進めたかの思考ログ。

    チェックリストから始めようとしたら、すぐ限界が見えた

    最初に考えたのは、PR テンプレートにデータ影響チェック項目を追加するという案だった。手軽だし、今日から始められる。

    でも、前回分析した根本原因を思い出すと、「調べようと思えば調べられたが、調べるべきだという認識がなかった」だった。

    これって要するに、知らないものはチェックできないということだ。

    「新旧テーブルの同期確認」という項目があったとしても、自分が担当している変更が新旧テーブルに関係しているとそもそも知らなければ、そのチェックボックスをスルーしてしまう。チェックリストは「何を調べるべきか」を知っていることが前提の仕組みなので、今回の問題の構造にはフィットしない。

    加えて、忙しい時期にはそもそもチェック自体が形骸化する。これは経験則として、みんな持っているんじゃないかと思う。

    「防ぐコスト」と「リカバリーコスト」を並べて考えた

    チェックリストが難しいなら、構造を作り変えるアーキテクチャ改修がある。たとえば、複数サービスが直接参照している共有 DB のテーブルを API 経由に統一するとか。確かに根本的な解決にはなる。

    でも、これは開発投資がかなり大きい。

    そこで一度、9件のインシデントのリカバリーコストをちゃんと並べて見てみた。

    #障害の性質復旧方法リカバリーコスト感
    大半のインシデントデータ整合性、設定ミス、パフォーマンスデータ修正、設定変更、index 追加低〜中
    1件だけ特殊誤ったビジネスアクションが実行された事実を取り消せない性質がある高(不可逆)

    大半のインシデントは、数時間〜1日で復旧できている。全ユーザーに影響しても、停止時間は短い。

    一方で、1件だけ性質が違うインシデントがあった。誤った状態でビジネスプロセスが進んでしまったタイプで、「その事実を元に戻す」こと自体が難しい。

    この整理から、投資判断の軸が見えてきた。

    「防ぐコスト」 vs 「リカバリーコスト + ビジネスダメージ」
    
    → 大半のインシデント: リカバリーの方が安い → 検知・復旧に投資
    → 不可逆なビジネス影響があるもの: 防ぐ方が安い → そこだけ防御
    → 両方に対して最小コストで効果を出す方法が必要

    アーキテクチャの大改修をしなくても、もっと現実的な解がありそうだと思い直した。

    既存の CI 基盤に乗せるという発想

    そのとき、「そういえば今の CI でコードの複雑度チェックをやっているな」という話になった。

    PR が作られると CI が動いて、自動的にコード品質の指標を出して PR にコメントする仕組みが既にある。

    これを応用すれば良いんじゃないか、という発想。

    「このファイルやテーブルに変更が入ったとき、別のどこかも確認が必要」というマッピングをルールとして持っておいて、PR の変更内容と照合する。

    これが CARE(Context-Aware Review Engine)の原型。名前も含めて、自分で考えたコンセプトだ。

    ポイントが2つある。

    ポイント1: 「何を調べるべきか」と「実際に調べる作業」を分ける

    前回の根本原因に立ち返ると、問題は2層構造だった。

    • 認識の問題: 調べるべきだと気づかなかった
    • 実行の問題: 気づいたとしても、複数リポジトリを横断して調べる物理的コストが高い

    チェックリストは認識の問題を一部解決しようとするが、実行の問題は解決しない。人が調べなければいけない状態は変わらない。

    CARE の役割分担はこう。

    • 「何を調べるべきか」 → マッピングルールとして人間が育てる
    • 「実際に調べる作業」 → LLM が担う

    人間は知見を蓄積することに集中して、調査作業そのものは LLM に任せる。

    ポイント2: 自己強化ループになっている

    ルールに合致しない PR があったとき、ただ何もしないのでは勿体ない。そこで LLM に変更内容を分析させて「このパターン、レビュー観点として登録した方が良くないですか?」と提案させる。

    開発者は Accept / Skip で判断するだけ。

    これで、使えば使うほどルールが充実するループが生まれる。インシデントが起きなくても、日常の PR からルールが育っていく。

    ルール管理をどう設計するか

    ここで一番悩んだのが、ルールの管理場所だった。

    案 A: 各リポジトリに分散配置(各リポジトリに .care/review-points.yaml を持つ)

    良い点は、そのリポジトリの開発者が自然に更新できること。コードと一緒に PR を出せる。

    悪い点は、今回のインシデントの大半が「リポジトリをまたいだ影響」だったこと。分散配置だと、クロスリポジトリの観点が書きにくい。

    案 B: 集中リポジトリで管理

    repo-care-rules/
      ├── product-a/
      │   ├── api.yaml
      │   └── batch.yaml
      ├── product-b/
      │   └── main.yaml
      └── cross-service/
          └── shared-tables.yaml

    一番防ぎたい問題が「リポジトリ間の依存」なので、一箇所で管理する方が自然。クロスリポジトリの観点も素直に書ける。ルールの全体像が見渡せる。

    デメリットは、コード変更とルール変更が別 PR になること。でも、ルール変更はコード変更とは違うライフサイクルで更新されることも多いので、それはそれで良いかもしれない。

    今回の問題の構造から考えると、案 B の集中管理が妥当という結論になった。

    陳腐化を防ぐ仕組みも設計した

    ルールを集中管理しても、更新されなければ意味がない。「定期的に見直しましょう」は機能しないと、経験上わかっている。

    必要なのは、更新が自然に発生する仕組み

    考えたのは3つの経路。

    経路1: PR 駆動(日常の開発フロー)

    リスクシグナルがある PR でルールに合致しない場合、LLM が自動でルール追加を提案する。開発者は Accept/Skip で判断するだけ。日常の開発フローの中で自然にルールが増えていく。

    経路2: インシデント駆動

    障害報告のテンプレートに2〜3個の質問を追加する軽いプロセス。

    • このインシデントは PR 起因か?
    • CARE ルールがあれば防げたか?
    • どんなルールがあれば防げたか?

    Yes の場合、LLM が障害報告の内容からルールのドラフトを自動生成する。ポストモーテムのような重い会議体は不要。復旧直後が一番原因を理解しているタイミングなので、そこで機械的にキャプチャする。

    経路3: 手動追加

    上の2つで拾えないものは、開発者が直接追加する。これは最後の手段。

    ルールには origin を記録する

    各ルールに「なぜこのルールが存在するのか」を記録することが重要だと思っている。

    - trigger:
        tables: ["shared_table_name"]
      prompt: |
        このテーブルは複数サービスから参照されています。
        スキーマ変更時、他サービスへの影響を確認してください。
      origin:
        incident: "YYYY-MM-DD 発生の障害名"
        date: "2026-04-XX"

    これがないと:

    • なぜこのルールがあるのかわからない → 消していいのか判断できない
    • リニューアルが完了して不要になったルールを判別できない

    ルールをコードと同じように Git 管理して、変更履歴を追えるようにする。「誰かが Wiki に書いた」ではなく「誰がなぜ変えたかがコミット履歴に残る」状態にする。

    過去9件のインシデントへの有効性を検証した

    設計がある程度固まったところで、「実際にこの仕組みが9件のインシデントを防げたか」をシミュレーションしてみた。

    #障害の種類CARE で防げたか調査内容
    1新旧テーブル同期漏れ(データ処理系)Yes差分更新/全件更新の仕様差をコードから発見できる
    2依存ライブラリのバージョン互換性Likelypackage.json の変更で互換性リスクのあるライブラリを調査可能
    3新旧テーブルの状態遷移不整合Yes旧テーブルのみ更新されている事実をコードから発見できる
    4JOIN クエリのパフォーマンスYesJOIN 対象テーブルの index 有無を DB 情報から確認可能
    5インフラ設定変更による実行環境の差異Likely設定ファイルの変更を検知し実行環境との照合が可能
    6データ移行タイミングのラグNoPR 起因でない作業は対象外
    7共有テーブルのスキーマ変更波及Yes別リポジトリのコードを検索して依存を発見できる
    8サーバーリソースの競合Likelyインフラ設定変更を検知しメモリ使用率との照合が可能
    9レガシー API からの JOIN 参照Yesレガシー API のコードを検索して発見できる

    9件中6〜7件に有効。PR 起因でない作業(#6 のデータ移行)は構造的に対象外。

    進め方: 最初から全自動にしない

    実装フェーズの話になったとき、「最初から Webhook で自動トリガーする必要はない」という判断になった。

    Phase内容投資規模
    1. 基盤構築 + 手動検証Jenkins 上に LLM エージェントの実行環境を構築する。Webhook 等の自動トリガーはまだ入れず、手動で実行。過去のインシデント PR や日常の PR を対象にレポートの質と有効性を評価する。
    2. 判断手動運用の実績をもとに、自動トリガーの範囲とコストを判断する
    3. 自動化Webhook 連携による自動トリガー、ルールの集中リポジトリ構築、対象リポジトリの段階的拡大

    Phase 1 で実行環境を先に揃えておくことで、自動化に進む際は Webhook を繋ぐだけで移行できる。検証環境と本番環境で挙動が違う、みたいな問題も起きない。

    LLM をエージェントとして動かすコストについても、最初は手動トリガーなので PR ごとにかかるコストを実際に測りながら判断できる。全 PR に対して実行するか、リスクシグナルに該当する PR だけに絞るかは、実績を見てから決める。

    現時点での率直な評価

    CARE で解決しようとしている問題は2つ。

    • 「調べるべきだという認識がなかった」→ ルールが担う
    • 「調べたくても横断検索が難しかった」→ LLM が担う

    前回の分析で、根本原因は「認識」と「実行」の両方にあると整理した。CARE はその両方を、既存の CI 基盤の延長線上で、現実的なコストで解決できる可能性がある。

    一方で、定着するかどうかはまだわからない。特に「ルールが育ち続けるか」という点。CARE の自己強化ループが実際に機能するかは、Phase 1 の検証で確認する必要がある。

    まだ設計の段階で、これから試すところ。引き続き検討の経緯を書いていく。

    この記事は役に立ちましたか?

    Coffee cup

    この記事が、何かの整理につながったら

    コーヒー1杯分の応援をもらえると嬉しいです。

    ※ これは応援とは別の話ですが、

    同じようなテーマを自分の文脈で整理したい場合は、 (文章だけだと詰まりやすい人向けに) 思考整理の壁打ちという形で対話の時間も取っています。

    対話の時間について