> 手写的自检清单永远是全绿的——它只包含你刚修过的东西
给工具链写自检时,检查项的覆盖面必须从被检查的东西推导出来,不能手写清单。
// TABLE_OF_CONTENTS
结论先行¶
给工具链写自检时,检查项的覆盖面必须从被检查的东西推导出来,不能手写清单。
手写清单有一个躲不掉的偏差:你想得起来的就是你刚改过的, 于是清单里装的正好是刚修好的那批,跑出来必然满分, 而没改的那批既不在清单里,也就永远不会变红。
一次实测,同一天同一套工具:
| 自检项写法 | 报告 | 真实情况 |
|---|---|---|
| 写死 7 个工具名 | 7/7 通过 | 另有 19 个文件 36 处是旧写法 |
| 扫全树枚举 | 当场报 36 处失败 | 同一时刻的同一批代码 |
假绿比没有检查更糟,因为它会让你停止找。
为什么¶
统一 --json 接口那轮改了 9 个工具,自检项照着改动写:
「这 7 个工具在 --json 不带值时必须把合法 JSON 打到 stdout」。
它一直是绿的,直到下一轮把它改成「扫 ~/Tools 与 ~/.claude/skills 下所有 .py,
任何一处 add_argument("--json" 不是 nargs="?" 就算失败」。
同一个毛病在另一处更严重:43 个技能里有 17 个声明了后端脚本却没有任何自检项。
自检有 40 项,看着覆盖得很密,但那 40 项是一条一条手写的,
覆盖的是做过工单的那些技能。改成「从每个 SKILL.md 里把它声明的后端路径抄出来,
逐个实跑」之后,覆盖数从 11 个技能跳到 36 条后端路径,
而且以后新加技能自动进入覆盖,不需要记得来补。
这一类和 最危险的工具故障是"静默少做"——技能在、后端不在 是同一个根: 故障不会报错,只会少做一层,报告照常是绿的。
怎么用¶
判断标准:这个检查项的覆盖面,是从被检查物推导的,还是我打字打出来的?
三种可枚举的推导源,按优先级:
- 从声明推导——工具/技能的定义文件里写了什么依赖,就检查什么。
grep -rhoE '(~|\$HOME)/(Tools|\.claude/skills)/[A-Za-z0-9._/-]+\.(py|sh)' */SKILL.md \ | sort -u | while read p; do timeout 30 python3 "$p" --help >/dev/null || echo "BROKEN $p"; done - 从代码树推导——接口一致性这种,直接扫全树 AST/正则,跳过 vendored 目录。
- 从产物推导——比如「每个
.md报告都必须能被json.load的兄弟命令解析」。
豁免必须写在被检查的源文件里,不能写在检查器里。
一个工具的 --json 是读入后端报告的参数而不是输出开关,它在自己的声明处写:
ap.add_argument( # --json: input(读入参数,不走全局输出约定,枚举检查按这行跳过)
"--json", required=True, help="后端的 JSON 报告,'-' 表示 stdin")
检查器只认这行注释。要是把豁免写进检查器的白名单, 白名单就会跟着改动走,又回到清单模式的假绿。
最后一条:自检项本身要在修复之前改成枚举式。 先改检查器,让它报出真实的失败数,再去修; 反过来做(先修再补检查)永远不知道分母是多少。
三个后来才踩到的坑(2026-09-07)¶
改成枚举之后又栽了三次,都是同一个道理的下一层:
一、枚举源本身也可能是清单。 「从每个 SKILL.md 里抄出声明的后端」听起来
够枚举了,但它只覆盖有人声明过的东西。一个工具当天被改坏、带着坏状态提交,
一直到手工排查才发现——它谁都没声明,所以谁都没在看它。把枚举源换成
「版本库跟踪的、带 __main__ 的 .py」之后覆盖才是全集,而且不依赖有人记得去声明。
判据升级:这个检查的范围,是从「谁登记过」推导的,还是从「实际存在什么」推导的? 前者仍然是清单,只是清单换了个人维护。
二、检查声明不等于检查行为。 有一项断言所有工具的 --json 都声明成
「可选值」形态,一路全绿;而其中三个子命令声明对了、代码还在走旧分支,
给了路径也不写文件。接口的声明和接口的实现是两个东西,要分别断言。
三、间歇性红和假绿一样有害。 一项安全扫描的检查每次都去远端拉规则集, 拉不到就红:完整跑五次红两次,单独跑三次全绿。它教会你的行为是「重跑到绿为止」, 而那恰好也是真出故障时你会做的事——于是这一项两种情况下都不起作用。 拆成两项:引擎用本地规则离线实跑(红=真坏了),网络那层单独查、重试一次才算数。
出处¶
~/Tools/skill-backend-check.sh,T10 / T11(2026-09-06)与 T14、 semgrep 引擎/规则源拆分、--json声明/实现拆分(2026-09-07)~/Tools/TOOLS_REWRITE_PLAN_2026-09-06.md,「续做的三条」- 同一根因的另一面:最危险的工具故障是"静默少做"——技能在、后端不在
- 检出了却不执行的那一类:自审的失效模式不是"没发现",是"发现了没执行"