mcpField
D
debugging-difficult-bugs

debugging-difficult-bugs

github.com/mastra-ai開発29.2k47 回インストール今日更新
リポジトリ

debugging-difficult-bugs について

中程度から難しい不具合向けのデバッグスキルです。実際の実行経路を記録して問題を再現し、JSONL ログを分析してから修正します。テストが実際の挙動を十分に表さない場合に適しています。

主な機能

  1. 01実行経路に一時ログを追加
  2. 02状態や分岐を JSONL に記録
  3. 03実際の問題を再現して調査
  4. 04ログから最初の差異を特定
  5. 05ログを削除し回帰テストを追加

活用シーン

  1. 01関数やプロセスをまたぐ不具合の調査
  2. 02並行処理・キャッシュ・永続化の問題追跡
  3. 03手動で再現する UI や実行時問題の検証
  4. 04不十分なテストに基づく推測修正の回避

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/mastra-ai/mastra --skill debugging-difficult-bugs

インストール後、Claude Code で/debugging-difficult-bugsを入力して読み込まれたか確認します。

詳細

難しいバグのデバッグ

通常の TDD では、テストが実際のバグを十分に捉えておらず、誤った確信につながる可能性がある中程度または難しいバグには、早い段階でこのスキルを使ってください。

基本方針:実際の実行時経路に計測ログを追加し、実際の問題を再現してから、修正を決める前に追記専用の JSONL ログを調べます。

使用するタイミング

次のいずれかに当てはまる場合は、デバッグの早い段階でこのワークフローを使ってください。

  • バグの複雑さが中程度または高く、特に複数の関数、パッケージ、プロセス、あるいは UI とランタイムの境界にまたがる場合。
  • テストが失敗しているものの、そのテストが実際のバグを不完全にしかモデル化できていない可能性がある場合。
  • 新たな実行時の証拠がないまま、推測に基づく 2 回目の修正をしようとしている場合。
  • バグが実行時の順序、状態、キャッシュ、ストリーミング、並行処理、永続化、UI 操作、または外部サービスに依存する場合。
  • ユーザーが手動で問題を再現できると言っている場合。
  • 変更後にテストは成功したものの、報告された実際のバグが修正されたことを証明できているか確信が持てない場合。

実行時の挙動を理解できていない場合は、テストだけを繰り返し修正しないでください。

スタックトレース、または実際の実行時経路を通る決定的な失敗テストによって根本原因が直接証明されている場合に限り、このワークフローを省略してください。推測に基づく 2 回目の修正をしようとしている場合は、このワークフローを使ってください。

必須のアプローチ

  1. 不確実な点を明示する

    • 現在のテストでは実際のバグを捉えられていない可能性があることを認めます。
    • 観察する必要がある実際のコード経路を特定します。
  2. 一時的に、無条件の計測ログを追加する

    • 疑わしいコードの流れに、必要最小限で十分なログを追加します。
    • 境界、重要な分岐の判断、状態遷移、非同期処理の順序を確認できる箇所、戻り値、捕捉したエラーを記録します。すべての行を記録する必要はありません。
    • ログは無条件で記録します。環境変数、デバッグフラグ、ログレベルによる制御はしないでください。
    • 各ログ出力では、現在の作業ディレクトリにある .jsonl ファイルへ、1 行につき JSON オブジェクトを 1 つ追記します。
    • 経路を再構成できるだけの情報を含めます。イベント名、タイムスタンプ、関連 ID、入力の形状、状態遷移、分岐の判断、戻り値、捕捉したエラーなどです。
  3. 実際の問題を再現する

    • 可能であれば、自分で再現を実行してください。
    • ユーザーの環境や手動操作が必要な場合は、計測ログを追加した後にユーザーへ再現を依頼します。
    • 送ってもらう .jsonl ファイルを正確に伝えるか、再現が完了したら知らせてもらい、こちらでログを調べます。
  4. 修正前にログを分析する

    • JSONL ログを時系列順に読みます。
    • 期待される流れと実際の流れを比較します。
    • 状態または挙動が最初に食い違った箇所を特定します。
    • その後で初めて修正を実装します。
  5. 計測ログを削除する

    • 根本原因を理解し、修正を検証した後、一時的な無条件ログをすべて削除します。
    • デバッグ用のインポート、ヘルパー関数、生成された .jsonl ファイル、その他の一時的な成果物も削除します。
    • 最終的な差分に計測ログの痕跡が残っていないか確認します。
    • ユーザーから明示的に依頼されない限り、最終的な差分にデバッグファイル、ログ用ヘルパー、実行時に大量のログを出す処理を残さないでください。
  6. テストを維持または改善する

    • 実際のバグを理解した後、焦点を絞った回帰テストを追加または調整します。
    • 以前の誤った想定ではなく、ログから判明した実際の不具合の挙動をテストで検証します。

