Claude Code验证08:从感觉到证据
克劳德代码将验证从事后动作改为系统默认闭环,通过固定顺序(构建、类型检查、静态检查、测试)防止局部成功误判为整体完成。区分基础与扩展验证,配合规则、命令、钩子三层机制,使交付状态从感觉转化为流程结果。
Claude Code Harness 08:Verify:从感觉走向证据
Plan锁定了方向,TDD锁定了行为。但问题在于:局部行为被锁定,并不代表整个系统就能交付出去。

在实际项目中,Claude Code最常见的停止点问题,不是“不会做”,而是“停得太早”。局部测试通过,代码阅读起来没有明显问题,还能给出一个自洽的解释——然后,系统就会做出“任务大概收敛了”的判断。但工程世界不接受“大概”,只接受“已经验证过了”。
这一章要做的事情非常具体:将Verify从“最后想起来再跑一下”,转变为系统默认的闭环动作。
一、Plan和TDD之后,究竟还缺什么
举个例子:修正了一个接口层的bug。问题复现明确,编写了失败测试,做了最小修复,局部测试也通过了。整套流程看起来非常完整。
但如果此时直接收工,依然可能遗漏:typecheck未通过、某个lint规则被触发、其他测试因为这个改动开始失败、甚至该接口对应的前端调用链也被牵连。
三者的分工其实如下:
Plan = 定地图,TDD = 锁局部行为,Verify = 看系统是否真的到站
没有Verify这道关卡,Claude Code很容易卡在“局部逻辑看起来没问题,所以任务差不多完成了”这个位置。而工程事故,恰恰最喜欢藏在这个“差不多”的背后。
二、为什么Claude Code特别容易缺失Verify
这背后有三个结构性原因。
偏向完成叙事。 强推理模型天生擅长将当前已有的信息,组织成看起来完整的结论。一旦bug修复、测试至少通过一部分、代码阅读起来没问题,它就会快速形成“任务大概收敛了”的内部判断。这并非低级错误,而是生成系统的结构特征。
偏向推理而非检查。 它更擅长分析、解释和生成,而不是枯燥地运行一串命令、再逐个查看结果。因此,Verify必须做成系统层的机制,仅靠一句“记得验证”的提示几乎无法起效。
没有固定顺序时,验证会退化。 先运行了test觉得没问题,就没再运行typecheck;build通过,就没回头检查lint。问题不在于会不会验证,而在于没有固定顺序时,验证最终会变成“运行了哪个就算哪个”。
三、为Verify设定一个固定顺序
很多团队说“有验证”,但实际做的是“想起来就跑一下,看到哪里顺手跑哪里”。要让Verify稳定下来,必须为其设定一个固定顺序:
Targeted behavior locked(TDD阶段完成)↓ Build ↓ Typecheck ↓ Lint ↓ Tests ↓ Review / Security Review(按需)↓ Ready or Not Ready
顺序的意义在于:让“完成”从一种感觉,变成流程的结果。
这里有一个更深层的设计原则——将“做”和“判”分离开。生成者天然对自己的结果偏乐观,Claude很擅长将当前实现解释得非常合理,把局部的成功组织成“任务完成了”的叙事。更稳妥的方式,是让生成和评估在明确的阶段分开。
四、任务清晰度 × 验证清晰度
这里有一张判断Claude Code是否适合深入推进的四象限图:
验证清晰 低 高 任务清晰 +----------------------+ 低 | 高效跑偏 | 可探索 | 高 | 卡在人工验收 | 最适合Agent | +----------------------+
当任务清晰且验证清晰时,Claude Code最能发挥其价值。任务清晰但验证不清晰,吞吐量通常会卡在人工验收环节。验证清晰但任务不清晰,系统就有可能高效跑偏。两者都不清晰时,不应扩大agent的自主度。
五、Verify在整个工作流中的位置
Task → Plan → Confirm → TDD / Minimal Implementation → Targeted test passes ↓ Verify ├── Build ├── Typecheck ├── Lint ├── Tests ├── Review └── Security Review(when needed) ↓ Ready / Not Ready
Verify不是收尾动作,而是“完成状态”的裁判。没有它,Claude Code所谓的“完成”,不过是一种语言输出。
六、一个真实案例
上一章所锁定的结算逻辑测试通过了。如果此时没有Verify,Claude很可能会说“问题已经修复”。但开发者还关心:这次改动是否影响了payout ledger的其他路径?类型定义是否被连带破坏?通知逻辑是否正常?是否引入了新的lint错误?
TDD证明的是“这个行为现在对了”。而Verify证明的是“这个改动放回系统里还能站住”。局部胜利,是最容易被误判为“整体完成”的陷阱。
七、/verify命令模板
直接固定为.claude/commands/verify.md,内容如下:
# /verify
运行验证时遵守以下顺序:
1. Build
2. Typecheck
3. Lint
4. Tests
5. Review / Security checks(当相关时)
输出格式:
## 验证报告
- Build:
- Typecheck:
- Lint:
- Tests:
- Review:
- Security:
## 结果
- Ready for delivery / Not ready
## 剩余问题
- ...
规则:
- 验证完成前,不要说任务完成了。
- 任何步骤失败,立即停止并清晰报告。
- 不要把局部成功当作最终完成。
这个模板固定了三件事:顺序、输出结构、失败时的行为。一旦缺少这三样约束,Claude Code特别容易先运行最容易通过的步骤、只汇报好的部分、失败时还继续硬跑。
八、Verify分层:基础版和扩展版
并非每个任务都需要重型审查。
基础Verify 适用于小功能、局部bugfix、低风险重构,包含build / typecheck / lint / tests。
扩展Verify 适用于鉴权、权限、支付、数据删除、涉及secret或PII的变更,额外包含review和security review。
同样,局部验证和全局验证也应分层。开发过程中先做局部收敛(targeted test、受影响模块的typecheck、相关路径的lint),在交付节点做全局确认(全量build、全量test、完整review)。先局部、再全局,既不会一开始过重,也不会让交付边界越来越模糊。
九、如何让Verify真正成为默认路径
仅在CLAUDE.md中写一句“完成前请先验证”,远远不够。需要三层配合:
Rules里立底线。 未验证前不要宣称完成;不要用解释替代验证证据。
Commands里立入口。 /verify作为固定触发点。
Hooks里做拦截。 Stop时提醒当前会话还未verify;高风险变更前强提醒。
这一套组合下来,Verify才会从“好习惯”转变为系统行为。
十、本章交付
Verify清单:
- 当前任务的targeted behavior是否已经被锁定?
- Build是否通过?
- Typecheck是否通过?
- Lint是否通过?
- 相关tests是否通过?
- 本次改动是否需要code review?
- 本次改动是否需要security review?
- 是否还有未解释的失败或跳过项?
- 是否可以明确判断为Ready / Not Ready?
社区参考方案:everything-claude-code仓库提供了三个相关命令——/verify(基础四项)、/quality-gate(将验证提升为门禁)、/eval(承接Generator/Evaluator分离)。先明确自己的项目缺少的是基础Verify,还是更成熟的评估闭环,再决定如何借鉴。
最小落地动作:创建.claude/commands/verify.md,先写死基础四项,将review / security review作为第二层补充进去。
十一、小结
Plan锁定方向,TDD锁定行为,Verify锁定交付。至此,工作系统开始具备了“知道什么时候才算做完”的能力。
但一套系统只要还在靠人记得执行,就一定会退化。下一章进入Hooks:将高频、机械、容易遗忘的动作自动化起来。
