mcpField
D
debug

debug

github.com/dyrits开发048 次安装1 天前更新
代码仓库

关于 debug

Debug 是用于调查复杂软件故障的结构化技能,面向开发者和编码 Agent。它要求先建立并缩减可复现的反馈循环,再提出排序后的假设,并指导探查、回归测试与清理。

主要功能

  1. 01建立可判定失败的反馈循环
  2. 02复现并缩减故障场景
  3. 03排列可证伪的假设
  4. 04通过定向插桩进行探查
  5. 05添加回归测试并清理

适用场景

  1. 01诊断症状明确且可复现的故障
  2. 02调查间歇性失败
  3. 03追踪性能回退
  4. 04依据原始场景验证修复

安装

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

$npx skills add https://github.com/dyrits/skills --skill debug

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

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

apm.yml
agents/
openai.yaml
assets/
hitl-loop.template.sh

详细介绍

调试

用于处理难以修复的 bug 的方法。只有在明确说明理由时才跳过阶段。

探索代码库时,如果 AGENTS.md 指向相关内容,请阅读你正在处理的区域中的术语表和架构决策记录,以清楚了解相关模块。报告中提及一个它未提到但可能相关的内容,而不是使用它。

脱敏

此技能要求你展示命令、输出和捕获的材料。先对所有秘密信息进行脱敏:用 <REDACTED> 替换。围绕环境变量构建循环,让凭据留在环境中,而不是出现在展示内容里。捕获的材料可能包含身份验证标头:只引用能体现关键信息的行。

如果脱敏后的输出不足以诊断 bug,请说明这一点并询问用户。

阶段 1:构建反馈循环

这就是本技能的核心。其他一切都是机械性的。如果你有一个针对该 bug 的紧密通过/失败信号(能在_这个_ bug 出现时变为失败),就能找到原因;二分查找、假设检验和插桩都只是利用这个信号。如果没有,再怎么盯着代码看也无济于事。

在这一步投入不成比例的精力。积极尝试。发挥创造力。不要轻言放弃。

构建反馈循环的方法,大致按优先顺序排列
  1. 失败测试:在任何能触及 bug 的边界上编写测试,包括单元测试、集成测试和端到端测试。
  2. Curl/HTTP 脚本:针对正在运行的开发服务器运行。
  3. CLI 调用:使用夹具输入,并将标准输出与已知正常的快照进行比较。
  4. 无头浏览器脚本:使用 Playwright/Puppeteer 驱动 UI,并断言 DOM/控制台/网络结果。
  5. **重放捕获的跟踪记录。**将真实的网络请求/负载/事件日志保存到磁盘,再通过隔离的代码路径重放。
  6. **临时测试框架。**启动系统的最小子集(一个服务、模拟依赖),通过一次函数调用触发 bug 所在的代码路径。
  7. **属性/模糊测试循环。**如果 bug 表现为“有时输出错误”,就运行 1000 个随机输入并查找故障模式。
  8. **二分查找测试框架。**如果 bug 出现在两个已知状态之间(提交、数据集、版本),就自动执行“在状态 X 启动、检查、重复”,以便运行 git bisect run。
  9. **差异循环。**使用相同输入分别运行旧版本与新版本(或两种配置),然后比较输出。
  10. **HITL bash 脚本。**最后的手段。如果必须由人点击,就使用 assets/hitl-loop.template.sh 的副本引导_他们_,让循环仍然有条理:填写步骤,请用户在自己的终端中运行,并读取他们粘贴回来的 KEY=VALUE 行。

构建正确的反馈循环,bug 就解决了 90%。

收紧循环

把循环当作产品来打磨。构建出_一个_循环后,继续收紧它:

  • 我能让它更快吗?(缓存设置、跳过无关初始化、缩小测试范围。)
  • 我能让信号更明确吗?(针对具体症状断言,而不是只检查“没有崩溃”。)
  • 我能让结果更确定吗?(固定时间、设定随机数种子、隔离文件系统、冻结网络。)

30 秒的间歇性失败循环几乎不比没有循环强;2 秒且结果确定的循环才足够紧凑,是调试的超能力。

非确定性 bug

目标不是获得干净的复现,而是提高复现率。将触发条件循环 100 次、并行运行、增加压力、缩小时间窗口、注入休眠。复现概率为 50% 的间歇性 bug 可以调试;1% 的不行,所以要持续提高复现率,直到可以调试为止。

确实无法构建循环时

停止并明确说明。列出你尝试过的操作。向用户索取:(a) 对复现问题所需环境的访问权限,(b) 脱敏后的捕获材料(HAR 文件、日志转储、核心转储、带时间戳的屏幕录制),或 (c) 添加临时生产环境插桩的许可。不要在没有循环的情况下继续提出假设。

完成标准:一个能稳定触发失败的紧凑循环

