mcpField
D
diagnose

diagnose

github.com/afonsoft开发1442 次安装3 天前更新
代码仓库

关于 diagnose

diagnose 是面向开发者和编码 Agent 的调试技能,用于调查复杂故障与回归问题。它要求先构建可失败的复现循环,再验证假设,并在每次修改后重新检查。

主要功能

  1. 01结构化梳理并复现故障
  2. 02修复前建立失败检测循环
  3. 03排列可证伪的假设
  4. 04按技术栈提供调试手册
  5. 05每次修改后重新验证

适用场景

  1. 01调查复杂回归问题
  2. 02缩减为最小复现案例
  3. 03诊断不稳定故障
  4. 04调试 .NET、Angular、Python 或 React

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/afonsoft/skills --skill diagnose

安装后在 Claude Code 中输入/diagnose确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
angular-debugging.md
condition-based-waiting.md
defense-in-depth.md
dotnet-debugging.md
python-debugging.md
react-debugging.md
root-cause-tracing.md
scripts/
find-polluter.sh
hitl-loop.template.sh

详细介绍

诊断

一套用于排查棘手 Bug 和回归问题的方法。只有明确说明理由时,才能跳过阶段。向用户报告的所有问题和发现都必须使用巴西葡萄牙语(pt-BR)。

探索代码库时,使用 .claude/CONTEXT.md 中的项目领域术语表(如果存在),以便清楚了解相关模块;并检查 docs/architecture/ 中与当前工作领域相关的决策和 ADR。

重新验证循环:每提出一个假设、进行一次修复或更改之后,都要重新运行复现步骤和回归检查,再宣布 Bug 已解决。

铁律:没有红色循环、没有确认根因,就不许修复。 如果在阶段 1 发出红色信号、阶段 4 确认假设之前就做出更改,那就是在猜测——而在压力下猜测,往往会让一个 Bug 变成三个。尤其是在时间紧迫、Bug“看起来很简单”,以及先前的修复已经失败时,更要遵守这一点:恰恰是在这些时候,这套流程最能发挥作用。违反流程的字面要求,就是违背调试的本意。

流程

Phase 0  Frame the bug          → symptom, expected vs actual, env, frequency, scope
Phase 1  Build a feedback loop  → ONE tight, red-capable command (the core of this skill)
Phase 2  Reproduce + minimise   → smallest scenario that still goes red
Phase 3  Hypothesise            → 3–5 ranked, falsifiable predictions
Phase 4  Instrument             → one probe per prediction, one variable at a time
Phase 5  Fix + regression test  → test at a correct seam, watch red → green
Phase 6  Cleanup + re-validate  → remove probes, re-run the original repro

   ↺ If the bug survives or mutates, return to Phase 3.
   ↺ If every hypothesis dies, see "Stuck — when hypotheses run out".

非代码问题的入口:

脱敏

此技能会要求你展示命令、输出和捕获的工件。先对所有机密信息进行脱敏:用 <REDACTED> 替换。围绕环境变量构建循环,让凭据留在环境中,而不是出现在展示内容里。捕获的工件中可能包含身份验证标头——只引用包含关键信号的行。

如果脱敏后的输出不足以诊断 Bug,请说明原因并用葡萄牙语询问用户。

何时使用

  • 用户用英语请求或提及此技能(例如:“use /diagnose”“run diagnose”)。
  • 用户用葡萄牙语请求或提及此技能(例如:“use /diagnose”“execute diagnose”)。
  • 问题出在 Agent 会话本身(循环、上下文漂移、重复调用工具)→ 转到 Agent 自我调试。
  • 行为异常的系统是 Agent 或 AI 工作流 → 执行 AI 工作流诊断。

技术栈操作手册

