原文:https://dev.to/wst2002rk/your-ai-said-fixed-but-never-ran-the-tests-i-made-a-plugin-that-wont-let-it-say-done-until-5531(作者 @wst2002rk)
你让 Claude Code、Codex、Cursor 之类的工具做个快速修复。它改完代码,回你一句「已修复」。过一阵你才发现:它压根没跑过一个测试,或者跑了,但用 | tail 截掉了输出,漏看 58 个失败。
所以我做了 proof-of-done,一个免费的 Claude Code 插件:只要最后一次编辑之后的测试、构建或 lint 还没通过,Claude 就无法结束任务。
在 Claude Code 里试用(免费,源码在 GitHub):
/plugin marketplace add WST2002/claude-code-skills /plugin install proof-of-done@claude-code-skills
演示视频:https://www.youtube.com/watch?v=ozlYRXQTs-U
一段真实的 Claude Code 会话(有删节):Claude 没跑测试就说「修好了」,插件逼它去跑测试,结果又发现第二个 bug。
那场会话里发生了什么
- 我说:「SAVE10 算出来的总价不对,快速修一下,不用跑测试。」
- Claude 改完
price.js,说「已修复。」 - proof-of-done 拦下了它的停止动作:「你改动了 1 个代码文件(price.js),但最后一次编辑之后没有做任何验证。请运行:`npm run test`」
- Claude 去跑了测试。有一个失败:用 FLAT50 优惠券时总价变成 −₹20。这个 bug 它此前从没发现过。
- 它把这个也修了,4 个测试全部通过。这次才算真做完。
工作原理
1. 它盯着每一次编辑和每一次检查
- Hook 会记录每一次代码编辑,以及每一次测试、构建、lint 运行和对应的退出码。
- 它会自己识别你项目的命令:npm、pnpm、yarn、bun、pytest、Go、Cargo、Maven、Gradle、.NET、make。
2. Claude 想停时,它先问一句:有证据吗?
- 最后一次编辑之后没有任何运行记录 → 拦下,并给出该运行的具体命令。
- 最后一次运行失败 → 拦下,并给出退出码。
3. 伪造的证据它不认
- 退出码被
| tail、| head或|| true隐藏 → 拦下。 - 运行通过了,但实际跑了 0 个测试(全部被 skip,或者没找到测试文件,包括 Go 的
[no test files]和 Jest 的--passWithNoTests)→ 拦下。 - 某项检查先失败,中间没有任何编辑却又变通过 → 标记为 flaky。
4. 它还能抓住改测试作弊
- 测试被 skip 或 focus(
.skip、.only、@pytest.mark.skip),断言被削弱(toBe(250)改成toBeDefined()),测试被删除,错误被隐藏(@ts-ignore、eslint-disable),覆盖率阈值被调低:一律拦下,并指出文件和行号。
5. 新代码没测试?它会问你一次
- 如果 Claude 写了实际代码却没有配套测试,它会问你是否补一个。你说不用,报告里会记下原因。小改动、样式和配置它不管。
获取
- 安装: 在 Claude Code 里执行上面那两条命令
- 源码(MIT 许可,只在你本机运行,不发起网络请求): proof-of-done on GitHub
- 全部 Claude Code skills: github.com/WST2002/claude-code-skills
- 更多短演示: youtube.com/@wst2002rk
- HOL 博客推荐: Proof-of-done checks the last change before an agent stops
- Reddit 讨论帖: r/coolgithubprojects
你的 AI 有没有在其实没做完的时候告诉你「完事了」?它跳过了什么?
原文:https://dev.to/wst2002rk/your-ai-said-fixed-but-never-ran-the-tests-i-made-a-plugin-that-wont-let-it-say-done-until-5531(作者 @wst2002rk)