当循环既紧凑又能触发失败时,阶段 1 就完成了:你可以说出一条命令(脚本路径、测试调用或 curl),并且至少已经运行过一次(展示调用和输出,并做脱敏),而且这条命令:

  • 能触发失败:它会走实际的错误代码路径,并断言用户遇到的确切症状,因此针对这个错误时能够失败,修复后能够通过。不能只是“运行时没有报错”;它必须能_捕获这个特定错误_。
  • 确定性:每次运行的判定结果相同(对于不稳定错误,按上述说明,复现率必须足够高且固定)。
  • 快速:几秒,而不是几分钟。
  • 可由 Agent 运行:可以无人值守地运行;只有通过 assets/hitl-loop.template.sh 才需要人工参与。

如果你发现自己正在阅读代码、构建理论,而这条命令还不存在,**请停下来:直接跳到假设正是这项技能要防止的问题。**没有能触发失败的命令,就不要进入阶段 2。

阶段 2:复现 + 最小化

运行循环。观察它在错误出现时触发失败。

确认:

  • 循环产生的是用户描述的故障模式,而不是碰巧发生在附近的另一种故障。错误的问题就会导致错误的修复。
  • 多次运行都能复现故障(对于非确定性错误,则复现率要足够高,以便据此调试)。
  • 已记录确切症状(错误消息、错误输出、耗时过长),以便后续阶段验证修复确实解决了问题。
最小化

循环触发失败后,将复现缩减为仍能触发失败的最小场景。一次只删减一项输入、调用方、配置、数据或步骤,每次删减后都重新运行循环,并且只保留导致故障不可或缺的部分。

为什么要做这件事:最小复现可以缩小阶段 3 的假设空间(可疑因素更少),也能成为阶段 5 中简洁的回归测试。

当剩余的每个元素都不可或缺时,就算完成:移除其中任何一个元素,循环都会通过。

复现并且完成最小化之前,不要继续。

阶段 3:提出假设

在测试任何假设之前,先生成 3–5 个按优先级排序的假设。只生成一个假设会让你锚定在第一个看似合理的想法上。

每个假设都必须可证伪:说明它会产生什么预测。

格式:“如果 是原因,那么 <更改 Y> 会让错误消失 / <更改 Z> 会让错误加重。”

如果无法说明预测,这个假设就只是凭感觉:要么舍弃,要么进一步明确。

**测试之前,先向用户展示排序后的列表。**他们通常掌握领域知识,能立即调整优先级(“我们刚刚部署了对 #3 的更改”),也可能知道哪些假设已经排除。这是成本很低却能节省大量时间的检查点。不要因此停滞;如果用户暂时不在线,就按你的排序继续。

阶段 4:添加检测

每个探查都必须对应阶段 3 中的一个具体预测。一次只更改一个变量。

工具优先级:

  1. 如果环境支持,优先使用调试器 / REPL 检查。一个断点胜过十条日志。
  2. 在能区分不同假设的边界处添加有针对性的日志。
  3. 绝不要“记录所有内容再 grep”。

为每条调试日志加上唯一前缀,例如 [DEBUG-a4f2]。最后清理时只需执行一次 grep。未加标记的日志会残留下来;加了标记的日志则会被清除。

**性能分支。**对于性能回归,日志通常不是正确的工具。应先建立基准测量(计时工具、performance.now()、性能分析器、查询计划),然后再做二分查找。先测量,再修复。

第 5 阶段:修复 + 回归测试

只有在存在合适的切入点时,才在修复前编写回归测试。

复现只能说明存在故障,并不意味着可以更改已达成一致的行为。当症状、规范和代码对预期行为的理解不一致时,应将这一冲突告知用户,并保留已观察到的失败和通过证据,而不是削弱要求来让流程通过。

合适的切入点是指测试能在调用点复现实际发生的错误模式。如果唯一可用的切入点过于浅层(例如,问题需要多个调用方,但测试只涉及单个调用方;或单元测试无法复现触发问题的调用链),那么在此处编写回归测试只会带来虚假的信心。

如果不存在合适的切入点,这本身就是一项发现。 记下来。代码库架构阻碍了对该问题的可靠防护。请在下一阶段标记此事。

如果存在合适的切入点:

  1. 将最小化复现转化为该切入点处的失败测试。
  2. 观察测试失败。如果你通过修改代码或测试夹具强行制造失败,请与原始副本执行 diff,确认修改确实生效后再采信结果。
  3. 应用修复。
  4. 观察测试通过。
  5. 针对原始(未最小化)场景,重新运行第 1 阶段的反馈循环。

第 6 阶段:清理

宣布完成前,必须完成以下事项:

  • 原始复现不再复现问题(重新运行第 1 阶段的反馈循环)
  • 回归测试通过(或已记录不存在合适的切入点)
  • 移除所有 [DEBUG-...] 埋点(使用 grep 搜索该前缀)
  • 删除临时原型(或将其移至明确标记的调试目录)
  • 在提交 / PR 消息中说明最终证实正确的假设,让后续调试人员有所借鉴

评论

支持 Markdown