实践手册。
三类清单、三个模板,一份失败模式库——每一条都能追溯到这里真实发生过的事。
叙事正文以四条纪律收尾。这里是它们的可工作版本:发布前要跑的清单、把一次判断从对话带进仓库的三个载体,以及一份写明出处的失败模式库。这里没有空泛建议——凡是无法追溯到本生态某次具体事故的规则,都没有被收进来。机制层面的原理见《工程机制》;本册只装这个案例自己教出来的东西。
四条纪律,展开
每一条都是习惯,不是工具。每一条都对应一种它要防住的失败。
一 · 定义先于实现
验收条件、非目标与边界写在第一行代码之前,意图用「去掉 AI 依然成立」的业务语言表达。防住的是:来来回回。方向未定的代价,最坏时是每提交 17.1 轮介入,上周 MRRC 是每提交 47.07 M token。
二 · 事故必须变成规则
把 bug 修好只是链条的第一环,不是最后一环。链条是:现场事故 → 设计裁决 → 机器可读约束 → 写前拦截。防住的是:同一类错误换一个症状再回来。本生态的两条闭环分别跑了 13 天和 7 天。
三 · 盯着不确定性花钱
token 峰值是方向雷达:花费在哪里尖起来,方向就在哪里没定。配合快照习惯——每个重要数字都要两个来源和一个截止时刻。防住的是:把钱花在错的问题上,以及引用一个已经在脚下变了的数字。
四 · 两本账分开记
产品成熟度与过程证据是两本独立的账。测试全过永远关不掉一个开放的安全问题,漂亮的注册表也永远不提升产品声明。防住的是:一个工程团队能获得的最舒服的那种自欺。
不成习惯形状的纪律,会在截止日期面前第一个消失。之所以选这四条,是因为每条都对应一个人每周要做几十次的决定:我先把这件事写下来了吗、我把闭环合上了吗、我去看钱花在哪了吗、我把两本账分开了吗。如果只能采纳一条,采纳第一条——验收写下来之后,另外三条都会变便宜。
三份清单,三个时刻
接受需求之前、编辑落盘之前、宣布发布之前。
接受一个需求之前
- 验收条件能不能写成机器可判定的形式?不能,就说明这个需求还没准备好被委托。
- 我明确不做的是什么?现在写下的非目标,是你这辈子能预防的最便宜的返工。
- 把「AI」这个词删掉,这句话还成立吗?不成立,那它就是一个披着业务外衣的技术 demo。
- 结果由哪个仓库负责,这个声明将建立在什么证据上——自动化测试、台架,还是现场?
编辑落盘之前
- 这次改动碰到已注册约束覆盖的范围了吗?52 条里有两批规则的存在,正是因为一个看起来合理的编辑其实是错的:
cat-no-dn与部署备份规则。 - 如果碰到硬件,此刻电台的发射状态是已知的,还是假设的?
- 厂商目录还是只读的吗?买来的解码器代码不属于我们改,适配要放在自己的补丁层里。
- 如果这是一次修复,它将成为哪条约束?没有后续规则的修复,是一次还会再需要的修复。
宣布发布之前
- 这次要声明的是产品阶梯上的哪一级——自动化测试、台架验证,还是现场验证?把这一级说出口。
- 有没有一个开放的已知缺陷与这个声明矛盾?FT710Mobile 那个未解决的 P0 PTT 问题,正是这样被公开保留着的。
- 两本账互相印证了吗?它们本来就不该互相印证。
- 如果发布说明里出现了数字,它带普查日期和测量窗口了吗?
发布前清单里关于「产品阶梯」的那一条,正是 EFHW 调谐器声明状态停在设计目标、而不是「已发布」的原因——板子还不存在。编辑前清单里关于约束的那一条,让拦截变成可复现的、带退出码的事实,而不是一次代码评审里的意见。
三个值得照抄的载体
周一就可以原样复制。它们长成这个样子,是因为更弱的版本失败过。
模板一 · 验收条件
需求 <一行需求,业务语言,不含「AI」> 变更 <对用户而言什么变了> 非目标 <明确不做什么> 判定 <机器如何判断通过 / 不通过> 阶梯 design-target | simulation | automated-test | bench | field | released 未关闭 <本次不关闭的已知问题,没有则写 none>
本生态测到的每一次返工尖峰,都落在范围还在移动的那一周。非目标这一行是固定范围最便宜的仪器:它把一条边界从「有人记得」变成「agent 读得到」。
模板二 · 约束注册表条目
id 短标识,例如 cat-no-dn severity block | warn | info scope 作用范围,文件 glob pattern 在编辑里匹配什么 message 告诉 agent 什么,用祈使句 sdd_ref 文档 + 章节 + 裁决编号,例如 AD-014 origin 出处:事故、日期与提交号
origin 是把一条风格规则变成一条论据的字段。52 条已注册约束中每一条都能追溯到某次决策或某次事故;填不出 origin 的规则只是意见,而下一位不同意的人会把它删掉。sdd_ref 则让拦截消息在触发的那一刻能解释自己。
模板三 · 从事故到约束
1 复现 写下失败的探针,记录退出码 2 裁决 把设计裁决写进 SDD,带裁决编号 3 编码 加注册表条目:severity、scope、pattern、sdd_ref、origin 4 验证 重跑探针;它现在必须被拦截,并给出非零退出码 5 记录 把日期与提交号写进 origin 字段
第 4 步是团队最常跳过的一步,而跳过它,正是一条被记录下来的教训变成一条没人遵守的教训的方式。规则写完探针仍然通过,这条规则就是装饰。契约时代相对文档时代的全部价值,就在于知识不再需要被记得,而是在该起作用的那一刻被执行。
这里的每条规则都花了代价
现像 → 根因 → 代价 → 它变成了什么规则 → 怎么复现这个检查。
| 事故 | 根因 | 代价 | 转成的规则 | 复现 |
|---|---|---|---|---|
| FT-710 频率漂移 | DN; 是 VFO 步进命令而不是 DNR 查询,却每 2 秒轮询一次 | 实机频率每次调用漂移约 20 Hz | cat-no-dn(裁决 AD-014) | 对探针文件跑 2498ec2 引入的 guardian 检查;拦截以非零码退出 |
| 部署备份打满磁盘 | 整站拷贝,把服务器自己管理的二进制目录也拷了进去 | 服务器 /var/tmp 到 100% | 备份按站瘦身 + 轮转 | 把包内容与排除清单对一遍 |
| portal 备份从未生效 | 远端 heredoc 未加引号,本地 shell 先展开了变量 | 每次都打印一个并不存在的备份路径 | 远端 heredoc 必须引号化(067f565) | 用 git log -S 查 heredoc 标记 |
| 普查错了 16 亿 | 某个工具的缓存输入是输入的子集;另一个工具的总量已含全部 | 一个被修正了两次的已发表数字 | 逐工具的字段语义表 | 两种求法各算一遍,与独立存储对帐 |
| 某个 harness 被发表为「未记录」 | 只查了一张表,而合计在另一张表里 | 少算 485,213,348 | 不列出每一张表,不得下「未记录」结论 | 遍历 schema,对每个 token 列求和 |
| 账本倒退且漂移 | 某个工具的日志保留策略;测量会话把自己算进去了 | 同一个脚本相隔 12 分钟给出不同合计 | 快照纪律:每个数字带截止时刻与明写窗口 | 连跑两次普查并对比合计 |
前四行在几天内就闭环了。后两行是在写本系列的过程中才发现的,所以它们是最新的规则、也是被验证得最少的规则。一份只装着陈年旧疾、且都已舒服解决的失败库是一座博物馆;真正有价值的条目,是你这个月新加进去的那些。