当目标代码库符合以下某种技术栈时,在构建循环前加载 references/ 中对应的操作手册——其中包含现成的复现命令、调试器/分析器工作流、检测代码片段和日志查询速查表:

  • references/dotnet-debugging.md — .NET / ASP.NET Core / EF Core(dotnet-counters、dotnet-stack、dotnet-dump、dotnet-trace、EF LogTo/TagWith、journalctl/jq 查询)
  • references/angular-debugging.md — Angular(Angular DevTools 分析器、ng.* 控制台 API、RxJS tap、变更检测分析)
  • references/python-debugging.md — Python(breakpoint()/pdb、pytest --pdb、py-spy、faulthandler、tracemalloc、asyncio 调试)
  • references/react-debugging.md — React(React DevTools 分析器、why-did-you-render、重新渲染/副作用 Bug 模式)

阶段 0 — 界定 bug

开始构建之前,先明确“故障”具体指什么。模糊的症状会导致模糊的循环,而模糊的循环会浪费之后每个阶段的时间。

从用户、bug 报告或证据中收集:

  • 症状,原文 — 完整的错误消息、错误值或发生时间。引用原文,不要改述。
  • 预期与实际 — 应该发生什么,以及实际发生了什么。
  • 环境 — 本地 / CI / 预发布 / 生产;操作系统、运行时、版本、配置配置文件。
  • 从何时开始 — 首次发现的时间;与之相关的部署、提交或数据变更;或者“始终如此”。
  • 发生频率 — 每次运行、偶发(大约多频繁?)或仅一次。
  • 影响范围 — 一个用户 / 输入 / 环境,还是所有情况。
  • 近期变更 — 代码、依赖项、配置、数据、基础设施。

如果报告信息不足,先用葡萄牙语向报告者询问,再动代码:

Antes de investigar, preciso enquadrar o bug:

1. O que deveria acontecer vs o que aconteceu? (mensagem de erro exata, se houver)
2. Onde acontece — local, CI, staging, produção?
3. Desde quando? Relacionado a algum deploy ou mudança recente?
4. Com que frequência — sempre, às vezes (quantas?), ou uma vez só?
5. Atinge um caso específico ou tudo?

阶段 0 的输出:用一句话描述 bug — “在 <env> 中,<input/action> 会产生 <actual>,而不是 <expected>,自 <when> 起(<frequency>)。” 如果你写不出这句话,就继续询问,不要开始阶段 1。

阶段 1 — 建立反馈循环

这就是核心技能。 其他一切都是机械性的。如果你有一个针对 bug 的紧密通过 / 失败信号——它会因这个 bug 而变红——你就能找到原因;二分查找、假设测试和插桩都只是利用这个信号。如果没有,再怎么盯着代码看也无济于事。

在这里投入不成比例的精力。大胆尝试。发挥创造力。绝不放弃。

构建反馈循环的方法 — 大致按以下顺序尝试
  1. 失败测试,选择任何能触达 bug 的接缝——单元测试、集成测试、端到端测试。
  2. 针对正在运行的开发服务执行 Curl / HTTP 脚本。
  3. 使用测试输入执行 CLI 调用,并将标准输出与已知正确的快照进行比较。
  4. 无头浏览器脚本(Playwright / Puppeteer)——驱动 UI,并断言 DOM / 控制台 / 网络。
  5. 重放捕获的跟踪记录。 将真实的网络请求 / 负载 / 事件日志保存到磁盘;通过隔离运行的代码路径重放。
  6. 临时测试工具。 启动系统的最小子集(一个服务、模拟依赖),通过一次调用触发 bug 的代码路径。
  7. 属性 / 模糊测试循环。 如果 bug 表现为“输出有时错误”,就运行 1000 个随机输入并查找故障模式。
  8. 二分查找测试工具。 如果 bug 出现在两个已知状态(提交、数据集、版本)之间,就自动执行“在状态 X 启动、检查、重复”,以便运行 git bisect run。如果要查找“哪个测试创建了这个多余文件 / 状态?”,scripts/find-polluter.sh 会逐个运行测试文件,直到多余内容出现。
  9. 差异循环。 将相同输入分别通过旧版本和新版本(或两种配置)运行,并比较输出。
  10. HITL bash 脚本。 最后的办法。如果必须由人点击,就用 scripts/hitl-loop.template.sh 驱动他们,让循环仍然保持结构化;捕获的输出会反馈给你。

