13 — 可核对的宣称:把每个对外数字接上一条命令
适用工具:所有写 README / 文档 / 看板的仓库 · 验证于 2026-09
09 章讲「让 agent 验得动这个仓库」,11 章讲「让证据进 PR」。本章补最后一环:仓库对外说出去的每个数字,也要能自己验。README 里的「283 家餐馆」「6,395 条记录」「167 个版本」「召回率 100%」——它们是别人引用你的依据,却常常是全仓库唯一没有任何东西在检查的部分。
13.1 一个数字没有命令,就不是证据
场景:README 写着「tRPC 950 文件,变异测试 28/28」。三个月后文件数变成 957,测试批次换了,README 没人动——它已经错了,而所有 CI 都是绿的。因为 CI 检查的是代码,不是你对外说过的数字。
做法:给每条宣称配一条能重新算出它的命令,并把命令与断言写进仓库里的 claims.json:
{
"id": "trpc-mutation-impact-recall",
"claim": "在 tRPC 上注入的 28 个变异全部被影响集覆盖",
"value": "28/28",
"metric": "eval/ 里 recall_hit 为真的条目数",
"method": "注入变异 → 跑全量测试 → 对比预测集",
"repro": "python3 eval/mutation_check.py", // 人读的复现方式
"evidence": "eval/mutation-2026-08-28-trpc-n30.json",
"as_of": "2026-09-13", // 这个值什么时候为真
"check": { // 机器跑的那一份
"cmd": "python3 -c \"import json;K=[e for e in json.load(open('eval/mutation-2026-08-28-trpc-n30.json')) if 'precision' in e];print('%d/%d'%(sum(1 for e in e if e.get('recall_hit')),len(K)))\"",
"expect": { "equals": "28/28" }
}
}
依据:verify-claims 是这一模式的实现(零依赖,Python 3.9+),退出码 0 全过 / 1 某个数字不再复现 / 2 形状非法——形状非法时拒绝运行,而不是给一个绿勾。--strict 会把「没有机器检查的宣称」也算失败,便于逐步收紧。
边界:只解决「可计算但没人算」的那一半。厂商数字、人工评分、别人的页面,仍然要人读(见 13.3)。
反模式:把断言写成「输出非空」。那不是检查,是把 exit 0 换个写法。
13.2 六种失效模式,都不是”手滑”
一次对 16 个仓库、553 条宣称的复核里约 100 条不成立(18%),集中在六类——每一类都有对应的检查写法(完整案例见 verify-claims/docs/case-studies.md):
| 失效模式 | 真实例子 | 用哪种检查 |
|---|---|---|
| 手写数字,数据走了它没走 | 卡片里写死的 60k★(当天是 74,442★),而这张卡片每天被重新生成,日更永远纠正不了它 |
equals:重数一遍 |
| 归因给了错的上游 | 某 agent 的「32 个工具 / 13 个 LSP 操作」,上游 README 是 31 / 14 | equals + 数字旁写上上游链接 |
| 文档里的功能不存在 | 「每天定时同步」的 cron 根本不存在;文档让你跑 ./search-bench.sh,而仓库里只有 edit-bench.sh |
cmd 就写 README 里那条指令 |
| 门禁不门禁 | --check 因为时间戳取自 date.today() 而每天都红;链接检查 --exclude-path 恰好排除了唯一有坏链的目录;task 集合检查只 warn 不 fail |
让门禁红一次:故意改坏一个数字,要求它失败 |
| 把估算写成实测 | README 的 ~20 s,实测 71 s;「命中率约 18%」的输入文件是 gitignored,无法复算 |
区分「实测 / 推导 / 估算」,实测进 check,其余进 check.manual |
| 两处自己打架 | 同一项目在两页写着 28K 与 237K 星;徽章写「Secondary TypeScript」,而页面自己生成的语言表把 JavaScript 排在前面 | 用生成替代手写;或一处的输出断言另一处 |
13.3 诚实地说「这个算不了」
做法:算不了的宣称不要删了事,也不要编一个命令——写 check.manual 加一句理由,让它每次都出现在报告里:
"check": { "manual": "25% / 75% / 57% / 20% 是人对评论质量的评分,没有任何命令能产出评审分" }
依据:verify-claims 把 manual 条目单独计数并逐条打印(6 machine-checked · 6 ok · 3 manual),所以「还差多少」是可见的;--strict 可以随时把它变成失败——这就是收紧的路径:先把数字接上命令,再决定哪些值得补。
边界:manual 不是免责声明。它是一条待办,写在每次 CI 的输出里。
反模式:为了让门禁变绿而把真实数字换成模糊措辞(「数百家」「约百个版本」)。那是把问题从「错」改成「空」。
13.4 落地顺序(约一小时)
- 挑对外可见的数字:README 首屏、徽章、看板、站点 meta、图表脚注里出现的那些。
- 每条写一条能重算它的命令(通常已有的脚本就够,例如
validate.py打印的那行计数)。 - 接进门禁:CI 里
uses: alloevil/verify-claims@v0.1.0,同时加每周定时——数据会在没人提交的日子里变;这次的 18% 里有一半是这样烂掉的。 - 加一步「故意改坏一个数字、要求这次运行失败」,证明门禁真的会红。
- 把 manual 清单当待办,定期清。
对应检查:verify-doctor 的 verify-command(本仓库里「一条命令能验完」的前置条件)· 跨仓库的那一半由姊妹工具 verify-claims 承担,本仓库不依赖它