bug-debugging-playbook

Use when debugging a reproducible or intermittent bug, regression, crash, freeze, flaky test, failing build, or production incident where symptoms, environments, logs, recent changes, or root cause ne

SKILL.md

GitHub

Bug 调试证据链手册

中文简介

Bug 调试证据链手册:把异常症状转为可复现案例或可关联观测,再用可证伪假设和单变量实验确认根因,最后交付最小修复、回归门禁与剩余风险。它不把“最可能的代码”当作根因,也不以临时缓解冒充永久修复。

使用背景

用于崩溃、接口错误、数据异常、卡死、回归、间歇性故障、失败构建和 flaky test。它消费症状、期望/实际行为、复现步骤、日志/trace、时间与数据、环境、近期变更和代码库证据,产出可复现案例或观测增强方案、假设日志、根因证据、最小修复与回归门禁。

在只有 Issue、尚未判断是否为 Bug 或需要安全推进实现时,可先用 issue-to-pr;陌生仓库没有入口或测试地图时,先用 codebase-onboarding。它不是性能容量规划、纯代码风格审查或在没有症状的情况下重构。

核心原则

  • 先分离症状、影响和机制:症状是观察到的差异,根因是被证据支持的机制;两者不能互相替代。
  • 每个 [事实] 回链到命令、日志、trace、指标、版本、代码或用户原话;[推断] 写依据与验证动作;[假设] 写可证伪预测;未知不补造。
  • 在代码修改前先得到最小复现,或明确记录为何不能复现并增加观测。没有证据门槛,不做猜测性修复。
  • 一个实验只改变一个可控变量,并预先写明预期信号、反证信号和恢复方式;不要并行修改多个“可能点”。
  • 缓解措施降低影响或采集证据,根因修复解释并移除故障机制。两者必须分别标记和验证。
  • 最小修复由最小可证明行为决定,而不是最少行数;回归门禁必须覆盖原始症状、邻近不变量和受影响环境。

适用场景

  • 接口在特定数据、权限、版本或环境下返回错误、超时或错误结果。
  • 用户旅程崩溃、卡死、重复提交、状态错乱,且有日志、会话、trace 或可补齐的观测点。
  • 测试间歇失败、回归或构建失败,需要区分 fixture、时序、隔离和真实产品行为。
  • 线上事故需要先减小用户影响,同时建立时间线、环境差异和变更范围来确认根因。
  • 已有近期变更、版本范围或 last-known-good,可用变更二分缩小责任范围。

不适用场景

  • 没有异常、期望行为或影响,只想“顺手看看”代码时;使用 code-review-assistant 或 refactor-with-safety。
  • 需要从产品反馈判断是否应改变需求时;使用 user-feedback-synthesizer、metric-diagnosis 或 prd-builder。
  • 已确认修复目标、验收、测试位置且只需实施和交付 PR 时;使用 issue-to-pr。
  • 需要为已知行为设计覆盖矩阵而非排障时;使用 test-generator。

输入要求

保留输入来源。最少收集以下内容;缺失项标为 [未知] 并说明其阻断的判断:

  1. 症状与影响:谁受影响、频率、严重度、开始/结束时间、期望与实际行为。
  2. 可复现材料:步骤、最小请求/数据、前置状态、失败信号、成功对照和复现率。
  3. 证据:脱敏日志、request/session/trace ID、堆栈、指标、截图、录屏和采集时间。
  4. 环境:应用、浏览器/设备、操作系统、区域、账户/权限、配置、feature flag、依赖与数据版本。
  5. 时间线与变更:首次出现、last-known-good、部署、配置、schema、依赖、流量或数据变化。
  6. 约束:允许的环境、数据处理/脱敏要求、变更窗口、回滚能力、代码库和测试访问权限。

信息不足时的处理

  • 没有期望或影响: 只交付澄清问题、已知症状和停止条件,不宣称这是 Bug 或给出修复。
  • 不能稳定复现: 记录每次尝试的变量和结果;建立最小观测增强(关联 ID、时间、版本、状态转换、耗时、错误边界和采样),定义采样窗口、隐私边界、owner 与触发条件。此时可给出可回退的缓解措施,但不能宣称根因已确认或合入永久修复。
  • 环境不全或表现不同: 先输出环境差异矩阵,优先验证能解释差异的一个变量;不要把本地成功、staging 失败直接归因于代码。
  • 缺日志但有近期变更: 记录变更候选和时间线;若前后版本可运行,使用受控变更二分。二分只缩小候选范围,仍需机制证据确认根因。
  • 用户要求先改“最可能”代码: 将请求列为 [假设],要求最小复现或观测、可证伪预测和单变量实验;若不满足,停止代码修改并交付调查或缓解计划。