构建正确的反馈循环,bug 就解决了 90%。

收紧循环

把循环当作产品来对待。建立一个循环之后,继续收紧它:

  • 更快? 缓存设置过程、跳过无关的初始化、缩小测试范围。
  • 信号更明确? 针对具体症状断言,而不是仅仅断言“没有崩溃”。
  • 更具确定性? 固定时间、设定随机数种子、隔离文件系统、冻结网络。

一个 30 秒且不稳定的循环几乎不比没有循环强;一个 2 秒且确定的循环则是调试超能力。

非确定性 bug

目标不是获得干净的复现,而是提高复现率。将触发操作循环 100 次、并行运行、增加压力、缩小时间窗口、注入睡眠。复现率为 50% 的间歇性 bug 可以调试;1% 则不行——持续提高复现率,直到它可以调试。

如果间歇性问题出现在通过 sleep/setTimeout 猜测时机的测试中,那么不稳定的等待本身可能就是 bug——将猜测的延迟替换为条件轮询(references/condition-based-waiting.md)。

当你确实无法构建闭环时

明确用葡萄牙语说明情况。列出你尝试过的内容。请求以下任一项:(a)能够复现问题的环境访问权限;(b)经过脱敏的捕获产物(HAR 文件、日志转储、核心转储、带时间戳的屏幕录像);或(c)添加临时生产环境埋点的许可。不要在没有闭环的情况下继续提出假设。

Preciso de um exemplo mínimo que reproduza o erro. Você consegue me fornecer:

1. O comando ou ação que dispara o problema.
2. A saída ou mensagem de erro exata.
3. O ambiente (local, CI, staging, produção).
4. Se possível, um artefato capturado (HAR, dump de log, gravação de tela) com segredos redigidos.

➡️ Se não tiver, vou tentar construir um caso de reprodução sozinho.
完成标准:一个能稳定触发失败的紧密闭环

当你能指出一个命令(脚本路径、测试调用、curl),并且至少已经运行过一次——展示调用命令及其输出,做好脱敏——且满足以下条件时,阶段 1 即告完成:

  • 能够触发失败——执行实际的 Bug 代码路径,并断言用户描述的确切症状,因此该命令在此 Bug 存在时能触发失败,修复后则能通过。“运行时没有报错”还不够;它必须能够捕获这个特定 Bug。
  • 确定性——每次运行的判定结果相同(对于不稳定的 Bug,复现率需固定且较高)。
  • 快速——耗时以秒计,而不是分钟。
  • 可由 Agent 运行——可以无人值守运行;只有通过 scripts/hitl-loop.template.sh 才需要人工参与。

如果你发现自己在这个命令成形之前就开始读代码构建理论,**请停下——直接跳到假设正是这项技能要避免的问题。**没有能触发失败的命令,就不能进入阶段 2。

阶段 2 — 复现 + 最小化

运行闭环。观察 Bug 出现时闭环触发失败。确认:

  • 闭环产生的是用户描述的故障模式,而不是附近碰巧发生的另一种故障。Bug 找错了,修复也就错了。
  • 故障在多次运行中都可复现(对于非确定性 Bug,复现率也要足够高,便于据此调试)。
  • 你已捕获确切症状(错误消息、错误输出、耗时过长),以便后续阶段验证修复确实解决了问题。
最小化

将复现用例缩减到仍能触发失败的最小场景。每次只删减一项,每次删减后都重新运行闭环,只保留对故障起关键作用的内容:

  1. 删除代码,直到 Bug 消失。
  2. 删除数据。
  3. 删除配置。
  4. 删除依赖项。
  5. 删除环境。

