# Diagnosing Bugs

> 面向棘手 Bug 和性能回归的诊断循环。当用户说"诊断"/"调试一下"，或反馈某项功能异常、抛错、失败、变慢时使用。诊断、调试、debug、排错、Bug、性能回归、报错

- Skill: `kscz0000/diagnosing-bugs` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add kscz0000/diagnosing-bugs`
- Raw SKILL.md: https://api.skillmd.com/api/skills/kscz0000/diagnosing-bugs/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- License: MIT
- Author: kscz0000 (https://skillmd.com/u/kscz0000)
- Updated: 2026-09-21
- Page: https://skillmd.com/skills/kscz0000/diagnosing-bugs

---


# 诊断 Bug

## 适用场景

当此工作流匹配用户请求时使用：按本文档记录的工作流使用该技能。


_来源：[mattpocock/skills](https://github.com/mattpocock/skills) (MIT)._

一套用于处理棘手 Bug 的纪律。只有在明确合理时才可跳过某个阶段。

在探索代码库时，请阅读 `CONTEXT.md`（若存在）以建立相关模块的清晰心智模型，并查阅你所触及领域的 ADR。

## 阶段 1 —— 建立反馈循环

**这才是技能的核心。** 其余一切只是机械执行。如果你针对这个 Bug 拥有**紧的**通过/失败信号——一个能就此 Bug 变红的信号——你就能找到根因；二分查找、假设检验、插桩都只是对它的消耗。如果没有，再怎么盯着代码也救不了你。

在这一阶段投入不成比例的精力。**要激进。要有创意。绝不放弃。**

### 构建反馈循环的方法——大致按此顺序尝试

1. **失败测试**——在能触达 Bug 的任意接缝处：单元、集成、端到端。
2. **Curl / HTTP 脚本**——对运行中的开发服务器发起请求。
3. **CLI 调用**——使用固定输入（fixture），将 stdout 与已知正常的快照做 diff。
4. **无头浏览器脚本**（Playwright / Puppeteer）——驱动 UI，对 DOM/控制台/网络做断言。
5. **回放已捕获的 trace**。将真实的网络请求 / payload / 事件日志保存到磁盘，在隔离环境中通过代码路径回放。
6. **临时测试夹具（Throwaway harness）**。启动系统的一个最小子集（一个服务、模拟依赖），用单次函数调用跑通 Bug 代码路径。
7. **属性 / 模糊循环**。如果 Bug 是"有时输出错误"，跑 1000 次随机输入寻找失败模式。
8. **二分夹具（Bisection harness）**。如果 Bug 出现在两个已知状态（commit、数据集、版本）之间，将"在状态 X 启动、检查、重复"自动化，以便用 `git bisect run`。
9. **差分循环**。将同一输入在旧版本与新版本（或两种配置）上各跑一遍，对比输出差异。
10. **HITL bash 脚本**。最后手段。若必须由人工点击，用 `scripts/hitl-loop.template.sh` 驱动**用户**，让循环保持结构化。捕获的输出会反馈给你。

构建正确的反馈循环，Bug 等于解决了 90%。

### 收紧循环

把循环当作一个产品。一旦你拥有了**某个**循环，就去**收紧**它：

- 能让它更快吗？（缓存初始化、跳过无关启动、缩小测试范围。）
- 能让信号更锋利吗？（断言到具体症状，而不是"没有崩溃"。）
- 能让它更确定吗？（固定时间、播种 RNG、隔离文件系统、冻结网络。）

一个 30 秒且不稳定的循环，几乎等同于没有循环；一个 2 秒且确定的循环就是紧——一种调试超能力。

### 非确定性 Bug

目标不是干净的复现，而是**更高的复现率**。循环触发 100 次，并行、加压、缩窄时间窗口、注入 sleep。50% 闪退的 Bug 是可调的，1% 则不可——持续提升比率直到可调。

### 当你真的无法建立循环时

停下来明确说明。列出你尝试过的事情。请用户提供：(a) 可复现该问题的环境访问权限，(b) 已捕获的工件（HAR 文件、日志转储、core dump、带时间戳的录屏），或 (c) 在生产环境临时加埋点的授权。**没有循环就绝不进入假设阶段。**

### 完成标准——能变红的紧循环

阶段 1 完成时，循环必须**紧**且**能变红**：你能指出**一条命令**——一个脚本路径、一个测试调用、一段 curl——你**已经至少跑过一次**（粘贴该调用及其输出），并且它满足：

- [ ] **能变红**——它驱动真实的 Bug 代码路径，并断言**用户描述的精确症状**，因此能就此 Bug 变红，并在修复后变绿。不是"运行不报错"——它必须能_捕获这个特定 Bug_。
- [ ] **确定性**——每次运行结论一致（对闪退 Bug：按上文固定高复现率）。
- [ ] **快速**——秒级，而非分钟级。
- [ ] **智能体可跑**——可无人值守运行；只有通过 `scripts/hitl-loop.template.sh` 时才有人参与。

如果你发现自己在该命令出现之前就开始读代码、构建理论——**停下来——直接跳到假设正是本技能要防止的失败。** 没有能变红的命令，就没有阶段 2。

## 阶段 2 —— 复现并最小化

运行循环。看到它变红——Bug 出现。

确认：

- [ ] 循环产生的失败模式是**用户**描述的那个——不是附近恰好出现的另一个失败。Bug 找错，修复也会错。
- [ ] 该失败在多次运行间可复现（或对非确定性 Bug 而言，复现率高到可以调试）。
- [ ] 已捕获精确症状（错误信息、错误输出、慢的耗时），以便后续阶段验证修复确实针对它。

### 最小化

一旦变红，就把复现压缩到**仍能变红的最小场景**。逐个裁剪输入、调用方、配置、数据和步骤，每次裁剪后重跑循环——只保留对失败承重的部分。

为什么要做：最小复现能压缩阶段 3 的假设空间（剩下的可疑活动部件更少），并自然成为阶段 5 的干净回归测试。

**当剩余的每个元素都是承重的**时算完成——移除任一元素都会让循环变绿。

在完成复现**并**最小化之前，不要进入下一阶段。

## 阶段 3 —— 假设

在测试任何假设之前，先提出 **3–5 个有排序的假设**。单一假设生成会锚定在第一个看似合理的想法上。

每个假设必须**可证伪**：明确说出它所做出的预测。

> 格式："如果 <X> 是原因，那么改变 <Y> 会让 Bug 消失 / 改变 <Z> 会让它更严重。"

如果你无法陈述预测，那么这只是一个 vibe——丢弃或打磨它。

**在测试之前向用户展示排序后的列表。** 他们往往具备能瞬间重排的领域知识（"我们刚改了 #3"），或知道已被排除的假设。这是廉价的检查点，却能省大量时间。**不要阻塞**——如果用户离线，按你的排序继续即可。

## 阶段 4 —— 插桩

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

工具偏好：

1. **Debugger / REPL 检查**，若环境支持。一个断点胜过十条日志。
2. **定向日志**，放在能区分假设的边界处。
3. 绝不要"全打日志再 grep"。

**给每条调试日志打上唯一前缀**，例如 `[DEBUG-a4f2]`。收尾时清理只需一次 grep。没打标签的日志会活下来，打了标签的日志会被清掉。

**性能分支。** 对性能回归，日志通常没用。取而代之：先建立基线测量（计时框架、`performance.now()`、profiler、查询计划），再做二分。先测量，再修复。

## 阶段 5 —— 修复 + 回归测试

**先于修复**写回归测试——但前提是存在一个**正确的接缝（correct seam）**。

正确接缝是指：测试在调用点位置，以**真实 Bug 模式**的方式运行。如果唯一可用的接缝太浅（Bug 需要多调用方却只有单调用方测试；单元测试无法复现触发 Bug 的整条链路），在此处放回归测试只会带来虚假信心。

**如果不存在正确接缝，这就是发现本身。** 记下来。代码库的架构正在阻止 Bug 被锁定。请在下一阶段标记此项。

若存在正确接缝：

1. 将最小复现转为在该接缝处失败的测试。
2. 观察它失败。
3. 实施修复。
4. 观察它通过。
5. 针对原始的（未最小化的）场景，重跑阶段 1 的反馈循环。

## 阶段 6 —— 收尾 + 事后复盘

宣布完成前必须满足：

- [ ] 原始复现已不再复现（重跑阶段 1 的循环）
- [ ] 回归测试通过（或已记录接缝缺失）
- [ ] 所有 `[DEBUG-...]` 埋点已移除（`grep` 该前缀）
- [ ] 临时原型已删除（或移至明确标记的调试位置）
- [ ] 最终被证实的假设已写进 commit / PR 描述——让下一位调试者学到东西

**然后追问：怎样才能从一开始阻止这个 Bug？** 若答案涉及架构层面变更（没有好的测试接缝、调用方纠缠、隐藏耦合），将具体情况交接给 `/improve-codebase-architecture` 技能。**待修复落地之后再**给建议——此时你掌握的信息比开始时更多。


## 局限性

- 当工作流点名需要上游工具、账号、API key 或本地环境时，需要相应配置。
- 未经用户明确授权，不会执行破坏性、生产环境、付费或对外消息类的操作。
- 在将生成的工件或建议视为最终结论前，请对照用户的真实来源做校验。
