关于 root-cause-tracing
面向开发者的调试技能,用于排查调用链深处出现的故障。它指导逐层追踪调用和数据,找到最初触发原因,并在多个层级添加校验。
主要功能
- 01沿调用链回溯触发原因
- 02通过堆栈跟踪添加诊断信息
- 03定位导致污染的测试
- 04在多个层级添加校验
适用场景
- 01排查执行深处出现的错误
- 02查找无效输入的来源
- 03定位造成文件系统污染的测试
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ jackspace/ claudeskillz --skill root-cause-tracing安装后在 Claude Code 中输入/root-cause-tracing确认已加载。
附带文件find-polluter.shSKILL.json
详细介绍
根因追踪
概述
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
追踪链:
git init在process.cwd()中运行 ←cwd参数为空- WorktreeManager 接收到空的 projectDir
- Session.create() 收到空字符串
- 测试在 beforeEach 之前访问了
context.tempDir - 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 项测试通过,未发生污染