根本原因追溯Skill RootCauseTracing

这个技能用于在软件开发过程中,当出现深层错误时,通过向后追溯调用堆栈来找到bug的原始触发点,避免仅修复症状,提高调试效率。关键词包括:根因追溯、调用堆栈、调试、软件测试、故障排除、防御性编程。

测试 0 次安装 0 次浏览 更新于 3/17/2026

name: 根本原因追溯 description: 通过调用堆栈向后系统性地追踪bug以找到原始触发点 when_to__use: 当错误在深度执行中发生,你需要回溯找到原始触发点时 version: 1.1.0 languages: all

根本原因追溯

概述

Bug通常深入调用堆栈中显现(例如,在错误目录中执行git init,在错误位置创建文件,以错误路径打开数据库)。本能是修复错误出现的地方,但那只是治标不治本。

核心原则: 向后追溯调用链,直到找到原始触发点,然后在源头修复。

何时使用

digraph when_to__use {
    "Bug出现在堆栈深处?" [shape=diamond];
    "可以向后追溯?" [shape=diamond];
    "在症状点修复" [shape=box];
    "追溯至原始触发点" [shape=box];
    "更好:同时添加深度防御" [shape=box];

    "Bug出现在堆栈深处?" -> "可以向后追溯?" [label="是"];
    "可以向后追溯?" -> "追溯至原始触发点" [label="是"];
    "可以向后追溯?" -> "在症状点修复" [label="否 - 死胡同"];
    "追溯至原始触发点" -> "更好:同时添加深度防御";
}

使用时机:

  • 错误发生在深度执行中(不在入口点)
  • 堆栈跟踪显示长调用链
  • 不清楚无效数据源自何处
  • 需要找出哪个测试/代码触发问题

追溯过程

1. 观察症状

错误:在 /Users/jesse/project/packages/core 中 git init 失败

2. 找到直接原因

什么代码直接导致此错误?

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

3. 提问:什么调用了这个?

WorktreeManager.createSessionWorktree(projectDir, sessionId)
  → 由 Session.initializeWorkspace() 调用
  → 由 Session.create() 调用
  → 由 Project.create() 的测试调用

4. 继续向上追溯

传递了什么值?

  • projectDir = '' (空字符串!)
  • 空字符串作为 cwd 解析为 process.cwd()
  • 那是源代码目录!

5. 找到原始触发点

空字符串来自哪里?

const context = setupCoreTest(); // 返回 { tempDir: '' }
Project.create('name', context.tempDir); // 在 beforeEach 之前访问!

添加堆栈跟踪

当无法手动追溯时,添加工具化:

// 在有问题的操作之前
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()(不是日志器 - 可能不显示)

运行并捕获:

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

分析堆栈跟踪:

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

找出哪个测试导致污染

如果某物在测试中出现,但不知道是哪个测试:

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

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

逐个运行测试,在第一个污染者处停止。查看脚本使用说明。

真实示例:空projectDir

症状: .gitpackages/core/(源代码)中创建

追溯链:

  1. git initprocess.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 {
    "找到直接原因" [shape=ellipse];
    "可以向上追溯一层?" [shape=diamond];
    "向后追溯" [shape=box];
    "这是源头吗?" [shape=diamond];
    "在源头修复" [shape=box];
    "在每一层添加验证" [shape=box];
    "Bug不可能发生" [shape=doublecircle];
    "永不只修复症状" [shape=octagon, style=filled, fillcolor=red, fontcolor=white];

    "找到直接原因" -> "可以向上追溯一层?";
    "可以向上追溯一层?" -> "向后追溯" [label="是"];
    "可以向上追溯一层?" -> "永不只修复症状" [label="否"];
    "向后追溯" -> "这是源头吗?";
    "这是源头吗?" -> "向后追溯" [label="否 - 继续追溯"];
    "这是源头吗?" -> "在源头修复" [label="是"];
    "在源头修复" -> "在每一层添加验证";
    "在每一层添加验证" -> "Bug不可能发生";
}

永不只修复错误出现的地方。 向后追溯以找到原始触发点。

堆栈跟踪提示

在测试中: 使用 console.error() 而不是日志器 - 日志器可能被抑制 在操作前: 在有风险的操作前记录,而不是失败后 包含上下文: 目录、cwd、环境变量、时间戳 捕获堆栈: new Error().stack 显示完整的调用链

实际影响

从调试会话(2025-10-03):

  • 通过5级追溯找到根本原因
  • 在源头修复(getter验证)
  • 添加了4层防御
  • 1847个测试通过,零污染