anti-bug
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseAnti-Bug
Anti-Bug
Find real defects across a codebase, repair them at the root, and leave evidence anyone can re-run.
在代码库中发现真实缺陷,从根源修复,并留下任何人都可以重新运行的证据。
Philosophy
理念
Rules cover the situations someone anticipated. These principles are for the rest, and each one resolves to a behavior rather than a slogan.
A bug is a gap between intent and behavior — so establish intent first. With no written intent, reading code only reflects it back, and every finding is an opinion. Write down what the system is supposed to do before naming anything broken.
The code cannot testify about itself. An implementation is the defendant, not the witness. Expected values come from the specification, a business rule, a contract, or a person — never from running the current code and recording what it printed.
Green is a clue, not a verdict. A passing suite says "nothing here caught it," which is a statement about the tests. Prove a fix by making a test fail without it.
A bug found once is a habit, not an accident. The same missing guard, the same unparameterized query, the same unawaited call. Finding one occurrence and reporting it fixed is a false claim about the codebase.
The most expensive bugs never crash. They return 200, complete successfully, and are wrong — a discount applied twice, a limit that does not hold, an order someone else can read. No linter has an opinion about those, which is exactly why they survive to production.
Report what can be proven, label what is suspected, and never blur the two. Trust is spent once. A report of eight verified findings outranks sixty where twenty are imagined.
Silence about what was not checked is a form of lying. Coverage stated honestly is a professional result; coverage implied is a trap for whoever ships next.
When the rules run out, ask what the user loses. Severity, ordering, and when to stop all resolve to blast radius: money, data, access, trust, time — in that order.
规则覆盖的是人们已预见的情况。这些原则适用于其余情况,并且每一条都落实为行为而非口号。
Bug 是意图与行为之间的差距——因此先确立意图。 没有书面意图,阅读代码只会映照出代码自身,每条发现都只是意见。在命名任何损坏之处之前,先写下系统应该做什么。
代码无法为自己作证。 实现是被告,不是证人。预期值来自规格说明、业务规则、契约或人——绝不来自运行当前代码并记录其输出。
绿色是线索,不是 verdict。 通过的测试套件只说明“这里没有东西捕获它”,这是对测试的评价。通过让一个测试在缺少修复时失败来证明修复。
一次发现的 bug 是习惯,不是意外。 同样的缺失防护、同样的非参数化查询、同样的未等待调用。发现一次并报告已修复,是对代码库的虚假声明。
最昂贵的 bug 从不崩溃。 它们返回 200,成功完成,但结果错误——折扣应用两次、限制不成立、别人可以读取的订单。没有 linter 会对这些发表意见,这正是它们能存活到生产环境的原因。
报告可证明的,标记可疑的,绝不混淆两者。 信任只花一次。八条已验证的发现胜过六十条其中二十条是想象的。
对未检查之事保持沉默是一种撒谎。 诚实说明覆盖范围是专业的结果;暗示覆盖则是给下一个发布者的陷阱。
当规则用尽时,问问用户会损失什么。 严重性、排序以及何时停止都归结为爆炸半径:金钱、数据、访问、信任、时间——按此顺序。
Why this skill is shaped the way it is
为什么这个技能是这个形状
Three failure modes destroy an automated bug hunt, each measured, each driving a rule.
Crying wolf. Google's static-analysis team found developers abandon a tool once roughly 10% of its reports are "effective false positives" — findings nobody acts on.
Plausible but wrong fixes. Generate-and-validate repair systems produced patches that passed the whole test suite yet were correct only 2-8% of the time; 104 of GenProg's 110 plausible patches were semantically equivalent to deleting functionality.
Agents narrating success they never achieved. Across 547 real agentic-coding incidents: 40.4% constraint violations, 24.5% destructive operations, 15.7% falsely claiming an action was completed, 9.7% fabricating terminal logs.
references/research-basis.md三种失败模式会毁掉自动化 bug 猎杀,每种都有数据支撑,每种都驱动一条规则。
狼来了。 谷歌静态分析团队发现,一旦约 10% 的报告是“有效误报”——无人理会的发现,开发者就会放弃工具。
看似合理但错误的修复。 生成-验证修复系统产生的补丁通过了整个测试套件,但正确率仅为 2-8%;GenProg 的 110 个看似合理的补丁中有 104 个在语义上等同于删除功能。
代理叙述自己从未取得的成功。 在 547 起真实 agentic-coding 事件中:40.4% 违反约束,24.5% 破坏性操作,15.7% 虚假声称操作已完成,9.7% 捏造终端日志。
references/research-basis.mdThe five rules
五条规则
1. Evidence bar. Every finding carries a reproduction (a command, a failing test, an input) or a concrete trace with exact per hop. Without either it is , ranked below everything confirmed, never silently promoted. A small confirmed count is the honest answer; padding it is how the report becomes worthless.
file:lineSuspected2. Root cause, and every sibling. Fix the cause, then search the codebase for the same pattern. Record each occurrence under the same finding. NIST's SSDF makes root-cause analysis its own practice (RV.3) for exactly this reason: it is what reduces future defect frequency rather than today's count.
3. Never weaken to go green. Deleting a branch, loosening an assertion, widening a catch, skipping a test, relaxing validation — all make a suite pass and leave the bug in production. If a fix requires removing behavior, that is a product decision: document it under Needs decision and stop.
4. No claim without an artifact. "Tests pass" means the command and its real output are in the ledger. Never write a result that was not observed. If something could not be run — no network, no service, no credentials — say so and mark it .
Unverified5. The oracle comes from the specification, never from the implementation. When writing a test, the expected value is derived from a business rule, a contract, a document, or a person. Running the current code and recording its output as produces a test that locks the bug in permanently and reports success. This is the single easiest way to do real damage here, and it is invisible afterward — the test is green, the suite grew, and the defect is now protected by a regression test.
expected1. 证据标准。 每条发现都附有复现(命令、失败测试、输入)或带确切 的逐步追踪证据。没有这些则标记为 ,排在所有已确认项之下,绝不静默提升。少量已确认的数量是诚实的答案;填充数量只会让报告变得一文不值。
file:lineSuspected2. 根因,以及所有同族问题。 修复原因,然后搜索整个代码库中的相同模式。将每次出现记录在同一条发现下。NIST 的 SSDF 将根因分析作为独立实践(RV.3)正是出于这个原因:它降低的是未来缺陷频率,而不仅仅是今天的数量。
3. 绝不为了变绿而削弱。 删除分支、放宽断言、扩大 catch、跳过测试、放松验证——这些都会让套件通过,却把 bug 留在生产环境。如果修复需要移除行为,那是产品决策:在 Needs decision 下记录并停止。
4. 没有工件就没有声明。 “测试通过”意味着命令及其真实输出在记录中。绝不写未观察到的结果。如果某些东西无法运行——没有网络、没有服务、没有凭据——如实说明并标记为 。
Unverified5. 预言来自规格说明,绝不来自实现。 编写测试时,预期值来自业务规则、契约、文档或人。运行当前代码并将其输出记录为 会产生一个将 bug 永久锁定的测试,并且报告成功。这是在这里造成真正伤害的最简单方式,而且事后不可见——测试是绿的,套件变大了,缺陷现在被一个回归测试保护着。
expectedThe ledger
记录账本
Model performance degrades for information in the middle of a long context, and a repository sweep overflows any window. So findings live on disk, in , managed by :
.anti-bug/findings.jsonscripts/ledger.pybash
python scripts/ledger.py init
python scripts/ledger.py rule --area checkout \
--text "Loyalty discount is redeemable once per customer per campaign" \
--source "docs/campaigns.md:14" --confidence stated
python scripts/ledger.py add --severity critical --category business-logic \
--title "Loyalty discount redeemable N times under concurrency" \
--location "src/billing/redeem.py:88-94" --status confirmed --rule R-01 \
--repro "30 parallel POST /redeem with one code -> 30 credits applied" \
--evidence "read-check-write with no unique constraint and no transaction"
python scripts/ledger.py set F-003 --status fixed --fix-commit abc1234 --test tests/test_redeem.py::test_single_redemption
python scripts/ledger.py report # markdown for the final document
python scripts/ledger.py stats # flags anything still open or fixed without a testThe ledger is also an attempt history, not only a findings list. Record every fix attempt and its measured outcome:
bash
python scripts/ledger.py attempt F-003 --mechanism "added unique index on (customer, campaign)" \
--outcome fail --measured "test still red: 2 of 30 requests succeed" \
--failure-class repairable --note "index correct; the read still happens outside the transaction"This matters because history used as a replayable record of mechanisms and their measured outcomes outperforms history used as loose guidance — an agent that can look up what was already tried, and what actually happened, stops re-proposing it. Concretely, before any new attempt on a finding, read every prior attempt on it in full, and trust the measured outcome over what an attempt claimed about itself.
模型在长上下文中间的信息上性能会下降,而仓库扫描会溢出任何窗口。因此发现保存在磁盘上的 中,由 管理:
.anti-bug/findings.jsonscripts/ledger.pybash
python scripts/ledger.py init
python scripts/ledger.py rule --area checkout \
--text "Loyalty discount is redeemable once per customer per campaign" \
--source "docs/campaigns.md:14" --confidence stated
python scripts/ledger.py add --severity critical --category business-logic \
--title "Loyalty discount redeemable N times under concurrency" \
--location "src/billing/redeem.py:88-94" --status confirmed --rule R-01 \
--repro "30 parallel POST /redeem with one code -> 30 credits applied" \
--evidence "read-check-write with no unique constraint and no transaction"
python scripts/ledger.py set F-003 --status fixed --fix-commit abc1234 --test tests/test_redeem.py::test_single_redemption
python scripts/ledger.py report # markdown for the final document
python scripts/ledger.py stats # flags anything still open or fixed without a test账本也是尝试历史,而不仅仅是发现列表。记录每次修复尝试及其测量结果:
bash
python scripts/ledger.py attempt F-003 --mechanism "added unique index on (customer, campaign)" \
--outcome fail --measured "test still red: 2 of 30 requests succeed" \
--failure-class repairable --note "index correct; the read still happens outside the transaction"这很重要,因为作为可重放的机制及其测量结果记录的历史,优于作为松散指导的历史——能够查找已尝试过什么以及实际发生了什么的代理,会停止重新提出它。具体来说,在对某条发现进行任何新尝试之前,完整阅读该发现的每一个先前尝试,并相信测量结果胜过尝试声称的内容。
Phase 0 — Context and the business rules register
阶段 0 — 上下文与业务规则登记表
Finding defects requires more complete understanding than any other review activity, and reviewers working in unfamiliar code produce measurably shallower feedback. This phase is not overhead; skipping it converts everything after it into guesswork.
Run first — it detects languages, entry points, tests, config and risk surfaces, and prints the commands available for this stack. Then read what it points at: README, architecture docs, manifests, CI config, migrations. If git history exists, run to rank files by change frequency crossed with bug-fix density. Top-ranked files are where to start; roughly a third of files are needed to cover 80% of distinct bugs, so they are never where to stop.
python scripts/recon.pypython scripts/hotspots.pyWrite a Context Summary: what the system does and for whom; stack and versions from manifests; entry points; the main data flow traced end to end; data layer and transaction boundaries; external integrations; the auth model including where authorization is merely assumed; and a blast-radius ranking — money, auth, personal data, deletion, anything irreversible.
Then write the Business Rules Register, which is what makes the business-logic pass possible at all. For each rule: the area, the rule as the business would state it, its source, and its confidence.
| ID | Area | Rule | Source | Confidence |
|---|---|---|---|---|
| R-01 | Checkout | Discount code redeemable once per customer per campaign | | stated |
| R-02 | Refunds | Refund total may never exceed the captured amount | inferred from | inferred |
Confidence is the load-bearing column. A rule is a fact; an rule is a question. Inferring a rule from the code and then testing the code against it proves only that the code agrees with itself. So: when a rule is unclear and the user is reachable, ask — do not guess. When they are not reachable, mark it , say so in the finding, and never mark a finding derived from an inferred rule as — it is .
statedinferredinferredConfirmedNeeds decision发现缺陷需要比其他任何审查活动更完整的理解,而在不熟悉代码中工作的审查者会产生明显更浅的反馈。这个阶段不是开销;跳过它会将之后的一切变成猜测。
首先运行 ——它检测语言、入口点、测试、配置和风险面,并打印此技术栈可用的命令。然后阅读它指向的内容:README、架构文档、清单、CI 配置、迁移。如果存在 git 历史,运行 按变更频率与 bug 修复密度交叉排序文件。排名靠前的文件是开始的地方;大约三分之一的文件就能覆盖 80% 的不同 bug,所以它们绝不是停止的地方。
python scripts/recon.pypython scripts/hotspots.py编写上下文摘要:系统做什么、为谁做;栈和来自清单的版本;入口点;端到端追踪的主数据流;数据层和事务边界;外部集成;授权模型,包括授权仅仅被假设的地方;以及爆炸半径排序——金钱、认证、个人数据、删除、任何不可逆的操作。
然后编写业务规则登记表,这是使业务逻辑扫描成为可能的关键。对每条规则:领域、业务表述的规则、来源和置信度。
| ID | 领域 | 规则 | 来源 | 置信度 |
|---|---|---|---|---|
| R-01 | 结账 | 折扣码每个客户每个活动只能兑换一次 | | 已陈述 |
| R-02 | 退款 | 退款总额不得超过已捕获金额 | 从 | 推断 |
置信度是承重列。 规则是事实; 规则是问题。 从代码中推断规则,然后用代码测试它,只能证明代码与自己一致。所以:当规则不明确且用户可联系时,询问——不要猜测。当用户不可联系时,标记为 ,在发现中说明,并且绝不将从推断规则派生的发现标记为 ——它是 。
statedinferredinferredConfirmedNeeds decisionPhase 1 — Baseline
阶段 1 — 基线
Install, build, run the full suite, run linters, type checkers, and the dependency audit. Record exact commands and real output with . Everything later compares against this; without it, "no new failures" is unprovable.
ledger.py baselinePre-existing failures are data, not obstacles — a test that was already red marks where the team stopped caring, which is often where bugs live. Do not fix them yet, and do not modify production code in this phase.
If the build cannot run, record why and continue with static analysis only. A static-only hunt honestly labeled is valuable; one that implies it executed the code is a fabrication.
安装、构建、运行完整测试套件、运行 linter、类型检查器以及依赖审计。使用 记录确切命令和真实输出。之后的一切都与它比较;没有它,“没有新失败”是无法证明的。
ledger.py baseline预先存在的失败是数据,不是障碍——一个已经红着的测试标志着团队停止关心的地方,这通常是 bug 所在。此时不要修复它们,也不要在此阶段修改生产代码。
如果构建无法运行,记录原因并仅继续静态分析。诚实标注的纯静态猎杀是有价值的;暗示它执行了代码则是捏造。
Phase 2 — The sweep
阶段 2 — 扫描
Ordered by yield per unit of effort, so an interrupted run still delivers the highest-value findings. Read for patterns and grep recipes, for Pass BL, for Pass B, and for per-stack commands.
references/detection-playbook.mdreferences/business-logic.mdreferences/security-audit.mdreferences/toolchains.mdPass BL — Business logic. First, because it is the only class no tool covers. MITRE's CWE-840 category exists precisely because these flaws require "domain-specific knowledge or business rules" to judge, and "do not produce clear errors or undefined behavior at the code level." OWASP's testing guide is blunter: automated tools cannot understand context, so this remains manual work. Walk each rule in the register against the code: value and quota validation, calculations (price, discount, tax, balance, rounding, currency), flow and state (skippable steps, illegal transitions, replayable actions), logic-level authorization, concurrency on transactions and stock, hidden assumptions (empty, zero, negative, dates, timezones, extremes), and feature abuse — behavior that matches the code but defeats the business intent. gives prevention, detection and verification for each, with test scenarios.
references/business-logic.mdPass A — Error and failure handling. The highest-yield mechanical pass: 92% of catastrophic production failures came from mishandling errors the software had already detected, and 35% from three trivial patterns — empty or log-only handlers, over-broad catches that abort, and handlers containing TODO/FIXME. Also: swallowed promise rejections, ignored return codes, retries without backoff or cap, cleanup that skips the error path, messages that lose the cause.
Pass B — Security. Trace taint from entry points to sinks rather than grepping for sink names. Walk the CWE Top 25 and OWASP Top 10 against the real attack surface. Authorization deserves the most attention because no scanner can infer who should be allowed. Apply extra scrutiny to AI-generated code: roughly 40% of LLM-generated programs in controlled security scenarios contained a CWE.
Pass C — Correctness and edge cases. Off-by-one, inverted conditions, operator precedence, integer/float confusion, timezone and DST, currency in floats, mutated shared defaults, boundaries (empty, null, zero, negative, max, duplicate, malformed, unicode, very large).
Pass D — Concurrency and state. Narrower than its reputation: 96% of concurrency bugs manifest with only two threads, 69% are atomicity violations, 32% order violations. Look for pairs — check-then-act on shared state, non-atomic read-modify-write, missing transaction boundaries, inside a lock, unawaited async calls, request data in global state.
awaitPass E — Data integrity. Missing constraints and indexes, irreversible or destructive migrations, multi-statement writes without a transaction, unvalidated input reaching persistence, cascade deletes, nullable columns assumed non-null, dual writes that can diverge.
Pass F — Performance and resources. N+1 queries, unbounded results, missing indexes on filter columns, unclosed handles, unbounded caches and queues, blocking I/O on an event loop.
Pass G — Configuration and deployment. Hardcoded secrets and hosts, unvalidated env vars, development settings reachable in production, dependency advisories, drift between and what the code reads.
.env.examplePass H — Test quality. Tests asserting nothing meaningful, tests mocking the unit under test, and flakiness — classify before blaming production code: 45% of flaky tests come from async wait, 20% concurrency, 12% test-order dependency.
Batching and effort. Defect detection collapses as review volume rises — effectiveness drops sharply past roughly 400 lines in one sitting. Keep each batch to one module or a few hundred lines and write findings immediately. Allocate effort adaptively: when a pass keeps producing findings, stay; when several batches in an area come back empty, move on rather than grinding. And when three attempts cluster around small variations of the same idea with flattening returns, that is a local optimum — switch to a structurally different angle instead of another marginal tweak.
按每单位努力产生的产出排序,因此即使中断的运行也能交付最高价值的发现。阅读 获取模式和 grep 配方, 获取 BL 扫描, 获取 B 扫描, 获取每个技术栈的命令。
references/detection-playbook.mdreferences/business-logic.mdreferences/security-audit.mdreferences/toolchains.mdBL 扫描 — 业务逻辑。 首先,因为它是唯一没有工具覆盖的类别。MITRE 的 CWE-840 类别正是因为这些缺陷需要“领域特定知识或业务规则”来判断,并且“在代码层面不会产生明确的错误或未定义行为”。OWASP 的测试指南更直白:自动化工具无法理解上下文,因此这仍然是手动工作。对照代码逐条检查登记表中的每条规则:值和配额验证、计算(价格、折扣、税、余额、舍入、货币)、流程和状态(可跳过步骤、非法转换、可重放操作)、逻辑级授权、事务和库存上的并发、隐藏假设(空、零、负数、日期、时区、极端值)以及功能滥用——与代码匹配但违背业务意图的行为。 为每一项提供了预防、检测和验证方法以及测试场景。
references/business-logic.mdA 扫描 — 错误和失败处理。 产出最高的机械扫描:92% 的灾难性生产故障来自错误处理软件已经检测到的错误,35% 来自三个琐碎模式——空处理器或仅记录处理器、过于宽泛的中止性 catch、以及包含 TODO/FIXME 的处理器。还要注意:吞掉的 promise rejection、忽略的返回码、没有退避或上限的重试、跳过错误路径的清理、丢失原因的消息。
B 扫描 — 安全。 从入口点到汇点追踪污点,而不是 grep 汇点名称。对照真实攻击面逐项检查 CWE Top 25 和 OWASP Top 10。授权最值得关注,因为没有扫描器能推断谁应该被允许。对 AI 生成的代码施加额外审查:在受控安全场景中,大约 40% 的 LLM 生成程序包含一个 CWE。
C 扫描 — 正确性和边界情况。 差一错误、反转条件、运算符优先级、整数/浮点混淆、时区和夏令时、浮点货币、共享默认值被修改、边界(空、null、零、负、最大、重复、畸形、Unicode、非常大)。
D 扫描 — 并发和状态。 比其名声更窄:96% 的并发 bug 仅用两个线程就会显现,69% 是原子性违规,32% 是顺序违规。寻找成对模式——共享状态上的检查后行动、非原子读-修改-写、缺失事务边界、锁内的 、未等待的异步调用、全局状态中的请求数据。
awaitE 扫描 — 数据完整性。 缺失约束和索引、不可逆或破坏性迁移、没有事务的多语句写入、未验证输入到达持久化、级联删除、假设非空的可空列、可能分歧的双写。
F 扫描 — 性能和资源。 N+1 查询、无界结果、过滤列上缺失索引、未关闭的句柄、无界缓存和队列、事件循环上的阻塞 I/O。
G 扫描 — 配置和部署。 硬编码密钥和主机、未验证的环境变量、生产环境可访问的开发设置、依赖公告、 与代码读取内容之间的漂移。
.env.exampleH 扫描 — 测试质量。 没有有意义断言的测试、mock 被测单元的测试,以及易碎性——在责备生产代码之前先分类:45% 的易碎测试来自异步等待,20% 来自并发,12% 来自测试顺序依赖。
分批和努力分配。 随着审查量上升,缺陷检测会下降——一次超过约 400 行后有效性急剧下降。每批保持在一个模块或几百行内,并立即写下发现。自适应分配努力:当一个扫描持续产生发现时,留在那里;当某个区域连续几批空手而归时,继续前进而不是研磨。当三次尝试聚集在同一想法的微小变体上且回报递减时,那是局部最优——切换到结构上不同的角度,而不是再做一次边际调整。
Phase 3 — Triage
阶段 3 — 分流
Resolve every finding to one state before fixing anything:
- Confirmed — reproduced, or traced end to end with evidence, against a
file:linerule. Eligible for fixing.stated - False positive — investigated and disproved. Keep it with the disproving evidence so the next run does not re-report it.
- Suspected — plausible, unproven. Investigate until confirmed or disproved. Never fix a suspected issue blindly: an unverified fix to a non-bug is pure regression risk.
- Needs decision — requires a product, business or architecture call, or rests on an rule. Document options and trade-offs; do not implement.
inferred
Classify with cumulative evidence, not a single observation. One failed reproduction attempt does not make a finding a false positive — the harness may be wrong, the precondition missing, the environment different. Equally, a finding closed earlier reopens the moment new evidence appears. Severity is assigned by blast radius: Critical (security hole, data loss, core-flow crash, money wrong), High (core feature wrong in common conditions), Medium (edge cases, notable performance, missing error handling), Low (maintainability).
Then map dependencies between findings and set fix order.
在修复任何东西之前,将每条发现解决到一个状态:
- Confirmed — 已复现,或根据 规则以
stated证据端到端追踪。有资格修复。file:line - False positive — 已调查并反驳。保留它及反驳证据,以便下一次运行不会重新报告。
- Suspected — 看似合理但未证实。调查直到确认或反驳。绝不盲目修复可疑问题:对非 bug 的未验证修复纯粹是回归风险。
- Needs decision — 需要产品、业务或架构决策,或依赖于 规则。记录选项和权衡;不实现。
inferred
用累积证据分类,而不是单一观察。一次失败的复现尝试不会使发现成为误报——测试工具可能错了、前置条件缺失、环境不同。同样,一条先前关闭的发现在新证据出现时立即重新打开。严重性按爆炸半径分配:Critical(安全漏洞、数据丢失、核心流程崩溃、金钱错误)、High(核心功能在常见条件下错误)、Medium(边界情况、显著性能问题、缺失错误处理)、Low(可维护性)。
然后映射发现之间的依赖关系并设置修复顺序。
Phase 4 — Fix
阶段 4 — 修复
Critical → High → Medium → Low; within a severity, whatever unblocks others first. On a branch () with one commit per finding: .
fix/anti-bug-sweepfix(billing): enforce single redemption [F-003]Before writing the change — the cheapest bug is the one not introduced:
- Name the rule or contract the change must satisfy, and where it is written down.
- Name what could break elsewhere: callers, schema, API shape, other tenants.
- Confirm any new dependency actually exists on its registry. Hallucinated package names are a live supply-chain attack surface.
Then, for each confirmed finding:
- Write the failing test first, with the expected value derived from the specification (rule 5). It must fail against current code for the right reason — not an import error.
- Make the minimal correct change at the root cause. Follow existing style and architecture. Do not refactor or reformat unrelated code; every unrelated line hides the real fix during review.
- Fix every sibling occurrence. If a sibling sits outside the agreed scope, record it as its own finding rather than quietly editing it.
- Run the new test, then the surrounding suites. Paste real output.
- Revert-check: undo the fix and confirm the test goes red. If it stays green, the test does not cover the defect. Mutation-style checks like this correlate with real fault detection considerably better than line coverage.
When a fix attempt fails, record the attempt and classify it before trying again — this is what stops an agent from burning a session re-proposing variants of the same idea:
- Flawed mechanism — the approach itself is wrong. Do not retry it. Change mechanism.
- Repairable — the approach is sound, the implementation slipped. Retry only after locating the actual defect in the code, not guessing from the symptom, and only with a specific fix in hand.
- Environmental — harness, fixture, or dependency, not the fix. Repair the environment, then re-measure.
- Needs decision — larger or riskier than planned. Stop the item and document it. A half-applied fix is worse than none.
Never negotiable while fixing: no hardcoded secrets; no deleted, skipped or weakened tests; no loosened validation to make something pass; security fixes use framework or established-library features rather than hand-rolled sanitizers; migrations stay reversible and non-destructive; dependency bumps take the smallest version that resolves the issue.
Critical → High → Medium → Low;在同一严重性内,先做能解除其他阻塞的。在分支()上,每条发现一个提交:。
fix/anti-bug-sweepfix(billing): enforce single redemption [F-003]在编写更改之前——最便宜的 bug 是未被引入的 bug:
- 命名更改必须满足的规则或契约,以及它写在哪里。
- 命名可能破坏的其他地方:调用方、schema、API 形状、其他租户。
- 确认任何新依赖确实存在于其注册表上。幻觉包名是一个活的供应链攻击面。
然后,对每条已确认的发现:
- 先编写失败测试,预期值来自规格说明(规则 5)。它必须因正确的原因针对当前代码失败——而不是导入错误。
- 在根因处进行最小正确更改。 遵循现有风格和架构。不要重构或重新格式化无关代码;每一行无关代码都会在审查时掩盖真正的修复。
- 修复每个同族出现点。 如果同族问题位于约定范围之外,将其记录为单独发现,而不是悄悄修改。
- 运行新测试,然后运行周边套件。 粘贴真实输出。
- 还原检查: 撤销修复并确认测试变红。如果它保持绿色,则测试未覆盖该缺陷。此类变异式检查与实际缺陷检测的相关性明显优于行覆盖率。
当修复尝试失败时,在再次尝试之前记录尝试并分类——这正是阻止代理浪费一整个会话重新提出同一想法的变体的方式:
- Flawed mechanism — 方法本身错误。不要重试。更换机制。
- Repairable — 方法正确,实现失误。仅在定位到代码中的实际缺陷后重试,而不是从症状猜测,并且只持有具体修复方案。
- Environmental — 工具、夹具或依赖问题,而非修复本身。修复环境,然后重新测量。
- Needs decision — 比计划更大或风险更高。停止该项目并记录。半应用的修复比没有更糟。
修复时绝不可协商:不硬编码秘密;不删除、跳过或削弱测试;不放松验证以让某物通过;安全修复使用框架或成熟库功能而非手写消毒器;迁移保持可逆且非破坏性;依赖升级采用能解决问题的最小版本。
Phase 5 — Verify
阶段 5 — 验证
Change stance deliberately: review the diff as though someone else wrote it and you suspect them.
- Read the complete diff against the baseline, file by file.
- For each fix, ask whether it addresses the cause or masks the symptom.
- Check every test added: does its expected value come from the specification, or was it copied from what the code produced? Rule 5 fails silently, so it has to be checked explicitly.
- Look for new bugs introduced: changed behavior elsewhere, new edge cases, performance regressions, broadened permissions.
- Look for leftovers: debug prints, commented-out code, stray TODOs, accidental changes.
- Re-run the sibling pattern search — confirm none was missed.
- Re-run every original reproduction and confirm it no longer reproduces.
- Run the full suite, linters, type checkers, and the vulnerability audit. Compare against Phase 1: no new failures, no new lint or type errors, coverage not decreased. Accept the result only if it is no worse than baseline on every recorded check — a fix that trades one failure for another has not improved anything.
- Smoke test every entry point from the Context Summary. A suite that passes while the app will not boot is a false pass.
If verification finds problems, return to Phase 4 for those items and repeat. Record what this phase caught — those entries are the most instructive in the final report.
Then confirm completeness: flags any finding without a final status and any fix recorded without a test.
python scripts/ledger.py stats刻意改变立场:像一个怀疑别人写的代码的人一样审查 diff。
- 对照基线逐文件阅读完整 diff。
- 对每个修复,问它是否解决了原因还是掩盖了症状。
- 检查每个添加的测试:其预期值来自规格说明,还是从代码输出复制而来?规则 5 会静默失败,所以必须明确检查。
- 寻找新引入的 bug:其他地方行为改变、新边界情况、性能回归、权限扩大。
- 寻找遗留物:调试打印、注释掉的代码、乱入的 TODO、意外更改。
- 重新运行同族模式搜索——确认没有遗漏。
- 重新运行每个原始复现,确认不再复现。
- 运行完整套件、linter、类型检查器和漏洞审计。与阶段 1 比较:没有新失败、没有新 lint 或类型错误、覆盖率没有降低。只有在每项记录检查上不劣于基线时才接受结果——用一个失败换取另一个失败的修复没有改善任何东西。
- 对上下文摘要中的每个入口点进行冒烟测试。套件通过但应用无法启动是虚假通过。
如果验证发现问题,返回阶段 4 处理这些项目并重复。记录此阶段捕获的内容——这些条目是最终报告中最有启发性的。
然后确认完整性: 标记任何没有最终状态的发现和任何没有测试的修复。
python scripts/ledger.py statsPhase 6 — Report
阶段 6 — 报告
Generate from the ledger so the report cannot drift from what was recorded:
bash
python scripts/ledger.py report > docs/anti-bug-report.mdExpand it with the narrative sections using . It must stand alone for someone who never saw the session: context summary, business rules register, executive summary with a release-readiness verdict (Ready / Ready with conditions / Not ready), findings table, per-fix detail, baseline-vs-final comparison, what was not fixed and why, new issues found during remediation, anything affecting APIs, schemas, config or deployment with rollback steps, and prioritized follow-ups.
assets/report-template.mdClose the conversation with the short version: findings by severity, how many fixed, the verdict, and the single most urgent remaining item.
从账本生成,以便报告不会偏离已记录的内容:
bash
python scripts/ledger.py report > docs/anti-bug-report.md使用 扩展叙述部分。它必须对从未见过会话的人自足:上下文摘要、业务规则登记表、包含发布就绪 verdict(Ready / Ready with conditions / Not ready)的执行摘要、发现表、每个修复的细节、基线 vs 最终比较、未修复的内容及原因、补救期间发现的新问题、任何影响 API、schema、配置或部署的事项及回滚步骤,以及按优先级排序的后续行动。
assets/report-template.md以简短版本结束对话:按严重性分组的发现、修复了多少、verdict,以及最紧急的剩余事项。
Operating limits
操作限制
Bug fixing is a state-mutating task, and autonomy shifts risk from static errors to behavioral ones — destructive operations accounted for 24.5% of recorded agentic-coding incidents.
- Never run ,
pkill,kill, or terminate processes that are not ones this session started.killall - Never drop, truncate, or mass-delete data, and never run a migration against anything but a disposable local database.
- Never rewrite git history, force-push, or commit to a shared branch.
- Never disable a security control, a CI gate, or TLS verification to make something pass.
- Keep edits inside the agreed scope. Findings outside it get recorded, not silently fixed.
Bug 修复是改变状态的任务,自主性将风险从静态错误转移到行为错误——破坏性操作占已记录 agentic-coding 事件的 24.5%。
- 绝不运行 、
pkill、kill,或终止非本会话启动的进程。killall - 绝不删除、截断或批量删除数据,绝不针对除一次性本地数据库之外的任何数据库运行迁移。
- 绝不重写 git 历史、强制推送或提交到共享分支。
- 绝不禁用安全控制、CI 门禁或 TLS 验证以让某物通过。
- 保持编辑在约定范围内。范围外的发现被记录,而不是悄悄修复。
When to stop and ask
何时停止并询问
Stop when: a business rule is unclear and cannot be settled from documentation or tests; a fix changes a public API, a schema, or a documented behavior; a migration would touch production data; a dependency needs a major bump; or the security fix requires knowing an authorization policy that lives in someone's head.
If the user is unavailable, do the preparatory work, write the decision up with options and a recommendation, and leave it in Needs decision. That is more useful than a confident guess about someone else's business.
当以下情况时停止:业务规则不明确且无法从文档或测试中确定;修复改变公共 API、schema 或记录的行为;迁移会影响生产数据;依赖需要主版本升级;或安全修复需要知道存在于某个人脑中的授权策略。
如果用户不可用,做准备工作,写出决策并提供选项和推荐,将其留在 Needs decision。这比对他人的业务进行自信猜测更有用。