诊断 Bug

SkillDev tools

A diagnostic loop for tricky bugs and performance regressions. Use when the user says "diagnose" / "debug this", or reports that something is broken / throwing exceptions / failing / slow.

Available today. Use it from your connected AI after setup.

Add ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.

Then ask your AI: use the 诊断 Bug skill

What this skill tells your AI

The instructions your AI receives, as published by wenwuzhidao/mattpocock-skills-zh in skills/engineering/diagnosing-bugs/SKILL.md and read by ahel’s review.

一套针对疑难 bug 的准则。只在有明确理由时才跳过某个阶段。

在探索代码库时,读 CONTEXT.md(如果存在)以对相关模块建立清晰的心智模型,并检查你正在触碰的区域里的 ADR。

脱敏

这个技能会让你展示命令、输出和捕获的产物。先给每一个密钥脱敏——用 <REDACTED> 替代它。围绕环境变量构建循环,让凭据留在环境里,而不是留在你展示的东西里。捕获的产物携带认证头:只引用携带信号的那些行。

如果脱敏后的输出不足以诊断 bug,就说出来并询问用户。

阶段 1 — 构建反馈循环

这才是本技能的核心。 其余一切都是机械操作。如果你有一个针对该 bug 的紧凑通过/失败信号——一个能在这个 bug 上变红的信号——你就会找到原因;二分、假设检验和埋点都只是消费它。如果你没有这个信号,再怎么盯着代码看也救不了你。

在这里投入不成比例的努力。要有攻击性。要有创造力。拒绝放弃。

构建它的几种方式——大致按此顺序尝试

  1. 在任何能触及该 bug 的接缝处写一个失败的测试——单元、集成、e2e。
  2. 针对运行中的开发服务器的 Curl / HTTP 脚本。
  3. 用固定输入的 CLI 调用,把 stdout 对照一个已知良好的快照做 diff。
  4. 无头浏览器脚本(Playwright / Puppeteer)——驱动 UI,对 DOM/console/network 做断言。
  5. 回放捕获的 trace。 把一个真实的网络请求 / 载荷 / 事件日志存到磁盘;在隔离环境中让它重新走一遍代码路径。
  6. 用完即弃的测试台。 起一个系统的最小子集(一个服务、mock 掉依赖),用单次函数调用触发 bug 的代码路径。
  7. 属性/模糊循环。 如果 bug 是「有时输出错误」,跑 1000 个随机输入,寻找失败模式。
  8. 二分测试台。 如果 bug 出现在两个已知状态之间(commit、数据集、版本),把「在状态 X 启动、检查、重复」自动化,这样你就能 git bisect run 它。
  9. 差分循环。 把同一个输入分别跑过旧版本和新版本(或两种配置),对输出做 diff。
  10. HITL bash 脚本。 最后手段。如果必须有人来点击,就用 scripts/hitl-loop.template.sh 驱动他们,让循环仍然是结构化的。捕获的输出反馈给你。

构建对的反馈循环,bug 就修好了 90%。

收紧循环

把循环当成一个产品来对待。一旦你有了一个循环,就收紧它:

  • 我能让它更快吗?(缓存 setup、跳过无关的初始化、缩小测试范围。)
  • 我能让信号更锐利吗?(对具体症状而不是「没崩」做断言。)
  • 我能让它更确定吗?(钉住时间、给 RNG 设种子、隔离文件系统、冻结网络。)

一个 30 秒的抖动循环几乎不比没有循环强;一个 2 秒的确定性循环才叫紧凑——一种调试的超能力。

非确定性 bug

目标不是一次干净的复现,而是更高的复现率。把触发器循环 100 次、并行化、加压力、缩窄时序窗口、注入 sleep。50% 抖动的 bug 是可调试的;1% 的不可调试——不断提高这个率,直到它可调试。

当你确实构建不出循环时

停下来并明确说出。列出你尝试过什么。向用户请求:(a) 访问任何能复现它的环境,(b) 一份脱敏后的捕获产物(HAR 文件、日志转储、core dump、带时间戳的录屏),或 (c) 添加临时生产环境埋点的许可。在没有循环的情况下不要继续去提出假设。

完成标准——一个能变红的紧凑循环

当循环紧凑且能变红时,阶段 1 就完成了:你能说出一条命令——一个脚本路径、一次测试调用、一个 curl——它是你已经至少运行过一次的(展示调用及其输出,已脱敏),并且它:

  • 能变红 — 它驱动真正的 bug 代码路径,并对用户确切的症状做断言,因此它能在这个 bug 上变红、修好后变绿。不是「运行不报错」——它必须能够捕获这个具体的 bug。
  • 确定性 — 每次运行判定相同(抖动 bug:如上所述,一个钉死的、高复现率)。
  • 快 — 秒级,而非分钟级。
  • agent 可运行 — 你能无人值守地运行它;只在 scripts/hitl-loop.template.sh 里才有人身处环中。

