ci-debugging について
ci-debugging は、実行証拠、検証可能な仮説、ローカル環境や直近の成功実行との比較を通じて CI 障害を調べるスキルです。調査から検証までを導き、診断と許可された変更を区別します。
主な機能
- 01CI プロバイダー別のログと成果物の収集
- 02失敗実行と直近の成功実行の比較
- 03順位付けした反証可能な仮説の検証
- 04CI とローカル環境の差分分析
- 05失敗時と同じコマンドによる修正確認
活用シーン
- 01GitHub Actions のジョブ失敗の調査
- 02CI とローカルテストの差の追跡
- 03複数回の実行結果から不安定性を判定
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ citypaul/ .dotfiles --skill ci-debuggingインストール後、Claude Code で/ci-debuggingを入力して読み込まれたか確認します。
詳細
CI のデバッグ
証明されるまでは、すべての CI 失敗は実際の問題です。不安定なだけだと決めつけないでください。
このスキルでは、パイプライン固有の証拠と環境差分を扱います。CI 以外で発生したローカルまたはランタイムの失敗には、debugging を使用してください。
データの取得
リポジトリの設定から CI プロバイダーを特定し、仮説を立てる前に、そのプロバイダーに接続されたツール、CLI、または UI を使って実際の失敗出力を取得してください。後で比較するときに同じ実行を参照できるよう、実行、ジョブ、試行、コミット SHA、タイムスタンプを記録してください。
GitHub Actions の場合:
gh run list --branch <branch> --limit 5 # find the failing run
gh run view <run-id> --log-failed # only the failed steps' logs
gh run view <run-id> --job <job-id> --log # one job's full log
gh run download <run-id> # artifacts (coverage, reports, screenshots)
ワークフローの再実行や CI 変数の変更は外部状態を変更し、デプロイ、マイグレーション、通知などの副作用を再度引き起こす可能性があります。ワークフローと失敗したジョブの副作用を確認したうえで、明示的な権限がある場合にのみ実施してください。許可されている場合は、gh run rerun <run-id> --failed を使って失敗したジョブのみを再実行するか、ステップ単位のログ記録には gh run rerun <run-id> --debug を使用してください。使用後は一時的なデバッグ変数を削除してください。別のプロバイダーを使う場合は、コマンドを推測で置き換えず、同等の制御機能を使用してください。失敗した実行と、同じブランチで最後に成功した実行を比較してください。この 2 つの実行間のコミット、依存関係のロックファイル、パイプラインファイルの差分が、最初に調査すべき候補です。
テスト対象のシステムが構造化されたテレメトリー(正規イベント、トレース、テスト実行から得られるメモリ内エクスポーターの出力)を出力する場合は、ログと合わせて証拠として取得してください。詳しくは observability スキルを参照してください。
仮説を先に立てた診断
編集する前に、考えられる原因を列挙し、証拠に基づいて優先順位を付け、反証可能な仮説を一度に 1 つずつ検証してください。リストを埋めるためだけに、根拠のない最低数を設けないでください。
テストタイムアウトの仮説の例:
- テストが CI では利用できないネットワークアクセスに依存している
- テストの並列実行によってリソースが競合している
- CI ランナーのメモリ/CPU がローカルマシンより少ない
ローカルでの再現
忠実な環境を用意できる場合は、修正をプッシュする前にローカルで再現してください。
- 近いコマンドではなく、失敗した正確なコマンドを実行してください
- CI 環境になるべく近づけてください(Node のバージョン、環境変数)
- ローカルで成功した場合は、原因を絞り込む証拠として環境差分を扱ってください。原因は依然としてタイミング、状態、または外部依存関係にある可能性があります
環境差分の分析
CI とローカルを比較します。
| 要因 | 確認内容 |
|---|---|
| Node/ランタイムのバージョン | CI 設定とローカルでの node -v |
| OS | Linux の CI と macOS のローカル環境 |
| 依存関係の解決 | リポジトリでロックされたクリーンインストールコマンドとパッケージキャッシュ(npm の場合は、npm ci とキャッシュされた node_modules) |
| 環境変数 | CI のシークレット/設定とローカルの .env |
| 並列度 | CI ではテストの並列実行方法が異なる場合があります |
| メモリ/CPU | CI ランナーは利用できるリソースが少ないことがよくあります |
| ネットワーク | CI では外部ネットワークへのアクセスがブロックされる場合があります |
| ファイルシステム | 大文字と小文字の区別(Linux)と区別しない動作(macOS) |
エラー全体を読む
- 最後の行だけでなく、完全なエラー出力を読んでください
- 直前のログ行や警告を確認してください。実際の原因が含まれていることがよくあります
- スタックトレースを確認し、実際の失敗箇所を特定してください
- 表示されているエラーに連鎖した可能性のある、それ以前の失敗を確認してください
修正の検証
依頼が診断のみの場合は、根拠のある根本原因、証拠、影響を受けるジョブ、不確実性、推奨される修正を報告して終了してください。診断を依頼されたからといって、ワークフロー、本番環境、依存関係、テスト、設定を変更する権限が与えられるわけではありません。
ユーザーが修正を依頼した場合は、原因を特定した後、次の手順を実行してください。
- 症状だけでなく、修正が根本原因に対処する理由を説明してください
- 失敗した正確なコマンドをローカルで実行してください
- 修正によって実際の問題が隠れていないことを検証してください(例:リトライの追加によって競合状態が隠れる)
アンチパターン
| アンチパターン | なぜ問題なのか | 代わりにすること |
|---|---|---|
| 「不安定なので、もう一度実行する」 | 実際の問題を覆い隠します | 失敗を調査します |
| やみくもな再試行やスリープの追加 | タイミングのバグを隠すおそれがあります | 原因を特定し、外部の契約で必要な場合に限り、上限を設けた再試行を追加します |
| 推測に基づく修正をプッシュする | CI の実行サイクルを無駄にします | ローカルで再現して検証します |
| 最後のエラー行だけを読む | 根本原因を見落とします | 出力を先頭から最後まで読みます |
| 症状だけを直す | 問題が再発します | 根本原因をたどります |
不安定さの証明
同じ制御された入力で独立した実行を行い、結果が異なることは、結果が非決定的である証拠です。原因がまだ診断されていなくても、これで不安定さが証明されます。実際に制御した入力と環境に関する事実を記録してから、競合状態、時間、共有状態、リソースの逼迫、外部依存関係などに原因を絞り込みます。説明のつかない単発の失敗は、依然として実際の失敗であり、成功するまで再実行してよいという意味ではありません。
引き継ぎ
根本原因を特定したら、診断のみの引き継ぎは、証拠と推奨する保護策を伝えて完了します。修正が許可されている場合は、その修正に適した最小限で永続的な回帰防止策を残します。本番環境の動作については、tdd(レガシー動作を先に記録する必要がある場合はcharacterisation-tests)を使い、修正の前に失敗する動作テストを書きます。プロバイダーの設定、権限、外部サービスの停止については、状況に応じて設定のアサーション、ドライラン、契約チェック、または復旧の監視による証明を使います。実行可能な保護策を用意できない場合は、テストをでっち上げるのではなく、証拠と残された検出手段を記録します。