原因:最小复现用例能缩小阶段 3 的假设空间(需要怀疑的变量更少),也会成为阶段 5 中简洁的回归测试。

当剩下的每个要素都不可或缺时,即可完成——删除其中任意一项都会让闭环通过。在复现并完成最小化之前,不要继续。

阶段 3 — 提出假设

在测试任何假设之前,先生成 3–5 个按优先级排序的假设。只生成一个假设会让人锚定在第一个看似合理的想法上。

每个假设都必须 可证伪——说明它会得出什么预测:

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

如果你无法说明预测,这个假设就只是凭感觉——舍弃它或把它说清楚。

假设的来源——先做成本低的检查:

  1. 近期差异——对改动区域运行 git log -p --since="<first sighting>",并检查依赖项和配置变更。bug 与近期变更高度相关;“以前能用”意味着可以通过二分法定位问题。
  2. 正常与异常路径——找出一个 确实可用 的同类流程,并对比两条路径(输入、配置、调用链、数据形状)。
  3. 环境差异——对比正常环境与异常环境中的环境变量、配置文件、功能开关和依赖版本。
  4. 边界检查——错误值在入口边界处就已经有误,还是在管道中途才出现?每个确认无误的边界都会将嫌疑范围减半。
  5. 反向追踪——当错误在调用栈深处显现时,抛出错误的位置是症状,不是原因。提出假设之前,先将错误值追溯到最初的触发因素(references/root-cause-tracing.md)。

bug 可能所在的位置,大致按以下顺序排列:

  1. 代码——bug 是在你正在查看的代码中、它调用的代码中,还是调用它的代码中?
  2. 文档——文档所述的行为本身正确吗?
  3. 日志——日志内容真实吗,还是掩盖了真正的错误?
  4. 测试——测试覆盖了真正的路径吗?
  5. 代码库——其他调用点是否也存在相同模式?

