45395 - シコウサクゴ -

AIに施策間の競合分析を依頼する:同時デプロイのリスク検出

2026-04-03
AI駆動開発
AI駆動開発
Claude Code
競合分析
デプロイ
リスク管理
Last updated:2026-04-05
16 Minutes
3026 Words

施策を1つずつ見ていると問題は見えません。2つの施策が同時に本番にデプロイされたとき、初めて競合が顕在化します。

本番システムで複数の施策を並行開発・同時デプロイした際に、施策間の競合が原因で障害が発生しました。AIに「全施策のコードを読み比べて競合を検出する」ことを依頼する手法を確立した結果、本番デプロイ前に競合を検出できるようになりました。本記事では、AIを使った施策間競合分析の実践を記録します。


問題:同時デプロイで起きた競合

実際のインシデント

RNG-B3(バッチ分割処理)とRNG-B4(Z-score閾値判定)を同日にデプロイしようとしました。

1
RNG-B3: バッチ分割処理
2
→ 一定間隔でリソースを複数保持する
3
→ リソースは個別にタイムアウト/リトライで管理
4
5
RNG-B4: Z-score閾値判定
6
→ 統計的Z-scoreが閾値を超えたらリソースを解放
7
→ 対象: 安定期間中に保持中の全リソース

個別に見ると、どちらも正しく動作します。しかし同時にデプロイすると問題が起きます。

1
競合シナリオ:
2
1. RNG-B3がsource_alphaで5段階のグリッド処理リソースを確保
3
2. RNG-B4が「Z-scoreが閾値超過」を検知
4
3. RNG-B4が安定期間中の全リソースを解放
5
4. → RNG-B3のグリッド処理リソースが意図せず解放される
6
5. → グリッド処理が破綻(中間リソースだけ残る等の不整合状態)

sc:analyze(Claude Codeの分析コマンド)がこの競合を検出しました。

1
sc:analyze の出力:
2
⚠️ CONFLICT DETECTED:
3
RNG-B4 could unintentionally release RNG-B3 grid resources
4
after API production migration.
5
6
Root cause: RNG-B4の _fetch_active_resources() が
7
processing_method_filter を使用していないため、
8
RNG-B3のリソースも取得対象に含まれる。
9
10
Recommendation: processing_method_filter に "grid" を
11
除外条件として追加するか、RNG-B4のスコープを明示的に制限する。

本番デプロイ前に検出できたことで、潜在的な障害を回避できました。


施策間競合の6カテゴリ

インシデント分析から、競合は6つのカテゴリに分類できます。

A. リソース競合

複数の施策が同一のリソースを操作しようとします。

1
# 競合の例: 2つの施策が同じリソースを解放しようとする
2
# RNG-B3のコード
3
def release_grid_resource(source: str, level: int) -> None:
4
resources = fetch_active_resources(source=source)
5
target = find_grid_level(resources, level)
6
release_resource(target.resource_id)
7
8
# RNG-B4のコード(競合あり)
9
def zscore_exit_check(source: str) -> None:
10
resources = fetch_active_resources(source=source) # ← RNG-B3のリソースも含む
11
for res in resources:
12
if calculate_zscore(res) > threshold:
13
release_resource(res.resource_id) # ← RNG-B3のグリッド処理を破壊

B. トリガーファイル競合

複数のプロセスが同じトリガーファイルを読み込み・消費します。

1
# 施策Aがトリガーファイルを書き込み
2
trigger_path = Path("triggers/entry_signal.json")
3
trigger_path.write_text(json.dumps(signal_data))
4
5
# 施策Bが同じファイルを読んで「消費済み」にする
6
signal = json.loads(trigger_path.read_text())
7
trigger_path.unlink() # ← 施策Aが読む前に削除される可能性
8
9
# 施策Aが読もうとしたときにはファイルが存在しない

C. launchdスケジュール競合

同時刻に起動するジョブがAPIレート制限に抵触します。

1
<!-- 施策A: 毎時0分にAPI呼び出し -->
2
<key>StartCalendarInterval</key>
3
<dict>
4
<key>Minute</key>
5
<integer>0</integer>
6
</dict>
7
8
<!-- 施策B: 毎時0分にAPI呼び出し(競合) -->
9
<key>StartCalendarInterval</key>
10
<dict>
11
<key>Minute</key>
12
<integer>0</integer>
13
</dict>
14
15
<!-- 同時起動 → APIレート制限(例: 1req/sec)に抵触 -->

D. Parquet参照競合

施策が同じParquetファイルに異なるカラムを期待します。

1
# 施策Aが新カラムを追加
2
df["new_indicator"] = calculate_indicator(df)
3
df.to_parquet("pipeline_output.parquet")
4
5
# 施策Bが古いスキーマを前提に読み込み
6
df = pd.read_parquet("pipeline_output.parquet")
7
result = df["old_column_name"] # ← リネームされていたらKeyError

E. リソース割当・リスク管理競合

施策を個別に見るとリスク許容内ですが、合算すると超過します。