JSONL ログの記録方法

CLI、開発サーバー、テスト、手動での再現のいずれでも動作するよう、cwd に追記専用の JSONL を使用します。

Node / TypeScript
import { appendFileSync } from 'node:fs';
import { join } from 'node:path';

function debugBug(event: string, data: Record<string, unknown> = {}) {
  appendFileSync(
    join(process.cwd(), 'debug-difficult-bug.jsonl'),
    `${JSON.stringify({
      ts: new Date().toISOString(),
      event,
      ...data,
    })}\n`,
  );
}

意味のある分岐や状態遷移のたびに呼び出します。

debugBug('workflow.start', { runId, stepId, inputKeys: Object.keys(input ?? {}) });

debugBug('workflow.beforeStep', {
  runId,
  stepId,
  status: step.status,
  hasResumeData: Boolean(resumeData),
});

try {
  const result = await executeStep();
  debugBug('workflow.afterStep', { runId, stepId, resultShape: Object.keys(result ?? {}) });
  return result;
} catch (error) {
  debugBug('workflow.stepError', {
    runId,
    stepId,
    errorName: error instanceof Error ? error.name : typeof error,
    errorMessage: error instanceof Error ? error.message : String(error),
  });
  throw error;
}

ログに記録する内容

膨大なダンプより、簡潔で構造化されたデータを優先します。

記録する内容:

  • 関数名またはフェーズ名。
  • 安定した ID:リクエスト ID、実行 ID、スレッド ID、リソース ID、ステップ ID、ツール呼び出し ID。
  • 入出力の形状:キー、件数、長さ、ステータス。
  • 分岐の判断と、その判断の根拠となったデータ。
  • ミューテーションの前後の状態。
  • エラー名/メッセージと関連するメタデータ。
  • 非同期、ストリーミング、並行処理のフローを示す順序マーカー。

記録を避ける内容:

  • API キー、認証ヘッダー、トークン、Cookie、認証情報。
  • 必要かつ安全な場合を除き、ユーザーコンテンツ全体。
  • ログが読みづらくなる大きなペイロード。
  • 不具合の調査に必要な場合を除き、バイナリデータやモデルの応答全体。

デバッグログには機密情報が含まれる可能性があるものとして扱います。ユーザーが内容を確認して、機密情報を削除またはマスキングする前に、公開 issue、PR、共有チャンネルへ貼り付けるよう求めないでください。

機密情報が含まれる可能性がある場合は、マスキングした要約を記録します:

debugBug('request.received', {
  hasAuthHeader: Boolean(headers.authorization),
  bodyKeys: Object.keys(body ?? {}),
  messageCount: body?.messages?.length,
});

ユーザーへの再現手順の引き継ぎ

ユーザーが手動で再現する必要がある場合は、次の形式をそのまま伝えます:

I added temporary unconditional JSONL instrumentation. Please reproduce the issue once, then send me or point me at:

<cwd>/debug-difficult-bug.jsonl

After I inspect that log, I’ll remove the instrumentation and make the actual fix.

複数のプロセスで作業ディレクトリが異なる場合は、次のいずれかを行います:

  • 起動時に、絶対パスの process.cwd()、プロセスの役割、pid を記録します。または
  • debug-server-flow.jsonl、debug-worker-flow.jsonl、debug-client-flow.jsonl のように、ファイルを分けて出力します。

分析チェックリスト

修正に取りかかる前に、次の問いに答えます:

  • 計測対象のコードパスは実際に実行されましたか?
  • 期待されるイベントの順序は何でしたか?
  • 実際のイベントの順序はどうでしたか?
  • 最初に発生した誤った状態、欠落した値、重複イベント、または誤った分岐は何ですか?
  • 元の red テストは、その差異を正確に捉えていますか?
  • そうでない場合、回帰テストをどう変更すべきですか?

最終確認

難しい不具合の対応は、次のすべてを満たすまで完了ではありません:

  • 実際の再現手順が成功する。
  • 実現可能な場合、回帰テストが修正前には失敗し、修正後には成功する。
  • 一時的に追加した無条件の計測コードを削除する。
  • 最終的な差分に、修正と意図したテストだけが含まれている。
  • JSONL ログの証拠に基づいて、根本原因を説明できる。

コメント