AI 改错字段,为什么测试与 CI 全绿
Claude Code 在修改姓名长度限制时,误改了相邻的邮箱规则,但测试、验证钩子与 CI 均通过。案例揭示了验证盲区:检查确实执行,并不代表改动符合需求。
AI 深度解读
Claude Code 提交了一次「把姓名长度限制改为 250 字符」的修改,测试通过,验证钩子盖章,CI 全绿。可姓名限制没动,邮箱限制却被改了。
这篇文章讨论的不是如何再加一道测试,而是如何补上一个常被忽略的问题:提交说明和实际改动,是否指向同一件事?作者给出的方案很克制,用确定性规则捕捉「改到了相邻行」这类错误,同时明确承认,规则通过也不代表修改正确。
为什么检查全过,代码还是改错了
作者维护的 laravel-ai-verify,会要求编程代理运行改动所需的检查,再宣布完成。出问题的是用于测试 GitHub Action 的普通 Laravel 联系表单。
下面两条校验规则,解释了错误为什么容易发生:
'name' => ['required', 'string', 'max:200'],
'email' => ['required', 'email', 'max:255'],
注意 name 这一行原本是 max:200,只有 email 那行包含 max:255。
任务要求把姓名上限改成 250,Claude Code 却执行了模式替换,把 max:255 换成 max:250。替换成功了,目标字段却错了。
表单测试没有锁定邮箱长度边界,因此没有发现问题。ai:verify 生成验证回执,git hook 又给提交添加了 AI-Verify: pass ... checks=4 标记。回执没有造假:列出的检查确实运行过,检查的也是最终提交的那份代码树。
直到一天后,CodeRabbit 才在审查中通过一条 diff 之外的评论指出错误。
这里有两个独立问题:检查是否在这份代码上通过,以及这份代码是否实现了提交说明。原来的流水线只回答了前一个。提交标题还可能影响人工判断:标题写着姓名,审查者容易带着「改的是姓名」的预期读代码。
检查记录可信,不等于提交内容符合任务。
怎样在提交前发现「改到了隔壁」
从 0.5.0 起,laravel-ai-verify 的 git hook 和 CI 检查都会对照每个提交的标题与 diff。它没有尝试理解完整需求,只识别两种具体信号。
第一种是位置错配:标题中的某个词能对应到已修改代码文件里的一行,那一行没有变化,但前后 12 行以内,一条结构相似的代码变了。姓名规则没动、邮箱规则被改,正好符合这个形状。
第二种是数字错配:标题出现了某个数字,所有新增行却都没有它。例如标题写 200,diff 实际写入 250。
代理通常用 git commit -m 提交,因此钩子能在提交创建前把警告写入 stderr,让代理立即选择修正代码或说明。提示也会提到 git commit --amend。到了 CI,同样的问题会变成修改行上的警告注解。
规则刻意缩小了覆盖范围:忽略散文文本、JSON、YAML、HTML、测试文件、合并提交、回滚提交,以及涉及超过 25 个文件的提交。
这不是通用的意图校验。标题只写「fix rounding」,即使舍入方向改反了,也能通过;标题太含糊、没有点名具体对象,同样可能通过。它擅长处理的是校验规则、配置数组、路由文件中,那些挨在一起、长得很像的代码行。
发布前,作者在自有的五个 PHP 仓库里检查了 937 个提交,标出了 23 个,约占 2.5%,其中包括开头那次错误。因此默认行为是 warn,而不是 fail。作者的考虑很实际:启发式规则一旦频繁阻塞提交,就容易被关掉。
我的判断
这个方案最有价值的地方,是把「验证过了」拆成了可以核对的证据。
验证回执回答哪些检查在什么代码树上运行;标题检查回答说明与 diff 有没有明显矛盾;审查继续判断修改是否正确。每一层的责任更清楚了。
但 937 个提交里标出 23 个,只能说明触发比例,不能说明准确率。原文没有交代其中多少是真问题,也没有统计漏掉多少错误,更没有与人工审查或 review bot 做对照。作者认为这个比例适合默认开启,仍是基于他们团队样本的经验判断。
它也依赖提交标题足够具体。标题不写字段名、不写数字,规则能利用的线索就少;大提交和被排除的文件类型则不在覆盖范围内。
与补充行为测试相比,这类检查可以发现一部分尚未被断言覆盖的错位修改;但如果要保证姓名上限变成 250、邮箱仍保持 255,直接测试这两个边界会更有说服力。与 CodeRabbit 这样的审查工具相比,它的判断条件更明确,也能更早反馈,但覆盖的问题更窄。
它适合补一道低成本警告,不能替代行为测试和代码审查。
能拿来做什么
- 让 AI 修改表单校验时,把目标字段、原值和目标值写清楚,并要求它检查相邻字段是否被误改。这个习惯也适用于 Node 项目里成排的校验配置。
- 修改长度、额度等边界时,同时验证目标字段的新边界和相邻字段的原边界。本例需要确认姓名上限为 250,邮箱上限仍为 255。
- 审查 AI 提交时,先核对标题点名的字段是否真的出现在改动中,再看测试结果,避免标题预先替你完成判断。
- 如果团队准备引入类似规则,先以警告方式运行,记录真实问题与误报,再决定是否升级为阻断;不要把作者样本里的 2.5% 当作自己的预期准确率。