1
# 施策A: 最大リソース割当量 = 全体キャパシティの3%
2
max_allocation_a = total_capacity * 0.03
3
4
# 施策B: 最大リソース割当量 = 全体キャパシティの3%
5
max_allocation_b = total_capacity * 0.03
6
7
# 合算: 6% → DAILY_ERROR_LIMIT(5%)を超過する可能性
8
combined_allocation = max_allocation_a + max_allocation_b # 0.06 > 0.05

F. Go/No-Go依存

施策Aの結果に基づいて施策Bの有効/無効が決まる関係です。

1
# 施策A(状態判定)がNo-Goを出した場合
2
state_result = evaluate_system_state() # → "NO-GO"
3
4
# 施策B(安定期処理ロジック)は施策AのGo判定に依存
5
if state_result != "GO":
6
# 施策Bは動作すべきでないが、
7
# 依存関係が未設定だと施策Bが独立に動いてしまう
8
pass

AIに競合分析を依頼する方法

基本プロンプト

1
プロンプト:
2
@.wbs/CURRENT.md 現在デプロイ済み・Dry-Run中の施策同士の
3
矛盾点がないか調査してください。
4
特に以下を確認:
5
1. 同一データソースのリソースを操作する施策の組み合わせ
6
2. 同じトリガーファイルを参照する施策
7
3. 同時刻に実行されるlaunchdジョブ

AIはWBSから施策一覧を取得し、各施策のコードを読み比べて競合を検出します。50以上の施策の組み合わせチェックは人間には不可能ですが、AIには得意な作業です。

特定施策のデプロイ前チェック

1
プロンプト:
2
RNG-B3とRNG-B4を同日にデプロイする予定です。
3
以下の観点で競合分析をしてください:
4
1. リソース操作のスコープが重複していないか
5
2. processing_method_filter の設定は正しいか
6
3. launchdの実行タイミングが衝突しないか
7
4. 合算したリソース割当量がリスク上限を超えないか
8
9
@engine_a/.docs/378_*.md(RNG-B3のドキュメント)
10
@engine_a/.docs/379_*.md(RNG-B4のドキュメント)

sc:analyzeの活用

1
プロンプト:
2
/sc:analyze
3
対象: RNG-B3, RNG-B4の同時デプロイ
4
観点: 施策間競合(リソース・トリガー・スケジュール・リスク)

sc:analyzeはコード全体を分析し、潜在的な競合を検出します。前述のRNG-B3/B4の競合もこのコマンドで発見されました。


施策間競合チェックリスト

デプロイ前に必ず確認するチェックリストです。

1
## 施策間競合チェックリスト
2
3
### A. リソース競合チェック
4
- [ ] 同一データソースのリソースを複数施策が操作しないか
5
- [ ] _fetch_active_resources のスコープに他施策のリソースが含まれないか
6
- [ ] processing_method_filter が正しく設定されているか
7
- [ ] リソース解放時に他施策への影響を確認したか
8
9
### B. トリガーファイル競合チェック
10
- [ ] 「消費済みシグナル」の二重処理は起きないか
11
- [ ] processing_method_filter の設定は正しいか
12
- [ ] 同一トリガーファイルを参照する施策が他にないか
13
- [ ] トリガーファイルの読み書きに排他制御があるか
14
15
### C. launchdスケジュール競合チェック
16 collapsed lines
16
- [ ] 同一時刻に起動するジョブがAPIレート制限に抵触しないか
17
- [ ] ジョブ間の実行順序に依存関係がある場合、順序保証があるか
18
- [ ] 1分以内に複数ジョブがAPIを叩かないか
19
20
### D. Parquet参照競合チェック
21
- [ ] 新施策が既存Parquetのスキーマを変更していないか
22
- [ ] カラム追加・リネームが他施策に影響しないか
23
24
### E. リソース割当・リスク管理競合チェック
25
- [ ] 施策の合算リソース割当量がDAILY_ERROR_LIMITを超えないか
26
- [ ] 同一方向のリソースが集中していないか
27
- [ ] CircuitBreakerが全施策をカバーしているか
28
29
### F. Go/No-Go依存チェック
30
- [ ] 施策間の依存関係がWBSに明記されているか
31
- [ ] 依存先がNo-Goの場合に依存元が正しく停止するか

競合の記録方法

検出された競合は、両方の施策のドキュメントに記録します。

1
# 施策A(.docs/378_*.md)に追加:
2
## 競合情報
3
- **競合施策**: RNG-B4(Z-score閾値判定)
4
- **競合カテゴリ**: A. リソース競合
5
- **内容**: RNG-B4の_fetch_active_resourcesがRNG-B3のグリッド処理リソースを
6
取得対象に含む。RNG-B4がZ-score超過で解放すると、
7
グリッド処理の一部リソースが意図せず解放される。
8
- **対策**: processing_method_filterに"grid"を除外条件として追加
9
- **ステータス**: 対処済み(2026-03-15)
10
11
# 施策B(.docs/379_*.md)に追加:
12
## 競合情報
13
- **競合施策**: RNG-B3(バッチ分割処理)
14
- **競合カテゴリ**: A. リソース競合
15
- **内容**: RNG-B3との競合あり。本番移行前に対処必須。
2 collapsed lines
16
- **対策**: processing_method_filterに"grid"を除外条件として追加
17
- **ステータス**: 対処済み(2026-03-15)

