关于 debugging-by-evidence
debugging-by-evidence 是面向 Agent 的软件故障排查技能,指导开展有边界的证据驱动实验,并让结论和修复范围与证据相符。
主要功能
- 01按待决问题选择实验
- 02区分观察与注入条件
- 03保留待测基线处理逻辑
- 04限制探测范围并设定停止点
- 05记录结论及证据缺口
适用场景
- 01本地无法复现时调查故障
- 02测试受控依赖结果下的调用方行为
- 03判断证据是否足以支持修复
- 04记录未确认的触发因素或兼容性
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ gabrielmoreira/ skills --skill debugging-by-evidence安装后在 Claude Code 中输入/debugging-by-evidence确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
evals/activation.scenarios.mjsderived.scenarios.mjslayered.scenarios.mjsevals/fixtures/guard-right-before-the-division/package.jsonevals/fixtures/guard-right-before-the-division/src/cart.jscatalog.jsshipping.jsshipping.test.jsevals/fixtures/its-the-cache-it-always-is/package.jsonevals/fixtures/its-the-cache-it-always-is/src/cache.jsdiscounts.jsdiscounts.test.jsevals/fixtures/undefined-arrives-and-nothing-threw/package.jsonevals/fixtures/undefined-arrives-and-nothing-threw/src/pricing/apply.tsload.tsevals/fixtures/undefined-arrives-and-nothing-threw/tests/fixtures/seed.tsrules/fix-at-the-source.mdminimising.mdprobing.mdregression-seam.mdrival-hypotheses.mdrunnable-signal.mdstopping-and-escalating.md详细介绍
基于证据调试
核心原则。 检验决策所需的主张,而不是事件中的每个未知因素。
- 假设用于选择实验;它不是已确认的原因。 在本地复现之前,报告、日志和代码都可以提供可证伪的假设。
- 使用互补的证据层。 事件记录能证明事件发生过;受控实验能证明处理方式有缺陷,但未必能确定最初的触发因素。
- 你是在处理某件事的途中打开了这份文档。 这里讲的是如何开展这项工作,而不是要取代原有工作。开始前先说明你正在做什么,完成后再回去继续。
为问题选择信号
- 从报告的问题和现有证据入手。 本地运行通过,并不能抹去已有的事件记录。
- 根据复现、回放、受控故障注入或跟踪各自能证明什么来选择。 它们是可选方案,不是必须依次执行的阶梯。
- 让被测试的处理逻辑保持真实。 注入有依据的依赖结果或调度安排,然后断言调用方可见的契约。
- 记录命令、条件和结果。 标注注入的条件;不要将其报告为生产环境中观察到的事件。
可以写入什么,以及何时写入
- 在获得支持修复的依据之前,写入操作仅限于经授权的诊断测试和检测手段。 对输入、依赖结果或调度进行受控更改属于实验,而不是生产修复。
- 保留基线。 更改正在调查的条件,而不是你要验证其正确性的处理逻辑。隔离替换内容并保留原始证据。
- 权限止于工作区边界。 不得提交、更改分支、执行远程操作或部署。移除临时检测手段;保留有用的回归测试。
首次运行前先确认
-
不要询问环境会回答的问题。 三件事足以确定设置,其中两件环境里已有。
- 用用户自己的原话引用症状。
- 项目已声明的、用于运行相关功能面的命令。
- 故障报告为持续发生还是偶发,以及有哪些条件或观察结果可用。
-
区分报告的发生率和实测发生率。 仅当频率对决策有帮助时才进行测量;频率未知时应如实标注,不要要求先反复失败才开始调查。
-
首次探查前,明确说明时间或次数预算。 说明你打算进行多大范围的调查,以探查次数或分钟数表示,并写在我能看到的地方。可中断的有限调查,胜过做完才交付的无限调查。
-
每次后续探查都必须能为某项决策提供依据。 如果再次运行无法在范围内回答剩余问题,就停止、更换切入点或交还处理。
应读取哪些规则
每行一条规则。 根据左列中的症状或当前状态进行匹配。
- 匹配结果决定从哪里开始。 证据决定接下来可以合理地做什么;这些状态并非每次调查都必须经历的顺序。
- 在需要作出相应决策时读取规则。 停止条件和权限限制适用于所有状态。
- 如果两行都符合症状,就两行都读。 读得太少会多耗费一整个循环;读得太多只多花费一个文件的时间。
- 先读完每一行,再按匹配项采取行动,优先处理最难撤销的事项。 读一行不花代价;被跳过的那一行,正是覆盖不足之处。
| 如果你看到…… | 读取 |
|---|---|
| 本地运行没有复现报告中的故障,或者循环缓慢、嘈杂、间歇性发生或不可用 | rules/runnable-signal.md |
| 一个失败的实验包含无关设置,掩盖了要论证的内容 | rules/minimising.md |
| 某种解释已经显得显而易见,或者你正要测试第一个想到的东西 | rules/rival-hypotheses.md |
| 需要在观察与对依赖项、输入或计划进行受控更改之间作出选择 | rules/probing.md |
| 故障在远离起始点的位置显现,或者有效的依赖项结果导致调用方行为无效 | rules/fix-at-the-source.md |
| 已证明存在处理缺陷,必须编写测试来防止其再次发生,即使原始触发因素仍不明 | rules/regression-seam.md |
| 尝试已无法为决策提供信息、回归问题对修复提出质疑,或无法获得必需的观察结果 | rules/stopping-and-escalating.md |
判别要点。
- 信号与最小化。 信号规则决定选择哪种可运行的观察或实验。最小化规则则在已有有用信号后移除无关设置。
- 假设与探测。 在探测之前明确预测。不同的独立问题可以在不同层面并行推进;应将各自的证据分开保留。
- 源头与接缝。 源头规则决定有依据的修复应落在哪里。接缝规则决定测试应保护哪项契约。
默认立场。
- 使用成本最低且足够的证据,而不是不论能证明什么都只选成本最低的检查。
- 将独立的工作线控制在有限范围内。 在输入已具备时,源代码分析、处理测试和环境观察不必互相等待。不要混合相互重叠的实验性修改。
- 不要作出超出测试范围的断言。 条件性的处理缺陷可以成为限定范围修复的依据,但不能据此认定过去事件的触发因素。
如实说明证据允许得出的结论
状态变化时报告状态,并说明已确立的结论和仍存在的缺口。
| 状态 | 含义 | 可以据此 |
|---|---|---|
debug/NO-SIGNAL | 有故障报告,但尚无可运行的检查 | 检查记录和代码、提出假设、构建受控实验 |
debug/RED | 在已记录的条件下,某次运行违反了相关契约 | 比较不同解释并测试其机制;标明观察到的条件与注入的条件 |
debug/MINIMISED | 已从有用的失败检查中移除无关设置 | 可选择进行简化实验,但并非每次修复的前提 |
debug/EXPLAINED | 证据支持某种机制及修复范围 | 实施已获授权的修复;明确指出未观察到的事件触发因素 |
debug/RESOLVED | 已修正经证实的缺陷,并检查了受影响的契约 | 按已测试的范围关闭该缺陷;除非已确认历史触发因素,否则不要声称已找出它 |
- 不要为了最小化而最小化。 实验已足够清晰并能支撑决策时,就停止缩减。
- 缺口只会阻止依赖它的结论和行动。 有用时调查另一个独立层面;不要反复追查同一个无法获得的观察结果。
- 一次运行通过,适用范围有限。 未观察到某事件,不代表间歇性事件不可能发生。
让结论与证据相匹配
- **发生:**可靠的事件记录或复现表明,故障在这些条件下发生过。
- **处理:**受控测试表明,真实代码如何响应指定条件。依赖项产生的结果必须符合其契约;虚构的行为不算复现。
- **历史原因:**要确定原始事件的触发因素,需要有该触发因素的证据,而不只是通过测试强行触发它。
- **修复:**移除有缺陷的依赖项或分支,需要有失败的契约检查和兼容性检查。不一定需要估算触发率。
- **调优:**调整重试、退避或超时,需要与恢复、时序、负载和副作用相关的证据。仅凭强行制造的错误,无法证明所选值合理。
对每项因果主张,引用代码或观察到的事件、能区分不同解释的结果,以及仍未查明的内容。如果某种合理的替代解释不会改变有依据的修复方案,就不必排除;记录这一界限即可。
何时停止,而不是再试一次
- 明确再次运行可能改变什么。 重复运行可以估算既定条件下的变异性,但不一定能推动查明原因。
- 将新出现的回归视为反对修复的证据,而不是架构有问题的自动证明。
- 当既定范围内的决策已有证据支持、无法获取必要观察结果、达到调查上限,或下一步需要新的授权时,就停止。 报告尚未解决的问题,但不要因此阻碍其他有依据的工作。
输出约定
Symptom as reported, with the available incident evidence
State the established claim and the next justified action
Experiments conditions, real code exercised, observed or injected inputs, results
Mechanism supported causal links at file:line, including conditional claims
Not shown historical trigger, frequency or compatibility still unverified
Fix the scoped change and affected callers/contracts
Proof the failing contract check before and after, relevant adjacent checks,
and removal of temporary instrumentation
- 报告你观察到的内容,而不是你排除了什么。
- 绝不要以“已修复”开头。 读者需要先了解推理链条。先陈述修复,再讲原因,听起来就像是碰巧奏效的猜测,有时确实如此。
以下情况也不要跳过
- 原因看起来显而易见。 这正是此技能要打破的思维定式。
- 有人已经报告了故障。 使用他们提供的证据;不要要求先在本地重新触发故障,才开始分析。
- 修复只有一行。 改错一行,同样是错误。
- 你赶时间。 猜测会导致第二次、第三次尝试。
路由
- 上表用于选择规则及其顺序。 完整阅读选定的规则,自行解读,并用一行说明你打开了哪条规则。
- 可以并行测试相互竞争的解释。 但对它们进行排序并判断结果意味着什么,不能委托他人。
- 用户的直接指示优先于此处的任何内容。
- 修复一旦存在,就不再是症状,而是一项变更。 将其交由差异审查,而不是在此处评判。
评论
支持 Markdown