Upgrade to Pro — share decks privately, control downloads, hide ads and more …

「この障害って半年前の、あのプロジェクトと同じ原因ですよね?なぜ防げないんですか?」を終わらせ...

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest. →
Avatar for tom tom
September 15, 2026
19

「この障害って半年前の、あのプロジェクトと同じ原因ですよね?なぜ防げないんですか?」を終わらせる 〜Reusable Workflows x Claudeで実装するプロジェクトを横断する障害防止戦略〜

「この障害って半年前の、あのプロジェクトと同じ原因ですよね?なぜ防げないんですか?」

複数のAndroidプロジェクトを抱えるエンジニアであれば、この一言にギクリとした経験があるはずです。
- Roomのマイグレーション漏れで端末アップデート後にユーザーデータが消えた。
- ProGuard / R8 の keep ルール漏れでリリースビルドだけがクラッシュした。
どちらも「半年前にも別のプロジェクトで踏みましたよね?」と言いたくなる典型例です。

私たちのチームは約20名で15プロジェクトを横断的に開発しており、OSやSDK起因のAndroid共通障害発生時のアラートはチームMTGやSlackしかありませんでした。
さらに、エンジニアは数ヶ月単位でプロジェクトをローテーションすることもあるため、過去の障害が別プロジェクトで再発する構造的リスクがありました。

この課題を改善するため、
Android共通障害カタログを1つのMarkdownで一元管理し、その更新をトリガーにGitHub ActionsのReusable Workflowsの仕組みを利用し、15プロジェクトリポジトリへ自動配布、さらにCopilotコードレビューのinstructionsとして障害情報を参照させる仕組みを構築しました。
これにより、「カタログを1つ更新するだけで全リポジトリへ自動展開され、AIコードレビューによる横断的なガードレールが効く」状態を実現したつもりでした。

しかし事はそう上手く運びません。
数ヶ月が経過しても、私以外のメンバーからのAndroid障害カタログへの追記数は0件だったのです。
通常業務で忙しい中で、仕組みだけ作っても障害情報のナレッジは追加されないというシビアな現実を突きつけられました。

そこでカタログを育てる主体を、人ではなくAIに移行することにしました。
ClaudeをGitHub Actionsに組み込み、各プロジェクトのPRマージ時に差分を解析し、「他のAndroidプロジェクトが参考にすべき共通障害が含まれているか」の判定をします。

Yesなら、他リポジトリでも再利用しやすい形に構造化し、カタログへ自動PRを作成します。
レビューしマージ後、Reusable Workflowsが15個のリポジトリに配信し、Copilotがレビュー時に参照する。
人が能動的に動かなくても、Android共通障害カタログが日々成長し続ける仕組みが完成しました。

導入後は15プロジェクトから障害情報を自動収集・展開し続け、モバイルチームの重大な共通障害は0件を維持しています。

本セッションでは皆さまのプロジェクトでも明日から導入し運用できるよう以下をご紹介いたします。
- GitHub Actionsの「Reusable Workflows」を利用したリポジトリ間を跨ぐMarkdown配布の仕組みと設定方法
- プロジェクト間の接続をなめらかにするCopilot instructions共通化戦略
- GitHub ActionsにClaudeを組み込み、PR差分から「Android共通障害か」を判定するためのプロンプト設計・除外条件のTips
- 私たちが運用しているAndroid共通障害カタログから、現象・原因・再発防止策のフォーマットと、すぐ持ち帰って使えるエントリ例

AIで開発スピードは飛躍的に向上する一方、チームが踏む障害の母数も増え続けています。
一度作れば自走する障害のガードレール、その設計と実装をお持ち帰りいただけます。

対象者
- 複数のAndroidプロジェクトを管理しており、Roomマイグレーションやライフサイクル起因のクラッシュなど、過去のAndroid障害が別プロジェクトで再発することに頭を抱えているリードエンジニア / プロジェクトマネージャー
- GitHub ActionsのReusable Workflowsを知りたい、本格的に運用したい、または導入を検討している方
- Claudeなどの生成AIをCI/CDのフローに組み込み、Androidプロジェクトで活用したい方
- GitHub Copilotコードレビューのinstructionsを活用し、自社のAndroid障害ナレッジをAIレビューのコンテキストに乗せたいと考えている方
- 「仕組みを作ったのに形骸化した」失敗を経験したことがある、あるいはこれから経験しそうな組織の方

