diagnosing-bugs

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Diagnosing Bugs

诊断Bug

Diagnose hard bugs by combining reproduction, code inspection, provisional hypotheses, and targeted probes. Choose the next step by the evidence missing; the sections below are tools for the investigation, not gates that must be completed in order.
When exploring the codebase, read
CONTEXT.md
(if it exists) to get a clear mental model of the relevant modules, and check ADRs in the area you're touching.
通过结合复现、代码审查、临时假设和针对性探测来诊断棘手的Bug。根据缺失的证据选择下一步;以下各节是调查的工具,而非必须按顺序完成的关卡。
探索代码库时,请阅读
CONTEXT.md
(如果存在)以建立相关模块的清晰心智模型,并查看你所涉及领域的ADR。

Redact

脱敏

This skill has you show commands, outputs and captured artifacts. Redact every secret first: write
<REDACTED>
in its place. Build loops against env vars, so the credential stays in the environment rather than in what you show. Captured artifacts carry auth headers: quote only the lines that carry the signal.
If the redacted output is not enough to diagnose the bug, say so and ask the user.
本技能会涉及展示命令、输出和捕获的工件。请先对所有敏感信息进行脱敏:将其替换为
<REDACTED>
。基于环境变量构建循环,这样凭证会保留在环境中,不会出现在你展示的内容里。捕获的工件带有认证头:仅引用包含有效信息的行。
如果脱敏后的输出不足以诊断Bug,请说明情况并询问用户。

Build a feedback loop

构建反馈循环

Start from the user's exact symptom, expected behavior, entry point, environment, inputs, and action sequence. Trace the relevant code and use provisional hypotheses to identify the conditions a reproduction must preserve. Keep those hypotheses distinct from established causes.
Prefer an existing check that can fail on the reported bug and pass after the fix. Build or adapt a feedback loop when it will distinguish causes or verify the outcome; do not require a runnable reproduction before inspecting code or forming a testable explanation.
从用户提供的确切症状、预期行为、入口点、环境、输入和操作序列开始。追踪相关代码,使用临时假设识别复现必须保留的条件。将这些假设与已确认的原因区分开来。
优先使用现有的检查项,它可以在报告的Bug上失败,在修复后通过。当反馈循环能够区分原因或验证结果时,构建或调整反馈循环;不要在检查代码或形成可测试的解释之前要求可运行的复现。

Choose a useful check

选择有用的检查项

Choose the cheapest check that reaches the reported failure. These are alternatives, not a sequence to exhaust:
  1. Failing test at whatever seam reaches the bug: unit, integration, e2e.
  2. Curl / HTTP script against a running dev server.
  3. CLI invocation with a fixture input, diffing stdout against a known-good snapshot.
  4. Headless browser script (Playwright / Puppeteer) that drives the UI and asserts on DOM/console/network.
  5. Replay a captured trace. Save a real network request / payload / event log to disk; replay it through the code path in isolation.
  6. Throwaway harness. Spin up a minimal subset of the system (one service, mocked deps) that exercises the bug code path with a single function call.
  7. Property / fuzz loop. For input-dependent failures, use bounded input generation and retain the seed and failing inputs.
  8. Bisection harness. If the bug appeared between two known states (commit, dataset, version), automate "boot at state X, check, repeat" so you can
    git bisect run
    it.
  9. Differential loop. Run the same input through old-version vs new-version (or two configs) and diff outputs.
  10. Human-assisted reproduction. If the agent cannot exercise the path, give the user precise actions and ask for the relevant observations. Use
    scripts/hitl-loop.template.sh
    when a repeatable terminal-guided loop helps.
Record the command or manual actions, relevant conditions, and observed result. Distinguish a check that has reproduced the symptom from one that is only expected to catch it.
选择能够触达报告故障的成本最低的检查项。这些是替代方案,而非必须穷尽的序列:
  1. 失败测试:在任何能触达Bug的接缝处:单元、集成、e2e。
  2. Curl / HTTP脚本:针对运行中的开发服务器执行。
  3. CLI调用:使用夹具输入,将stdout与已知良好的快照进行对比。
  4. 无头浏览器脚本(Playwright / Puppeteer):驱动UI并对DOM/控制台/网络进行断言。
  5. 重放已捕获的追踪记录。将真实的网络请求/payload/事件日志保存到磁盘;在隔离的代码路径中重放。
  6. 一次性测试工装。启动系统的最小子集(单个服务、模拟依赖),通过单次函数调用触发Bug代码路径。
  7. 属性/模糊测试循环。对于依赖输入的故障,使用有界输入生成,并保留种子和失败的输入。
  8. 二分法测试工装。如果Bug出现在两个已知状态(commit、数据集、版本)之间,自动化“在状态X启动、检查、重复”的流程,这样你就可以执行
    git bisect run
    。
  9. 差异对比循环。将相同输入分别运行在旧版本和新版本(或两种配置)上,并对比输出差异。
  10. 人工辅助复现。如果Agent无法执行该路径,向用户提供精确的操作步骤,并请求相关观察结果。当需要可重复的终端引导循环时,使用
    scripts/hitl-loop.template.sh
    。
