diagnose について
diagnose は、コーディングエージェント向けの難しいバグのデバッグスキルです。調査に先立って確実なフィードバックループを作り、再現、仮説の検証、計測、回帰テスト、後片付けへと進めます。
主な機能
- 01決定的な不具合フィードバックループの構築
- 02障害の再現と正確な記録
- 03反証可能な仮説の順位付け
- 04要所に絞った計測
- 05回帰テストの追加と後片付け
活用シーン
- 01断続的な障害のデバッグ
- 02報告された本番環境の問題調査
- 03コミットやバージョン間の回帰追跡
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ leandrocfe/ skills --skill diagnoseインストール後、Claude Code で/diagnoseを入力して読み込まれたか確認します。
同梱ファイルscripts/hitl-loop.template.sh
詳細
診断
難しいバグに取り組むための手順です。明確な根拠がない限り、フェーズを飛ばさないでください。
コードベースを調べる際は、プロジェクトのドメイン用語集を使って関連モジュールの明確なメンタルモデルを構築し、対象領域の ADR も確認してください。
フェーズ 1 — フィードバックループを構築する
これがこのスキルの本質です。 それ以外はすべて機械的な作業です。バグに対して高速かつ決定論的で、エージェントが実行できる合否判定のシグナルがあれば、原因を見つけられます。二分探索、仮説検証、計測はいずれもそのシグナルを利用するだけです。シグナルがなければ、どれだけコードを眺めても解決にはつながりません。
ここに、通常よりはるかに多くの労力をかけてください。積極的に取り組んでください。創意工夫してください。諦めないでください。
構築方法 — おおむね次の順に試してください
- バグに到達できる seam での失敗するテスト — unit、integration、e2e。
- 起動中の dev server に対する curl / HTTP スクリプト。
- fixture input を使った CLI の実行。stdout を既知の正常な状態のスナップショットと比較します。
- ヘッドレスブラウザーのスクリプト(Playwright / Puppeteer)— UI を操作し、DOM/console/network をアサートします。
- キャプチャした trace の再生。 実際の network request/payload/event log をディスクに保存し、該当する code path を分離して再生します。
- 使い捨ての harness。 システムの最小限のサブセット(1 つの service、モック化した依存関係)を起動し、1 回の function call でバグの code path を実行します。
- property/fuzz のループ。 バグが「出力がときどき間違う」なら、ランダムな入力を 1000 件実行して failure mode を探します。
- 二分探索用 harness。 バグが 2 つの既知の状態(commit、dataset、バージョン)の間で発生した場合は、「状態 X で起動して確認し、繰り返す」を自動化し、
git bisect runを使えるようにします。 - 差分ループ。 同じ入力を旧バージョンと新バージョン(または 2 つの設定)で実行し、出力を比較します。
- bash による HITL。 最後の手段です。人間がクリックする必要がある場合は、
scripts/hitl-loop.template.shで 人間を 操作し、ループを構造化します。キャプチャした出力を次の調査に使います。
適切なフィードバックループを構築すれば、バグは 90% 解決したも同然です。
ループ自体を改善する
ループを 1 つのプロダクトとして扱ってください。1 つ ループを構築したら、次の点を確認します。
- もっと速くできるか?(セットアップをキャッシュする、無関係な初期化を省く、テスト範囲を絞る。)
- シグナルをもっと明確にできるか?(「クラッシュしなかった」ではなく、特定の症状をアサートする。)
- もっと決定論的にできるか?(時刻を固定する、乱数生成器にシードを設定する、ファイルシステムを分離する、ネットワークを固定する。)
不安定で 30 秒かかるループは、ループがない状態と大差ありません。決定論的で 2 秒のループは、デバッグの強力な武器です。
非決定論的なバグ
目標はクリーンな再現ではなく、再現率を上げることです。トリガーを 100 回実行し、並列化し、ストレスを加え、タイミングの間隔を狭め、sleep を挿入します。再現率 50% のバグならデバッグできますが、1% ではできません。デバッグできるまで再現率を上げてください。
どうしてもループを構築できない場合
作業を止め、明確にその旨を伝えてください。試したことを列挙します。ユーザーに次のいずれかを依頼してください。(a)再現できる環境へのアクセス、(b)キャプチャした成果物(HAR file、ログダンプ、core dump、タイムスタンプ付きの画面録画)、または(c)本番環境に一時的な計測を追加する許可。ループがない状態で、仮説の検討に進まないでください。
信頼できるループを構築するまでは、フェーズ 2 に進まないでください。
フェーズ 2 — 再現する
ループを実行し、バグが発生することを確認します。
次の点を確認してください。
- ループが、ユーザーの説明した failure mode を発生させること。近くで発生する別の failure ではありません。違うバグを対象にすれば、修正も間違います。
- 複数回の実行で failure を再現できること(非決定論的なバグの場合は、デバッグに十分な再現率であること)。
- 正確な症状(エラーメッセージ、誤った出力、遅いタイミング)を記録し、後続フェーズで修正が実際に対処できているか確認できること。
バグを再現するまでは先に進まないでください。
フェーズ 3 — 仮説を立てる
どれかを検証する前に、優先順位を付けた仮説を3〜5個挙げてください。仮説を1つだけ立てると、最初に思いついたもっともらしい案に固執してしまいます。
各仮説は反証可能である必要があります。仮説が予測することを明記してください。
形式:「が原因なら、<Yを変更>するとバグが消える/<Zを変更>すると悪化する。」
予測を明記できないなら、それは勘にすぎません。破棄するか、具体化してください。
検証を始める前に、優先順位付きのリストをユーザーに提示してください。 ユーザーは多くの場合、優先順位をすぐに見直せるドメイン知識を持っています(「#3の変更をたった今デプロイしました」など)。すでに除外した仮説を知っていることもあります。確認の手間はわずかですが、大幅な時間の節約になります。確認待ちで作業を止めないでください。ユーザーが離席中なら、提示した優先順位に従って進めてください。
フェーズ 4 — 計測手段を仕込む
各プローブは、フェーズ 3 の特定の予測に対応させてください。一度に変更する変数は1つだけです。
ツールの優先順位:
- デバッガー/REPLによる検査。環境が対応しているならこちらを優先します。ブレークポイント1つは、ログ10個に勝ります。
- 仮説を見分けられる境界に対象を絞ったログを追加します。
- 「すべてをログに出してgrepする」方法は使わないでください。
各デバッグログに、例:[DEBUG-a4f2]のような一意のプレフィックスを付けてください。最後のクリーンアップはgrep 1回で済みます。タグのないログは残り、タグ付きのログは削除できます。
パフォーマンスの分岐。 パフォーマンスのリグレッションでは、ログが誤解を招くことがよくあります。代わりに、まずベースラインを計測してください(タイミング用ハーネス、performance.now()、プロファイラー、クエリプランなど)。その後、二分探索します。先に計測し、修正はその後です。
フェーズ 5 — 修正とリグレッションテスト
適切なテストシームがある場合に限り、修正の前にリグレッションテストを書いてください。
適切なテストシームとは、呼び出し元で発生するのと同じバグのパターンをテストで再現できる箇所です。利用可能なテストシームが浅すぎる場合(バグの再現には複数の呼び出し元が必要なのに、単一の呼び出し元しかテストできない場合や、バグを引き起こした呼び出しチェーンを再現できないユニットテストなど)、そこでリグレッションテストを書いても誤った安心感を与えます。
適切なテストシームが存在しないこと自体が、発見事項です。 記録してください。コードベースのアーキテクチャが、バグを確実に防ぐ妨げになっています。次のフェーズに申し送ってください。
適切なテストシームがある場合:
- 最小化した再現ケースを、そのテストシームで失敗するテストにします。
- テストが失敗することを確認します。
- 修正を適用します。
- テストが成功することを確認します。
- フェーズ 1 のフィードバックループを、元の(最小化していない)シナリオに対して再実行します。
フェーズ 6 — クリーンアップと事後検証
完了を宣言する前に、必ず実施してください。
- 元の再現ケースで再現しなくなった(フェーズ 1 のループを再実行)
- リグレッションテストが成功する(または、テストシームがないことを記録済み)
-
[DEBUG-...]の計測コードをすべて削除した(プレフィックスをgrepで検索) - 使い捨てのプロトタイプを削除した(または、デバッグ用と明示した場所に移動した)
- 正しいと判明した仮説をコミット/PRのメッセージに記載した(次のデバッガーが学べるようにするため)
そのうえで、このバグを防ぐには何が必要だったかを考えてください。 回答にアーキテクチャの変更(適切なテストシームがない、呼び出し元が複雑に絡み合っている、隠れた結合など)が含まれる場合は、詳細を添えてスキル/improve-codebase-architectureに引き継いでください。提案は修正が入った後に行ってください。作業を始めた時点より、今のほうが多くの情報を得られています。