Avatar for tom

tom

September 15, 2026

Transcript

  1. DroidKaigi 2026 「この障害って半年前の、あのプロジェクトと 同じ原因ですよね? なぜ防げないんですか?」 を終わらせる Reusable Workflows × Claude

    で実装する、プロジェクトを横断する障害防止戦略 PLAY, inc. 鈴木 斗夢 copyright (c) 2026 - PLAY, inc. 1 / 80
  2. 鈴木 斗夢 Tomu Suzuki PLAY, inc. モバイルエンジニア ― 動画配信基盤を開発する会社 2024

    PLAY 入社 大規模動画配信サービスの iOS / Android アプリを開発・保守 パーソル パ・リーグTV / WOWOW オンデマンド など 2026 AI タスクフォース 開発プロセス改善チーム リーダー 自動コードレビューの全社リポジトリ展開、 仕様駆動開発、Docs as Code の仕組み化など、AIを活用した組織全体の開発生産性の向上に注力 copyright (c) 2026 - PLAY, inc. 2 / 80
  3. なぜ防げない? チームは複数案件を掛け持ち 👤 Aさん 👤 情報共有はチーム MTG と Slack にしかない

    案件 A 先月 targetSdk 34 で foreground service の… 案件 B 2ヶ月前 R8 で release だけ落ちる件、解決 案件 C Bさん 👤 Cさん 全員が全リポジトリを見るのは不可能 copyright (c) 2026 - PLAY, inc. 案件 D 3ヶ月前 Room の Migration 漏れでデータ消えた… 案件 E …×15 古いものから沈み、薄れて、消えていく 5 / 80
  4. 当時の AI コードレビューの仕組み リポジトリごとにドメイン知識を MD ファイルで用意 .github/instructions/ 01_XXX.instructions.md 02_XXX.instructions.md 03_XXX.instructions.md

    04_XXX.instructions.md 05_XXX.instructions.md PR を作成 案件ごとに作成した MD ファイル Copilot が起動 ドメイン知識 (MD) を読んで コードレビュー PR をすると Copilot がドメイン知識 (MD ファイル) を読んでコードレビュー copyright (c) 2026 - PLAY, inc. 10 / 80
  5. 共通障害ファイルを AI コードレビューのコンテキストに リポジトリごとにドメイン知識を MD ファイルで用意 .github/instructions/ 01_XXX.instructions.md 02_XXX.instructions.md 03_XXX.instructions.md

    04_XXX.instructions.md 05_XXX.instructions.md PR を作成 案件ごとに作成した MD ファイル New 06_COMMON_INCIDENT.instructions.md Copilot が起動 (共通障害ファイル) ドメイン知識 (MD) を読んで コードレビュー Copilot が共通障害ファイルも読んでコードレビュー copyright (c) 2026 - PLAY, inc. 11 / 80
  6. 更新のたびに15リポジトリへ PR 案件リポジトリ A 共通障害ファイルを更新 人の手で15PR 案件リポジトリ B 案件リポジトリ C

    …×15 マージされれば15リポジトリから参照される ― 仕組みとしては成立するが持続可能ではない copyright (c) 2026 - PLAY, inc. 14 / 80
  7. 発想はシンプル ― 書いて、配って、防ぐサイクル 人 書く COMMON_INCIDENT_ANDROID.md 知見が一周して 次の障害を防ぐ Copilot コードレビューの

    コンテキストに copyright (c) 2026 - PLAY, inc. 共通障害ファイル 配信 案件リポジトリ × 15 マージ 16 / 80
  8. Reusable Workflows とは GitHub Actions の公式機能 ワークフローから別のワークフローを、関数のように呼び出せる 呼び出し側 定義側 関数を呼ぶ側

    関数を定義する側 uses で呼ぶ jobs: on: fanout: workflow_call: uses: 定義側 yml のパス jobs: # 再利用したい処理 呼び出し側は uses で指定し、定義側は on: workflow_call で受ける 出典: GitHub Docs「Reuse workflows」 copyright (c) 2026 - PLAY, inc. 19 / 80
  9. Reusable Workflows を動かすリポジトリ構成 中央リポジトリ/ ├─ COMMON_INCIDENT_ANDROID.md 共通障害ファイルの原本 ― 障害の知見はここに集まる └─

    .github/ └─ workflows/ ├─ distribute-on-merge.yml マージを検知して15リポジトリ分呼び出す(呼び出し側) └─ _distribute-incidents.yml 1リポジトリへ PR を出す処理の本体(定義側) 原本1つと、配るためのワークフロー2本 ― これだけ copyright (c) 2026 - PLAY, inc. 20 / 80
  10. 呼び出し側ワークフローの中身 1 2 3 4 # 呼び出し側: distribute-on-merge.yml(配信の起点) on: push:

    branches: [main] paths: ["COMMON_INCIDENT_ANDROID.md"] permissions: # GITHUB_TOKEN の権限 contents: read jobs: fanout: strategy: matrix: include: - { repo: 案件 A } # …計15行 uses: ./.github/workflows/_distribute-incidents.yml with: target_repo: ${{ matrix.repo }} secrets: # App の ID と秘密鍵を名前指定で渡す copyright (c) 2026 - PLAY, inc. 1 いつ動く? 原本が main にマージされた時だけ on: push + paths で限定 2 配信先を増やすには? matrix に1行足すだけ 3 何をする? 配信先リスト(matrix)の数だけ 定義側ワークフローを呼ぶ 自分では PR を出さない ― 呼ぶだけ 4 何を渡す? with: で引数、secrets: で鍵を 定義側へ手渡す 21 / 80
  11. 定義側ワークフローの中身 1 2 3 # 定義側: _distribute-incidents.yml on: workflow_call: inputs:

    # 配信先リポジトリ secrets: # App の ID と秘密鍵 jobs: distribute: steps: # 1. App トークンを発行 # 2. 原本から配信ファイルを生成 # 3. 案件リポへ同期 PR を作成 1 いつ動く? 呼ばれた時だけ動く on: workflow_call が入口 ― 自分からは起動 しない 2 何を受け取る? 引数(配信先リポと platform)と 鍵(App の ID と秘密鍵) 呼び出し側から手渡されたものだけ使える 3 何をする? トークンを発行 → ファイルを生成 → 案件リポへ同期 PR 「1リポジトリへ配る」処理の本体 copyright (c) 2026 - PLAY, inc. 22 / 80
  12. 初回だけのセットアップ ― GitHub App と secrets 他リポジトリへ PR を出すには、bot(GitHub App)の書き込み権限が必要

    ① GitHub App を作成 ② 案件 org にインストール ③ 中央リポに secrets 登録 組織で bot を1回だけ作る 権限は2つだけ Contents: write Pull requests: write 作成すると ID と秘密鍵が 発行される bot に自分の org への 書き込みを許可する操作 APP_ID(識別番号) APP_PRIVATE_KEY(秘密鍵) これで中央からの同期 PR を bot 名義で受け取れる 配信ワークフローがこの2つで 書き込み用トークンを発行する secrets は処理を実行する側に、App のインストールは書き込まれる側に この3つは最初に1回だけ ― 案件を増やすときの追加作業はゼロ copyright (c) 2026 - PLAY, inc. 23 / 80
  13. Reusable Workflows で配信を自動化 Reusable Workflows で実現 人 書く COMMON_INCIDENT_ANDROID.md 知見が一周して

    次の障害を防ぐ Copilot コードレビューの コンテキストに copyright (c) 2026 - PLAY, inc. 共通障害ファイル 配信 案件リポジトリ × 15 マージ 24 / 80
  14. 共通障害ファイルを配信する作業コストが15分の1に ① 中央リポの共通障害ファイルに追記 PR ② マージが配信を起動 ③ 15案件に同期 PR ×15

    Merged Open #123 ⚙ Distribute Incidents on Merge [INC-YYYY-NNNN] Room マイグレーション欠落を追記 ✓ fanout 15 jobs COMMON_INCIDENT_ANDROID.md +12 👤 人がレビューしてマージ 呼び出し側 → 定義側 ×15 案件リポ A chore: sync COMMON_INCIDENT from 中央リポジトリ 🤖 bot 名義で自動作成 1箇所の更新のみで15リポジトリに配信 数分後には、15リポジトリすべてに同じ内容の同期 PR が並ぶ copyright (c) 2026 - PLAY, inc. 25 / 80
  15. Reusable Workflows ― 設定/運用で詰まって得た、4つのナレッジ 1. secrets は名前指定 3. fail-fast で全滅を防ぐ

    copyright (c) 2026 - PLAY, inc. 2. 加工せず丸ごとコピー 4. PAT ではなく App 退職でシステムが停止することも 26 / 80
  16. 呼び出し側から定義側への、この鍵の手渡し 1 2 3 4 # 呼び出し側: distribute-on-merge.yml(配信の起点) on: push:

    branches: [main] paths: ["COMMON_INCIDENT_ANDROID.md"] permissions: # GITHUB_TOKEN の権限 contents: read jobs: fanout: strategy: matrix: include: - { repo: 案件 A } # …計15行 uses: ./.github/workflows/_distribute-incidents.yml with: target_repo: ${{ matrix.repo }} secrets: # App の ID と秘密鍵を名前指定で渡す copyright (c) 2026 - PLAY, inc. ④ で出てきた secrets の手渡し この渡し方は複数ある。 27 / 80
  17. secrets の渡し方 ― 全渡しか、名前指定か secrets: inherit(全渡し) ― 1行で楽。さて、どちらで書く? 全渡し secrets:

    inherit 名前指定 ― 本システムで採用 secrets: app_id: ${{ … }} app_private_key: ${{ … }} secrets: inherit 渡るもの: 見える secrets 全部 署名鍵 AWS Store Slack App鍵 1行で楽。でも org の鍵まで丸ごと渡る 後から secrets が増えても、黙って渡り続ける copyright (c) 2026 - PLAY, inc. … 渡るもの: この2件だけ APP_ID APP_PRIVATE_KEY 何の鍵を使うかが yml に明文で残る = レビューや監査で追える 28 / 80
  18. 配信は丸ごとコピーして、差分がある時だけ PR にする 最初の実装は、全案件の PR に謎の空行コミットを配信してしまった 最初の実装 ― 既存ファイルに切り貼り追記 今の実装

    ― 丸ごとコピー マーカーで挟んで、既存 instructions に追記 再実行のたびに空行が1行増える 専用ファイルを新設して丸ごと配信 加工しない = 壊れる余地がない 実際に全案件へ届いた diff: (空行だけの追加) <!-- COMMON_INCIDENT_ANDROID --> + 差分ゼロなら何もしない (静かに終わる) 変更がある時だけ、同期専用の PR 人の PR を汚さない 全 PR の push で起動し、PR ブランチに直接コミット → 案件側から修正依頼 copyright (c) 2026 - PLAY, inc. 29 / 80
  19. matrix が生む15ジョブ ― 1つ失敗したら、残りは? 1 2 3 4 # 呼び出し側:

    distribute-on-merge.yml(配信の起点) on: push: branches: [main] paths: ["COMMON_INCIDENT_ANDROID.md"] permissions: # GITHUB_TOKEN の権限 contents: read jobs: fanout: strategy: matrix: include: - { repo: 案件 A } # …計15行 uses: ./.github/workflows/_distribute-incidents.yml with: target_repo: ${{ matrix.repo }} secrets: # App の ID と秘密鍵を名前指定で渡す copyright (c) 2026 - PLAY, inc. ② の matrix(配信先リスト) 一覧の数だけジョブが 自動生成されて、同時に走る では、15ジョブのうち 1つが失敗したら、残りは? 30 / 80
  20. fail-fast ― 1案件のミスで全滅させない matrix の15ジョブ ― 3番目のリポで配信が失敗すると? fail-fast: true (デフォルト)

    ✓ ✓ ✕ - - - - - - - - - - - - ✓ ✓ 失敗した時点で、実行中・待機中の残りジョブが全てキャンセル(完了済みだけが残る) fail-fast: false (本システムで採用) ✓ ✓ ✕ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ 失敗はそのリポだけに隔離 ― 14リポは完走。失敗分だけ後から再配信すればよい 明示しないと true ― 1案件の設定ミスが、残りの案件への配信を道連れにする copyright (c) 2026 - PLAY, inc. 31 / 80
  21. fail-fast: false は、strategy に1行 # 呼び出し側: distribute-on-merge.yml jobs: fanout: strategy:

    fail-fast: false # ← この1行を足すだけ max-parallel: 4 matrix: include: - { repo: 案件 A, platform: android } uses: ./…/_distribute-incidents.yml 置き場所は matrix と同じ strategy: の直下 これで失敗は そのリポだけに隔離され、 残り14リポは完走する デフォルトのままにしない ― ファンアウトする matrix には必ず明示する copyright (c) 2026 - PLAY, inc. 32 / 80
  22. PAT ではなく App ― 人に紐づく鍵を仕組みに使わない 個人の PAT でも動く ― 違いは「鍵が誰に紐づいているか」

    個人 PAT ― 鍵が個人アカウントと紐付く 🔑 退職で線ごと消える 退職・失効の瞬間、 全案件の配信が突然止まる 👤 個人 GitHub App ― 鍵は org の持ち物 🔑 人が替わっても切れない 🏢 org 担当者が辞めても、 仕組みは動き続ける 権限は本人が触れる範囲すべて PR も個人名義になる 仕組みの鍵は、人ではなく組織に持たせる copyright (c) 2026 - PLAY, inc. 33 / 80
  23. Copilot instructions ― 配った知識を指摘に変える 1. Reusable Workflows copyright (c) 2026

    - PLAY, inc. 2. Copilot instructions 3. Claude 判定 4. 共通障害ファイル 34 / 80
  24. 共通障害ファイルは Copilot の instructions フォルダに入れる .github/instructions/ 01_XXX.instructions.md 02_XXX.instructions.md 03_XXX.instructions.md 04_XXX.instructions.md

    05_XXX.instructions.md New 06_COMMON_INCIDENT.instructions.md 入れるだけで、次の PR から共通障害ファイルが指摘の根拠になる copyright (c) 2026 - PLAY, inc. 35 / 80
  25. Copilot レビューのコンテキストとして入れるコツ 冒頭でお見せした、案件リポジトリの instructions フォルダ .github/instructions/ 01_XXX.instructions.md 02_XXX.instructions.md 03_XXX.instructions.md 04_XXX.instructions.md

    05_XXX.instructions.md その 1 ファイルの中身 ― 先頭に frontmatter --applyTo: "**" excludeAgent: "cloud-agent" --## 共通障害ファイル (以下、レビュー観点を Markdown で記述) applyTo: 効かせるファイルを glob で指定("**" = 全ファイル) excludeAgent: コーディング用途を除外しレビュー専用に 先頭の frontmatter で、どのファイルに・どの用途で効かせるかを制御できる copyright (c) 2026 - PLAY, inc. 36 / 80
  26. Copilot が共通障害ファイルを根拠に指摘してくる C Copilot AI review · いつもの案件の、いつもの PR で

    fallbackToDestructiveMigration() が追加されています。 社内共通障害ファイル INC-YYYY-NNNN「Room マイグレーション欠落」に 記録された既知障害のパターンです。Migration の実装を検討してください。 参照: .github/instructions/06_COMMON_INCIDENT.instructions.md 半年前の障害情報から PR に指摘が入る copyright (c) 2026 - PLAY, inc. 37 / 80
  27. 障害対応の直後、書くはいつも最後尾に沈む 1 復旧対応 いま燃えている火を消す 2 原因調査と修正 PR 再発させないための本丸 3 関係者への報告

    事業部・カスタマーサポート 4 遅れた分の開発 締切は待ってくれない 5 共通障害ファイルへの追記 …いつかやる(やらない) copyright (c) 2026 - PLAY, inc. 42 / 80
  28. 配る仕組みは動いていても、源泉が枯れていた 人 枯れた源泉 追記 0件 COMMON_INCIDENT_ANDROID.md 源泉が枯れて ループが回らない Copilot コードレビューの

    コンテキストに 共通障害ファイル 配信 (Reusable Workflows) 案件リポジトリ × 15 マージ 配る側は問題なく動いていた copyright (c) 2026 - PLAY, inc. 44 / 80
  29. 共通障害ファイルが「育つ」仕組み 1. Reusable Workflows copyright (c) 2026 - PLAY, inc.

    2. Copilot instructions 3. Claude 判定 4. 共通障害ファイル 49 / 80
  30. 共通障害ファイルを育てる主体を、人から AI へ 人 交代 案件リポジトリ内の開発 PR を 共通障害なら自動 PR

    Claude が解析 COMMON_INCIDENT_ANDROID.md 育てる主体を 人から AI へ Copilot コードレビューの コンテキストに copyright (c) 2026 - PLAY, inc. 共通障害ファイル 配信 (Reusable Workflows) 案件リポジトリ × 15 マージ 50 / 80
  31. 起点は案件リポジトリでマージされた PR ― closed + merged の2段構え # 各案件リポ: .github/workflows/detect-incident.yml

    on: pull_request: types: [closed] jobs: detect: if: github.event.pull_request.merged == true uses: your-org/your-repository /.github/workflows/_detect-incident.yml@main secrets: anthropic_api_key: ${{ secrets.… }} copyright (c) 2026 - PLAY, inc. 51 / 80
  32. Reusable Workflows で org を跨いで呼び出す 中央リポジトリ 案件リポジトリ × 15 呼び出し側

    ― detect-incident.yml PR マージを検知して、中央を呼ぶだけ uses: your-org/your-repository 定義側 ― _detect-incident.yml 呼び出し 共通障害かどうかの判定を実行 中央に置くのは2ファイルだけ /.github/workflows/ _detect-incident.yml(受け口) _detect-incident.yml@main detect_incident.py(判定本体) 同じ判定処理を15リポジトリに置くこともできる ― ただし直すたびに15箇所 ロジックは中央に1つ。呼び出し側が増えても、直すのは1ヶ所 copyright (c) 2026 - PLAY, inc. 52 / 80
  33. org を跨いで呼ぶための3つのポイント 1 同一 enterprise 配下であること 2 呼ばれるリポジトリ(中央リポジトリ)が internal 設定

    3 Actions の Access 設定で許可 enterprise の外からは呼び出せない 中央リポジトリの Settings > Actions > General > Access で許可 copyright (c) 2026 - PLAY, inc. 53 / 80
  34. ほとんどの PR は、障害と無関係 feat: 視聴履歴の一覧画面を追加 chore: ライブラリの依存を一括更新 fix: 番組詳細の文言修正 refactor:

    プレイヤー周りの整理 ✓ fix: 再生停止の不具合 ― 再発しうる障害パターン ← 載せるべきはこれだけ test: 課金フローのテスト追加 feat: お知らせバナーの出し分け 必要なのは書く仕組みではなく、仕分ける仕組み copyright (c) 2026 - PLAY, inc. 55 / 80
  35. 仕分ける仕組みは、中央の定義側の中 中央リポジトリ 案件リポジトリ × 15 定義側 ― _detect-incident.yml 呼び出し側 ―

    detect-incident.yml PR マージを検知して、 中央の定義側ワークフローを呼ぶ uses: your-org/your-repository /.github/workflows/ _detect-incident.yml@main copyright (c) 2026 - PLAY, inc. 呼び出し 共通障害かどうかの判定を実行 中央に新設するのは2ファイル: _detect-incident.yml(受け口) detect_incident.py(判定本体) 56 / 80
  36. 定義側の中身は「受け口」と「判定本体」の2ファイル 案件リポジトリから呼ばれる _detect-incident.yml ― 受け口 secrets を受け取り、判定スクリプトを起動する ― それだけ 起動

    ― PR 情報と鍵を渡す detect_incident.py ― 判定本体 1 マージされた PR の情報と、既存の共通障害ファイルを集める 2 Claude に「共通障害か?」を判定させる 3 共通障害なら、中央の共通障害ファイルへ候補 PR を作成 ワークフローは配線だけ ― 判定のロジックは Python で実行 copyright (c) 2026 - PLAY, inc. 57 / 80
  37. 判定は3段構え ― 共通障害だけを通すフィルター ① 除外条件 bot の PR・差分なしを機械的に捨てる ― Claude

    を呼ぶ前に ② 重複チェック 既存共通障害ファイルの全タイトル+冒頭をプロンプトに同梱し、既出なら止める ③ 重要度判定 影響の大きさ × 再現性 × 学習価値 ― 3条件の AND で足切り 通過するのは他の案件も踏み得る Android 障害だけ copyright (c) 2026 - PLAY, inc. 58 / 80
  38. Android 障害の典型パターンを、判定基準としてプロンプトに載せる # 判定プロンプト(Android 固有基準の抜粋) 採用しやすい例(Android 固有の判定補足): - Room /

    DataStore のマイグレーション漏れ - Activity / Fragment ライフサイクル起因のクラッシュ - ProGuard / R8 の keep ルール漏れ - 社内 SDK・自社基盤に固有の障害パターン - EncryptedSharedPreferences / Keystore の誤用 - WorkManager / Coroutine / Flow の誤用 迷ったら false ― 価値の高い事例だけを厳選 copyright (c) 2026 - PLAY, inc. 判定のものさしを Android の語彙で与える — 一般論の「重要そう」ではなく OS 固有の地雷リストで判定 — このリスト自体がチームの資産になる 59 / 80
  39. 最初のプロンプトは、Renovate の PR を障害だと言い張った ✗ 初期版 ✓ 改善版 ライブラリ一斉更新の PR

    を bot 除外+差分なしスキップを追加 「重大な非互換の兆候」と誤判定 重要度判定を 3条件 AND に強化 検証段階でノイズ PR が複数発生 ノイズはほぼゼロに 除外条件は机上で設計したものではなく、誤判定の失敗から生まれた copyright (c) 2026 - PLAY, inc. 60 / 80
  40. 判定結果は JSON で受け取り、 そのまま共通障害ファイルへ整形する # Claude からの出力例(Tool Use でスキーマを強制) {

    "is_common_incident": true, "severity": "high", "title": "Room マイグレーション欠落による…", "phenomenon": "アップデート後にデータが失われ得る", "cause": "Migration 未実装のまま schema 変更", "prevention": "Migration テストを CI に追加…", "detection": "fallbackToDestructive… の使用" 自由文で 返させない — 「JSON で返して」と頼まず Tool Use のスキーマで強制 — API が適合を保証するので パース失敗が構造的に消える } copyright (c) 2026 - PLAY, inc. 61 / 80
  41. ここからは ― ある日の普通の PRが 共通障害ファイルを育てるフロー Merged fix: 動画再生画面の復帰時クラッシュを修正 developer-a が

    develop へマージ · 案件 A リポジトリ Fragment の onViewCreated で binding 参照が null になるケースを修正 開発者は何も特別なことをしない ― いつも通りマージするだけ copyright (c) 2026 - PLAY, inc. 62 / 80
  42. マージの数分後 ― 共通障害ファイルへの PR が自動で立つ Open chore: 共通障害を追加 ― Fragment

    binding 参照 your-sync-app[bot] が your-org/your-repository に作成 元 PR: 案件 A の障害修正 PR ― Claude 判定: is_common_incident = true 共通障害ファイルが自分で育った瞬間 copyright (c) 2026 - PLAY, inc. 63 / 80
  43. 現象・原因・再発防止策まで、構造化されて届く ### [INC-YYYY-NNNN]【ライフサイクル】 Fragment の binding 参照 重大度: high 現象:

    バックグラウンド復帰時に NPE でクラッシュ 原因: onDestroyView 後も binding を保持し、破棄済み View を参照 再発防止策: viewLifecycleOwner スコープで参照する 検出方法: onViewCreated 外での binding 直接参照 元事例: 案件 A の障害修正 PR copyright (c) 2026 - PLAY, inc. 64 / 80
  44. 共通障害ファイルへのマージが、 15リポジトリへの配信を起動する ✓ distribute / 案件 A 34s ✓ distribute

    / 案件 B 31s ✓ distribute / 案件 C 36s ✓ distribute / 案件 D 29s … ほか 11 リポジトリ、すべて成功 instructions が15ヶ所で同時に更新される copyright (c) 2026 - PLAY, inc. 65 / 80
  45. 後日、別の案件の PR で ― ループが一周した C Copilot AI review ·

    案件 B の新規画面 PR で lateinit var binding が Fragment で宣言されています。 社内共通障害ファイル INC-YYYY-NNNN(Fragment の binding 参照)の再発パターンです。 viewLifecycleOwner スコープでの参照に変更を検討してください。 参照: .github/instructions/06_COMMON_INCIDENT.instructions.md 案件 A の失敗が、案件 B の障害を未然に止めた copyright (c) 2026 - PLAY, inc. 66 / 80
  46. AI に読ませる量を増やさない 1 instructions は短い宣言文が最も効く 2 エントリは要点だけ ― 現象・原因は OS

    の一般語彙で1〜2文 3 膨張は前提 ― 将来は原本と配信版を分離する 長文を注入するほど1件あたりの指示の効きは薄まっていく 画面名・機能名を削るから、他案件がそのまま照合できる 不変 ID(INC-)と重大度を今から記録済み ― 配信版を重大度で絞り込む準備 copyright (c) 2026 - PLAY, inc. 70 / 80
  47. 共通障害ファイルの中身 1. Reusable Workflows copyright (c) 2026 - PLAY, inc.

    2. Copilot instructions 3. Claude 判定 4. 共通障害ファイル 71 / 80
  48. レビュー精度を高める ― エントリは4部構成 現象 どのようなバグか(ユーザーレベル) 原因 なぜ起きたか(コードレベル) 再発防止策 どう書けば防げるか 検出方法

    レビューで何を見れば気づけるか 「検出方法」があるから、AI レビューの根拠として機能する copyright (c) 2026 - PLAY, inc. 72 / 80
  49. 例 Room マイグレーション欠落 現象: アップデート後の初回起動でローカルデータが失われ得る 原因: Migration 未実装のまま schema 変更。

    fallbackToDestructiveMigration() が本番でテーブルを再生成 再発防止策: - fallbackToDestructiveMigration() の使用を原則禁止 検出方法: version = の変更が Migration 追加なしで 入っていたら要指摘 copyright (c) 2026 - PLAY, inc. 73 / 80
  50. うちの案件の話を削ぎ、Android の話だけを残す プロジェクト固有の文脈は書かない 画面名・機能名は消し、API とライフサイクルの言葉に置き換える 再現条件を Android の一般語彙で書く 「targetSdk 34

    以上で」「プロセス再生成時に」― 他案件がそのまま照合できる 対策はコードで示す スローガンではなく、参照できる修正パターンまで書く copyright (c) 2026 - PLAY, inc. 74 / 80
  51. 導入後 ― 障害情報は、自動で集まり続けている Claude が判定・起票 自動で集まる 共通障害なら自動 PR マージ差分を解析 COMMON_INCIDENT_ANDROID.md

    今日も 自動で回っている 案件リポジトリ ×15 日々の PR と障害 copyright (c) 2026 - PLAY, inc. 共通障害ファイル Reusable Workflows 各リポへ配信 配って防ぐ 75 / 80