debugging-ci-failures について
PostHog の CI 失敗をトリアージするエンジニアリング向けスキルです。集約インサイトと個別実行の確認で失敗を分類し、ログを調べ、確認済みの不安定なテストなどを関連スキルに引き継ぎます。
主な機能
- 01CI 失敗の集約ダイジェスト
- 02失敗分類のガイダンス
- 03読み取り専用の実行確認
- 04ログ抽出の手順
- 05専門スキルへの引き継ぎ
活用シーン
- 01複数の CI 実行にまたがる失敗のトリアージ
- 02特定の GitHub Actions 実行の調査
- 03失敗が広範かブランチ固有かの判定
MCP 対応
失敗したジョブのログや構造化されたテスト失敗情報の取得に PostHog MCP ツールを参照します。テストの不安定さの調査は trunk MCP サーバーのツールに引き継ぎます。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ posthog/ posthog --skill debugging-ci-failuresインストール後、Claude Code で/debugging-ci-failuresを入力して読み込まれたか確認します。
同梱ファイルreferences/master-red-incident.mdreferences/master-red-workflow-setup.md
詳細
PostHog CI の失敗をデバッグする
CI への変更を提案する前に、そのアイデアについてすでに試されたことを確認してください。そこには、何が測定されたか、そしてなぜ良さそうに思えた一部の変更が元に戻されたり却下されたりしたかが記録されています。
最初の意味のある失敗を見つけ、それを分類し、適切な場合は最小限の有用なケースをローカルで再現し、結果を報告してください。ユーザーが明示的に求めない限り、公開されて見える操作や取り消せない操作は避けてください。
対話的な調査では、hogli ci:insights のダイジェストから始めてください。これは実行とブランチをまたいで集計するため、gh では低コストにはできないことです。これにより、失敗がトランク由来の可能性が高いのか、ゲートのみなのか、少数のブランチに限定されているのかがわかります。gh は 1 回の実行の現在の状態と帰属に対して権威があります。ダイジェストは_何を_調べるかを決めるために使い、gh はそれが_誰の_失敗なのか、そして特定の実行で正確に何が失敗したのかを確認するために使ってください。
無人で実行される Master-red ワークフローは例外です。そのリファレンスに従ってください。これはタスクサンドボックスで動作する最初のステップを定義しています。
このスキルはトリアージと分類を行います。失敗がフレーキーであると確認されたら、fixing-flaky-tests スキルに引き継いでください。そのスキルがローカルでの再現、根本原因の修正、N 回実行の検証を担います。「誰が master を壊したか」、つまり原因となったコミットとそれを修正したコミットについては、investigating-ci-failures スキルに引き継いでください。そのスキルが green/red の境界分析を担います。集約されたパイプラインの健全性(CI が遅くなっているか、どのワークフローがボトルネックか、PR がマージされるまでにどれくらいかかるか)については、diagnosing-ci-and-merge-bottlenecks を読んでください。どちらも products/engineering_analytics/skills/ 配下の製品スキルであり、ここから呼び出すことはできません。そのパスにある SKILL.md を読んでください。
まずプラットフォームの障害を除外する
GitHub Actions は十分な頻度でダウンするため、ログを読む前に確認すべきです。プラットフォームのインシデントが起きていると、他のあらゆるシグナルが症状になります。確認には 2 回のページ読み込みしかかかりません。GitHub は https://www.githubstatus.com/、ランナーは https://status.depot.dev/ です。失敗が広範囲に及ぶときは常に確認してください。たとえば複数のワークフローが同時に失敗する、多数の実行がまとめて失敗する、Checkout より前にジョブが落ちる、無関係な PR をまたいで何かが赤くなる、といった場合です。
障害は障害として報告し、コンポーネントを明示し、再実行の推奨をやめてください。
安全ルール
現在の会話で明示的な承認がない限り、次のいずれも行わないでください。
- GitHub Actions の実行を再実行またはキャンセルする、または Depot CI の実行を再試行、再実行、キャンセルする。
- 任意の CLI、MCP、API ツールを通じて GitHub のコメント、PR レビュー、issue コメントを投稿する。
- コミットをプッシュする、force-push する、ブランチの名前を変更する、またはブランチを削除する。
.github/workflows/ファイルを編集する(CI インフラの変更には人によるレビューが必要です)。- PR をマージ、クローズ、または再オープンする。
- スナップショットを受け入れるまたは更新する。
読み取り専用の gh 呼び出しと読み取り専用の GitHub ツールは問題ありません。ローカルの Git 状態を変更する必要がある場合は、それがタスクに必要であり、無関係な作業を上書きしないことを確認してください。
ワークフロー
1. 対話的な調査は CI インサイトから始める
hogli ci:insights は PostHog 自身のエンジニアリング分析を読み取ります。これは単一の実行では見えない、実行をまたいだ失敗履歴です。生の gh ログの発掘調査を行う前に、これを参照してください。
hogli ci:insights # digest for the current repo + branch
hogli ci:insights search "<error or test name>" # match a specific failure
hogli ci:insights view <ref> # one failure in full
hogli ci:insights view <ref> --logs # ...plus the failing log lines
- 広い質問(「CI は赤いか?」「今日 master はグリーンか?」「今壊れているものは何か?」): 引数なしのダイジェストが直接答えます。デフォルトブランチの判定(最新の実行で失敗しているワークフローがいくつあり、どれか)、状態ごとにグループ化された現在の失敗、現時点でトランク上で赤いジョブ、デフォルトブランチの失敗のグループ化されたフィード、および自分のブランチが属する PR を提供します。対象の PR や実行がそもそも不要なこともよくあります。ダイジェストから報告してください。
- 特定の失敗: ログを読む前に
search "<error>"を実行して一致させ、次にダイジェストまたは search が出力した行に対してview <ref>を実行します。--logsはその失敗の最新実行から間引かれた失敗行を出力し、通常はghに触れずに分類するのに十分です。
各行の state はトリアージの順位として読んでください:
| 状態 | 意味 |
|---|---|
breaking_master | デフォルトブランチで失敗しており、そのジョブの最新実行がまだ赤い |
blocking_merge_queue | ウィンドウ内のマージキューのゲートブランチでのみ失敗した |
novel_burst | 1 日以内に新規発生し、すでにブランチ間で広がっているが、まだトランク上ではない |
potentially_resolved | トランクに到達したが、そのジョブの最新実行は再びグリーンになった |
flaky | 1 日以上にわたり 2 つ以上のブランチで散発的に発生している |
pr_only | ブランチの広がりが限定的。ジョブのステータスが欠落しているか、失敗行より古い可能性がある |
potentially_resolved はヒントであり、結論ではありません。失敗をすでに修正済みとして報告する前に、実行データから確認してください。
blocking_merge_queue は、ウィンドウ内でゲートの失敗が発生したことを証明するものであり、それが今もなおランディングをブロックしていることを証明するものではありません。アクティブであると報告する前に、gh で現在のキューの実行を確認してください。同様に、失敗を PR に割り当てる前に、現在の実行から pr_only を確認してください。これはジョブのステータスが欠落しているか古い場合のフォールバックでもあります。
報告内容に必ず含めるべき注意点:
- 失敗のグループ化は pytest のみです。Jest、Playwright、cargo の失敗は、ダイジェストのグループ化された master 失敗セクションにのみ現れ、ref を持つ行としては決して現れません。
- すべての数値は絶対値であり、決して割合ではありません。成功した実行はテストレベルのデータに含まれないため、引用できる分母がありません。ジョブの結論にはグリーンも記録されています。そこから実際の割合を求める方法は、以下のベースレートのセクションで説明します。
- 実行の結論は、GitHub の
workflow_runWebhook が確定するまで遅れることがあるため、インシデントの最中には特定の実行をghで確認してください。
このマシンで誰もサインインしていない場合、hogli ci:insights は 78 で終了します。終了コード 78 は「CI インサイトが利用できない」として扱い、以下の gh ベースの検査にフォールバックしてください。その後、ユーザーに hogli posthog:login を一度実行できると伝えてください。これはブラウザーを開き、API キーは不要です。自分で実行しないでください。あなたには見えない同意画面を待ちます。見つけた内容は安全性のルールに従って提示してください。修正を自動適用しないでください。
2. 失敗した実行を見つける(特定の失敗について)
対象は次の順序で特定します。
- ユーザーが PR 番号、実行 ID、チェック名、またはブランチを指定した場合は、それを使用します。
- そうでない場合は、現在のブランチから
gh pr view --json number,headRefName,statusCheckRollupで推測します。 - どちらもうまくいかない場合は、ユーザーに PR URL または実行 ID を尋ねます。推測してはいけません。
マージキューからキックされた PR は例外です。その PR 自身のチェックは
誤った対象です。 Trunk はキューに入った各 PR を trunk-merge/pr-<n>/<uuid>
ブランチでテストします。このブランチは master に加えて、影響を受けるターゲットが
自身と重複する、先にキューされたすべての PR を含みます。レーンスクリプトは
意図的にターゲットを過剰に報告するため、実際にはそれがキューの大半です。したがって:
- 失敗した実行はそのブランチ上にあり、PR のヘッド SHA 上では決してありません。
gh pr checksではなくtrunk merge status <n>(/merging-prsのステップ 4)から取得します。Trunk はここでチェック実行を公開しません。 ブランチは一時的なものです。実行とそのログは GitHub に残り、 ウェアハウスはそのhead_branchの下にジョブを保持します(investigating-ci-failuresリファレンスのクエリ 8)。 例外は、CI_BACKEND_DEPOT_MERGE_QUEUE_PERCENTがバッチを Depot CI に渡す場合のバックエンド CI です。その場合バックエンドテストは Depot 上で実行され、Django Tests Passチェックがその実行にリンクします。 - PR 自身のチェックはグリーンでも、失敗したジョブがスキップされているか 絞り込まれていることがあります。PR ではパスフィルターはその差分のみを参照し、Django スイートは 選択されたサブセットを実行します。キューブランチでは差分は引き継がれたすべての PR のものであり、 完全なマトリックスが常に実行されます。ドキュメントのみの PR が、自身の CI では決して実行されなかったジョブによってキックされることがあります。
- ブランチの名前は 1 つの PR を指しますが、多くの PR を保持しています。そのブランチでの失敗は、 原因となった変更を見つけるまではその PR に対する証拠にはなりません。ブランチの他の マージコミットが最初の容疑者です。
…-bisectionブランチは「他のマージコミットが最初の容疑者」の例外です。Trunk は バッチが失敗した後にこれを作成し、master とその 1 つの PR のみを保持します。テスト PR の本文は 基にしている master SHA を示します。その SHA での master の実行が同じテストに合格していれば、 その失敗は環境依存のレース(fixing-flaky-testsのステップ 1)であり、この PR のものではありません。- ダイジェストでは、これは
blocking_merge_queue状態です。
3. CI レポートのコメントを読む(PR の場合)
ログを読む前に、共有された CI レポートのコメントを読んでください。これは独立した CI シグナルと勧告を多くのセクションにまとめたものです。
GitHub の折りたたまれた表示ではなく、生のコメント全体を読んでください。このコマンドは、 PR に多くのコメントがある場合でもそれを見つけられます:
gh api --paginate "repos/<owner>/<repo>/issues/<pr>/comments?per_page=100" \
--jq '.[] | select(.user.login == "github-actions[bot]" and (.body | startswith(""))) | .body'
未知のセクションも含め、すべての ci-report:section ブロックを確認してください。その
タイトル、ステータス、サマリー、リンクを記録します。最初の fail セクションで止まったり、
コメントの見出しを全体の判定として扱ったりしないでください。
failは手がかりとして扱い、現在のジョブと照合してください。alertとwarnはブロッキングではない指摘として扱ってください。その詳細を確認し、 記載されたアクションに従ってください。ただし、そのジョブが失敗していない限り、どちらも 失敗したジョブと呼んではいけません。okとinfoはテスト結果ではありません。- レポートが見つからない場合は、レポーターが実行しなかったか、書き込めなかったことを 意味します。これは PR が健全であることを証明するものではありません。
レポートはサマリーです。head SHA や run リンクのないセクションは古い可能性があります。 現在のジョブと照合して確認してください。現在のログと矛盾する場合は、その不一致を報告し、 原因の特定にはログを使用してください。
読み取り専用で確認します:
gh pr checks <pr>
gh pr view <pr> --json statusCheckRollup
gh run view <run-id> --json jobs,conclusion,name,workflowName,url
gh run view <run-id> --log-failed
--log-failed に失敗したコマンドや十分な周辺出力がない場合にのみ、ジョブの完全なログを
使用してください:
gh run view <run-id> --log --job <job-id>
run id を指定すると、engineering-analytics-run-failure-logs MCP ツールは、失敗した
すべてのジョブのエラー領域を元の行番号付きで、すでに間引かれた状態で返します。ジョブ一覧の
取得とログのダウンロードの代わりに 1 回の呼び出しで済み、テストが実行される前にジョブが
終了した場合でも機能します。Logs の保持期間によって制限されるため、古い run については
gh にフォールバックしてください。run id の代わりに PR 番号を指定すると、
engineering-analytics-ci-failure-logs がその PR がプッシュしたすべての run に対して同じ
ことを行うため、以前のプッシュの失敗も残っています。
分類する前に、以下を抽出してください:
- ワークフロー名またはファイル名。例:
.github/workflows/ci-backend.yml。 - ジョブ名。例:
backend-tests (4/10)。 - ステップ名。例:
Run pytest。 - 失敗したコマンドと、最小限の有用な出力の抜粋。
ログをスキャンするときは、FAIL、Error、error:、assert、Traceback、exit code、
##[error] を検索してください。run の結論を説明する最初の失敗ステップで止めてください。
抜粋は 40 行未満に保ってください。
テストジョブの失敗については、trunk MCP サーバーの investigate-ci-failure ツールが
ログスキャンを省略できる近道です。run URL
(https://github.com/PostHog/posthog/actions/runs/<run-id>) を渡すと、CI が Trunk Flaky
Tests にアップロードした結果から、失敗したテストの詳細(名前、エラーメッセージ、
stdout/stderr)を構造化して返します。隔離された既知の flaky テストはすでに除外されて
います。これは実行されてアップロードされたものだけを対象とします。テストの前に終了した
ジョブ(build、setup、lint)については、
engineering-analytics-run-failure-logs または gh run view --log を使用してください。
/mcp → trunk(ブラウザ OAuth)で一度認証します。ヘッドレス環境では代わりに、
.mcp.json のサーバーエントリに TRUNK_API_TOKEN 組織トークンを使った
Authorization: Bearer ヘッダーを追加します。1 つのテストの flaky 履歴を詳しく調べるには、
search-test と fix-flaky-test ツールを扱う fixing-flaky-tests に引き継いでください。
Depot CI で実行されたバックエンドテスト
PR はそのバックエンドテストを Depot CI にルーティングできます。
その場合、GitHub Actions の実行は中継のみを担います。Django Tests Pass は "Backend tests on Depot CI concluded failure" で失敗し、GitHub の実行ログにはそれ以上の情報は表示されません。
そのジョブの再実行は読み取り専用ではありません。失敗した Depot ジョブとキャンセルされた Depot ジョブを再試行し、新しい判定を報告するため、CI を再実行しないというルールがこれにも適用されます。
Depot がジョブのタイムアウトを過ぎても実行中と表示している実行はスタックしています。再実行はそれを待機するため、まず depot ci cancel でキャンセルしてください。
Relay the Depot verdict ステップのログには、Depot の実行 URL、失敗した各ステップとそのログ行、そして PR を GitHub Actions に戻すラベルが出力されます。
Depot からの失敗の詳細は、flox 環境がインストールする depot CLI で確認してください。
中継ログにある Depot の実行 URL から得られる 2 つの id を指定して、depot ci diagnose --org <org> --workflow <workflow> を実行します。
ログ、アーティファクト、テスト結果については、depot-ci スキルを読み込んでください。
その references/posthog-check-run-semantics.md は、中継ログがない場合にコミットのチェック実行から Depot の id を取得します。
depot コマンドの認証に失敗する場合は、まず DEPOT_TOKEN を確認してください。これは保存されたログインを上書きするため、誤った値だとすべてのコマンドが失敗します。
これがない場合は、ユーザーに ! depot login --clear の実行を依頼してください。
自分で実行しないでください。ブラウザでのサインインを待機します。
ユーザーが Depot 組織へのアクセス権を持っていない場合は、代わりに中継ログの Depot なしの再試行オプションを報告してください。
分類
| ログに見られるシグナル | クラス | 最初のアクション |
|---|---|---|
コミットされたテストファイル内の AssertionError、テストの差分、FAILED test_... | コードリグレッション | hogli test <path>::<test> で再現する |
ここでは失敗したが、master または同じ PR での再実行では成功したテスト | フレーキーテスト | master の履歴と照合する。修正には fixing-flaky-tests を使用する |
ruff、oxlint、stylelint、markdownlint、prettier のエラー | lint | 変更したファイルに対して hogli lint:python:fix または hogli format を実行する |
mypy、pyright、tsc、typescript:check のエラー | typecheck | スイート全体ではなく、同じチェッカーをローカルで実行する |
| Chromatic / Storybook / Playwright の視覚的差分、スナップショットの不一致 | スナップショット / 視覚 | 差分の URL を提示する。スナップショットを自動承認しない |
manage.py migrate のエラー、migrations:check の失敗、マイグレーションの欠落 | マイグレーション / スキーマ | ローカルで hogli migrations:check を実行する |
| OpenAPI スキーマの差分、生成された API 型の不一致 | codegen のドリフト | hogli build:openapi |
Cannot connect、ECONNREFUSED、address already in use、OOM、ランナーの強制終了、セットアップステップのタイムアウト | インフラ / ランナー | 一時的なものと判断する前にベースレートを確認する(下記参照) |
startup_failure の結論、記録されたステップがゼロのジョブ、404 になるログブロブ | インフラ / ランナー | 読むべきログがない。https://www.githubstatus.com/ とその前後の実行を確認する |
apt-get、uv sync、pnpm install、docker pull、セットアップアクションの失敗 | 環境 / セットアップ | .nvmrc、pyproject.toml、package.json、Dockerfile を比較する |
hogli lint:skills、hogli build:skills の失敗 | skills ビルド | 同じ hogli コマンドをローカルで実行する |
SDK 互換性チェック、ci-survey-sdk-check、バージョン間の失敗 | SDK 互換性 | 影響を受けるパッケージの SDK バージョンマトリックスを確認する |
複数のシグナルが一致する場合は、最も具体的なクラスを選択します。たとえば、 lint より codegen のドリフト、typecheck よりマイグレーション、 一般的な Playwright テストの失敗よりスナップショット / 視覚を優先します。
インフラとセットアップの失敗に関する基準率
「一時的」とは、そのジョブがどれくらいの頻度で失敗するかについての主張なので、1 回の実行から断定してはいけません。テストが実行される前に落ちたジョブは、テストレベルの証拠を残しません。FAILED 行がないため、フィンガープリントもスパンも存在せず、broken_tests やフレーキーテストツールの行として現れることはありません。それでもジョブの結論としては可視化されており、ダイジェストの master-failures セクションはそれでグループ化しています。また、engineering-analytics-run-failure-logs はテスト単位ではなく実行単位で読み取るため、失敗した行を引き続き返します。テストからではなく、そこから始めてください。
スパン由来のテスト読み取りとは異なり、こちらは実際の率を得られます。ウェアハウスは成功分も含めてすべてのジョブ試行を記録しているため、分母は正確です。
products/engineering_analytics/skills/investigating-ci-failures/references/investigation-queries.md
のクエリ 7 はそのまま使えます。より広範な調査もこのスキルが担っています。
結果は次のように読みます。
- 低い割合、直近数時間はほぼグリーン — 一時的です。報告して次に進みます。
キューに入った PR については、コード変更ではなく再エンキューを勧めてください。自分で
trunk mergeを実行するには、上記の安全性ルールに従い承認が必要です。 - 直近数時間が完全にレッド — フレークではなく障害です。そのように伝え、再試行を促すのをやめてください。このリポジトリに帰属させる前に https://www.githubstatus.com/ を確認してください。プラットフォームのインシデントがあれば、他のあらゆるシグナルは症状になります。
- 数分以内にまとめて失敗する実行のバースト — 複数のバグではなく、1 つの共通原因です。多くのマージが継承した不良コミット、または GitHub のディスパッチ過多を探してください。後者は実行が始まる前に
startup_failureとして失敗するため、ログがまったく残りません。 - 数日間にわたり安定して継続 — 誰かがオーナーである恒常的な欠陥です。各発生がノイズに見えても、チケットにする価値があります。
ローカルでの再現
失敗を再現する最小限のコマンドだけを実行してください。コマンドの形が不明な場合は、.agents/skills/hogli/SKILL.md と hogli <command> --help を読んでください。
| クラス | 再現ガイダンス |
|---|---|
| コードのリグレッション | hogli test path/to/test.py::TestClass::test_method または hogli test <file.test.ts> |
| フレーキーテスト | fixing-flaky-tests スキルに引き継ぎます。 |
| lint | 変更したファイルに対して失敗しているフォーマッター/リンターを使用します。例: hogli format:python。 |
| typecheck | 失敗しているチェッカーを実行します。例: pnpm --filter=@posthog/frontend typescript:check。 |
| スナップショット / ビジュアル | 該当する Playwright または Storybook ワークフローを実行します。必要なら playwright-test を読みます。 |
| マイグレーション / スキーマ | hogli migrations:check。ユーザーが同意した場合にのみマイグレーションを実行します。 |
| codegen のドリフト | hogli build:openapi。 |
| インフラ / ランナー | ローカルでの再現はありません。基準率(上記)を取得し、報告して終了します。 |
| 環境 / セットアップ | 変更したファイルに対して安価で関連がある場合にのみ、セットアップ手順を再現します。 |
| スキルのビルド | hogli lint:skills。これが通れば hogli build:skills。 |
引数なしで hogli test を実行しないでください。近道として hogli nuke や
hogli dev:reset を実行しないでください。--no-verify でフックをバイパスしないでください。
PostHog CI に関する注意事項
- PostHog のほとんどのジョブは
depot-ubuntu-latestまたはdepot-ubuntu-latest-16で実行されます。 Depot の実行は、標準の GitHub ホストランナーと同様に GitHub Actions の UI /gh run viewを通じて ログを表示するため、まずはそこで確認してください。 - Depot ランナーがジョブの途中で停止した場合、GitHub には読むべきログが残りません。そのジョブには
ステップが表示されず、そのログ blob は 404 になります。Depot 自身のダッシュボードにはそのジョブの
ページが残っており、GitHub が失った判定(OOM キル、ランナーの喪失)を確認できます。chrome-devtools
MCP を通じてブラウザで開いてください。
status.depot.devは Depot 自体が障害であるケースをカバーし、depot-github-runnersスキルはトリアージを超えるランナーのトラブルシューティングを担います。 - PR はそのバックエンドテストを Depot CI にルーティングできます。 そこでの失敗を確認してください。上記の「Depot CI で実行されたバックエンドテスト」を参照してください。
- ジョブが
Checkoutの完了前に失敗した場合(アプリのコードが実行されていない)、infra / runnerに分類してください。コードの修正を提案しないでください。 - PostHog CI は同じテストクラスを N 個のシャードにまたがって頻繁に並列化します
(
backend-tests (3/10)形式)。シャードインデックスではなく、失敗した特定のテストパスから 再現してください。
レポートの形式
回答は短く保ってください。考えられる原因を 1 文含め、深い推測は避けてください。
Target: PR #<num> - run <run-id> (<workflow file>)
Failing job: <job name>
Failing step: <step name>
Command: <failing command>
Excerpt:
<up to 40 lines, trimmed around the failure>
Classification: <class from the table>
Shadow run: <yes | no>
Likely cause: <one sentence>
Local repro: <exact command, or "none">
Next action (needs your approval):
- <push fix | rerun job | update snapshot | none>
分類が infra / runner またはシャドウ実行の場合は、その旨を述べて終了してください。
コードの変更を提案しないでください。infra / runner の場合は、ベースレートと
リトライが妥当かどうかを含めてください。