门禁三段式:入场、过程、封存
原则之后,是机制
《用质量门禁约束 AI 协作开发》说过一句话:判断"这次改动是否合格"不依赖某个模型说合格,而依赖一组每次都一样、可以被人复现的检查。这篇接着往下讲——那组检查具体是怎么判断的。
三道门按顺序排列:入场检查提交前的暂存区,过程检查是一条固定顺序的验证链,封存检查核对验证链跑完之后工作区有没有被意外弄脏。三道门各自只做一件事,互不代管。
入场:白名单与硬禁止路径分开判断
入场检查读取当前任务书允许改动的文件清单,再看暂存区里实际有哪些文件,按三条规则依次判断:暂存区不能是空的;暂存的文件不能落在少数几个硬性禁止的路径下;暂存的文件必须全部出现在任务书的白名单里,一个不在就整体拒绝。
这里的关键设计是把"硬禁止路径"和"任务书白名单"分成两层判断,且顺序固定为先查硬禁止、再查白名单。硬禁止的路径写死在检查脚本里,不依赖任务书配置——这样即使某一轮任务书写错了、或者被人不小心改宽了白名单,那几条路径依然拦得住,不会因为一份 JSON 配置的失误就被绕过。任务书白名单则每一轮都不同,随当前允许改动的范围变化。两层职责不同:一层管"永远不能碰",一层管"这一轮能碰什么"。
过程:一条链,第一处失败就停
入场通过之后,进入过程检查——一条按任务书里固定顺序排列的检查链:内容校验、类型检查、单元测试、静态检查、构建。链条按顺序逐个执行,每一步都会记录下命令、状态、耗时和输出尾部;只要有一步失败,整条链立即停止,不会带着一个已知失败的步骤继续跑后面的步骤,也不会为了让报告"看起来完整"而把已经失败的链条跑到底。
有一种特殊状态介于"通过"和"失败"之间:某一步因为环境原因主动退出(比如资源不足、进程已被锁定)而不是逻辑失败退出。这种情况链条同样停止,但标记为「结论不明确」而不是「失败」——区分"这一步证明改动有问题"和"这一步没能给出判断",避免把环境噪音误判成代码问题,也避免把环境噪音误判成通过。
封存:检查链跑完之后,工作区该长什么样
过程检查全部通过后,最后一步核对工作区状态:除了任务书预期改动的文件,不应该再有别的追踪文件被检查链本身弄脏——理论上一条纯粹的校验/构建流程不应该产生任何未预期的文件改动,如果有,说明某个环节有副作用没被识别。
这里有一个例外,专门给内容清单文件用:清单文件里有一个时间戳字段,每次重新生成都会变,这是预期行为而不是异常。封存检查的处理方式是把清单文件和上一次提交的版本做结构比较——先各自去掉时间戳字段,再逐字段比较剩下的内容。如果只有时间戳变了,就把这一个文件恢复到提交前的状态,当作正常;如果时间戳之外还有别的字段变了(比如条目内容本身),则视为异常,因为这意味着构建流程本身悄悄改动了内容,而不只是刷新了一个时间戳。除了这一个例外,任何其他被弄脏的追踪文件都会让封存检查判定为异常,需要人工介入排查,而不是自动忽略或自动清理。
三道门为什么要分开,而不是合成一道
如果把入场、过程、封存合并成一次性的"全部检查",一旦中间出问题,很难说清楚到底是范围出了问题、是代码本身有缺陷、还是检查过程本身产生了副作用。分成三道各管一段之后,每一道门给出的失败信号本身就带着定位信息:入场失败说明这一轮想改的范围不对,过程失败说明改动内容本身有问题,封存失败说明检查流程本身不干净。信号越窄,排查越快,也越不需要靠人去猜"这次到底是哪里错了"。