クロスリファレンスにすることで、どちらの施策を見ても競合の存在がわかります。


競合分析のタイミング

チェックを実行すべき3つのタイミングがあります。

1
┌────────────────────────────────────────────────────┐
2
│ タイミング1: 施策設計完了直後(実装開始前) │
3
│ → 設計段階で検出すれば、実装方針の変更が容易 │
4
│ → WBSの依存関係を追加するだけで済むことが多い │
5
├────────────────────────────────────────────────────┤
6
│ タイミング2: 本番デプロイ前 │
7
│ → 実コードを対象にsc:analyzeで検出 │
8
│ → processing_method_filterの設定漏れなど具体的な問題│
9
├────────────────────────────────────────────────────┤
10
│ タイミング3: 複数施策を同日デプロイする場合 │
11
│ → 同日デプロイは競合リスクが最大 │
12
│ → 全組み合わせのチェックが必要 │
13
│ → RNG-B3/B4のインシデントはこのタイミングで検出 │
14
└────────────────────────────────────────────────────┘

施策ワークフローへの組み込み

CLAUDE.mdの施策ワークフローに競合チェックを必須化しました。

1
## 施策開始(AUTO実行)
2
- A-1: git-new-feature.shでブランチ作成
3
- A-2: CLAUDE.md・WBS・.docs/から施策内容把握
4
- **A-3: 競合チェック(リクエスト系・フィルター系・パイプライン)→ ユーザー確認待ち**

A-3の競合チェックがない状態で実装に入ることはできません。


AIに競合分析を任せる理由

人間には不可能なスケール

1
53のアクティブ施策の組み合わせ:
2
53 × 52 / 2 = 1,378 ペア
3
4
各ペアで6カテゴリをチェック:
5
1,378 × 6 = 8,268 チェックポイント
6
7
人間が全てを確認するのに必要な時間:
8
8,268 × 5分/チェック = 688時間 ≈ 86営業日
9
10
AIの場合:
11
コード読み比べ + WBS参照 = 数分〜数十分

AIは「全施策のコードを読み比べる」ことが人間より圧倒的に得意です。特に、_fetch_active_resourcesのような関数が複数の施策で使われている場合に、スコープの違いを正確に比較できます。

ただし完全ではない

AIが検出できないタイプの競合もあります。

1
AIが得意:
2
- コードレベルの競合(関数呼び出し・変数参照の重複)
3
- スケジュールの衝突(plistの時刻比較)
4
- データスキーマの不整合(Parquetカラムの差異)
5
6
AIが苦手:
7
- ビジネスロジックレベルの競合(運用環境に依存する競合)
8
- タイミング依存の競合(特定の負荷状況でのみ発生)
9
- 暗黙の前提に基づく競合(ドキュメント化されていない仕様)

AIの分析結果は「スクリーニング」として使い、最終判断は人間が行います。


学んだこと

1. 1つの施策を見ているだけでは競合は見つからない

WBS全体を俯瞰して初めて検出できます。RNG-B3のコードだけを見ても、RNG-B4との競合は見えません。@.wbs/CURRENT.mdを起点に全施策の関係を分析させるプロンプトが効果的でした。

2. AIは「全施策のコードを読み比べる」ことが人間より得意

50以上の施策の組み合わせチェックは人間には不可能です。1,378ペア × 6カテゴリ = 8,268チェックポイントを人間が確認するには86営業日かかります。AIなら数分から数十分で完了します。

3. 競合検出は「やらないと事故が起きてから気づく」タイプの作業

競合チェックを怠っても、99%の場合は何も起きません。しかし1%の確率で、本番でリソース競合が発生して障害が起きます。チェックリスト化して施策ワークフローに組み込み、必須化するしかありません。


まとめ

AIを使った施策間競合分析で重要なのは以下の3点です。

  1. 6カテゴリで網羅的にチェック: リソース・トリガーファイル・スケジュール・Parquet・リスク・Go/No-Go依存の6観点。チェックリストを使って漏れを防止します
  2. 3つのタイミングで実行: 設計完了後・デプロイ前・同日デプロイ時。特に同日デプロイは競合リスクが最大であり、全組み合わせチェックが必須です
  3. AIを「スクリーニング」として活用: 1,378ペアの組み合わせチェックは人間には不可能です。AIに網羅的に検出させ、最終判断は人間が行います
Article title:AIに施策間の競合分析を依頼する:同時デプロイのリスク検出
Article author:45395
Release time:2026-04-03

記事へのご質問・ご感想をお聞かせください

フィードバックを送る