mcpField
D
diagnosing-bugs

diagnosing-bugs

github.com/ouyangjiahong26開発580 回インストール1 日前に更新
リポジトリ

diagnosing-bugs について

コーディングエージェントや開発者向けに、難しいバグの診断手順を定めたスキルです。再現可能な短いフィードバックループを先に作り、問題の縮小、仮説検証、修正、確認へ進みます。

主な機能

  1. 01失敗を検出するループの構築
  2. 02最小再現への縮小
  3. 03反証可能な仮説の順位付け
  4. 04診断ポイントへの計測追加
  5. 05回帰テストと修正の検証
  6. 06完了時のデバッグ用成果物の削除

活用シーン

  1. 01再現性のあるバグの診断
  2. 02断続的な障害の調査
  3. 03サービス間の問題の追跡

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/ouyangjiahong26/skills --skill diagnosing-bugs

インストール後、Claude Code で/diagnosing-bugsを入力して読み込まれたか確認します。

同梱ファイルscripts/hitl-loop.template.sh

詳細

プロジェクトの README より

诊断 bug

一套处理难调 bug 的纪律。只有明确说出理由时才能跳过阶段。

探索代码库时,先读 CONTEXT.md(若存在)建立相关模块的心智模型,并查你将要改动区域的 ADR。

脱敏

本 skill 会让你展示命令、输出和抓取到的产物。先给每个密钥脱敏:在原来的位置写 <REDACTED>。回路基于环境变量搭建,让凭证留在环境里,而不是留在你展示的内容里。抓取的产物带 auth header:只引用承载信号的那几行。

如果脱敏后的输出不足以诊断 bug,说明情况,问用户。

阶段 1:建立反馈回路

这一步就是本 skill 的全部。其余都是机械操作。你有一个紧的通过/失败信号(一个在这个 bug 上会失败的信号),就一定能找到根因。二分、验证假设、加打点,全都只是在用它。没有这样一个信号,盯着代码看到天亮也没用。

在这里投入不成比例的精力。积极点。有创意点。别放弃。

怎么搭一个回路:大致按这个顺序试
  1. 失败的测试,落在能触达 bug 的任意接口:单元、集成、端到端。
  2. curl / HTTP 脚本,打本地 dev server。
  3. CLI 调用,喂一个 fixture 输入,把 stdout 和一个已知正确的快照做 diff。
  4. 无头浏览器脚本(Playwright / Puppeteer):驱动 UI,对 DOM / console / network 做断言。
  5. 回放一条抓到的 trace:把一个真实的网络请求 / payload / 事件日志存到磁盘,单独喂回代码路径。
  6. 一次性脚手架:起一个系统的最小子集(一个服务、依赖打桩),用一次函数调用走通出 bug 的代码路径。
  7. 性质测试 / fuzz 回路:如果 bug 是“偶尔输出错”,跑 1000 个随机输入找失败模式。
  8. 二分脚手架:如果 bug 出现在两个已知状态之间(commit、数据集、版本),把“启动到状态 X、检查、再来”自动化,好让 git bisect run 接管。
  9. 差分回路:同一输入分别跑老版本和新版本(或两套配置),diff 输出。
  10. HITL bash 脚本:最后手段。如果非得人手点,用 scripts/hitl-loop.template.sh 驱动他们,让回路仍然有结构。抓到的输出再喂回给你。
收紧回路

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

  • 能不能更快?(缓存 setup、跳过无关初始化、收窄测试范围。)
  • 信号能不能更锋利?(断言具体的症状,而不是“没崩”。)
  • 能不能更确定?(固定时钟、固定随机种子、隔离文件系统、冻结网络。)

一个 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。

如果这条命令还不存在,你却开始读代码、构建理论,停下:跳过回路直接跳到假设,正是本 skill 要防止的失败模式。没有会失败的命令,就没有阶段 2。

阶段 2:复现 + 缩小

跑回路。看它失败:bug 出现了。

确认:

  • 回路产出的是用户描述的那个失败模式,不是恰好挨着的另一个失败。搞错 bug 就是修错地方。
  • 多次跑都能复现(或:偶发 bug 以足够高的复现率出现,能拿来调)。
  • 已经抓下了精确的症状(错误信息、错误输出、慢的耗时),后面的阶段才能验证修复确实对上了症状。
缩小

一旦失败,把复现缩到仍然会失败的最小场景。一次砍掉一项(输入、调用方、配置、数据、步骤),每砍一项就重跑一次回路,只留下对失败真正承重的。

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

缩小完成的标志是剩下的每一项都承重:去掉任何一项,回路都会通过。

在复现并缩小之前,不要往下走。

阶段 3:假设

测试之前,先给出 3 到 5 条排好序的假设。只生成一条假设,就会被锚在第一个听起来靠谱的念头上。

每条假设必须可证伪:能说出它做出的预测。

格式:“如果 <X> 是根因,那么 <改 Y> 会让 bug 消失 / <改 Z> 会让它更严重。”

说不清预测,这条假设就只是个感觉:丢掉,或磨利它。

测试之前,把排好序的清单给用户看一眼。他们常有领域知识,能立刻重排(“我们刚把 #3 那块部署上去了”),或知道哪些假设已经被排除。这是一次便宜的检查点,能省下大把时间。用户不在时不要等,按你的排序继续。

阶段 4:打点

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

工具优先级:

  1. 调试器 / REPL 检查,环境支持时用。一个断点抵十条 log。
  2. 针对性的 log,打在能区分各假设的边界上。
  3. 永远不要“什么都 log 再 grep 筛选”。

给每条 debug log 打一个唯一前缀,比如 [DEBUG-a4f2]。收尾时一次 grep 就能清干净。没打标签的 log 会留下来,打了标签的会被清掉。

性能分支:对性能回归,log 多半不是对的办法。改成先建立基线测量(计时脚手架、performance.now()、profiler、query plan),固定要看的指标(如 P95 延迟、分配次数、查询耗时)和可判定阈值,再用同一指标二分。先量,再修。

分布式分支:跨服务 bug 的打点放在服务边界,给请求注入同一个 trace id 并让它沿调用链传播。在每个服务的入口与出口打点(收到、发出、耗时、状态)。按 trace id 把各服务日志汇成一条时间线,再对照假设。跨服务比较时间戳前先对齐时钟源,或只比较同一服务内的相对耗时。线上抓不到流量时,用阶段 1 的回放回路重放一条抓取到的请求。

阶段 5:修复 + 回归测试

在修复之前写回归测试,但前提是存在一个正确的接口。

正确的接口,是测试能在调用点真正演练 bug 发生模式的接口。如果手头唯一的测试面太浅(bug 需要多个调用方,却只有单调用方的测试。或者 bug 需要整条调用链,单元测试却复现不了),在那里加回归测试只会带来虚假的信心。

如果没有正确的接口,这本身就是一条发现。记下来。代码库的架构正在妨碍用回归测试锁住这个 bug。标给下一阶段。

存在正确的接口时:

  1. 把缩小后的复现变成那个接口上的失败测试。
  2. 看它失败。
  3. 应用修复。
  4. 看它通过。
  5. 用阶段 1 的回路,对着原始(未缩小的)场景再跑一遍。

阶段 6:收尾

宣布完成之前必做:

  • 原始复现不再复现(重跑阶段 1 的回路)
  • 回归测试通过(或:接口缺失已被记录)
  • 所有 [DEBUG-...] 打点已移除(grep 前缀)
  • 一次性原型已删(或挪到一个明确标注的 debug 位置)
  • 最终验证成立的那条假设写进了 commit / PR message,下一个调它的人能学到东西

コメント