root-cause について
Root Cause は、再現可能な証拠、優先順位付きの仮説、人による因果関係の判定を軸に技術調査を進めるエージェントスキルです。修正の前に失敗を示すシグナルと最小再現を求め、推測によるパッチを防ぎます。
主な機能
- 01調査前に失敗シグナルを構築
- 02問題を再現して最小化
- 03反証可能な仮説を順位付け
- 04人による因果判定を要求
- 05修正前に回帰テストを追加
- 06修正を検証して計測コードを削除
活用シーン
- 01再現可能なソフトウェア不具合の調査
- 02システム境界をまたぐ障害の追跡
- 03提供された性能・イベント記録の分析
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ jayden-dang/ skills --skill root-causeインストール後、Claude Code で/root-causeを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
eval.jsonexternal-dependency-evidence.mdTESTS.md詳細
根本原因
鉄則
NO FIXES WITHOUT ROOT CAUSE INVESTIGATION FIRST
NO AGENT-AUTHORED AUTHORITATIVE CAUSAL ACCEPTANCE
推測でパッチを当てると、何時間も無駄にするうえ、新たなバグを生みます。このプロセスはあらゆる技術的な問題に適用されます。特に、つい省略したくなる緊急事態、「明らか」に見える1行の修正、そして前の修正がうまくいかなかった直後こそ、徹底して適用してください。
因果関係の確認は人間だけが行えます。Causal disposition(唯一の参照先)を参照してください。
フェーズ1 — フィードバックループを構築する(ゲート)
報告された障害がデプロイ済み環境(本番、ステージング、リモート開発)で発生しており、リモート証拠パックがまだない場合は、必ず最初に debug-remote サブスキルを使用してください。そのパックがフェーズ1のシグナルです。ループを作るために、本番環境で kubectl exec を実行したり、状態を変更するリクエストを再生したりしないでください。
理論を立てる前に、まず失敗を検出できるシグナルを構築して実行してください。1つのコマンド、つまりテストの実行、スクリプト、または curl で、今はこのバグが原因で失敗し、修正後には成功するものです。適切なフィードバックループを構築できれば、バグの修正は90%完了したも同然です。以降のフェーズは、すべてそのループを利用するだけです。
このコマンドを作る前に、理論を立てようとしてコードを読み始めたことに気づいたら、そこで止めてください。失敗を検出できるコマンドがなければ、フェーズ2には進めません。
構築方法の候補を、おおよその優先順に示します。
- バグに到達する任意の境界での失敗するテスト(ユニット、統合、E2E)
- 稼働中の開発サーバーに対する curl/HTTP スクリプト
- フィクスチャ入力を使った CLI の実行と、正常な出力との差分比較
- DOM/コンソール/ネットワークを検証するヘッドレスブラウザースクリプト
- 保存済みのリクエスト、ペイロード、イベントログなど、記録済み監査トレースをコードパスで再生
- 使い捨てのハーネス:バグの経路を実行するシステムの最小限の一部
- 出力が「時々間違う」場合に、ランダムな入力を使うプロパティテスト/ファジングループ
- 既知の2つの状態の間でバグが発生した場合の二分探索ハーネス(
git bisect run) - 差分ループ:同じ入力を旧バージョンと新バージョンに通し、出力を比較
- 人間が介在するスクリプト — 最終手段。人間が物理的に操作しなければならない場合に限り、ループの構造を保てるよう手順をスクリプト化します
次に、さらに磨き上げます。高速化(セットアップをキャッシュし、範囲を絞る — 分単位ではなく秒単位にする)、精度向上(「クラッシュしなかったか」ではなく、ユーザーの具体的な症状を検証する)、決定性の確保(時刻を固定し、乱数にシードを指定し、ファイルシステムを分離する)を行ってください。非決定的なバグの場合は、きれいな再現を追い求めないでください。根本原因を特定できるだけの再現率に達するまで、トリガーを100回ループさせたり、負荷を加えたり、タイミングの間隔を縮めたりして、再現率を高めます。
どうしても構築できない場合は、そう明言し、試したことを列挙したうえで、再現環境、記録済みの成果物、または一時的な計測を追加する許可をユーザーに求めてください。根拠のない推測で先に進んではいけません。
渡された証拠そのものが成果物である場合 — cpuprofile、ヒープスナップショット、spindump、トレース、または事後に渡されたイベントログなど — 構築可能な失敗検出コマンドは存在せず、すでに手元にある記録済み成果物をユーザーに求めても堂々巡りになります。その成果物がループです。内容を読み、症状を示す1つのフレーム、リテイナーチェーン、またはブロックされたスレッドに絞り込み、ファイルとシンボルを特定してください。成果物は引用付きの診断であり、修正ではありません。いったん診断を返し、誰かが症状を失敗するコマンドとして表現できるようになったら、フェーズ1に戻ってください。
ゲートチェック: コマンドを明示し、その失敗出力を1回分貼り付けてください。
フェーズ 2 — 再現して最小化する
ループを実行し、ユーザーが説明した失敗と同じエラーで失敗する様子を確認します(近いものの異なるエラーの場合は、別のバグであり、修正も間違っています)。エラーをすべて確認します。メッセージ全文、スタックトレース全体、行番号を確認してください。エラーに答えが含まれていることはよくあります。最近の変更を確認します。git diff、新しい依存関係、設定、環境を確認してください。
再現手順を一度にひとつずつ削ります(入力、設定、呼び出し元、手順)。各削減後に再実行し、残ったすべての要素が不可欠になるまで続けます。どれかひとつを取り除くと成功する状態が目標です。最小限の再現手順は仮説の範囲を狭め、回帰テストになります。
複数のコンポーネントで構成されるシステム(CI → ビルド → デプロイ、API → サービス → DB)では、各境界に計測を追加します。各レイヤーへの入力と出力をログに記録し、修正に手を加える前に一度実行して、どこで壊れるのかを確認してください。呼び出しチェーンの深いところでエラーが発生した場合は、呼び出し元をたどって不正な値を監査し、元のトリガーを突き止めます。エラーが現れた箇所だけを修正してはいけません。それは症状への対処にすぎません。
検索は、失敗を検出できるループではありません。 フェーズ 1〜2 では、フィードバックのシグナルとして
load-subgraph / 検索を使用しないでください。進行のゲートとなるのは、失敗を検出できるコマンドだけです。
フェーズ 2 の後 — 機能の所有関係に関するコンテキスト(フェーズ 3 の前)
フェーズ 2 が完了し、パスまたは安定した用語を特定したら、フェーズ 3 の仮説を立てる前に、必須のサブスキルとして所有関係/隣接関係のコンテキストを把握するために load-subgraph を使用します(シードとなるパス/用語を指定し、適切に neighbors または blast_radius を使います)。根拠に基づく主張(一元管理):skills/execution/load-subgraph/references/grounded-claims.md に従ってください。エンベロープから根本原因の仮説を作り上げてはいけません。また、隣接情報が有力に見えるからといって、失敗ループを省略してはいけません。
フェーズ 2 の後の運用ドキュメント(任意 — 失敗ループの代わりにはなりません)
フェーズ 2 の後に限ります(フェーズ 1〜2 では引き続き、最初に失敗を検出できるコマンドが必要です)。読み込み先: skills/project/define-system-doc/consult-recipe.md。該当する場合のパス: docs/ops/runbooks.md(およびランブックのスラッグ)、docs/ops/observability.md、docs/ops/disaster-recovery.md。これらはフェーズ 3 以降の参考コンテキストに限られ、失敗ループの代わりにはなりません。存在しない場合は何もしません。重要な場合は /define-system-doc ops/runbooks|observability|disaster-recovery を一度だけ提案してください。自動で呼び出してはいけません。
フェーズ 2 の後の外部依存関係の根拠(条件付き — フェーズ 3 の前)
最小化した失敗経路が、バージョン管理された外部依存関係(ライブラリ、フレームワーク、SDK、データベース、キャッシュ、検索/オブザーバビリティプラットフォーム、クラウドサービス、外部 API、CLI、プロバイダーのディストリビューション、プロトコル)を通る場合は、仮説を書く前にこの根拠ゲートを完了してください。フェーズ 1 のシグナルとフェーズ 2 の最小再現手順が引き続きゲートとなります。ドキュメントがどちらかの代わりになることはありません。
この条件に該当する場合は、このファイルと同じ場所にある external-dependency-evidence.md を読み、記載どおりに厳密に従ってください。実行時の識別情報、research による所有元のドキュメント、コントラクト差分表、見解が食い違う場合の履歴確認、主張のステータスを確認します。すべての手順はフェーズ 1 の失敗出力をゲート条件とし、実行時の根拠を利用できない場合は、未解決の扱いを原文どおりに記載します。
フェーズ 3 — 仮説を立てる
検証を始める前に、優先順位を付けた仮説を3~5個書き出します(仮説が1つだけだと、最初に思いついたもっともらしい考えに固執してしまいます)。それぞれに、明確な予測を伴う反証可能な内容を記述します。「原因がXなら、Yを変更するとバグが消える」。予測を述べられない場合、それはただの勘です。内容を明確にするか、破棄してください。優先順位を付けたリストをユーザーに提示します(ユーザーがすぐに順位を変更することもよくあります)。ユーザーが不在でも作業を止めないでください。
まず、もっとも小さな仮説を検証します。一度に変更する変数は1つだけです。変更を重ねてはいけません。
ランタイムの調査 — このフェーズにおける仮説を見分けるための実験であり、フェーズ1の代わりではありません。仮説に記述した予測を使います。アタッチしただけでは因果関係を認めたことにはなりません(「因果関係の扱い」を参照)。
テスト対象のプロセスがローカル環境または専用のチェックアウトにある場合(赤信号が出ており、最小限の再現手順もすでにあります):ログを大量に出すより、デバッガー、REPL、またはDAPセッションを優先します。ブレークポイントやウォッチ式を1つ設定するほうが、出力を10個追加するより効果的です。ブラウザーのみで発生する障害では、同様にDevTools/CDPを使用できます。以下を記録します。
## Inspection evidence
- Prediction: <from the hypothesis under test>
- Tool: <debugger | REPL | DAP | DevTools/CDP | profiler | [DBG-…] log>
- Commands: <literal>
- Observation: <frame / locals / snapshot / paste>
- Outcome: <confirms | falsifies | inconclusive>
障害が共有デプロイ済みの環境でのみ発生する場合:そこでexecしたりアタッチしたりしないでください。その境界はdebug-remoteです。フェーズ3のプローブはローカル環境または専用のコピーで実行するか、変更を加えない証拠の収集にとどめてください。
それ以外の場合(デバッガーが使えない、またはログの追跡が適している場合):プローブごとに一意のプレフィックス(例:[DBG-x7q2])を付けて、対象を絞ったログを出します。後片付けはgrep 1回で済むようにし、すべてをログに出してからgrepする方法は使わないでください。
パフォーマンスやメモリに関するバグでは、まずベースラインを測定してから(プロファイラー、サニタイザー、計測ハーネスなど)、二分探索で絞り込みます。ここではログが誤解を招きます。
わからないことがあれば、「Xがわかりません」と伝えて調査してください。わかったふりをして推測してはいけません。
仮説が反証された場合は、その仮説を取り消し、次に進みます。否定された仮説の上に新たな修正を積み重ねてはいけません。
因果関係の扱い — 権威ある確認の前に必須
調査の状態(open/unresolved/falsified/superseded)と、要求する確度(candidate/probable_contributor/confirmed_for_scope)は別々に管理します。要求する確度は命題であり、受け入れられた結論ではありません。
## Causal disposition request
- Proposition: <one exact causal claim>
- Investigation state: <open | unresolved | falsified | superseded>
- Requested strength: <candidate | probable_contributor | confirmed_for_scope>
- Scope: <reproduced condition / environment bound>
- Support set: <commands, outputs, artifacts that bear on this proposition>
- Contradictions / alternatives still live: <none | list>
- Ask: accept / reject / supersede (eligible human only)
コミット、PR、または締めくくりの報告で、エージェントが権威ある形で`confirmed root cause`と記述してはいけません。エージェントの判断として`probable_contributor`/`confirmed_for_scope`を捏造してはいけません。Exit、記入済みのブリーフ、または文章によるLGTMを、人間が命題を受け入れたものとして扱ってはいけません。
ロールバック、緩和策、エラー率の回復といった運用上の成功によって、受け入れられた因果関係の確度が上がることはありません。
フェーズ1~3がすべてグリーンなら、調査は判断を求める準備ができています。確認済みとは、適格な人間がその命題を受け入れた状態です。これらは同じではありません。
フェーズ 4 — 修正
- 修正依頼に命題が記載されたら、まず回帰テストを失敗させます(必須サブスキル:
test-firstを使用)。テストは適切な接合点に配置します。実際に発生したバグのパターンを再現できる接合点でなければなりません。適切な接合点が存在しない場合、それ自体が発見事項です。その旨を記録し、事後検証で取り上げます。浅いテストを配置すると、誤った安心感につながります。 - 本番コードを修正として取り込む前に、その正確な命題(強さ+範囲+裏付けの集合)について人間の承認を得ます。文章に対するSlackでの「出荷してよい」という返答や、フェーズ1~3が完了したように感じることは、その承認には当たりません。セッション中は、提示した命題に対するユーザーの明示的な承認が該当します。承認の延期: 無人で実行する依頼者の指示に、処置の決定を完了報告まで延期すると明記されている場合(
run-dogfoodが該当します)、修正を適用し、マージしていないそのブランチにpending dispositionと記してコミットします。実行中に確認を求めてはいけません。依頼は依頼者の完了報告を通じて行い、承認資格のある人間が承認するまで、修正をマージしてはいけません。 - 承認された命題に対処する修正は1つだけです。「ついでに」行う改善や、まとめて行うリファクタリングはしません。
- 回帰テストが成功することを確認し、全テストスイートを再実行してから、元の未最小化シナリオに対してフェーズ1のループを再実行します。
修正の試行が3回失敗したら、停止します。 問題なのは最新の仮説ではなくアーキテクチャです。特に、修正のたびに別の場所で新たな結合が明らかになる場合はそうです。4回目の試行に進む前に、ユーザーと相談してください。
終了 — ミニ仕様、クリーンアップ、事後検証
- Tier-1ミニ仕様:担当する機能の
requirements.mdに、修正要件とSHALL CONTINUE TOガード要件を追加します。担当する機能がない場合は、docs/specs/fixes.mdに追加します。タスクレポートまたは仕様レビューで、回帰テストをそのIDに対応付けます。これはドキュメントのみの背骨です。利用者向けアプリのテストソース内に検索可能なIDを必須にしてはいけません。 - 計測コードをすべて削除します。
[DBG-...]のプレフィックスを検索し、使い捨てのハーネスを削除します。 - コミット/PRでは、命題、要求された、または人間が承認した強さ、範囲、裏付けを示す参照先を明記します。人間による処置がまだ決定していない場合は、
requested/pending dispositionと記載します。エージェントによる承認の代わりとして、confirmed root cause: …を使ってはいけません。 - タスクを問い直します。「このバグを防ぐには何が必要だったか?」答えがアーキテクチャに関するもの(適切な接合点がない、隠れた結合がある、呼び出し元が複雑に絡み合っている)なら、具体的な内容を記録し、ユーザーに
/scan-architectureを実行するよう伝えます。修正が取り込まれた後、最も状況を把握できている時点で実施します。 - 必須サブスキル:バグを修正したと主張する前に、
prove-claimを使用します。
正当化の言い訳
| 考え | 実態 |
|---|---|
| 「緊急事態で、手順を踏む時間がない」 | 根本原因のデバッグは、当てずっぽうで試行錯誤を繰り返すよりも速いです |
| 「明らかに X だ。すぐ修正しよう」 | 症状を見ただけでは、原因を理解したことにはなりません |
| 「今は応急修正して、後で調査しよう」 | 応急修正は恒久対応になり、原因が再び問題を起こします |
| 「時間を節約するため、一度にいくつか変更しよう」 | どれが効いたのか分からず、変更のどれかが別の問題を引き起こします |
| 「再現手順が必要なほど複雑ではない」 | 単純なバグにも根本原因はあります。このループにかかるのは数分です |
| 「修正後に回帰テストを追加しよう」 | テストされていない修正は再発を招きます。失敗するテストが、修正で直ることの証明です |
| 「もう一度だけ試そう」(2 回以上失敗した後) | アーキテクチャについて議論せずに 4 回目を試すのは、堂々巡りです |
| 「まず機能のサブグラフを読み込もう。それがこのループだ」 | フェーズ 1~2 では、失敗を検出できるコマンドが必要です。検索はフェーズ 2 の後にのみ行います |
| 「隣接カードに担当者が書いてあるから、最小化は省こう」 | 担当者の情報はフェーズ 2 の後に参考にするものです。フェーズ 3 に進むには、最小限の再現手順が依然として必要です |
| 「このライブラリは知っている。ありそうな修正をした後でドキュメントを取得しよう」 | 外部の挙動に関する仮説を立てる前に、実行時の識別情報と、使用バージョンに対応する担当ドキュメントを確認します |
| 「終了時には確認済みの根本原因を記すとある。このコミット行が承認だ」 | 終了時には命題と判定ステータスを記録します。承認できるのは、条件を満たす人間だけです |
| 「フェーズ 1~3 は完了した。人間による判定は形式的なものだし、このリポジトリには記録しない」 | 鉄則により、エージェントが権威ある承認を記すことは禁止されています。判定依頼が文書化されたゲートです |
| 「スタッフが説明に LGTM を出した。終了して出荷しよう」 | 説明への LGTM は、裏付け一式に照らした特定の命題の承認とは異なります |
| 「ロールバックが機能した。確認済みに格上げしよう」 | 緩和策の成功は運用上の結果であり、因果関係の確度を高めるものではありません |
| 「デバッガーをアタッチしたので、原因は確認済みだ」 | アタッチは実験です。承認には、依然として人間による判定が必要です |
| 「本番環境/ステージング環境だから、ローカル変数を見るために lldb/exec を使おう」 | 共有のデプロイ済み環境では、debug-remote を読み取り専用で使用します。プローブはローカル環境から開始します |
危険信号 — 停止してください
- エージェントが記した
confirmed root causeをコミットまたは PR に入れようとしている - フェーズ 4/終了を、人間による因果関係の承認として扱おうとしている
- ロールバックやエラー率の回復を理由に、因果関係の確度を高めようとしている
- 「以前はスキルに確認済みと書かれていた」という理由で、判定依頼を省こうとしている
- 共有のデプロイ済み環境でデバッガーをアタッチまたは exec しようとしている
- 「デバッガーを使った」ことを、原因が承認されたものとして扱おうとしている
ユーザーのシグナル — フェーズ 1 に戻る
| ユーザーの発言 | 意味 |
|---|---|
| 「推測はやめて」 | 根本原因なしに修正案を提案しました。フェーズ 1 に戻ってください |
| 「それは実際に起きているの?」 | 検証せずに仮定しました。証拠を集めてください |
| 「それで何か分かるの?」 | プローブがどの予測にも結びついていません。仮説を言い直してください |
| 「堂々巡りだ」 | 失敗した修正の回数を数えてください。おそらくアーキテクチャのゲートに達しています |
| 「その原因を承認したのは誰?」 | 自分で承認してしまいました。判定依頼を実行してください |