diagnosing-ci-and-merge-bottlenecks について
エンジニアリングチームや自律型エージェント向けに、CI とマージのボトルネックを診断するスキルです。名前付き MCP ツールで PR のライフサイクル、ワークフローの健全性、テスト失敗を分析し、集計データの範囲と制約も明示します。
主な機能
- 01オープン中と最近クローズした PR を確認
- 02CI ワークフローの成功率と所要時間を比較
- 03個別 PR のライフサイクルを追跡
- 04テスト健全性キューを確認
- 05ワークフロー、PR、ライフサイクル分析を連携
- 06データの上限、遅延、欠落を考慮
活用シーン
- 01遅い、または不安定な CI ワークフローを発見
- 02CI が失敗または保留中のオープン PR を特定
- 03PR のライフサイクルで遅延箇所を特定
- 04隔離候補テストと影響を評価
MCP 対応
`pull-requests`、`workflow-health`、`pr-lifecycle`、テスト健全性キューなど、名前付き MCP ツールを通じて GitHub のエンジニアリング分析データを読み取ります。SQL を書かず、これらのツールを呼び出して調査します。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ posthog/ skills --skill diagnosing-ci-and-merge-bottlenecksインストール後、Claude Code で/diagnosing-ci-and-merge-bottlenecksを入力して読み込まれたか確認します。
詳細
CI とマージのボトルネックを診断する
エンジニアリング分析では、プルリクエストをプロダクト分析におけるユーザーのように扱います。PR はパイプライン
(opened → CI → review → merged → deployed)を進み、どこで遅くなるかを特定するのが目的です。表層は名前付きの
MCP ツールです。SQL を書くのではなく、ツールを呼び出します。PostHog/posthog で自社利用しており、同じツールは
自律型エージェント(例:PostHog Desktop)が自らの PR について推論する際にも利用できます。対象はパイプライン全体の
健全性です。失敗したテストや赤い実行を個別に調べて結論を出すには、investigating-ci-failures スキルに切り替えてください。
ツール
pull-requests— PR 関連の主要ツールです。オープン中の PR と、date_from(デフォルトは-30d)以降にマージまたはクローズされた PR を、新しい順に表示します。各行には、author(ネストされたオブジェクト:handle、display_name、is_bot)、repo(ネストされたオブジェクト:owner、name)、state、is_draft、labels、open_to_merge_seconds、ready_to_merge_seconds、 および head-SHA の結合から得られるciの集計(runs/passing/failing/pending)が含まれます。PR 単位の質問の多くに答えられます。CI が失敗中または保留中の PR、最も長くオープン状態が続いている PR、作成者別またはリポジトリ別のトリアージ、マージまでの時間の統計(返されたマージ済みの行を自分で集計し、平均ではなく中央値と p95 を使ってください。ドラフト期間を除外するため、null でなければready_to_merge_secondsを優先してください)。workflow-health— 期間(date_from/date_to、デフォルトは過去 24 時間)における、ワークフローごとの CI の健全性です。run_count、success_rate、p50_seconds、p95_seconds、last_failure_atを返します。「CI は速くなっているか、遅くなっているか」「遅い、または不安定なボトルネックになっているワークフローはどれか」といった質問に答えられます。組み込みのトレンド機能はありません。隣接する 2 つの期間で呼び出し、比較してください。success_rateの対象は、成功した実行、または明確な失敗(failure、timed_out、startup_failure、stale)で終了した実行です。スキップ、キャンセル、ニュートラル、アクションが必要な実行は除外されます。p50_seconds/p95_secondsの対象は成功した実行のみです。キャンセルや失敗は早期に終了し、所要時間のトレンドを歪めるためです。対象となる実行がない期間では、いずれもnullになります。2 つの期間を比較する前に null を確認してください(ある期間には実行があり、もう一方にはない場合があります)。run_scope=pull_requestを指定すると、PR に関連付けられた実行に絞り込まれ、master/main は除外されます(同一リポジトリ内の PR のみが対象です。フォークからの実行には PR の関連付けがありません)。pr-lifecycle— 単一の PR のタイムラインです。ヘッダーと、時系列に並んだイベントを返します。オープン、レビュー可能への移行、ドラフトへの変更(issue-events テーブルが同期されている場合)、ワークフロー実行ごとの CI 開始/終了のペア(複数のワークフローがあるリポジトリでは多数のイベントが時間順に混在します)、その後のマージ/クローズが含まれます。「PR N はどこで停滞しているか」という質問に答えられます。metric_qualityはpartialです(レビューやコメントのイベントはありません)。engineering-analytics-flaky-tests— テストごとの CI スパンをもとに、期間(date_fromのデフォルトは-7d、最大 30 日)のアクティブなテスト健全性キューを返します。証拠は CI 実行ごとにカウントされ、スパン単位や実行試行単位ではカウントされません。classificationがconfirmed_flakeとなるのは、証拠によって非決定性が確認された場合のみです(same_commit_recovery_run_count > 0:同じコミットが同じマトリックスジョブでテストに失敗し、その後成功しています。「失敗したジョブを再実行」の試行で成功した場合、またはジョブ内の再試行で成功した場合が該当します。FOSS に対する EE のように別のレッグで成功しても、復旧とはみなされません)。quarantinedは、マスクされた状態で許容された失敗が記録されたことを意味します。suspected_regressionは失敗のみが記録されたことを意味します。これは証拠がないということであり、実際に問題がある証拠ではありません。同一コミットでの復旧、隔離された状態での失敗、master/main での失敗、またはmin_failed_prs件以上の異なる PR での失敗(failed_pr_count)のいずれかを満たすテストが対象となります。「このテストの失敗によって、どのようなコストが発生しているか」という質問に答え、隔離候補を選ぶのに役立ちます。「不安定なテストはどれか」という質問には答えられません。このキューが対象とするのは、メインの Backend pytest スイートと Frontend Jest スイートのみです。また、復旧の証拠が得られるのは、誰かが失敗したジョブを再実行した場合(または pytest のテストに@pytest.mark.flaky(reruns=N)を手動で指定した場合)に限られます。件数は絶対的なシグナルであり、割合ではありません。成功した実行のほとんどは出力されないため、信頼できる分母がありません。CI のセットアップ障害では、その試行の失敗だけでなく、すべての試行が除外されます。テストでエラーが発生したジョブが 3 つ以上、または担当チームが 3 つ以上ある実行試行、あるいは失敗またはエラーになったテストが 100 件以上あるジョブ試行が対象です。 これほど広範囲に及ぶ実際の問題も除外されるため、スイート全体またはジョブ全体が失敗した場合は、空のキューを健全と判断せず、workflow-healthを確認してください。engineering-analytics-sources:チームに接続されている GitHub のソースとリポジトリです。ソースまたはリポジトリが複数ある場合は、最初にこれを呼び出し、選択したエントリのsource_idとrepoをpull-requests、workflow-health、pr-lifecycle、team-ci-healthに渡してください。source_idだけを渡すと、選択したリポジトリではなく、そのソースのデフォルトのリポジトリが読み込まれます。ソースとリポジトリがそれぞれ1つの場合、ツールはそれをデフォルトで使用します。
マージまでの時間を集計するツールも「件数」ツールもありません。pull-requests から(滞留/失敗件数やマージ時間のパーセンタイルを)算出してください。
すべての回答に反映する必要がある注意点
これらは現在のスナップショットデータにおける構造的な制限です。隠さず、明記してください。
open_to_merge_secondsは概算値です。 ドラフト の時間と レビュー可能になってから の時間を1つの数値にまとめています。「マージまでのオープン時間」として報告し、「サイクルタイム」や「レビュー時間」とは呼ばないでください。長期間ドラフトの状態にあったため数値が大きくなっている場合は、その旨を明記してください。ready_to_merge_secondsは、より正確な対応指標です。merged_atから、最後に観測されたレビュー可能状態への遷移時点を差し引いた値です(ドラフト/レビュー可能の切り替えのうち、最後のものだけを使用します)。ドラフト化されていないことが確実なマージ済み PR については、created_atから差し引きます。nullは「観測されていない」を意味します(PR の全期間が同期済みの Issue イベント期間内にないか、テーブルが同期されていません)。ゼロを意味するものではありません。そのため、集計対象はnullでない行だけにし、観測可能だった件数を明記してください。- CI のステータスは古い可能性があります。 CI ソースはウォーターマークに基づいて同期され、新しい実行が追加された後に完了した実行は再取得されません(
workflow_runWebhook が提供されるまで)。pendingの件数は未確定として扱い、確定した失敗とは見なさないでください。結論ではなく、まずステータスを示してください。 - PR の CI は、ヘッド SHA による結合結果だけです。
ciの集計は、最新コミットの実行結果だけを反映しています。PR とそのチェックを結び付ける方法はほかにありません。 - レビューの読み取りは意図的に保留されています。 GitHub の
reviewsエンドポイントは、レビューの送信とそのタイムスタンプを同期しますが、読み取りは必要とするウェッジツールが使われるまで保留されます。レビューが見当たらないことから、レビューの動向を推測しないでください。同じ理由で、pr-lifecycleの状態はpartialです。 - デプロイ指標は
engineering-analytics-doraにあります。GitHub のデプロイメントテーブルが同期されている場合に利用できます(deploy_data_available)。その変更失敗率と復旧時間の各フィールドは、デプロイステータスに基づく代理指標であり、インシデントとの関連付けはありません。実際の DORA の定義としてではなく、正確なフィールド名で報告してください。 pull-requestsの出力にはボットとドラフトが含まれますが、通常は除外します。 スループットやマージ時間に関する質問では、authorの下にネストされており行レベルのフィールドではないauthor.is_botとis_draftで除外してください。ボットの影響に関する質問では含めてください。pull-requestsが返すページには上限があります。 最新順の1,000行で、固定のサーバー側上限です。レスポンスのlimitにも反映され、どのパラメーターを指定しても増やせません。truncatedがtrueの場合、算出したパーセンタイルや件数は全期間ではなく、最新のページだけを対象にしています。その旨を明記してから、実データ全体が収まるように対象を絞ってください。authorで1つのハンドルに、source_id/repoで1つのリポジトリに絞り込み、date_fromで期間を短縮できます。
ツールの選び方
| 質問 | ツール | 方法 |
|---|---|---|
| CI は遅くなっていますか? 最も時間がかかっているワークフローはどれですか? | workflow-health | 隣接する2つの期間(例:date_from=-14d、続いて date_from=-28d date_to=-14d)で呼び出し、ワークフローごとに p50_seconds と p95_seconds を比較します。中央値を中心に説明しますが、p95 も必ず別途確認してください。両者は独立して変動します。 |
| オープン中の PR のうち、CI が失敗または保留になっているのはどれですか? | pull-requests | ci.failing > 0 または ci.pending > 0 の行を残します。pending は未確定(または古い状態)を意味し、確定した失敗ではありません。 |
| 最も長くオープン状態で止まっている PR はどれですか? | pull-requests | state = open で、is_draft ではなく、author.is_bot でもないものを残し、created_at の昇順(古いものが先)で並べ替えます。 |
| PR のマージにはどのくらいかかっていますか? 作成者ごとでは? | pull-requests | マージ済みの行(merged_at が設定され、ボットでも下書きでもないもの)について、値が null でない ready_to_merge_seconds を集計します(なければ概算値としてラベルを付けた open_to_merge_seconds を使用します)。中央値と p95 を算出します。author.handle ごとにグループ化するのは コホートの状況把握のためであり、順位付けではありません(開発者ごとの監視は明確に対象外です)。2つの date_from 期間で呼び出し、傾向を確認します。 |
| PR N はどこで止まっていますか? | pr-lifecycle | イベントを時系列順に確認します。opened → ready_for_review(遷移イベントがある場合は下書きの時間)、CI の期間(最初の開始から最後の終了まで。ワークフローごとに1組)、last CI finished → merged を見ます。最も長い空白がボトルネックです。CI がすぐ終わっているのに ready→merge が長い場合は、レビューまたは待機時間が原因と考えられますが、partial データではまだ内訳を示せないことを伝えてください。 |
| 失敗するテストによる損失はどのくらいですか? 何を隔離すべきですか? | engineering-analytics-flaky-tests | デフォルトの期間は -7d です。行は影響範囲(master での失敗、次に影響を受けた PR の数)に基づいてすでにランク付けされています。件数を報告し、割合は報告しないでください。「不安定かどうか」については、confirmed_flake の行だけが実証済みです(同じマトリックスジョブ内で、1つのコミットが失敗と成功の両方を記録していること。再実行で成功した場合、またはジョブ内の再試行で復旧した場合です)。 |
価値の高い調査フロー
人が調査する方法にならいます。集計されたシグナル → 確認 → 具体的な PR。
workflow-health (find the slow/flaky long-pole workflow)
→ pull-requests (confirm it's dragging merge time; list the affected PRs)
→ pr-lifecycle (open a representative stuck PR and show the gap)
「CI の中央値が上昇したのは、e2e-playwright の p95 が2倍になったためです。このワークフローが PR #1234 の最大のボトルネックで、その PR はマージまでの間に CI で47分を費やしました。」
出力の要件
- まず結論を1行で示し、その後に根拠となる数値を示してください。
- 粗い/部分的/古い可能性があるという注意点は、その区別が重要な場合は必ず添えてください。
- 複数の期間やワークフローを比較する場合は、文章より簡潔な表を使ってください。中央値とp95を並べて報告し、 1つの「平均」にまとめないでください。
してはいけないこと
open_to_merge_secondsをサイクルタイムやレビュー時間と呼ばないでください。これはオープンからマージまでの粗い指標です。 サイクルタイムの値はready_to_merge_secondsで、nullでない場合に限ります。pending > 0の場合、CIの件数を確定した失敗として報告しないでください。未確定または古い可能性があります。- レビューや承認を推測しないでください。レビューの読み取りは、ウェッジツールで必要になるまで延期されます。チェックごとの件数も推測しないでください。デプロイは推測ではなく
engineering-analytics-doraから取得します。 - 作成者ごとの分類をリーダーボードにしないでください。これは滞留中の作業を見つけるためのものであり、人を順位付けするためのものではありません。
- 生のPR内容や差分を取得するために、これらのツールを使わないでください。これらのツールが提供するのはパイプラインのシグナルであり、PRのスレッドではありません。
回答の保存
これらのツールは一時的な読み取り用であり、インサイトとして保存したり、購読したりすることはできません。同じ数値を保存済みインサイト、ダッシュボードタイル、またはスケジュール配信のメール/Slackで利用したい場合は、
turning-engineering-analytics-into-insights スキルに切り替えてください。基盤となるウェアハウステーブル
(engineering-analytics-sources から取得したプレフィックスを使う <prefix>github_pull_requests / <prefix>github_workflow_runs)はHogQLで直接クエリでき、このスキルには、厳選された列の意味と、
インサイト作成/購読作成のワークフローが含まれています。
DORA環境のデフォルトには、本番環境としてマークされた、または本番環境と名付けられたすべての永続的なリージョンが含まれます。検証済みの正確な対象範囲は selected_environments を確認してください。DRFは、一時的な環境も含め、明示的なフィルターを実在する名前と照合して検証します。有効な名前はトリミングして重複を除去し、空白の名前や不明な名前は400レスポンスで拒否します。デフォルトを使う場合は、フィルターを省略してください。リージョンごとのデプロイはそれぞれ個別にカウントされます。リードタイムでは、選択した環境のいずれかへの最初のデプロイが成功した時点で、各PRを1回だけカウントします。