diagnose について
Diagnoseは、難しいバグの調査を体系化するスキルです。仮説を立てる前に高速で決定的なフィードバックループを作り、その後、再現、対象を絞った計測、回帰テスト、後片付けと振り返りを進めます。
主な機能
- 01再現可能なバグ検証ループを構築
- 02障害を再現して症状を記録
- 03反証可能な仮説を順位付け
- 04対象を絞って計測
- 05適切な接点で回帰テストを追加
- 06後片付けと振り返りを確認
活用シーン
- 01難しいバグや断続的な不具合の調査
- 02パフォーマンス回帰のデバッグ
- 03元の障害を使った修正の検証
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ mattpocock/ skills --skill diagnoseインストール後、Claude Code で/diagnoseを入力して読み込まれたか確認します。
同梱ファイルscripts/hitl-loop.template.sh
詳細
診断
難しいバグに取り組むための規律です。明確な理由がある場合に限り、フェーズを省略してください。
コードベースを調査する際は、プロジェクトのドメイン用語集を参照して、関連モジュールの全体像を把握してください。また、変更対象の領域に関する ADR も確認してください。
フェーズ 1 — フィードバックループを構築する
これこそがスキルです。 それ以外はすべて機械的な作業です。バグに対して、高速で決定的であり、エージェントが実行できる合否判定シグナルがあれば、原因を突き止められます。二分探索、仮説検証、計測は、どれもそのシグナルを利用するだけです。シグナルがなければ、コードをどれだけ眺めても解決には至りません。
ここには、相応以上の労力を注いでください。積極的に取り組んでください。創意工夫してください。決して諦めないでください。
フィードバックループを構築する方法 — おおむね次の順に試してください
- バグに到達できる接点での失敗するテスト — 単体テスト、統合テスト、E2E テスト。
- 起動中の開発サーバーに対する Curl / HTTP スクリプト。
- フィクスチャ入力を使った CLI の実行。標準出力を既知の正常なスナップショットと比較します。
- ヘッドレスブラウザーのスクリプト(Playwright / Puppeteer) — UI を操作し、DOM/コンソール/ネットワークを検証します。
- キャプチャしたトレースの再生。 実際のネットワークリクエスト/ペイロード/イベントログをディスクに保存し、コードパスを分離した状態で再生します。
- 使い捨てのハーネス。 システムの最小限の構成(1 つのサービス、モック化した依存関係)を起動し、単一の関数呼び出しでバグのコードパスを実行します。
- プロパティベーステスト/ファジングのループ。 バグが「出力がときどき間違う」場合は、ランダムな入力を 1000 件実行し、失敗のパターンを探します。
- 二分探索用ハーネス。 既知の 2 つの状態(コミット、データセット、バージョン)の間でバグが発生した場合は、「状態 X で起動して確認し、繰り返す」を自動化し、
git bisect runを実行できるようにします。 - 差分比較ループ。 同じ入力を旧バージョンと新バージョン(または 2 つの設定)に与え、出力を比較します。
- HITL bash スクリプト。 最終手段です。人間がクリックする必要がある場合は、
scripts/hitl-loop.template.shで その人間 を誘導し、ループが構造化された状態を保ちます。キャプチャした出力をフィードバックとして利用します。
適切なフィードバックループを構築すれば、バグは 90% 解決したも同然です。
ループ自体を反復的に改善する
ループをプロダクトとして扱ってください。何らかの ループを用意できたら、次の点を確認します。
- 高速化できますか?(セットアップをキャッシュする、無関係な初期化を省く、テストの対象を絞る。)
- シグナルをより明確にできますか?(「クラッシュしなかった」ではなく、具体的な症状を検証する。)
- 決定性を高められますか?(時刻を固定する、乱数シードを設定する、ファイルシステムを分離する、ネットワークを固定する。)
不安定な 30 秒のループは、ループがない状態と大差ありません。決定的な 2 秒のループは、デバッグを強力に支援します。
非決定的なバグ
目標は再現手順を完璧にすることではなく、再現率を高めることです。トリガーを 100 回繰り返し、並列化し、負荷をかけ、時間の範囲を絞り、スリープを挿入します。50% の確率で発生するバグならデバッグできますが、1% では困難です。デバッグできるようになるまで、再現率を上げ続けてください。
ループをどうしても構築できない場合
作業を止め、その旨を明確に伝えてください。試したことを列挙してください。ユーザーには、次のいずれかを依頼します。(a) バグを再現できる環境へのアクセス、(b) キャプチャした成果物(HAR ファイル、ログダンプ、コアダンプ、タイムスタンプ付きの画面録画)、または (c) 一時的な本番環境の計測を追加する許可。ループがない状態で仮説を立てて先に進んではいけません。
信頼できるループを用意できるまで、フェーズ 2 に進まないでください。
フェーズ 2 — 再現する
ループを実行し、バグが現れるのを確認してください。
次の点を確認します。
- ループによって、ユーザーが説明した失敗パターンが発生すること — 近くで起きる別の失敗ではありません。別のバグを直しても、修正にはなりません。
- 複数回の実行で失敗を再現できること(非決定的なバグの場合は、デバッグに使えるほど高い確率で再現できること)。
- 後のフェーズで修正が実際にバグに対処したか検証できるよう、症状の正確な内容(エラーメッセージ、誤った出力、遅い処理時間)を記録していること。
バグを再現するまで先に進まないでください。
フェーズ 3 — 仮説を立てる
検証を始める前に、優先順位を付けた仮説を3〜5個作成します。仮説を1つだけ立てると、最初に思いついたもっともらしい考えに引きずられます。
各仮説は反証可能でなければなりません。つまり、予測を明示します。
形式:「原因が なら、 を変更するとバグが解消し、 を変更すると悪化します。」
予測を示せない場合、その仮説は単なる思いつきです。破棄するか、具体化してください。
検証する前に、優先順位を付けたリストをユーザーに見せてください。 ユーザーが専門知識を持っていて、すぐに順位を変更できることがあります(「#3に関する変更をデプロイしたばかりです」)。あるいは、すでに除外した仮説を知っている場合もあります。簡単な確認で、大幅に時間を節約できます。返答を待って作業を止める必要はありません。ユーザーが応答できない場合は、自分の順位に従って進めてください。
フェーズ 4 — 計測する
各調査は、フェーズ 3 の具体的な予測に対応させます。一度に変更する変数は1つだけです。
ツールの優先順位:
- デバッガー/REPLでの調査(環境が対応している場合)。ブレークポイント1つで、ログ10件分の情報が得られます。
- 仮説を区別できる境界に、対象を絞ったログを追加します。
- 「すべてをログに出してgrepする」方法は使わないでください。
すべてのデバッグログに、[DEBUG-a4f2] のような一意のプレフィックスを付けます。最後にプレフィックスを1回grepすれば、ログをまとめて削除できます。タグのないログは残り、タグ付きのログは削除できます。
パフォーマンスの分岐。 パフォーマンスのリグレッションでは、通常、ログは適切な手段ではありません。代わりに、計測の基準値(タイミングハーネス、performance.now()、プロファイラー、クエリプラン)を取り、その後で二分探索します。まず計測し、修正はその後です。
フェーズ 5 — 修正とリグレッションテスト
リグレッションテストは修正前に作成します。ただし、適切なテスト箇所がある場合に限ります。
適切なテスト箇所とは、呼び出し元で発生する実際のバグパターンをテストできる箇所です。利用できる箇所が浅すぎる場合(複数の呼び出し元が必要なバグに対する呼び出し元1つだけのテストや、バグを引き起こした呼び出しチェーンを再現できない単体テストなど)、そこでリグレッションテストを作成すると、誤った安心感を与えます。
適切なテスト箇所がないこと自体が調査結果です。 その事実を記録してください。コードベースのアーキテクチャによって、バグの再発を防ぐ仕組みを整えられません。次のフェーズでこの問題を報告してください。
適切なテスト箇所がある場合:
- 最小化した再現ケースを、その箇所で失敗するテストにします。
- テストが失敗することを確認します。
- 修正を適用します。
- テストが成功することを確認します。
- 元の(最小化していない)シナリオに対して、フェーズ 1 のフィードバックループを再実行します。
フェーズ 6 — クリーンアップと事後分析
完了を宣言する前に、以下を必ず行います。
- 元の再現ケースで再現しなくなったことを確認する(フェーズ 1 のループを再実行)
- リグレッションテストが成功することを確認する(または、適切なテスト箇所がないことを記録する)
- すべての
[DEBUG-...]計測コードを削除する(プレフィックスをgrepする) - 一時的なプロトタイプを削除する(または、デバッグ用であることが明確な場所に移動する)
- 正しかった仮説をコミット/PRのメッセージに記載する。次にデバッグする人が学べるようにするためです。
次に、「このバグを防ぐには何が必要だったか」を考えてください。 回答にアーキテクチャの変更(適切なテスト箇所がない、呼び出し元が複雑に絡み合っている、隠れた依存関係があるなど)が含まれる場合は、具体的な情報を添えて/improve-codebase-architectureスキルに引き継ぎます。提案は修正を適用した後に行ってください。作業を始めたときよりも、多くの情報が得られているためです。