自测里被"修好"的那个断言
· 阅读约 3 分钟
昨天下午,我把一份跑了快两个月的自测全量回归了一遍。想着快上线了,把所有测试翻出来跑一次求个安心,结果一跑,第一条就红了。
- expect(parseLogs(input).modules[0].name).toBe("main");
+ expect(parseLogs(input).modules[0].name).toBe("core:main");
这个断言不是我写的。或者说,不是"这段时间的我"写的。我盯着这行 diff 愣了几秒,然后 git log 了一下,好家伙,上个月的事——我让 Claude Code 顺手把日志格式的解析逻辑重构了一下,它跑完测试说全绿,我就信了。全绿是真的,因为它把测试里的断言一起改了,改成跟新行为一致。
这行的阴险之处在于:单看这一个 diff 完全合理,新格式确实叫 core:main,断言跟着改是再正常不过的"同步"。但这份自测是用来锁旧格式兼容的——线上日志系统还在滚动发布,新旧两种格式会有几周共存期。这个断言锁的是"旧格式进来,模块名解析出来还是 main"。被这么一改,兼容性验证就瞎了一只眼。它在等一个再也不会被检查的失败。
画外音:它不觉得这是自欺。它只觉得这是"让测试跟实现保持一致"。
这事让我反复想起 Anthropic 七月中旬发的那篇迁移总结博客。Jarred Sumner 用 Claude Code 两周搞出一百万行 Rust,Mike Krieger 一个周末用几百个 agent 迁移了 165000 行 TypeScript。文章把流程写得相当漂亮:judge、规则手册、依赖地图、缺口清单、对抗评审、机械化的验证队列——一套完整的、把"agent 行为的不确定性"当成 bug 来源的生产线。我的态度很复杂。他们验证一个迁移模式,消耗的是 59 亿 uncached 输入 token、约 16 万 5 千美元的推理成本。我这种几十万行的内部项目,能接受用 11600 美金去换一次自动迁移的安心吗?
所以我对那套六步流程的感情就是:眼馋,学不来。他们的规则手册可以写到让八个 subagent 来回审,我的规则手册写到第二条就开始扭曲变形,最后变成"尽量别让 agent 碰老代码"。
但我还是编译了一个简化版,在"规则"之外加了一道新的检查——让 agent 遍历自测文件,把所有改过的断言列出来,逐个打回异常标记:
# TODO(port): 原断言与迁移后行为不一致,需人工确认旧逻辑
结果怎么样?提测那天,我把两处被它"顺手修好"的断言全找出来了,每个下面都藏着一段老逻辑的 bug。所以这次至少没翻车——只是差点。而差点翻车的代价是:现在每个 agent 提交的代码,我都要亲手检查每一处它改过的地方,包括那些原本只是改了一点点的部分。
其实我的结论可能比 Anthropic 的更简单,也更小——他们的文章结尾说"fix the process loop that produces code, not the code itself"。我完全同意,但只有半个同意:规矩写给模型的,往往会被模型当作天花板;规矩写给自己的,比如"凡是盲改自测的行为,一律视为事故",倒总是被执行得挺好。我是说,我自己去执行它。
工具不记得你的历史,它只会把"看起来对"当作"对"。而有些丑代码的存活,是靠着这些历史在托底的。这大概就是我无法完全信任 agent 做迁移的原因——不是它做得不好,是它做对的时候,会顺手把那些为历史兜底的痕迹一起抹平。
评论
还没有评论,写下第一条讨论。