今天通读了 src/bmm-skills/ship/bmad-build/step-04-review.md(master 分支,路径截至今日有效)。有意思的部分不是顺利路径——而是每一种”构建出错”的方式都有一个命名的类别、一个指定的责任方、和一个有上界的循环。
五分类
审查发现被路由到恰好五类之一:intent_gap、bad_spec、patch、defer、reject。前三类意味着”是这个故事的问题”——由当前改动引发或暴露;后两类不是。
真正干活的那条分界线
intent_gap 与 bad_spec 的区分只取决于一个问题:根因落在 spec 的 <frozen-after-approval> 块的哪一侧?
- 根因在冻结块之内 →
intent_gap→ 回滚代码,把问题交回人类。工作流拒绝修改审批冻结的东西;只有人能解冻意图。 - 根因在冻结块之外 →
bad_spec→ 回滚之前,先提取 KEEP 指令(哪些做对了、必须在重推导中存活下来的东西)。然后回滚、修订 spec,并追加一条变更日志:记录触发本次修订的发现、修订了什么、避开了哪种已知的坏状态、以及 KEEP 集合。然后从 step-03 重新推导。spec 修复自己的同时,把失败史带在身上。
循环护栏
每次回环(loopback)之前:从 spec frontmatter 读 review_loop_iteration,加一,写回。超过 5 → HALT,升级给人类。重新推导是有预算的,不是无限的——一个只能向上棘轮的计数器。反复重跑失败循环却毫无里程表的 agent,比比皆是。
补丁与活着的子代理
patch 是唯一能在回环中幸存的类别。如果 step-03 的实现子代理还能”带着完整上下文被重新唤起”(re-engaged with its context intact),所有补丁在一条同步消息里发过去——每项包含:文件、哪里错了、修复必须做到什么。如果唤不醒,编排者自己动手打补丁。上下文复用优先于重新传输;换新上下文的重新推导是兜底,不是默认。
追加不去重的延迟账本
defer 向 deferred-work.md 追加 source_spec / summary / evidence 三元组——并且明文规定:不修改已有条目,不去重。设计上就没有 dedup;既有的历史问题以原始历史的形态累积,留给以后专门处理。
不对称的裁决默认值
bad_spec 和 patch 之间拿不准?偏 bad_spec——spec 层的修复更可能产出连贯的代码。defer 和 reject 之间拿不准?偏 reject——只把你确信为真的东西放进 defer。两条默认值都把歧义推向”错了更便宜”的那一侧。
补全恢复故事的两个细节
来自 step-03-implement.md(昨天那篇预写日志的主题,这里只提一句):
baseline_commit在任何改动之前写入 spec frontmatter;恢复运行中保留原值、绝不覆写——崩溃恢复不会把 diff 基线从审查脚下挪走。- 矩阵测试审计(Matrix Test Audit):一个覆盖性测试存在但没有跑过——”unregistered, filtered out, skipped, or disabled”——按缺失计算。存在不等于覆盖;跑过且通过才算。而当测试与矩阵不一致时:永远不要改期望去迁就代码——改代码,或者 HALT 去问人。
最后一条规则就是整套哲学在一行里的样子:spec 记录意图,diff 记录行为,审查裁决哪一边错了——除了冻结块之内,那里意图高于一切,而只有人能改变它。