工作流

  1. 保护现场并定义症状。 记录工作区状态、当前版本、时间范围、影响、期望/实际和已知未受影响对照;不覆盖现有用户改动。
  2. 建立证据链与时间线。 给日志、命令、trace、指标、截图和代码阅读分配 E-*;按发生、部署/配置/数据变化、首次观察和恢复排列,标明采集时间与时区。
  3. 做最小复现。 消去与故障无关的步骤、数据和并发,保留最少前置状态与失败信号;记录复现率和成功对照。无法复现则转入观测增强,不进入猜测性代码修复。
  4. 比较环境与输入。 用矩阵比较成功/失败样本的版本、flag、权限、数据、时间、浏览器/设备、依赖和网络;每次只选一个解释力最高的差异验证。
  5. 建立假设日志。 每个 H-* 写机制、支持/反对证据、优先级、预测、实验和判定条件。优先级由影响、可解释证据、可测试性和恢复风险决定,不由直觉决定。
  6. 运行单变量实验。 为 X-* 固定其他变量,变更一个输入、配置、版本、时间序列或隔离条件;记录前后信号、反证和可恢复性。实验失败也保留为证据。
  7. 二分变更和检查机制。 若时间线指向近期变更,用版本、配置或数据变更二分缩小范围;随后读取最小调用链,验证候选机制怎样从输入产生症状。二分命中不是根因确认。
  8. 确认根因或明确未确认。 只有当机制同时解释症状、环境差异和复现,并由独立证据或反向实验支持时,标记为 [已确认根因];否则保持 [未确认假设]。
  9. 实施最小修复或缓解。 先写会失败的回归测试或等价可观察断言,确认红灯原因;一次只改变当前根因所需责任。缓解措施要写范围、失效条件和撤除标准。
  10. 回归验证与交接。 运行原始复现、根因测试、邻近不变量、受影响环境的构建/类型/lint/集成或人工检查;交付证据、回滚、监控和剩余风险。

专业判断规则

证据、症状与根因

结论状态 最小要求 禁止表述
[事实] 可定位来源、时间、环境或命令结果 用截图印象替代原始观察
[推断] 至少一个事实依据与下一步验证 当作已确认根因
[假设] 可证伪预测、单变量实验和反证条件 “最可能所以直接改”
[已确认根因] 机制解释复现/差异且有独立验证 仅因改动后暂时不报错
[缓解措施] 减少影响的证据、范围、撤除条件 标记为永久修复
  • 最小复现必须同时写前置状态、输入、执行动作、失败信号和成功对照。只有错误日志而没有可控制输入时,称为“可关联观察”,不是“可复现”。
  • 环境差异表只比较会影响机制的变量;不同项没有因果证据前仍是候选。生产数据、令牌、个人信息和凭据必须脱敏。
  • 同一轮实验不同时改代码、依赖版本、feature flag 和测试 fixture。若必须改变多个变量,先声明该实验只能生成线索,不能确认因果。
  • 变更二分的候选集合需要明确基线、目标、每步版本/配置、运行环境与失败信号;数据漂移、不可重复构建或外部服务变化会使二分结论降级。

修复与回归门禁

  • 在根因未确认时,代码改动只能作为明确标记的可回退缓解;不得把它写成“已修复”。
  • 最小修复只触及证明机制所需的输入校验、状态转换、错误边界、幂等控制或资源释放责任;重构、格式化、依赖升级需另列并获得确认。
  • 回归测试先验证原始症状,再固定根因不变量和一个未受影响对照。若不能自动化,写明人工步骤、环境、观察窗口、owner 与自动化缺口。
  • 每个“已验证”都记录工作目录、完整命令或动作、执行时间、退出码/观察、关键脱敏输出和 E-* 位置;[未运行] 只写阻断原因,不写通过。

输出契约

按 references/templates.md 交付;没有信息也保留状态:

  1. 调试卡:症状、影响、期望/实际、范围、停止条件和事实/推断/假设/未知账本。
  2. 证据链与时间线:E-*、来源、采集时间、环境、关联 ID、脱敏状态和结论边界。
  3. 最小复现或观测增强:步骤/信号/对照/复现率,或采集字段、采样、隐私、owner 与停止条件。
  4. 环境与数据差异矩阵:成功/失败样本及下一轮只验证的一个变量。
  5. 假设日志与单变量实验:H-*、X-*、优先级、预测、反证、结果和后续。
  6. 变更二分与机制证据:基线、候选范围、每步结果、最小调用链和确认状态。
  7. 根因与缓解决策:明确区分 [已确认根因]、[未确认假设] 和 [缓解措施]。
  8. 最小修复与回归门禁:红灯、最小改动、绿灯、原始复现、邻近不变量、环境验证、回滚/监控和剩余风险。

质量门槛

  • 不把症状、日志关键词、最近改动或“最可能文件”直接写成根因。
  • 不在没有最小复现或观测增强计划时修改代码,也不同时试多个猜测性改动。
  • 不遗漏成功对照、环境差异、数据/时间线或会改变结论的未知项。
  • 不把变更二分结果、测试暂绿或影响下降单独当作根因确认。
  • 不以“已测试”替代带 E-* 的命令/观察证据;无法运行的门禁明确为未运行和阻断。
  • 不合入没有原始症状覆盖、邻近不变量、回滚/缓解边界与剩余风险的修复结论。

常见失败与修正

失败 修正
看见 500 就在 controller 加 catch 先保留请求/数据/版本证据,验证错误来源与期望映射;catch 只能是标记的缓解。
本地正常、staging 失败就断言部署代码坏了 建环境差异矩阵,一轮只验证一个能解释差异的变量。
卡死不能复现仍改“可能死循环”的代码 补状态转换、长任务、错误边界和会话关联观测;先确定采样与停止条件。
一次改重试、超时、缓存和 fixture 拆为 X-* 单变量实验;多变量结果只作为线索。
二分到某个提交就宣布根因 阅读最小调用链,用反向实验确认机制并排除数据/环境漂移。
降低重试次数后事故减少就关闭问题 标记缓解,保留重复请求机制、撤除条件和永久修复验证。

参考资料

  • references/usage-guide.zh.md:中文独立调用方式、输入准备和上下游衔接。
  • references/templates.md:调试卡、证据/实验账本、根因/缓解和回归门禁模板。
  • references/checklists.md:输入、证据、实验、修复和交接质量门。
  • references/examples.md:稳定接口错误、偶发前端卡死和拒绝先改猜测代码的示例。