Diagnosing bugs
Skill toRolex/rolex-skills/skills/engineering/diagnosing-bugs
硬 Bug 和性能回归的诊断循环。当用户说"诊断"/"排查这个",或报告有东西坏了/抛异常/失败/慢时使用。From its SKILL.md
npx -y skills add toRolex/rolex-skills --skill diagnosing-bugsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
8.7 KB, ~3.2k tokens by cl100k_base, as published. Nobody here has run it
术语约定: 以下关键术语保持固定译法:
English 中文 feedback loop 反馈循环 bisection / bisect 二分查找 harness harness(不翻译) regression test 回归测试 hypothesis 假设 seam seam(不翻译) repro 复现 flaky flaky(不翻译) deterministic 确定的 non-deterministic 非确定的 instrumentation 仪表化 HITL HITL(不翻译) plausible 看似合理的
Diagnosing Bugs(Bug 诊断)
针对困难 Bug 的规范流程。只在明确有理由时跳过某个阶段。
浏览代码库时,阅读 CONTEXT.md(如果存在)以获得相关模块的清晰心智模型,并检查你正在接触区域的 ADR。
阶段 1 — 建立反馈循环
这是本 skill 的核心。 其他一切都是机械的。如果你有一个针对此 bug 的紧的通过/失败信号——一个能在此 bug 上变红的信号——你就能找到原因;二分查找、假设检验和仪表化都只是消耗它而已。如果你没有这样一个信号,再多的代码凝视也救不了你。
在此投入不成比例的努力。要激进。要创造。拒绝放弃。
构建反馈循环的方法——大致按此顺序尝试
- 失败的测试 —— 在触及 bug 的任意 seam 上——单元、集成、e2e。
- Curl / HTTP 脚本 —— 针对运行中的 dev server。
- CLI 调用 —— 使用 fixture 输入,将 stdout 与已知正确的快照 diff。
- 无头浏览器脚本(Playwright / Puppeteer)—— 驱动 UI,在 DOM/控制台/网络上断言。
- 重放捕获的 trace。 将真实的网络请求/载荷/事件日志保存到磁盘;在隔离环境中通过代码路径重放。
- 一次性 harness。 启动系统的最小子集(一个服务,mocked 依赖),用单个函数调用执行 bug 代码路径。
- Property / fuzz 循环。 如果 bug 是"有时输出错误",运行 1000 个随机输入并查找失败模式。
- 二分查找 harness。 如果 bug 出现在两个已知状态之间(commit、数据集、版本),自动化"在状态 X 启动、检查、重复",这样你就能
git bisect run它。 - 差分循环。 旧版本 vs 新版本(或两种配置)跑相同输入并 diff 输出。
- HITL bash 脚本。 最后手段。如果人类必须点击,用
scripts/hitl-loop.template.sh驱动他们,让循环仍然有结构。捕获的输出反馈给你。
构建了正确的反馈循环,bug 就修复了 90%。
收紧循环
把循环当产品对待。一旦你有了一个循环,收紧它:
- 能更快吗?(缓存设置、跳过无关初始化、缩小测试范围。)
- 能让信号更锐利吗?(对特定症状断言,而不是"没崩溃"。)
- 能让它更确定吗?(固定时间、种子 RNG、隔离文件系统、冻结网络。)
一个 30 秒的 flaky 循环几乎不比没有循环好;一个 2 秒确定的循环是紧的——调试的超能力。
非确定性 bug
目标不是干净的复现而是更高的复现率。循环触发 100 次、并行化、增加压力、缩小时机窗口、注入 sleep。50% flake 的 bug 是可调试的;1% 则不是——持续提高比率直到可调试。
当你真的无法构建循环时
停下来并明确说明。列出你尝试过的。向用户请求:(a)访问复现它的环境,(b)捕获的工件(HAR 文件、日志转储、核心转储、带时间戳的屏幕录制),或(c)添加临时生产仪表化的权限。在没有循环的情况下,不要继续假设。
完成标准——一个能变红的紧循环
阶段 1 完成时,循环是紧的且能变红:你可以命名一个命令——脚本路径、测试调用、curl——你已经至少运行过一次(粘贴调用和输出),并且它满足:
- 能变红 —— 它驱动实际的 bug 代码路径并断言用户的确切症状,所以它能在此 bug 上变红,修复后变绿。不是"运行不报错"——它必须能_捕获这个特定的 bug_。
- 确定的 —— 每次运行结果相同(flaky bug:固定的高复现率,按上面所述)。
- 快速的 —— 几秒,不是几分钟。
- Agent 可运行的 —— 你可以无人值守地运行;人只在
scripts/hitl-loop.template.sh的循环中。
如果你发现自己在这个命令存在之前就读代码来构建理论,停下来——直接跳到假设正是此 skill 要防止的失败。 没有能变红的命令,就没有阶段 2。
阶段 2 — 复现 + 最小化
运行循环。看到它变红——bug 出现。
确认:
- 循环产生了用户描述的失败模式——不是恰好附近的另一个失败。错误的 bug = 错误的修复。
- 失败在多次运行中可复现(或对非确定性 bug,复现率高到足以调试)。
- 你已经捕获了确切症状(错误消息、错误输出、缓慢的时机),以便后续阶段可以验证修复确实解决了它。
最小化
一旦变红,将复现缩小到仍然能变红的最小场景。一次一个地削减输入、调用者、配置、数据和步骤,每次削减后重新运行循环——只保留对失败有承重作用的部分。
为什么要费心:最小的复现缩小了阶段 3 的假设空间(更少的可疑因素)并成为阶段 5 中干净的回归测试。
完成时每个剩余元素都是有承重作用的——移除任何一个都会使循环变绿。
在已经复现和最小化之前不要继续。
阶段 3 — 假设
在测试任何一个之前生成 3–5 个排序的假设。单一假设生成会锚定在第一个看似合理的想法上。
每个假设必须是可证伪的:陈述它所做的预测。
格式:"如果 <X> 是原因,那么 <改变 Y> 将使 bug 消失 / <改变 Z> 将使 bug 更严重。"
如果你无法陈述预测,这个假设只是一种感觉——丢弃或锐化它。
在测试之前向用户展示排序列表。 他们通常有领域知识可以立即重新排序("我们刚部署了对 #3 的变更"),或者知道他们已经排除的假设。便宜的时间检查点,巨大的时间节省。如果用户不在,用你的排序继续,不要阻塞。
阶段 4 — 仪表化
每次探测必须映射到阶段 3 的特定预测。一次只改变一个变量。
工具偏好:
- 调试器 / REPL 检查 —— 如果环境支持。一个断点胜过十条日志。
- 有目标的日志 —— 在区分假设的边界上。
- 永远不要"全部记录然后 grep"。
给每条调试日志加唯一前缀,例如 [DEBUG-a4f2]。最后的清理变成一次 grep。带标签的日志存活;未带标签的删除。
性能分支。 对于性能回归,日志通常是错的。替代方案:建立基线测量(计时 harness、performance.now()、分析器、查询计划),然后二分查找。先测量,后修复。
阶段 5 — 修复 + 回归测试
在修复之前写回归测试——但只在有正确的 seam 的情况下。
正确的 seam 是测试在调用方实际发生的位置上运行真正的 bug 模式。如果唯一可用的 seam 太浅(单个调用者测试但 bug 需要多个调用者、无法复现触发 bug 的链条的单元测试),那里的回归测试会给出虚假的信心。
如果没有正确的 seam,这本身就是发现。 记下来。代码库架构阻止了将 bug 锁定。将此标记给下一阶段。
如果存在正确的 seam:
- 将最小化的复现转化为该 seam 上的失败测试。
- 看到它失败。
- 应用修复。
- 看到它通过。
- 针对原始(未最小化的)场景重新运行阶段 1 的反馈循环。
阶段 6 — 清理 + 事后分析
在宣布完成前必须进行:
- 原始复现不再复现(重新运行阶段 1 的循环)
- 回归测试通过(或 seam 缺失已记录)
- 所有
[DEBUG-...]仪表化已移除(grep该前缀) - 一次性原型已删除(或移到明确标记的调试位置)
- 最终正确的假设已在 commit / PR 消息中陈述——这样下一个调试者能学习
然后问:什么本可以防止这个 bug? 如果答案涉及架构变更(没有好的测试 seam、调用者纠缠、隐藏耦合),将具体细节交接给 /improve-codebase-architecture skill。在修复之后而非之前提出建议——你现在拥有的信息比开始时更多。
What ships with it: 1 file
1.1 KB alongside SKILL.md, 1 of them executable
scripts/
- hitl-loop.template.shruns1.1 KB