是让它别写坏、别写漏、别把上个月刚对齐的账再写歪一次。
第一条路是大多数人实际在走的流程,第二条路是这套东西长出来的原因。两者的差别不在提示词写得多巧,在于第 0 步有没有那十一层。
所谓「AI 写代码写不好」,多数时候不是模型不行,是没人告诉它这个系统的边界在哪、红线在哪、怎么算做完。
全量扫描 1067 条标题,这里不是把它们平铺出来:标题清单在 04 区逐条列全,这一区按「拦什么事故」归成十一道防线,每道讲完同一条因果链——什么时候触发、它能干什么、它解决什么问题、怎么实现、最后解决了什么。卡片顶上那排出处是指针,点一下跳到 04 区对应章节并展开;反过来 04 区每一章也写清它归入哪道防线。措辞全部脱敏:所有具体名称、表名、接口、地址一律换成功能性描述,没有替任何文件编造过一条标题。
03 区是因果链,看着抽象。这一区把其中三条机制画出来:一张单据要在多少环节之间跳转、每一跳谁在监听;隔离为什么是两道、而且顺序不能反;动手之前怎么把「不知道」变成能对账的格子。图里不新增任何事实——每一句都能在 04 区的标题清单里找到对应条目,节点与数字取同一次真实交付的快照。
事件不是一句通知,是一份有名字的契约:谁发布、谁订阅、按什么顺序。左边那条链是一张单据的真实生命周期,每个节点下面写着接住它的那一方。
这一跳是假设,不是现状。但它对应的失效模式是真实写在清单里的:发了一条没人监听的事件,不会崩、不会报错、不会重试,只在日志留一行警告。所以「谁订阅谁」这张映射表不是文档装饰,它让漏挂订阅在评审时就暴露,而不是在上线后。
订阅回调里一次没被接住的异常,会让那条订阅任务永久死亡。之后每一次投递都发现「没有接收者」,于是静默跳过:进程健康、其余接口正常,只有那一个每次都等到超时才返回。这一条被单独提成一行红线,配了排查顺序——先翻日志找异常回溯,别先怀疑连接池和网络。
这一条是被一次审计逼出来的。三个开关你随便关,但请按这个顺序读:只关第二道,数据不会串、数据库也不吭声;把第一道一起关掉,才会看见别人的行。两道单独失效都看不见,合起来才致命——而项目当时恰好同时具备这两条。
状态—
第一道是唯一依据,第二道只是兜底,而且明文写着「不得作为省略第一道的理由」。规则里还有一条更硬的:禁止在注释里写「靠隔离层兜底」。这句话在本项目不是风格问题——它被当成了授权,后面长出一百三十余处不显式带条件的查询,而当时估计的数字是七处。
同一批节点,用两把尺子各量一遍。第一把把维度拉高:终点是需求原文逐字抄,禁改写;从终点倒推「要满足它,必须存在什么」,从起点正推「手上已经有什么能直接用」,中间交给脚本做双向差集——需求没有节点承接是缺口,节点没有需求指向是镀金,倒推卡住的那一格逼出一条未知。第二把把维度压下来:双向差集是「需求 ↔ 节点」的二部图,它结构性地看不见「节点 ↔ 节点」的同构重复;于是把同一批节点换一个轴再摆一次,按(层 × 模块角色)投影,够两个以上落进同一格、且入口签名相同,才提名一件通用件。节点一个不删、顺序不变——不是合并,是投影。下面是一次真实交付的快照,编号保留原样,名称已全部换成功能性描述。
左边是「手上已经有什么能直接用」,右边是逐字钉住的需求原文。丝从两头同时往外探,两头都接上的那一格才凝固成节点;倒推探到底也没接上的,不许像黏菌那样静默收回——停在原地、发虚、钉上编号,就是下面那五条未知。接上多少条不算成绩,剩几条没人认领才算。右下角那个空着的终点是 R4:一条丝都没指向它,因为它带着一句非空的豁免理由。
不是「全都知道」。是每一个不知道都有编号、有探明动作、有非空理由;缺口和镀金必须为 0——有节点不承接任何需求,就是多做的;有需求没有节点承接,就是漏做的。两条主动承担的风险(云端取证需授权、事件全量枚举未做)留在页面上,标着不阻塞,不折算成已完成。抹掉任意一个节点的「承接」,对账脚本立刻把它报成镀金:这条红线是活的。
因为轴一全绿。缺口 0、镀金 0、退出码 0,十八个节点各自都有需求承接——地图是干净的,代码库照样是重复的。二部图的差集只回答「这条需求有没有人做」,不回答「这几个人是不是各写了一遍同一件事」;而且每一步都做了正确决定的局部最简,横向一比仍是五份。所以换一根轴重摆一次:不删节点、不改顺序,只改分组键,重复自己显形。判据同样活的——把任意一格的投中数改成 1,脚本立刻报空转件;把某一件的检查栏清空,它从「已实现」掉回「候选」。
上面按「拦什么事故」横切,这一区按「它长在哪份文件里」纵切。真正承载「能好好写代码」这些细节的,就是两个文件名的东西:一份每次会话开头自动加载的路由索引,一份按需切片查询的开发手册。它们都不是私有魔法——文件名本身就是公开约定,任何项目明天就能建。点开每一章看它的真实骨架:标题逐条列全、照原样抄,只把可识别的名称换成功能性描述;带「正文」灰标的那几行不是原标题,是我对该节装了什么做的一句说明。每一章下面那行灰色小字是它归入的防线编号,来历和因果链写在 03 区,这一区不再重复一遍。
定位方式、红线、收尾清单。其余全部按需加载。三百行换两千行不进上下文——省的是每一轮对话的预算,不是省一次点击。
手册的目录不是给人翻的,是给机器指路的坐标。但行号一定会漂,所以规则写成「以重新查锚点的结果为准,不信表里写死的行号」。
速查表最右一列是已知陷阱,写的是具体事故形态,不是感想。没有这一列,一张表就只是一份清单, agent 抄完仍然会踩。
模型只做路由,
事实交给脚本与落盘。
一个事实
只允许有一个真源。
绿灯必须有
能力变成红灯。
写这十一层文档花掉的时间和 token,远小于它替你省下的那笔账:
约定一旦不落盘,模型就在后续每一次会话里逐渐失去理智——凭记忆瞎写、把库改炸、再花半天收拾残局。
事故只发生一次,
这种消耗是每天都在付。