mcpField
D
diagnose

diagnose

github.com/mksglu开发32.8k53 次安装1 天前更新
代码仓库

关于 diagnose

diagnose 是面向编码 Agent 的系统化疑难调试技能,要求先建立可重复的反馈循环,再逐步复现、验证假设、修复并清理。

主要功能

  1. 01构建自动化反馈循环
  2. 02复现并记录故障症状
  3. 03提出可证伪的排序假设
  4. 04按预测逐项进行探查
  5. 05添加回归测试并修复
  6. 06清理调试痕迹并复盘

适用场景

  1. 01定位偶发或难以复现的缺陷
  2. 02验证性能回归的可能原因
  3. 03为修复建立可靠回归检查

安装

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

$npx skills add https://github.com/mksglu/context-mode --skill diagnose

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

附带文件scripts/hitl-loop.template.sh

详细介绍

诊断

专门用于处理棘手 bug 的方法。只有在明确说明理由时,才能跳过阶段。

探索代码库时,使用项目的领域术语表,清楚了解相关模块,并查看你要修改的部分的 ADR。

阶段 1 — 建立反馈循环

这就是关键技能。 其他一切都是机械操作。如果你有一个快速、确定、可由 Agent 运行的通过/失败信号,就能找到原因——二分查找、假设检验和插桩都只是利用这个信号。如果没有,再怎么盯着代码看也无济于事。

在这里投入不成比例的精力。积极尝试。发挥创意。绝不轻易放弃。

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

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

不断改进循环本身

把循环当作产品。建立_一个_循环后,思考:

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

一个耗时 30 秒且不稳定的循环,几乎不比没有循环强。一个耗时 2 秒且确定的循环,是调试的超能力。

非确定性 bug

目标不是构造出干净的复现步骤,而是提高复现率。重复触发 100 次、并行运行、增加压力、缩小时间窗口、注入休眠。复现率为 50% 的 bug 可以调试;1% 的不行——持续提高复现率,直到能够调试。

确实无法构建循环时

停下来并明确说明。列出你尝试过的方法。向用户请求:(a) 访问能够复现问题的环境,(b) 捕获的产物(HAR 文件、日志转储、核心转储、带时间戳的屏幕录像),或 (c) 添加临时生产环境插桩的许可。不要在没有循环的情况下继续提出假设。

在建立你确信可靠的循环之前,不要进入阶段 2。

阶段 2 — 复现

运行循环。观察 bug 出现。

确认:

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

在复现 bug 之前不要继续。

阶段 3 — 提出假设

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

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

格式:“如果 是原因,那么 <更改 Y> 会让 bug 消失 / <更改 Z> 会让 bug 恶化。”

如果无法说出预测,那这个假设就只是凭感觉——应当舍弃或进一步明确。

测试之前,先向用户展示排序后的列表。 用户通常掌握能立即改变排序的领域知识(“我们刚部署了与 #3 有关的更改”),或者知道哪些假设已经排除。这是一个成本低、收益大的检查点。不要因此停下来等待——如果用户暂时不在,就按你的排序继续。

阶段 4 — 添加探针

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

工具优先级:

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

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

性能分支。 对于性能回退,日志通常不是正确做法。应先建立基准测量(计时测试框架、performance.now()、分析器、查询计划),再进行二分排查。先测量,再修复。

阶段 5 — 修复 + 回归测试

在修复之前编写回归测试——但前提是存在正确的测试切入点。

正确的测试切入点,是指测试能在调用点复现真实的 bug 模式。如果唯一可用的切入点太浅(bug 需要多个调用方,却只有单个调用方的测试;单元测试无法复现触发 bug 的调用链),那么在该处编写回归测试会带来虚假的信心。

如果不存在正确的测试切入点,这本身就是一个发现。 记录下来。代码库架构导致这个 bug 无法通过测试加以锁定。将此问题标记给下一阶段。

如果存在正确的测试切入点:

  1. 将最小化复现转换为该切入点处的失败测试。
  2. 确认它会失败。
  3. 应用修复。
  4. 确认它会通过。
  5. 针对原始(未最小化)场景重新运行阶段 1 的反馈循环。

阶段 6 — 清理 + 事后复盘

宣布完成之前,必须做到:

  • 原始复现不再出现(重新运行阶段 1 的反馈循环)
  • 回归测试通过(或已记录不存在测试切入点)
  • 已移除所有 [DEBUG-...] 插桩(对前缀执行 grep)
  • 已删除临时原型(或将其移至明确标记的调试目录)
  • 在 commit / PR 消息中说明最终证实正确的假设——让下一个调试人员从中学习

然后思考:什么本可以避免这个 bug? 如果答案涉及架构更改(缺少合适的测试切入点、调用方之间纠缠、存在隐藏耦合),请将具体情况交给 /improve-codebase-architecture 技能。在修复完成之后再提出建议,而不是之前——现在你掌握的信息比刚开始时更多。


从 mattpocock/skills 引入,版本为 b843cb5 — MIT License。有关更新说明,请参阅 skills/UPSTREAM-CREDITS.md。

评论

支持 Markdown