Root Cause Tracing\n\n概述\n\nBug 往往在调用栈深处才显现(例如在错误的目录执行 git init、文件创建在错误位置、数据库以错误路径打开)。直觉上你会想修复错误出现的地方,但那只是治标。\n\n核心原则:沿调用链向上回溯,直到找到最初的触发点,然后从源头修复。\n\n适用时机\n\n资料以判定图说明使用条件:当 Bug 出现在栈深处,且可以向上回溯时,应追溯到原始触发点;若无法回溯,可能只能先修症状点。更佳做法是在追溯并修复源头之外,再添加纵深防御。\n\n使用场景包括:\n- 错误发生在执行深處(而非入口点)\n- 堆栈跟踪显示很长的调用链\n- 不清楚无效数据来自何处\n- 需要找出哪个测试或代码触发了问题\n\n追溯流程\n\n1. 观察症状\n\n示例:git init failed in /Users/jesse/project/packages/core\n\n2. 找到直接原因\n\n哪些代码直接导致该问题?示例代码:\n\nawait execFileAsync('git', ['init'], { cwd: projectDir });\n\n3. 追问:是谁调用了它?\n\nWorktreeManager.createSessionWorktree(projectDir, sessionId)\n → called by Session.initializeWorkspace()\n → called by Session.create()\n → called by test at Project.create()\n\n4. 继续向上追溯\n\n传入的值是什么?\n\nprojectDir = ''(空字符串!)\n\n空字符串作为 cwd 会解析为 process.cwd()\n\n那正是源代码目录!\n\n5. 找到原始触发点\n\n空字符串从哪里来?\n\nconst context = setupCoreTest(); // Returns { tempDir: '' }\nProject.create('name', context.tempDir); // Accessed before beforeEach!\n\n添加堆栈跟踪\n\n当无法手动追溯时,可添加检测代码。示例:\n\n// 在问题操作之前\nasync function gitInit(directory: string) {\n const stack = new Error().stack;\n console.error('DEBUG git init:', {\n directory,\n cwd: process.cwd(),\n nodeEnv: process.env.NODE_ENV,\n stack,\n });\n\n await execFileAsync('git', ['init'], { cwd: directory });\n}\n\n关键:在测试中使用 console.error()(不要用 logger,它可能不显示)。\n\n运行并捕获:\n\nnpm test 2>&1 | grep 'DEBUG git init'\n\n分析堆栈跟踪:\n\n- 查找测试文件名\n- 找到触发调用的行号\n- 识别模式(同一个测试?同一参数?)\n\n找出哪个测试造成污染\n\n如果测试期间出现问题但你不知道是哪个测试:使用分治脚本 @find-polluter.sh\n\n./find-polluter.sh '.git' 'src/**/*.test.ts'\n\n该脚本逐个运行测试,遇到第一个污染者时停止。用法见脚本说明。\n\n真实示例:空的 projectDir\n\n症状:.git 被创建在 packages/core/(源代码目录)\n\n追溯链:\n\ngit init 在 process.cwd() 中运行 ← 空的 cwd 参数\n\nWorktreeManager 收到空的 projectDir\n\nSession.create() 传入空字符串\n\n测试在 beforeEach 之前访问了 context.tempDir\n\nsetupCoreTest() 初始返回 { tempDir: '' }\n\n根因:顶层变量初始化时访问了空值\n\n修复:把 tempDir 改成 getter,如果在 beforeEach 之前访问就抛错\n\n同时添加纵深防御:\n\n第 1 层:Project.create() 校验目录\n\n第 2 层:WorkspaceManager 校验非空\n\n第 3 层:NODE_ENV 保护,拒绝在 tmpdir 之外执行 git init\n\n第 4 层:git init 前记录堆栈跟踪\n\n关键原则\n\n资料以流程图强调:找到直接原因后,能再往上追溯一层吗?能则继续回溯;不能则绝不要只修症状。回溯中判断是否已到源头:不是则继续追溯;是则从源头修复,并在每一层添加校验,最终使 Bug 不可能发生。\n\n绝不要只修复错误出现的位置。要回溯找到最初的触发点。\n\n堆栈跟踪技巧\n\n- 在测试中:使用 console.error() 而非 logger——logger 可能被抑制\n- 在操作前:在危险操作之前记录日志,而不是在失败之后\n- 包含上下文:目录、cwd、环境变量、时间戳\n- 捕获堆栈:new Error().stack 显示完整调用链\n\n实际影响\n\n来自 2025-10-03 的调试会话:\n\n- 通过 5 层追溯找到根因\n- 在源头修复(getter 校验)\n- 添加 4 层防御\n- 1847 个测试通过,零污染\n\n限制与补充说明\n\n关于该技能的具体安装命令、运行环境要求、是否收费、支持平台及版本信息,资料暂未提供。
root cause tracing
测试与质量
更新于 10-15 10:22