mcpField
D
debug-hypothesis

debug-hypothesis

github.com/lichamnesia开发23153 次安装20 周前更新
代码仓库

关于 debug-hypothesis

面向编码 Agent 的假设驱动调试技能,按观察、假设、实验和结论四阶段推进。它要求先以证据验证原因再编写修复,并将调查过程记录在 DEBUG.md 中。

主要功能

  1. 01四阶段调试循环
  2. 02提出并排序根因假设
  3. 03实验改动最多五行
  4. 04在 DEBUG.md 记录调查
  5. 05确认原因后添加回归测试

适用场景

  1. 01调查原因不明的测试失败
  2. 02追查修复后复发的缺陷
  3. 03诊断不熟悉的崩溃或错误
  4. 04排查不同环境间的行为差异

安装

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

$npx skills add https://github.com/lichamnesia/lich-skills --skill debug-hypothesis

安装后在 Claude Code 中输入/debug-hypothesis确认已加载。

详细介绍

假设驱动调试

一个四阶段循环,将调试从“随便试些修复,然后碰运气”转变为严谨的调查。每个阶段都有目标、硬性规则,以及一张合理化借口表,列出 Agent 为跳过该阶段会编造的理由。

核心原则:**在有证据证明假设正确之前,不得编写修复代码。**猜测不是调试。

适用场景

  • 测试失败,且原因无法立即看出
  • 同一个 Bug 已经“修复”过两次,却再次出现
  • Agent 尝试的修复不起作用——阻止它再试另一个
  • 遇到从未见过的崩溃或错误消息
  • 性能退化,但没有明显的罪魁祸首
  • 不同环境下的行为不一致(本地与 CI、开发与生产)
  • Agent 陷入循环,反复应用同一个错误修复

不适用场景

  • 拼写错误、缺少导入或语法错误——直接修复
  • 原因明显且只有一行的构建失败
  • 编译器或代码检查器的消息已准确指出问题及位置
  • 你已经知道根本原因,只需编写修复代码

如果 Bug 在尝试修复一次后仍然存在,请立即切换到此技能。

调试循环

  OBSERVE  ──▶  HYPOTHESIZE  ──▶  EXPERIMENT  ──▶  CONCLUDE
     │              │                  │               │
     ▼              ▼                  ▼               ▼
  Gather          List 3-5         One minimal       Root cause
  symptoms,       possible         test per          confirmed
  reproduce       causes +         hypothesis,       or loop
  reliably        evidence         max 5 lines       back
     │              │                  │               │
     └──────────────┴──────────────────┴───────────────┘
              write everything to DEBUG.md

硬性规则:

  1. 所有内容都要写入 DEBUG.md。如果推理只存在于对话中,上下文压缩会将其吞掉。
  2. 在观察、假设或实验阶段,不得编写修复代码。
  3. 不得跳过假设阶段。“我想我知道原因了”就是一个假设——把它写下来,并像检验其他假设一样进行测试。
  4. 每次实验最多改动 5 行。如果实验需要更多改动,说明假设过于模糊——将其拆分。

阶段 1:观察

**目标。**收集原始事实。复现 Bug。区分你知道的内容与假设的内容。

步骤。

  1. 复现 Bug。获取准确的错误消息、堆栈跟踪或错误输出。如果无法复现,这就是你的第一个发现。
  2. 找到最小复现。移除无关代码,直到 Bug 仍然出现。
  3. 记录环境:操作系统、运行时版本、依赖项、配置。
  4. 记录哪些内容可以正常工作。正常与异常之间的边界,就是 Bug 所在之处。
  5. 将所有观察结果写入 DEBUG.md 的 ## Observations 小节。

退出标准。

  • 已复现 Bug(或记录了无法复现的情况及条件)
  • 已记录准确的错误消息或错误行为
  • 已找到最小复现
  • 已将观察结果写入 DEBUG.md

常见合理化借口

借口实际情况
“我已经知道问题出在哪了”那就把它写成假设并证明它。如果你是对的,只需 2 分钟。
“让我先试试这个快速修复”这样你最终就会花 45 分钟,尝试 6 次都失败。
“错误消息已经说得很清楚了”错误消息描述的是症状,而不是原因。NullPointerException 告诉你什么出了问题,却没有说明为什么。
“我不需要复现,我能从代码里看出 Bug”你确定吗?那为什么它还没有被修复?

阶段 2:提出假设

目标。 提出 3-5 个可能的根本原因。对于每个原因,列出阶段 1 中支持和相悖的证据,并按可能性排序。

步骤。

  1. 列出 3-5 个假设。不是 1 个,也不是“我觉得是 X”。至少 3 个。 从以下类别进行思考:
    • 数据:输入错误、字段缺失、类型不匹配、编码问题
    • 逻辑:条件错误、差一错误、竞态条件、顺序错误
    • 环境:配置、版本、依赖、权限
    • 状态:缓存过期、状态泄漏、初始化顺序
  2. 对于每个假设,写出:
    • 支持证据: 支持该理论的观察证据
    • 相悖证据: 不支持该理论的证据
    • 测试: 能证实或推翻该理论的最小实验
  3. 标记 根本假设——有支持证据且没有相悖证据的那个假设。如果有多个符合条件,选择最容易测试的一个。
  4. 将所有内容写入 DEBUG.md 中的 ## Hypotheses 下。

