实践手册。
三类清单、三个模板,一份失败模式库——每一条都来自这里真实发生过的事故。
叙事正文以四条纪律收尾,这一册是它们的落地版本:发布前要过的清单、把一次判断从对话固化进仓库的三个载体,以及一份条条都有出处的失败模式库。这里没有空泛建议——凡是追溯不到本生态某次具体事故的规则,一律不收。机制层面的原理见《工程机制》;本册只写这个案例自己蹚出来的东西。
四条纪律,展开
每一条都是习惯,不是工具;每一条都对应一种它要防住的失败。
一 · 定义先于实现
验收条件、非目标和边界,都要写在第一行代码之前;意图要用「去掉 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 频率漂移 | 误把 VFO 步进命令 DN; 当成 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 分钟给出不同合计 | 快照纪律:每个数字都要带截止时刻和写明的窗口 | 连跑两次普查并对比合计 |
前四行在几天内就闭环了。后两行是写本系列的过程中才发现的,所以它们是最新的规则,也是验证最少的规则。一座只装陈年旧疾、而且件件都已妥善解决的失败库,是博物馆;真正有价值的条目,是你这个月新添进去的那些。