如果你发现自己在这条命令存在之前就在读代码来构建一个理论,停下——直接跳到假设正是这个技能所要防止的失败。 没有能变红的命令,就没有阶段 2。

阶段 2 — 复现 + 最小化

运行循环。看着它变红——bug 出现了。

确认:

  • 循环产出了用户所描述的那个失败模式——而不是恰好在附近的另一个失败。错的 bug = 错的修复。
  • 失败在多次运行中可复现(或者,对于非确定性 bug,以足够高、可供调试的率复现)。
  • 你已经捕获了确切的症状(错误消息、错误输出、变慢的时序),这样后面的阶段能验证修复确实解决了它。

最小化

一旦它变红,就把复现收缩到仍然会变红的最小场景。一次一个地削减输入、调用方、配置、数据和步骤,每削减一次就重新跑一遍循环——只保留对失败起承重作用的东西。

为什么费这个劲:一个最小复现在阶段 3 缩小了假设空间(剩下可怀疑的活动部件更少),并在阶段 5 成为那个干净的回归测试。

当每一个剩余元素都起承重作用时——移除其中任何一个都会让循环变绿——就完成了。

在你复现并且最小化之前,不要继续。

阶段 3 — 提出假设

在检验任何一个之前,先生成 3–5 个排好序的假设。单一假设的生成会锚定在第一个看似合理的想法上。

每个假设都必须是可证伪的:陈述它做出的预测。

格式:「如果 是原因,那么 <改变 Y> 将让 bug 消失 / <改变 Z> 将让它变得更糟。」

如果你陈述不出预测,那这个假设就是一种感觉——丢弃它或把它磨锐利。

在检验之前把排好序的列表展示给用户。 他们常常拥有能瞬间重新排序的领域知识(「我们刚给 #3 部署了一个改动」),或者知道他们已经排除掉的假设。廉价的检查点,巨大的省时。别为此阻塞——如果用户 AFK,就按你的排序继续。

阶段 4 — 埋点

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

工具偏好:

  1. 如果环境支持,用调试器 / REPL 检查。一个断点胜过十条日志。
  2. 在区分不同假设的边界处打有针对性的日志。
  3. 绝不「打一堆日志然后 grep」。

给每条调试日志打标签,用一个唯一前缀,例如 [DEBUG-a4f2]。最后的清理就变成一次 grep。没打标签的日志会残留;打了标签的日志会被清掉。

性能分支。 对于性能回归,日志通常是错的做法。改为:建立一个基线测量(计时测试台、performance.now()、profiler、查询计划),然后二分。先测量,再修复。

阶段 5 — 修复 + 回归测试

在修复之前写回归测试——但仅当存在一个正确的接缝时。

一个正确的接缝,是指测试能在调用点触发真实的 bug 模式(如其真实发生的那样)。如果唯一可用的接缝太浅(bug 需要多个调用方而测试只有单个调用方、单元测试无法复现触发 bug 的调用链),在那里放一个回归测试会给出错误的信心。

如果不存在正确的接缝,那本身就是一个发现。 记下它。代码库架构正在阻止这个 bug 被锁死。把它标记出来供下一阶段处理。

如果存在正确的接缝:

  1. 把最小化后的复现变成该接缝处的一个失败测试。
  2. 看着它失败。
  3. 施加修复。
  4. 看着它通过。
  5. 针对原始的(未最小化的)场景重新跑阶段 1 的反馈循环。

阶段 6 — 清理 + 事后复盘

宣布完成之前必须做到:

  • 原始复现不再复现(重新跑阶段 1 的循环)
  • 回归测试通过(或接缝缺失的情况已记录在案)
  • 所有 [DEBUG-...] 埋点已移除(grep 那个前缀)
  • 用完即弃的原型已删除(或移到一个明确标记的调试位置)
  • 最终证明正确的那个假设写在了 commit / PR 消息里——好让下一个调试者学到东西

然后问:什么本可以防止这个 bug? 如果答案涉及架构改动(没有好的测试接缝、调用方纠缠、隐藏耦合),就把具体情况交接给 /improve-codebase-architecture 技能。这个建议要在修复落地之后给出,而不是之前——你现在掌握的信息比开始时更多。

Signals

GitHub stars
23
Forks
4
Last commit
Aug 2026
Advanced
Item type
skill
Key
diagnosing-bugs-wenwuzhidao
Source
github.com/wenwuzhidao/mattpocock-skills-zh