DEBUG.md 中的格式示例:

## Hypotheses

### H1: Race condition in session middleware (ROOT HYPOTHESIS)
- Supports: only happens under concurrent requests, timing-dependent
- Conflicts: none yet
- Test: add mutex lock around session read, check if bug disappears

### H2: Stale cache returning expired token
- Supports: works after restart (cache cleared)
- Conflicts: cache TTL is 5min, bug appears within 30s
- Test: disable cache, reproduce

### H3: Wrong env variable in CI
- Supports: works locally, fails in CI
- Conflicts: env diff shows identical values
- Test: print actual runtime value in CI logs

退出条件。

  • 至少写出 3 个假设
  • 每个假设都有支持证据和相悖证据
  • 每个假设都有具体且精简的测试
  • 已标记根本假设
  • 所有内容都已写入 DEBUG.md

常见借口

借口事实
“我只有一个理论”你只有一个最喜欢的理论。再仔细想想。万一不是它呢?
“写下来太慢了”不写下来调试更慢。压缩一旦把它吃掉,你就会忘记假设 2。
“第一个假设显然是对的”那么证实它只需 2 分钟。如果跳过验证,等发现它是错的,就要花 30 分钟。
“我没有相悖证据”这意味着你还没有足够深入地调查,或者它确实就是根本原因。无论哪种情况,都要测试。

阶段 3:实验

目标。 用尽可能小的改动测试根本假设。 你是科学家——你要尝试证伪,而不是证实。

步骤。

  1. 运行实验前先写下实验方案。你要改什么?什么结果能证实假设?什么结果能推翻假设?
  2. 做出改动。最多 5 行。 如果需要更多,说明你的假设太模糊。
  3. 运行阶段 1 中的复现步骤。
  4. 将结果记录在 DEBUG.md 中的 ## Experiments 下。

实验规则。

  • 一次只改一个变量。不要为了“节省时间”而合并两个修复。
  • 不要编写生产环境修复代码。编写诊断代码:日志语句、断言、简化逻辑、硬编码值。
  • 记录结果后撤销实验。保持工作区整洁。
  • 如果实验没有明确结论,那也是一种结果——记录下来并测试下一个假设。

退出条件。

  • 已执行实验(一次改动、一个变量)
  • 已记录结果:证实、推翻或无法得出结论
  • 已撤销实验代码
  • 结果已写入 DEBUG.md

常见借口

借口事实
“我直接修复,不测试了”不确认原因就修复,可能会提交错误的修复并导致其他问题。
“我一次测试两件事,节省时间”两者都改了而 Bug 消失时,你怎么知道是哪一个修复了它?现在你还得重新测试。
“5 行不够”5 行足以添加日志、断言、硬编码值或短路逻辑。如果不够,你的假设就只是“某处出了问题”,而不是一个假设。
“不用撤销,修复基本上就是实验”实验用于诊断,修复是生产代码。两者的质量要求不同。

阶段 4:总结

目标。 确认根本原因,编写真正的修复,并添加回归测试。

步骤。

  1. 如果根本假设得到确认:
    • 在 DEBUG.md 中用一句话写明根本原因。
    • 现在——且仅限现在——编写生产环境修复代码。
    • 添加一个回归测试,确保没有修复时测试失败,有修复时测试通过。
    • 将修复和测试一起提交。
  2. 如果根本假设被否定:
    • 在 DEBUG.md 中记录否定结论及证据。
    • 将下一个假设提升为根本假设。返回阶段 3。
    • 如果所有假设都被否定,则带着新的观察结果返回阶段 1。
  3. 在 DEBUG.md 中更新最终的 ## Root Cause 和 ## Fix 部分。

退出标准。

  • 已找出根本原因,并用一句话写明
  • 已提交修复
  • 已提交回归测试
  • DEBUG.md 已补全完整的调查过程
  • 原始复现用例现在可以通过

常见借口

借口实际情况
“我不需要回归测试,这只是个简单修复”简单的 bug 修复不需要这项技能。你之所以在这里,是因为问题并不简单。添加测试。
“DEBUG.md 只是用来调试的,我会把它删掉”保留它。将来你再次调试同一区域时,会感谢现在的自己。
“所有假设都不成立,我卡住了”回到观察阶段。你漏掉了什么。bug 确实存在,因此一定有原因。

反蛮干规则

AI 调试中最常见的失败模式:Agent 形成一个理论,写出 150 行“修复”代码,发现不起作用,于是沿着同一个错误理论继续深入,又写出 150 行代码。

这项技能就是为防止这种情况而存在的。 如果你发现自己或 Agent:

  • 在确认假设前写了超过 5 行代码 → 停下。回到阶段 2。
  • 第二次尝试相同的方法 → 停下。该假设已被否定。尝试下一个。
  • 忽视相互矛盾的证据 → 停下。把证据写下来,重新排列假设的优先级。
  • 连续失败 3 次后觉得“快成功了” → 停下。你正在蛮干。

写下来。测试它。证明它。然后再修复。

评论

支持 Markdown