记录命令或手动操作、相关条件和观察到的结果。区分已复现症状的检查项和仅预期能捕获症状的检查项。

Tighten the loop

优化反馈循环

Improve the loop when doing so will make the next experiment more useful:
  • Can I make it faster? (Cache setup, skip unrelated init, narrow the test scope.)
  • Can I make the signal sharper? (Assert on the specific symptom, not "didn't crash".)
  • Can I make it more deterministic? (Pin time, seed RNG, isolate filesystem, freeze network.)
Speed, determinism, and unattended execution help iteration, but none is a prerequisite for useful evidence. Stop optimizing the harness when the next diagnostic check would teach more.
当优化循环能让下一个实验更有价值时进行优化:
  • 能否让它更快?(缓存设置、跳过无关初始化、缩小测试范围。)
  • 能否让信号更清晰?(针对特定症状进行断言,而非“没有崩溃”。)
  • 能否让它更具确定性?(固定时间、设置RNG种子、隔离文件系统、冻结网络。)
速度、确定性和无人值守执行有助于迭代,但都不是获得有效证据的前提。当下一个诊断检查能带来更多信息时,就停止优化测试工装。

Non-deterministic bugs

非确定性Bug

Use bounded runs and record attempts, failures, and conditions. Control scheduling, seeds, concurrency, or workload when the suspected mechanism justifies it and the experiment preserves the reported failure. Choose further runs or instrumentation by the uncertainty they can resolve, not a required reproduction rate. A run without failures does not by itself prove a flaky bug is gone.
使用有限次运行,并记录尝试次数、失败情况和条件。当疑似机制支持且实验能保留报告的故障时,控制调度、种子、并发或工作负载。根据运行或插桩能解决的不确定性来选择后续操作,而非要求达到某个复现率。一次没有失败的运行本身并不能证明不稳定Bug已经消失。

When reproduction is unavailable

无法复现时

State what was tried and the evidence gap. Continue relevant code inspection, trace analysis, and safe probes that can narrow the cause. Ask for a specific environment, redacted artifact, or permission for production instrumentation only when that missing input blocks further progress; continue independent investigation while waiting.
Keep the leading cause provisional until the evidence establishes the mechanism. If an authorized fix is supported by code or captured evidence despite unavailable reproduction, explain that basis and the verification still missing. Do not claim the original bug was reproduced or proven fixed without observing it.
说明已尝试的方法和证据缺口。继续进行相关的代码审查、追踪分析和安全探测,以缩小原因范围。仅当缺失的输入阻碍进一步进展时,才请求特定环境、脱敏后的工件或生产环境插桩权限;等待期间继续独立调查。
在证据确认机制之前,始终将主要原因视为暂定的。如果即使无法复现,经授权的修复仍有代码或捕获的证据支持,请说明依据和仍缺失的验证。在未观察到Bug的情况下,不要声称已复现原始Bug或已证明修复有效。

Reproduce and reduce the scenario

复现并简化场景

When execution is available, establish that the check reaches the user's failure mode, rather than a nearby error or merely successful execution. Capture the exact symptom and relevant conditions for comparison after the fix. Repeat only when needed to distinguish a stable result from noise.
Reduce inputs, callers, configuration, data, or steps when doing so helps isolate the mechanism or makes verification practical. Change one suspected factor at a time and check whether the same failure remains.
Stop reducing when the scenario is small enough to test the leading explanation or a different probe would be more informative. Complete minimization is not required before testing a hypothesis or applying a supported fix. Retain the original scenario for final verification; a reduced path may bypass the reported defect.
当可以执行时,确认检查项触达了用户的故障模式,而非相近的错误或仅仅是成功执行。捕获确切的症状和相关条件,以便修复后进行对比。仅在需要区分稳定结果和噪声时才重复执行。
当简化输入、调用方、配置、数据或步骤有助于隔离故障机制或使验证可行时,进行简化。每次只更改一个疑似因素,并检查是否仍存在相同的故障。
当场景足够小,可以验证主要解释或其他探测更有价值时,停止简化。在测试假设或应用有依据的修复之前,不需要完成完全最小化。保留原始场景用于最终验证;简化后的路径可能会绕过报告的缺陷。