测试之前,先向用户展示按优先级排序的列表——领域知识能立即调整优先级(“我们刚部署了 #3 的变更”,“#2 已经排除”)。这是一个成本低、节省时间多的检查点。不要因此停下来等待:如果用户暂时不在线,就按你的排序继续。

Hipóteses ranqueadas:

1. [HIPOTESE_1] — previsão: [PREDICAO_1]
2. [HIPOTESE_2] — previsão: [PREDICAO_2]
3. [HIPOTESE_3] — previsão: [PREDICAO_3]

Vou validar a nº [N] com [ACAO_EXPERIMENTAL]. Se confirmar, o próximo passo é [PROXIMO_PASSO].

Concorda, ou quer que eu teste outra hipótese primeiro?
诊断日志

对于任何非简单的问题,都要持续记录日志——这能避免重复测试已排除的假设,也能在上下文漂移/压缩后保留信息:

## Diagnostic Journal — <one-sentence bug statement>
- Loop: `<the Phase 1 command>` → currently red
- Min repro: <smallest red scenario>

| Hypothesis | Prediction | Test run | Result |
|---|---|---|---|
| H1: ... | ... | ... | rejected / confirmed |

- Root cause: <filled at the end>

阶段 4 — 添加检测

每个探测都必须对应阶段 3 中的某个具体预测。每次只更改一个变量。

工具优先级:

  1. 如果环境支持,优先使用 调试器/REPL 检查——一个断点胜过十条日志。
  2. 在能区分不同假设的边界添加 定向日志。
  3. 使用 指标/追踪测量可疑行为并跟踪请求路径。
  4. 使用能快速对不变量进行检查的 断言。
  5. 绝不要“记录所有内容再用 grep 搜索”。

为每条调试日志添加唯一前缀,例如 [DEBUG-a4f2]——最后只需运行一次 grep 就能清理。未加标签的日志会遗留下来;加了标签的日志则会被清除。

探测位置。 将探测放在能逐步缩小假设范围的边界上:函数入口/出口、每次转换的前后、每次外部调用(网络、DB、文件系统)以及每次状态转换。一个能区分 H1 和 H2 的探测,胜过十个无法区分的探测。

多组件扫描。 当 bug 可能出现在管道的任何位置时(CI → 构建 → 部署、API → 服务 → DB、前端 → 网关 → 后端),先进行一次取证运行,再深入排查:在单次运行中记录每个组件边界的输入和输出——数据形状、环境/配置传递情况、状态。通常这次运行就能揭示是哪一层出了问题;然后集中探测该层,而不是对整个管道添加检测。

关联。 尽早为请求/追踪添加 ID,并在每次探测时记录——否则并发流程会交错,导致证据含糊不清。

性能分支。 对于性能回退,日志通常不可靠。先建立基准测量(计时工具、性能分析器、查询计划),然后进行二分定位。先测量,再修复。

阶段 5 — 修复 + 回归测试

在修复之前编写回归测试,但前提是存在合适的切入点——测试能在调用点复现实际的错误模式。如果唯一可用的切入点过于浅层(无法复现触发错误的调用链的单元测试),那么在那里编写回归测试会带来虚假的信心。

如果不存在合适的切入点,这本身就是一项发现。 架构阻碍了问题的彻底解决——在阶段 6 和 improve-codebase-architecture 中将其标记出来。

如果存在合适的切入点:

  1. 在该切入点将最小化复现用例转化为失败测试。
  2. 确认测试失败。
  3. 应用最小且最安全的改动,消除根本原因——不要打补丁。
  4. 确认测试通过。
  5. 针对原始(未最小化)场景重新运行阶段 1 的反馈循环。
  6. 如果根本原因是无效数据或被违反的不变量,且问题已深入系统,则强化它经过的各层——单次检查可以修复这个问题;在每一层进行验证,才能杜绝这类问题(references/defense-in-depth.md)。

如果修复涉及许多文件,请在编辑前用葡萄牙语向用户说明计划:

Raiz do problema: [RAIZ].
Correção proposta: [DESCRICAO_DA_CORRECAO].
Arquivos afetados: [LISTA].

Posso aplicar a correção e depois rodar os testes?

阶段 6 — 清理 + 重新验证

宣布完成前必须完成:

  • 原始复现用例不再复现问题(重新运行阶段 1 的反馈循环)。
  • 回归测试通过(或已记录不存在合适的切入点)。
  • 运行受影响的测试层(单元、集成、端到端测试),并对相邻流程进行轻量级回归测试。
  • 移除所有 [DEBUG-...] 插桩(使用 grep 搜索此前缀)。
  • 删除临时原型(或将其移至明确标记的调试位置)。
  • 在提交 / PR 消息中说明最终证实的假设,让下一位调试人员有所借鉴。

用葡萄牙语报告结果:

Correção aplicada em [ARQUIVOS].

- Reprodução original: [não reproduz mais / ainda falha]
- Teste de regressão: [PASS/FAIL]
- Testes afetados: [PASS/FAIL]
- Instrumentação removida: [SIM/NÃO]

O bug está resolvido. Quer que eu abra uma Issue para documentar a causa raiz com /create-issues?

陷入停滞 — 假设用尽时

三次失败规则。 统计已应用的修复次数,而不是假设数量:如果 3 次修复均告失败,问题仍然存在或发生变化——每次修复都在不同位置暴露出新问题,或者每次修复都需要变通方案才能应用——那么可疑的可能是问题模式本身。停止,先用葡萄牙语与用户一起审视架构,再尝试第 4 次修复:这个设计在根本上是否合理?还是我们只是在修复错误结构造成的症状?这属于 improve-codebase-architecture 的范畴,不是再打一个补丁。

如果所有假设都被否定,失败原因就在你的假设之外:

  1. 质疑反馈循环——它真的能针对这个问题产生失败结果吗?重新检查阶段 1 的完成清单;无法产生失败结果的反馈循环,会让之后的每个阶段都沦为表演。
  2. 质疑问题框架——重新运行阶段 0。报告的症状可能是实际问题的下游现象(例如,用户看到超时,但根本原因是 10 秒前发生了死锁)。
  3. 扩大搜索范围——原因可能在代码之外:数据、配置、基础设施、依赖项行为变化。对整个环境进行差异比较,而不只是比较源代码。
  4. 向用户提供证据——用葡萄牙语报告诊断记录:尝试了什么、每项测试证明或排除了什么,以及接下来需要什么(访问权限、制品或决策)。
  5. “没有根本原因”是最后的手段,不是结论——大多数“环境问题 / 无法解释”的判定都意味着调查不完整。如果证据确实指向系统之外(时序、外部服务、硬件),请记录已排除的因素,在边界处添加处理(重试、超时、明确的错误),并通过 observability-and-instrumentation 添加持久化监控,让下次发生问题时能留下证据。

Agent 自我调试 / 内省(当故障出在 Agent 本身时使用)

如果问题不在代码库,而是在 Agent 会话中——例如工具调用反复失败、陷入循环、上下文漂移,或预期的文件系统状态与实际状态不符——请应用 Agent 内省循环。

阶段 A — 故障捕获

尝试恢复之前,请记录:

  • 错误类型、消息和堆栈跟踪(如果可用)
  • 最近一次有意义的工具调用序列
  • Agent 当时试图做什么
  • 当前上下文压力:重复提示词、过长的粘贴日志、重复计划或失控的笔记
  • 当前环境假设:当前工作目录、分支、相关服务状态、预期文件
## Failure Capture
- Session / task:
- Goal in progress:
- Error:
- Last successful step:
- Last failed tool / command:
- Repeated pattern seen:
- Environment assumptions to verify:
阶段 B — 根因诊断

将故障与已知模式匹配:

模式可能原因检查
达到最大工具调用次数 / 重复执行同一命令循环或没有退出条件的观察路径检查最近 N 次工具调用是否重复
上下文溢出 / 推理能力下降无限制的笔记、重复计划、过长的日志检查近期上下文中是否存在重复内容和低信息量的大段内容
ECONNREFUSED / 超时服务不可用或端口错误验证服务健康状态、URL 和端口假设
429 / 配额耗尽重试风暴或缺少退避机制统计重复调用次数并检查重试间隔
写入后文件缺失 / 差异过时竞态条件、当前工作目录错误或分支偏移重新检查路径、当前工作目录、git 状态和文件是否实际存在
“修复”后测试仍然失败假设错误隔离出确切的失败测试并重新推导 bug

诊断问题:

  • 这是逻辑故障、状态故障、环境故障还是策略故障?
  • Agent 是否忘记了真正的目标,转而优化错误的子任务?
  • 故障是确定性的还是暂时性的?
  • 哪个最小且可逆的操作可以验证该诊断?
阶段 C — 有限恢复

优先按以下顺序采取干预措施:

  1. 用一句话重述真正的目标。
  2. 核实实际状态,而不是相信记忆。
  3. 缩小故障范围。
  4. 运行一项有区分力的检查。
  5. 只有在此之后才重试。

不良模式:用略有不同的措辞将同一操作重试三次。 良好模式:捕获故障 → 对模式进行分类 → 运行一项直接检查 → 仅在检查结果支持时更改计划。

阶段 D — 自我调试报告

最后输出:

## Agent Self-Debug Report
- Session / task:
- Failure:
- Root cause:
- Recovery action:
- Result: success | partial | blocked
- Token / time burn risk:
- Follow-up needed:
- Preventive change to encode later:

AI 工作流诊断

当行为异常的系统是 Agent 或 AI 工作流(而非代码路径)时,请从 5 个维度进行审查。每项按 1–5 分评分,并用葡萄牙语报告具体发现。

维度 1 — 提示词质量

结构(角色、上下文、指令、输出区块);明确的输出架构;指令清晰度;边缘情况处理;反模式(大段文本、矛盾、格式隐含不明)。

维度 2 — 上下文效率

上下文预算分配(计划内与临时分配);注意力梯度(关键信息放在开头/结尾);上下文窗口利用率;状态管理(显式与隐式);适合对话长度的记忆策略。

维度 3 — 工具健康状况

工具数量(理想为 3–7 个,13 个以上则有问题);描述质量;错误处理;架构完整性(输入/输出/错误);幂等性。范围归因:区分项目配置的工具与 Agent 级/内置工具——只标记项目实际能够控制的开销。

维度 4 — 架构适配性

拓扑结构是否合适(单 Agent 或多 Agent 是否有充分理由);Agent 边界(清晰还是重叠);交接协议(结构化还是临时处理);可观测性;成本意识。

维度 5 — 安全性与可靠性

输入验证;输出过滤(PII、内容策略——结合上下文确定范围:用户自己的前端→后端风险低于外部服务);成本控制;错误恢复;评估策略(黄金测试还是“看起来能用”)。

报告格式
╔══════════════════════════════════════╗
║          WORKFLOW DIAGNOSTIC         ║
╠══════════════════════════════════════╣
║ Prompt Quality       ████░  4/5      ║
║ Context Efficiency   ███░░  3/5      ║
║ Tool Health          ██░░░  2/5      ║
║ Architecture         ████░  4/5      ║
║ Safety & Reliability ██░░░  2/5      ║
╠══════════════════════════════════════╣
║ Overall Score:       15/25           ║
╚══════════════════════════════════════╝

ACHADOS CRÍTICOS:
1. [Problema mais severo — ação imediata]
2. [Segundo mais severo]
3. [Terceiro]

AÇÕES RECOMENDADAS:
1. [Correção específica para o achado nº 1]
2. [Correção específica para o achado nº 2]
3. [Correção específica para o achado nº 3]
评分指南
分数含义建议操作
5生产级优秀无需采取行动
4良好,但存在少量不足优化提示词的清晰度或输出架构
3功能可用,但存在风险添加错误处理或降低复杂度
2存在重大问题立即处理——添加重试机制或保护措施
1已损坏或缺失从头开始重建,并采用清晰的结构

排查静默失败

当代码“能运行”但悄无声息地行为异常时,在宣布 bug 已解决之前,先排查静默失败。

排查目标
  1. 空的 Catch 块 — catch {}、被忽略的异常、没有上下文就将错误转换为 null / 空数组。
  2. 日志记录不足 — 日志缺少足够的上下文、严重级别错误、记录后便置之不理。
  3. 危险的回退机制 — 会掩盖真实故障的默认值、.catch(() => []),以及看似正常、实则让下游 bug 更难诊断的处理路径。
  4. 错误传播问题 — 丢失堆栈跟踪、通用的重新抛出、缺少异步处理。
  5. 缺少错误处理 — 网络/文件/数据库操作缺少超时或错误处理,事务操作缺少回滚机制。
输出格式

对每项发现,列出:

  • 位置
  • 严重程度
  • 问题
  • 影响
  • 修复建议

重新验证循环

诊断是一个迭代过程。每次修改后,都要重新运行复现步骤。如果 bug 的表现或位置发生变化,就回到阶段 3。在复现通过且回归测试套件全部通过之前,不要宣布 bug 已修复。

危险信号——停止并重新进入流程

如果你发现自己在想以下任何一句话,就说明你偏离了流程——返回你跳过的阶段:

  • “先快速修复,之后再调查。”
  • “试着改一下 X,看看有没有用。”
  • “大概是 X——我来修复。”(没有经过确认的假设就直接修复,只是在猜)
  • “打包几项改动,然后运行测试。”(你将不知道哪项改动起了作用)
  • “跳过复现,我会手动验证。”
  • “我还没完全弄明白,不过这样或许能行。”
  • “这个 bug 看起来很简单——没必要走完整个流程。”(简单的 bug 也有根本原因;对于简单问题,这个循环反而更快)
  • “情况紧急——没时间走流程。”(系统化处理胜过盲目折腾,尤其是在压力之下)
  • “再尝试修复一次”——此前已失败 2 次或更多。修复失败 3 次意味着架构有误,而不是假设有误(见“陷入困境”)。

用户从外部提出的质疑也传递着同样的信号:“真的会发生吗?”“你验证过了吗?”“别再猜了。”“我们在原地打转。”听到这些时,停下来并返回你跳过的阶段。

常见错误

错误修正方法
调查模糊的症状先执行阶段 0——用一句话描述 Bug,或继续询问。
未先复现就开始修复先建立一个能稳定触发错误的循环,再修改代码。
尚未建立紧凑的循环就开始假设先满足阶段 1 的完成标准——没有触发错误的命令,就不要提出理论。
只测试第一个看似合理的假设生成 3–5 个经过排序、可证伪的假设。
跳过最小化步骤先将问题最小化,否则修复的只是症状,而非原因。
用“没有崩溃”代替症状断言提高信号精度——断言用户报告的确切故障。
回归测试选择的切入点过于浅显使用正确的切入点,或记录不存在这样的切入点。
过早移除检测日志保留 [DEBUG-...] 日志,直到确认修复有效,然后用 grep 清理。
未添加回归测试每个修复的 Bug 都值得添加测试。
重新测试已否定的假设保留诊断日志;记录每项结果。
假定近期变更没有问题先检查差异——新代码是首要嫌疑对象。
并发流程中的证据含糊不清添加关联 ID,并在每个探测点记录该 ID。
调试了错误的环境在相信结果之前,确认环境与阶段 0 报告一致。
未重新验证就宣布完成重新运行复现步骤和测试套件。
在抛出错误的位置修复沿着错误值追溯到它的来源(references/root-cause-tracing.md)。
只修复直接原因在错误数据经过的每一层添加验证(references/defense-in-depth.md)。
通过增加 sleep 时长修复不稳定测试等待实际条件,而非猜测时间(references/condition-based-waiting.md)。
一次性检测整条流水线先遍历所有组件边界,再深入检查发生故障的层。

参考资料

  • scripts/hitl-loop.template.sh — 人机协同复现驱动程序
  • scripts/find-polluter.sh — 对测试文件进行二分查找,找出哪个文件创建了多余的文件或状态
  • references/root-cause-tracing.md — 沿调用栈反向追踪错误值,直至其来源
  • references/defense-in-depth.md — 在每一层进行验证,让这类 Bug 不可能发生
  • references/condition-based-waiting.md — 在不稳定测试中用条件轮询替代猜测的休眠时长
  • references/dotnet-debugging.md — .NET 诊断工具和日志查询
  • references/angular-debugging.md — Angular DevTools、变更检测和 RxJS 调试
  • references/python-debugging.md — pdb/pytest/py-spy 调试和日志查询
  • references/react-debugging.md — React DevTools 和重新渲染调试
  • qa-analyst — 用于测试规划和 Bug 报告
  • write-specs — 当 Bug 暴露出需求缺失时,用于编写规格说明
  • improve-codebase-architecture — 当诊断发现缺少切入点或存在结构性问题时使用
  • observability-and-instrumentation — 当修复需要持久化日志、指标或追踪,而非临时探测时使用
  • create-issues — 用于跟踪已记录的根本原因
  • agent-introspection-debugging — 当故障出在 Agent 会话本身时使用(循环、上下文偏移、重复调用工具)
  • silent-failure-hunter — 当代码可以运行但悄然出现异常行为时使用

评论

支持 Markdown