mcpField
R
root-cause-tracing

root-cause-tracing

github.com/zenobi-us开发6844 次安装今天更新
代码仓库

关于 root-cause-tracing

面向开发者的调试技能,通过调用链逆向追踪故障,定位并修复最初诱因,而不只处理表面症状。

主要功能

  1. 01沿调用链追踪故障
  2. 02定位最初诱因
  3. 03通过堆栈跟踪添加检测
  4. 04查找造成污染的测试
  5. 05在多个层级添加验证

适用场景

  1. 01调试执行深处发生的错误
  2. 02查明无效数据的来源
  3. 03定位造成文件系统污染的测试

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/zenobi-us/dotfiles --skill root-cause-tracing

安装后在 Claude Code 中输入/root-cause-tracing确认已加载。

附带文件find-polluter.sh

详细介绍

根因追踪

概述

Bug 往往会在调用栈深处显现(在错误的目录中运行 git init、在错误的位置创建文件、使用错误的路径打开数据库)。你的直觉可能是修复错误出现的位置,但那只是在处理症状。

**核心原则:**沿着调用链向回追踪,直到找到最初的触发点,然后从源头修复。

适用场景

digraph when_to_use {
    "Bug appears deep in stack?" [shape=diamond];
    "Can trace backwards?" [shape=diamond];
    "Fix at symptom point" [shape=box];
    "Trace to original trigger" [shape=box];
    "BETTER: Also add defense-in-depth" [shape=box];

    "Bug appears deep in stack?" -> "Can trace backwards?" [label="yes"];
    "Can trace backwards?" -> "Trace to original trigger" [label="yes"];
    "Can trace backwards?" -> "Fix at symptom point" [label="no - dead end"];
    "Trace to original trigger" -> "BETTER: Also add defense-in-depth";
}

适用于:

  • 错误发生在执行深处(而非入口点)
  • 堆栈跟踪显示调用链很长
  • 不清楚无效数据的来源
  • 需要找到触发问题的测试或代码

追踪流程

1. 观察症状
Error: git init failed in /Users/jesse/project/packages/core
2. 找到直接原因

是什么代码直接导致了这个问题?

await execFileAsync('git', ['init'], { cwd: projectDir });
3. 追问:是谁调用了它?
WorktreeManager.createSessionWorktree(projectDir, sessionId)
  → called by Session.initializeWorkspace()
  → called by Session.create()
  → called by test at Project.create()
4. 继续向上追踪

传入了什么值?

  • projectDir = ''(空字符串!)
  • 空字符串作为 cwd 时会解析为 process.cwd()
  • 那就是源代码目录!
5. 找到最初的触发点

空字符串是从哪里来的?

const context = setupCoreTest(); // Returns { tempDir: '' }
Project.create('name', context.tempDir); // Accessed before beforeEach!

添加堆栈跟踪

如果无法手动追踪,可以添加检测代码:

// Before the problematic operation
async function gitInit(directory: string) {
  const stack = new Error().stack;
  console.error('DEBUG git init:', {
    directory,
    cwd: process.cwd(),
    nodeEnv: process.env.NODE_ENV,
    stack,
  });

  await execFileAsync('git', ['init'], { cwd: directory });
}

**关键:**在测试中使用 console.error()(不要用 logger——它可能不会显示)

运行并捕获:

npm test 2>&1 | grep 'DEBUG git init'

分析堆栈跟踪:

  • 查找测试文件名
  • 找到触发调用的行号
  • 识别模式(是否是同一个测试?同一个参数?)

找出导致污染的测试

如果某些内容在测试期间出现,但你不知道是哪个测试导致的:

使用二分脚本:@find-polluter.sh

./find-polluter.sh '.git' 'src/**/*.test.ts'

逐个运行测试,在第一个导致污染的测试处停止。用法请参阅脚本。

实例:空的 projectDir

**症状:**在 packages/core/(源代码目录)中创建了 .git

追踪链:

  1. git init 在 process.cwd() 中运行 ← cwd 参数为空
  2. WorktreeManager 接收到空的 projectDir
  3. Session.create() 收到空字符串
  4. 测试在 beforeEach 之前访问了 context.tempDir
  5. setupCoreTest() 最初返回 { tempDir: '' }

**根本原因:**顶层变量初始化时访问了空值

**修复:**将 tempDir 改为 getter,使其在 beforeEach 之前被访问时抛出错误

还增加了纵深防御:

  • 第 1 层:Project.create() 验证目录
  • 第 2 层:WorkspaceManager 验证目录非空
  • 第 3 层:NODE_ENV 防护确保不会在 tmpdir 外运行 git init
  • 第 4 层:在运行 git init 之前记录堆栈跟踪

核心原则

digraph principle {
    "Found immediate cause" [shape=ellipse];
    "Can trace one level up?" [shape=diamond];
    "Trace backwards" [shape=box];
    "Is this the source?" [shape=diamond];
    "Fix at source" [shape=box];
    "Add validation at each layer" [shape=box];
    "Bug impossible" [shape=doublecircle];
    "NEVER fix just the symptom" [shape=octagon, style=filled, fillcolor=red, fontcolor=white];

    "Found immediate cause" -> "Can trace one level up?";
    "Can trace one level up?" -> "Trace backwards" [label="yes"];
    "Can trace one level up?" -> "NEVER fix just the symptom" [label="no"];
    "Trace backwards" -> "Is this the source?";
    "Is this the source?" -> "Trace backwards" [label="no - keeps going"];
    "Is this the source?" -> "Fix at source" [label="yes"];
    "Fix at source" -> "Add validation at each layer";
    "Add validation at each layer" -> "Bug impossible";
}

**绝不要只修复错误出现的位置。**向回追踪,找到最初的触发点。

堆栈跟踪提示

**在测试中:**使用 console.error(),不要用 logger——logger 可能会被屏蔽
**执行操作前:**在危险操作之前记录日志,而不是失败后
**包含上下文:**目录、cwd、环境变量、时间戳
捕获堆栈:new Error().stack 会显示完整的调用链

实际效果

来自一次调试会话(2025-10-03):

  • 通过 5 层追踪找到根本原因
  • 在源头修复(getter 验证)
  • 增加了 4 层防御
  • 1847 项测试通过,未发生污染

评论

支持 Markdown