Test hypotheses

验证假设

Form and revise hypotheses throughout the investigation. Use one leading explanation when the evidence is specific; compare alternatives when several mechanisms fit the observations. Do not invent candidates to fill a quota.
For each hypothesis worth testing, identify its supporting evidence and a prediction that would distinguish it from the alternatives or disprove it. Choose the cheapest decisive check, then update the explanation from the result.
For example: if a stale cache causes the wrong value, bypassing that cache under the same inputs should restore the expected value. Check whether the result supports that mechanism rather than assuming any improvement confirms it.
Share the leading explanation, material uncertainty, and next check when they help the user follow or correct the investigation. Continue without waiting unless a decision or missing evidence actually blocks the next step.
在整个调查过程中提出并修正假设。当证据明确时,使用一个主要解释;当多种机制都符合观察结果时,对比替代假设。不要为了凑数而编造候选假设。
对于每个值得测试的假设,识别其支持证据和一个能将其与替代假设区分开或证伪它的预测。选择成本最低的决定性检查,然后根据结果更新解释。
例如:如果过期缓存导致了错误的值,那么在相同输入下绕过该缓存应该能恢复预期值。检查结果是否支持该机制,而非假设任何改进都能证实它。
当主要解释、重大不确定性和下一步检查有助于用户跟进或纠正调查时,分享这些信息。除非决策或缺失的证据确实阻碍了下一步,否则继续进行,无需等待。

Instrument

探测方法

Each probe must resolve a specific uncertainty or test a prediction. Change one variable at a time when comparing outcomes so the result remains attributable.
Tool preference:
  1. Debugger / REPL inspection if the env supports it. One breakpoint beats ten logs.
  2. Targeted logs at the boundaries that distinguish hypotheses.
  3. Never "log everything and grep".
Tag every debug log with a unique prefix, e.g.
[DEBUG-a4f2]
. Cleanup at the end becomes a single grep. Untagged logs survive; tagged logs die.
For performance regressions, establish a baseline under the reported workload with a timing harness, profiler, or query plan. Use profiling, bisection, or a focused experiment according to the suspected cause. Compare the same workload after the fix; do not claim a measured improvement when baseline or after-change measurements are unavailable.
每个探测都必须解决特定的不确定性或验证一个预测。对比结果时每次只更改一个变量,这样结果才具有可归因性。
工具偏好:
  1. 调试器/REPL检查:如果环境支持。一个断点胜过十条日志。
  2. 针对性日志:放在能区分假设的边界处。
  3. 永远不要“记录所有日志再grep”。
给每条调试日志打上唯一前缀的标签,例如
[DEBUG-a4f2]
。最后清理时只需一次grep即可。未打标签的日志容易残留;打了标签的日志可被清理。
对于性能回退,使用计时测试工装、性能分析器或查询计划,在报告的工作负载下建立基线。根据疑似原因使用性能分析、二分法或针对性实验。修复后对比相同的工作负载;如果无法获得基线或修复后测量结果,不要声称有可测量的提升。

Fix and verify

修复与验证

