root-cause
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseRoot Cause
根本原因
The Iron Law
铁律
NO FIXES WITHOUT ROOT CAUSE INVESTIGATION FIRSTGuess-and-patch wastes hours and plants new bugs. This process applies to every technical issue — and applies hardest when it's tempting to skip: emergencies, "obvious" one-liners, and the moment right after a previous fix didn't work.
NO FIXES WITHOUT ROOT CAUSE INVESTIGATION FIRST猜测式修补会浪费数小时时间,还会引入新Bug。此流程适用于所有技术问题——尤其是在你想跳过的场景下更需严格执行:紧急情况、“显而易见”的单行修复、以及上一次修复无效后的时刻。
Phase 1 — Build the feedback loop (the gate)
阶段1 — 构建反馈循环(准入门槛)
Before ANY theory-building, construct and RUN a red-capable signal: one command — a test invocation, a script, a curl — that is red now because of this exact bug and will go green when it is fixed. Build the right feedback loop and the bug is 90% fixed; every later phase merely consumes it.
Catch yourself reading code to form a theory before this command exists? Stop. No red-capable command, no Phase 2.
Tactics for constructing one, in rough order of preference:
- Failing test at whatever seam reaches the bug (unit, integration, e2e)
- curl / HTTP script against a running dev server
- CLI invocation on a fixture input, diffed against known-good output
- Headless browser script asserting on DOM/console/network
- Replay of a captured audit-trace (saved request, payload, event log) through the code path
- Throwaway harness: a minimal slice of the system exercising the bug path
- Property/fuzz loop over random inputs when output is "sometimes wrong"
- Bisection harness () when the bug appeared between two known states
git bisect run - Differential loop: same input through old vs new version, diff the outputs
- Human-in-the-loop script — last resort, only when a human must physically act; script their steps so the loop stays structured
Then tighten it: faster (cache setup, narrow scope — seconds, not minutes), sharper (assert the user's exact symptom, not "didn't crash"), deterministic (pin time, seed randomness, isolate filesystem). Non-deterministic bug? Don't chase a clean repro — raise the reproduction rate (loop the trigger 100x, add stress, shrink timing windows) until it's high enough to root-cause against.
Genuinely cannot build one? Say so explicitly, list what you tried, and ask the user for a reproducing environment, a captured artifact, or permission to add temporary instrumentation. Do not proceed on vibes.
Gate check: name the command, paste one run of its red output.
在构建任何理论之前,先构建并运行一个red-capable signal:一条命令——测试调用、脚本、curl请求——当前因该Bug显示失败(red),修复后会显示成功(green)。构建正确的反馈循环,Bug就已经解决了90%;后续所有阶段都只是基于此循环开展工作。
发现自己在这条命令完成前就开始阅读代码以形成理论?立刻停止。没有red-capable命令,就不能进入阶段2。
构建该命令的策略,按优先级从高到低排列:
- 在能触及Bug的任意层级编写失败测试(单元测试、集成测试、端到端测试)
- 针对运行中的开发服务器执行curl/HTTP脚本
- 对测试输入执行CLI调用,与已知正确输出对比差异
- 无头浏览器脚本,断言DOM/控制台/网络状态
- 通过代码路径重放捕获的审计跟踪(保存的请求、负载、事件日志)
- 临时测试工具:仅包含触发Bug路径的最小系统切片
- 针对随机输入的属性/模糊测试循环,适用于“输出偶尔错误”的场景
- 二分测试工具(),适用于Bug出现在两个已知状态之间的场景
git bisect run - 差异循环:相同输入分别在旧版本和新版本中运行,对比输出差异
- 人工参与的脚本——最后手段,仅当必须人工操作时使用;将操作步骤脚本化,保持循环结构化
然后优化循环:更快(缓存设置、缩小范围——以秒为单位,而非分钟)、更精准(断言用户遇到的具体症状,而非“未崩溃”)、可确定(固定时间、随机种子、隔离文件系统)。遇到非确定性Bug?不要追求完美的复现方式——提高复现率(循环触发100次、增加压力、缩小时间窗口),直到复现率足够高以便进行根因分析。
确实无法构建该循环?明确说明这一点,列出你尝试过的方法,并请求用户提供复现环境、捕获的工件,或允许添加临时监控。不要凭感觉继续。
准入检查:命名该命令,粘贴一次其失败(red)输出的运行结果。
Phase 2 — Reproduce and minimise
阶段2 — 复现并最小化
Run the loop; watch it go red with the failure the user described (a nearby different failure = wrong bug = wrong fix). Read the complete error — full message, full stack trace, line numbers; errors often contain the answer. Check recent changes: git diff, new dependencies, config, environment.
Shrink the repro one cut at a time (inputs, config, callers, steps), re-running after each cut, until every remaining element is load-bearing — removing any one turns it green. A minimal repro shrinks the hypothesis space and becomes the regression test.
For multi-component systems (CI → build → deploy, API → service → DB): instrument each boundary — log what enters and exits every layer — and run once to see WHERE it breaks, before touching any fix. When the error surfaces deep in a call chain, audit-trace the bad value backward through its callers to the ORIGINAL trigger. Never fix only where the error appears; that is treating the symptom.
Retrieval is not the red-capable loop. During Phases 1–2, do not use
/ retrieval as the feedback signal. The red-capable command alone
gates progress.
load-subgraph运行循环;观察它是否因用户描述的故障显示失败(若出现附近的不同故障,则说明找错了Bug,对应的修复也会错误)。阅读完整错误信息——完整消息、完整堆栈跟踪、行号;错误信息往往包含答案。检查近期变更:git diff、新依赖项、配置、环境。
逐步缩小复现范围(输入、配置、调用方、步骤),每次修改后重新运行,直到剩余的每个元素都是必要的——移除任何一个元素都会让循环显示成功(green)。最小化的复现范围会缩小假设空间,并成为回归测试用例。
对于多组件系统(CI → 构建 → 部署,API → 服务 → 数据库):为每个边界添加监控——记录每一层的输入和输出——运行一次以确定故障发生位置,再进行任何修复操作。当错误出现在调用链深处时,跟踪错误值反向遍历调用方,找到最初的触发点。永远不要只修复错误出现的位置;那只是治标不治本。
检索并非red-capable循环。在阶段1-2期间,请勿将/检索作为反馈信号。只有red-capable命令才能管控进度。
load-subgraphAfter Phase 2 — feature-ownership context (before Phase 3)
阶段2之后 — 功能所有权上下文(阶段3之前)
When Phase 2 is complete and you have a path or stable term, and before
Phase 3 hypotheses: REQUIRED SUB-SKILL: use for ownership /
neighbor context (seed paths/terms; or as fits).
Grounded claims (one home): follow
— never invent
root-cause hypotheses from the envelope; never skip the red loop because neighbors
look suggestive.
load-subgraphneighborsblast_radiusskills/execution/load-subgraph/references/grounded-claims.md当阶段2完成,你获得了路径或稳定术语,并且在阶段3提出假设之前:必须使用子技能:获取所有权/相关上下文(种子路径/术语;根据情况使用或)。基于事实的声明(单一来源):遵循——永远不要凭空提出根因假设;永远不要因为相关内容看起来有提示性就跳过失败循环。
load-subgraphneighborsblast_radiusskills/execution/load-subgraph/references/grounded-claims.mdOps docs after Phase 2 (optional — never replaces the red loop)
阶段2之后的运维文档(可选——永远不能替代失败循环)
Only after Phase 2. Phases 1–2 still require a red-capable command first. Load:
.
skills/project/define-system-doc/consult-recipe.mdPaths when applicable: (and runbook slugs),
, — advisory Phase 3+
context only; never a substitute for the red loop. No-op when absent; suggest once
if material;
never auto-invoke.
docs/ops/runbooks.mddocs/ops/observability.mddocs/ops/disaster-recovery.md/define-system-doc ops/runbooks|observability|disaster-recovery仅在阶段2之后使用。阶段1-2仍需先构建red-capable命令。加载:。
skills/project/define-system-doc/consult-recipe.md适用路径:(及运行手册别名)、、——仅作为阶段3及之后的参考上下文;永远不能替代失败循环。若不存在则无需操作;若内容重要,可建议执行一次;切勿自动调用。
docs/ops/runbooks.mddocs/ops/observability.mddocs/ops/disaster-recovery.md/define-system-doc ops/runbooks|observability|disaster-recoveryExternal dependency evidence after Phase 2 (conditional — before Phase 3)
阶段2之后的外部依赖证据(有条件——阶段3之前)
IF the minimized failure path crosses a versioned external dependency — a
library, framework, SDK, database, cache, search/observability platform, cloud
service, external API, CLI, provider distribution, or protocol — THEN complete
this evidence gate before writing hypotheses. The Phase 1 signal and Phase 2
minimal repro remain the gate; documentation never replaces either.
- Runtime identity. Capture product, distribution/provider, server/runtime
version, client/SDK version, topology/deployment mode, effective relevant
configuration, and the exact error/output. The artifact cites the literal
Phase 1 command and red output; a handoff claim that they ran is not evidence.
Unknown fields stay .
unresolved - Owning documentation. REQUIRED SUB-SKILL: use for the exact failing concept. For libraries/frameworks/APIs, it resolves current documentation through Context7 first. Match the source to the observed version/provider; latest docs do not establish older-runtime behavior.
research - Contract diff. Produce this artifact before Phase 3:
| Surface | Actual runtime evidence | Official documented expectation | Applicability | Match |
|---|---|---|---|---|
| | | | |
- History check. When actual and current docs disagree, inspect the owning changelog, migration guide, deprecation notice, or official issue history for the observed version. A community answer may locate a source; it is not the evidence entered in the table.
- Disposition. becomes a hypothesis candidate, not a confirmed cause.
match=noblocks dependency-behavior claims; report the missing identity/source instead of filling it from model memory.applicability=unresolved
When runtime access or identity is unavailable, use this disposition verbatim in
the artifact:
text
Runtime evidence unavailable: <missing access/artifact>.
Version-matched owning documentation cannot be resolved.
Current official documentation is reference only; applicability is unresolved.
Phase 3 external-behavior hypotheses are blocked pending: <required evidence>.Gate check: the Phase 1 command/red output is cited; runtime identity is
explicit; an owning source is version-matched or explicitly unavailable; every
table cell is filled; and no Phase 3 hypothesis claims external behavior beyond
that artifact.
如果最小化的故障路径涉及版本化的外部依赖项——库、框架、SDK、数据库、缓存、搜索/可观测性平台、云服务、外部API、CLI、供应商发行版或协议——那么在提出假设之前,必须完成此证据检查。阶段1的信号和阶段2的最小化复现仍为准入门槛;文档永远不能替代这两者。
- 运行时标识。捕获产品、发行版/供应商、服务器/运行时版本、客户端/SDK版本、拓扑/部署模式、有效相关配置,以及确切的错误/输出。工件需引用阶段1的命令和失败输出;仅口头声称已运行不算证据。未知字段保留为。
unresolved - 官方文档。必须使用子技能:查找确切的故障概念。对于库/框架/API,先通过Context7获取最新文档。确保来源与观察到的版本/供应商匹配;最新文档不能代表旧运行时的行为。
research - 契约差异。在阶段3之前生成此工件:
| 层面 | 实际运行时证据 | 官方文档预期 | 适用性 | 匹配情况 |
|---|---|---|---|---|
| | | | |
- 历史检查。当实际行为与当前文档不符时,检查对应版本的官方变更日志、迁移指南、弃用通知或官方问题历史。社区答案可能会找到来源,但不能作为表格中的证据。
- 处理结果。成为假设候选,而非已确认的原因。
匹配情况=否会阻止关于依赖项行为的声明;报告缺失的标识/来源,而非用模型记忆填充。适用性=未解决
当无法获取运行时访问权限或标识时,在工件中使用以下固定处理结果:
text
Runtime evidence unavailable: <missing access/artifact>.
Version-matched owning documentation cannot be resolved.
Current official documentation is reference only; applicability is unresolved.
Phase 3 external-behavior hypotheses are blocked pending: <required evidence>.准入检查:引用阶段1的命令/失败输出;明确运行时标识;已匹配版本的官方来源或明确说明无法获取;表格的每个单元格均已填写;阶段3的假设未超出该工件所记录的外部行为。
Phase 3 — Hypothesise
阶段3 — 提出假设
Write 3–5 ranked hypotheses before testing any (a single hypothesis anchors you to the first plausible idea). Each must be falsifiable with a stated prediction: "if X is the cause, then changing Y makes the bug disappear". If you cannot state the prediction, it is a vibe — sharpen it or discard it. Show the ranked list to the user (they often re-rank it instantly); don't block if they're away.
Test the smallest hypothesis first. ONE variable at a time — never stack changes. Instrument with a debugger/REPL when available (one breakpoint beats ten logs), else targeted logs with a unique prefix per probe (e.g. ) so cleanup is one grep — never log-everything-and-grep. Performance bugs: measure a baseline first (profiler, timing harness), then bisect; logs mislead here. Don't understand something? Say "I don't understand X" and investigate — never pretend and guess.
[DBG-x7q2]Hypothesis falsified? Strike it, move to the next. Don't pile a new fix on top of a failed one.
在测试任何假设之前,先写出3-5个排序后的假设(单一假设会让你局限于第一个看似合理的想法)。每个假设必须可证伪,并附带明确的预测:“如果X是原因,那么修改Y会让Bug消失”。如果你无法明确预测,那只是一种感觉——要么细化它,要么舍弃它。将排序后的列表展示给用户(他们通常会立即重新排序);如果用户不在,也无需等待。
先测试最小的假设。每次只改变一个变量——永远不要同时进行多项变更。如果可用,使用调试器/REPL进行监控(一个断点胜过十条日志),否则使用带有唯一前缀的定向日志(例如),这样清理时只需一次grep——永远不要记录所有内容再去搜索。性能Bug:先测量基线(性能分析器、计时工具),然后二分排查;日志在此处会产生误导。有不理解的内容?直接说“我不理解X”并进行调查——永远不要假装懂而猜测。
[DBG-x7q2]假设被证伪?划掉它,继续下一个。不要在失败的修复上叠加新的修复。
Phase 4 — Fix
阶段4 — 修复
- Failing regression test first. REQUIRED SUB-SKILL: use . The test goes at a CORRECT seam — one that exercises the real bug pattern as it occurred. If no correct seam exists, that is itself a finding: document it and flag it for the post-mortem; a shallow test there is false confidence.
test-first - One fix addressing the root cause. No "while I'm here" improvements, no bundled refactoring.
- Watch the regression test pass, re-run the full suite, re-run the Phase 1 loop against the original un-minimised scenario.
Three failed fix attempts = STOP. The architecture is in question, not your latest hypothesis — especially if each fix reveals new coupling somewhere else. Discuss with the user before attempt 4.
- 先编写失败的回归测试。必须使用子技能:。测试要放在正确的层级——能复现实际Bug模式的层级。如果没有合适的层级,这本身就是一个发现:记录下来并在事后复盘时标记;在此处编写浅层测试只会带来虚假的信心。
test-first - 仅修复根本原因。不要附带“顺便优化”的改进,不要捆绑重构。
- 观察回归测试通过,重新运行完整测试套件,针对原始未最小化的场景重新运行阶段1的循环。
三次修复尝试失败 = 停止。问题出在架构上,而非你最新的假设——尤其是如果每次修复都暴露出新的耦合问题。在第四次尝试前与用户讨论。
Exit — mini-spec, cleanup, post-mortem
收尾 — 迷你规范、清理、事后复盘
- Tier-1 mini-spec: add a fix requirement plus a guard requirement to the owning feature's
SHALL CONTINUE TO(orrequirements.mdif no feature owns it). Map the regression test to that ID in the task report / Spec review — docs-only spine; do not require greppable IDs in test source for consumer apps.docs/specs/fixes.md - Remove ALL instrumentation: grep for your prefixes; delete throwaway harnesses.
[DBG-...] - State the confirmed root cause in the commit message.
- Route Task: "what would have prevented this bug?" If the answer is architectural (no good seam, hidden coupling, tangled callers), write the specifics down and tell the user to run — after the fix lands, when you know the most.
/scan-architecture - REQUIRED SUB-SKILL: use before claiming the bug fixed.
prove-claim
- 一级迷你规范:在对应功能的中添加修复要求和
requirements.md防护要求(如果没有对应功能,则添加到SHALL CONTINUE TO)。在任务报告/规范评审中将回归测试映射到该ID——仅文档层面;对于消费类应用,不要求测试代码中包含可搜索的ID。docs/specs/fixes.md - 移除所有监控:搜索你的前缀;删除临时测试工具。
[DBG-...] - 在提交信息中说明已确认的根本原因。
- 发起任务:“什么可以防止这个Bug再次发生?”如果答案是架构层面的(没有合适的层级、隐藏的耦合、混乱的调用方),写下具体内容并告知用户运行——在修复完成后,当你对问题了解最透彻的时候。
/scan-architecture - 必须使用子技能:在声称Bug已修复前使用。
prove-claim
Rationalizations
常见借口与真相
| Thought | Reality |
|---|---|
| "Emergency, no time for process" | Root-cause debugging is FASTER than guess-and-check thrashing |
| "It's obviously X, let me just fix it" | Seeing a symptom is not understanding a cause |
| "Quick patch now, investigate later" | The patch becomes permanent and the cause strikes again |
| "Try several changes at once to save time" | You can't tell which one worked, and one of them broke something |
| "Too simple to need a repro" | Simple bugs have root causes too; the loop takes minutes |
| "I'll add the regression test after the fix" | Untested fixes regress; the red test is the proof the fix fixes |
| "One more attempt" (after 2+ failures) | Attempt 4 without an architecture discussion is thrashing |
| "Load the feature subgraph first — that is the loop" | Phases 1–2 need a red-capable command; retrieval only after Phase 2 |
| "Neighbor card says who owns it — skip minimize" | Ownership context is advisory after Phase 2; the minimal repro still gates Phase 3 |
| "I know this library; fetch docs after the likely fix" | Runtime identity and version-matched owning docs complete before external-behavior hypotheses |
| 想法 | 真相 |
|---|---|
| “紧急情况,没时间走流程” | 根因调试比猜测式尝试更快 |
| “显然是X的问题,我直接修复就行” | 看到症状并不等于理解原因 |
| “先快速修补,之后再调查” | 修补会变成永久方案,而原因会再次引发Bug |
| “同时尝试多个变更以节省时间” | 你无法知道哪个变更起作用,而且其中一个可能会破坏其他功能 |
| “太简单了,不需要复现” | 简单Bug也有根本原因;构建循环只需几分钟 |
| “我会在修复后添加回归测试” | 未测试的修复会再次退化;失败测试是修复有效的证明 |
| “再试一次”(已失败2+次) | 不讨论架构就进行第四次尝试纯粹是浪费时间 |
| “先加载功能子图——这就是循环” | 阶段1-2需要red-capable命令;仅在阶段2之后进行检索 |
| “相关卡片显示了所有者——跳过最小化步骤” | 所有权上下文仅在阶段2之后作为参考;最小化复现仍管控阶段3的准入 |
| “我了解这个库;在可能的修复之后再获取文档” | 在提出外部行为假设之前,必须完成运行时标识和版本匹配的官方文档检查 |
User signals — return to Phase 1
用户信号 — 返回阶段1
| The user says | It means |
|---|---|
| "Stop guessing" | You proposed fixes without a root cause — back to Phase 1 |
| "Is that actually happening?" | You assumed without verifying — gather evidence |
| "Will that show us anything?" | Your probe maps to no prediction — restate hypotheses |
| "We're going in circles" | Count your failed fixes; you're probably at the architecture gate |
| 用户表述 | 含义 |
|---|---|
| “别瞎猜了” | 你在未做根因分析的情况下提出了修复方案——回到阶段1 |
| “真的是这样吗?” | 你未经验证就做出了假设——收集证据 |
| “这能告诉我们什么?” | 你的监控没有对应预测——重新表述假设 |
| “我们在绕圈子” | 数一下你的失败修复次数;你可能已经触及架构门槛 |