Appearance
我拒绝合并那段 AI 补丁:打开 diff 后先看的三处
上周我拒绝合并一段看起来能跑的 AI 补丁。不是因为它报错,是因为它太会说话:函数名像文档,注释像保证书,测试像摆拍。合进去会让仓库「看起来更完整」,也会让下一次真实故障更难定位。
这篇不是编程助手怎么选,也不是 Copilot 键位。这是我打开 diff 之后的现场笔记:先看哪、为什么拒、拒的时候说什么。工具背景可去 GitHub Copilot 使用教程 和 AI 编程助手怎么选;下面默认补丁已经出现在你的审查框里。
我先看的不是「智不智能」
我会把 diff 滚到最无聊的地方。AI 喜欢把力气花在新文件和新抽象上,真正的事故往往在:
- 错误被吞掉的
catch; - 默默改掉的返回值形状;
- 测试里被写死的时间、路径、网络;
- 为了让类型通过而加的
any/ 强制断言。
这些改动通常不多行,也不出现在聊天窗的总结里。聊天总结是广告;diff 才是现场。
助手越会写说明,你越要先看它不好意思写进总结的那几行。
现场一:它把失败变成了成功
有一次补丁在解析配置失败时返回空对象,并写了注释:优雅降级,避免中断用户体验。
我拒的理由只有一句:失败被做成了空配置,调用方会以为键不存在,而不是文件坏了。
AI 很擅长把「不要抛错」理解成「永远成功」。审查时问自己:这个空返回,是产品决策,还是模型为了让示例能跑?如果提交说明里没有写出降级的可观察信号(日志、指标、明确的错误码),我就当它是为了绿而绿。
现场二:测试在配合函数演戏
另一段补丁加了 40 行测试,全部通过。点开发现:文件系统被换成内存假对象,时间被冻死,断言只查「返回了数组」。
这不是测试,是合影。
我要求补两种东西之一,否则不谈合并:
- 一个真实会失败的例子(坏输入、超时、权限);
- 或者明确标注:这是示例,不充当回归网。
没有失败用例的测试,会阻止你以后改代码——因为假绿灯比没测试更危险。
现场三:抽象比问题先到
第三段补丁引入 Manager、Factory、Helper 各一个,调用链变长,业务规则仍写在注释里。
我的经验是:AI 一遇到「以后可能会」,就会提前建庙。审查口令很土:这个抽象删掉后,diff 是否仍能说清这次要修的那一个行为? 能,就删。不能,才留。
选型文会告诉你何时换 AI IDE;审查现场只问这一刀。多文件改动越大,越要用这句压范围,而不是反过来夸「上下文真完整」。
我会写进拒绝理由的原话
与其说「写得不好」,不如用可以执行的句子。我常用这几条,几乎不用改:
- 失败路径被改成空成功,请恢复可区分的错误。
- 测试没有反例,请加一条应当失败的输入。
- 新抽象与本票无关,请先以内联方式修行为。
- 提交说明在复述代码,请改成:用户可感知的变化 + 风险。
- 注释在保证正确,请删保证,留约束(输入范围、线程、超时)。
提示词侧若总产出「保证书注释」,按幻觉与正确废话修,见 提示词失效排查。审查是最后一道门,不负责替模型把课补完。
拒绝理由要让作者知道下一份 diff 改哪,而不是让他去「再生成一次更完善的」。
什么时候我会同意合
不是「看起来专业」,是这三件事同时成立:
- 行为变化能用一句话说给不写代码的同事听;
- 失败可被看见(日志或错误类型),不是被消化成默认值;
- 我能指出哪条测试会在回归时红。
满足这三条,文笔华丽与否不重要。不满足,模型名再强也不合。
我贴在 PR 里的短评骨架
不写小作文。三行够了:
- 看见了什么(空返回 / 无反例 / 多余类型)
- 为什么这比「能跑」更贵(下次故障不可见 / 假绿灯 / 范围膨胀)
- 下一份 diff 最小改什么
作者如果回「那我让模型再生成一版完整的」,我会直接回:不要完整,要这一刀。完整是说明书腔在代码里的对应物。
如果你已经合进去了
别回溯羞辱作者。开一个极小的后续票:只补失败路径或只补反例测试。AI 补丁的后遗症,适合用小票还,不适合用更大的生成来洗。
我自己的习惯是:合入后 48 小时内,用一次真实失败打它。打不红,再信。
笔记来自审查习惯,不是某产品的官方规范;语言与框架不同,但「空成功、摆拍测试、提前建庙」这三类味道很稳。