Write the regression test before the fix when it can exercise the real bug through a practical seam.
A correct seam is one where the test exercises the real bug pattern as it occurs at the call site. If the only available seam is too shallow (single-caller test when the bug needs multiple callers, unit test that can't replicate the chain that triggered the bug), a regression test there gives false confidence.
If no practical regression-test seam exists, explain the limitation and use the closest meaningful check through the real behavior, such as the original browser flow, replay, or command. Do not create substantial test infrastructure or a misleading test merely to satisfy this workflow.
When that test is practical:
  1. Turn the supported failure scenario into a focused regression test at that seam.
  2. Run it before fixing the code and confirm it fails for the intended reason. If it does not, investigate the mismatch rather than treating it as proof of the reported bug.
  3. Apply the fix supported by the established mechanism.
  4. Run the check again and confirm the intended behavior passes. If it still fails, return to the investigation.
Preserve the relevant starting state, configuration, and real decision path in the regression. Setup must not repair a prerequisite that the reported workflow lacks. A check that expects graceful rejection does not prove the required operation succeeds.
Change expectations only when an authorized requirement changed or evidence establishes that the test was wrong against the requirement. Interface or setup changes must retain the protected failure case. Do not accept new output, replace a failing collaborator with a successful stub, or skip the regression merely to get green.
Continue authorized fixes and necessary restructuring. If a valid failure depends on an unresolved decision, unavailable prerequisite, or material scope expansion, preserve the failing test and report the blocker and remaining work. A reproduction-only request can finish with a red test; an implementation request remains incomplete. Distinguish behavioral failure from a check that could not reach the behavior, and confirm the reported command actually ran the regression.
Whether or not a durable test was added, verify the fix through the original entry point, environment, inputs, and sequence when accessible. A reduced reproduction or lower-level test supports that verification but does not replace it. For intermittent failures, report the before/after observations and remaining uncertainty. If either failing-before evidence or original-scenario verification is unavailable, state that gap explicitly.
After confirming the fix, consider whether the bug exposed a stable invariant that can be enforced at the seam that owns it. Prefer an existing structural mechanism—such as a type or schema constraint, boundary validation, lint rule, or canonical entry point—when it prevents the demonstrated bug class. Keep the regression test as behavioral proof. Do not add machinery for an isolated failure with no credible recurrence, and do not expand the authorized scope to enforce the invariant.
当回归测试能够通过实际的接缝复现真实Bug时,在修复前编写回归测试。
正确的接缝是指测试能够复现调用点处发生的真实Bug模式的位置。如果唯一可用的接缝太浅(例如Bug需要多个调用方却只做单调用方测试,单元测试无法复现触发Bug的调用链),在那里做回归测试会带来虚假的信心。
如果没有实用的回归测试接缝,请说明限制,并通过真实行为使用最接近的有意义检查,例如原始浏览器流程、重放或命令。不要仅仅为了满足此工作流而创建大量测试基础设施或误导性测试。
当该测试可行时:
  1. 将已确认的故障场景转化为该接缝处的针对性回归测试。
  2. 在修复代码前运行它,确认它因预期原因失败。如果没有,请调查不匹配的原因,而非将其视为报告Bug的证据。
  3. 根据已确认的故障机制应用修复方案。
  4. 再次运行检查,确认预期行为通过。如果仍然失败,返回调查。
在回归测试中保留相关的初始状态、配置和真实决策路径。设置过程不应修复报告工作流中缺少的前置条件。一个预期优雅拒绝的检查不能证明所需操作成功。
仅当经授权的需求发生变更或证据证明测试不符合需求时,才更改预期。接口或配置变更必须保留受保护的失败用例。不要为了通过测试而接受新输出、将失败的协作方替换为成功的存根,或跳过回归测试。
继续进行授权范围内的修复和必要的重构。如果有效的故障依赖于未解决的决策、不可用的前置条件或重大范围扩展,请保留失败的测试,并报告阻塞项和剩余工作。仅要求复现的请求可以以失败测试结束;实现需求则仍未完成。区分行为故障和无法触达行为的检查,并确认报告的命令确实运行了回归测试。
无论是否添加了持久化测试,在可访问的情况下,通过原始入口点、环境、输入和操作序列验证修复。简化后的复现或更低层级的测试支持该验证,但不能替代它。对于间歇性故障,报告修复前后的观察结果和剩余的不确定性。如果缺少修复前失败的证据或原始场景验证不可用,请明确说明该缺口。
确认修复后,考虑该Bug是否暴露了一个可以在其所属接缝处强制执行的稳定不变量。当现有结构性机制——例如类型或schema约束、边界验证、lint规则或规范入口点——能够防止已证实的Bug类别时,优先使用这些机制。保留回归测试作为行为证明。不要为孤立的、没有可信复发可能的故障添加额外机制,也不要扩大授权范围来强制执行不变量。

Cleanup and report

清理与报告

Before finishing:
  • Record the original-scenario result, regression check, and any verification gap. Reuse results from the final implementation; rerun only after a relevant change or when uncertainty warrants it.
  • Remove temporary debug instrumentation and throwaway artifacts created for the investigation, or keep useful artifacts in an agreed debug location.
  • Report the supported cause, fix, verification evidence, and remaining uncertainty. Include the cause in a commit or PR description when that publication was requested.
完成前:
  • 记录原始场景结果、回归检查和任何验证缺口。复用最终实现的结果;仅在相关变更后或不确定性需要时重新运行。
  • 移除为调查创建的临时调试插桩和临时工件,或将有用的工件保存在约定的调试位置。
  • 报告已确认的原因、修复方案、验证证据和剩余的不确定性。如果要求发布,请在commit或PR描述中包含原因。