> 最危险的工具故障是"静默少做"——技能在、后端不在
自动化工具链的故障按危险程度排序,和直觉相反:
结论先行¶
自动化工具链的故障按危险程度排序,和直觉相反:
| 类 | 故障 | 表现 | 危险度 |
|---|---|---|---|
| A | 技能/命令在,但它调用的后端没装 | 静默少做,报告不会说"我没跑" | 🔴 最高 |
| B | vendored 的上游代码落后 | 行为陈旧但一致 | 🟡 中 |
| C | 能力真空(工具和技能都没有) | 你知道自己没有 | 🟢 低 |
C 类最不危险,因为你知道。A 类最危险,因为报告看起来是绿的。
一次实际体检:40 个技能 + 24 个命令 + 43 个工具目录里, 6 个技能声明的后端根本没装。
为什么¶
最典型的一个:一个安全扫描技能声明五层工具链,实际只装了一层。
| 层 | 声明的工具 | 实际 |
|---|---|---|
| Python SAST | bandit |
❌ 未装 |
| 多语言 SAST | semgrep |
❌ 未装 |
| 依赖 CVE | pip-audit |
✅ |
| 密钥扫描 | detect-secrets |
❌ 未装 |
| 容器/镜像 | trivy |
❌ 未装 |
跑一次,5 层里 4 层出不了结果,而报告不会提这件事。 你会得到一份"没发现问题"的安全报告,并且相信它。
另外三个 LaTeX 工具的后端目录是空的(0 个文件),技能却还挂着。 一个跑不动的技能比没有这个技能更糟——它占着位置,让你以为这块已经覆盖了。
还有一类介于中间的:"内容在,入口不在"—— 代码有 1237 个文件 / 43 MB,但既不在 PATH 也不能 import,只能按绝对路径调用。 这种不算坏,但必须在文档里写明,否则下一个人(或半年后的你)会当成 A 类。
怎么用¶
定期体检的方法(关键是验后端,不验技能):
- 逐个读技能定义,抄出它声明的每一个后端二进制 / Python 模块。
- 对每一个做实际可用性检查,不是看目录存不存在:
command -v <bin> # 在 PATH 里吗 python3 -c "import <module>" # import 得动吗 find <vendored-dir> -type f | wc -l # 目录是不是空的 - 对 vendored 的 git 仓库做只读
git ls-remote比对上游,别盲拉。
给工具本身的两条设计规则(比事后体检更根本):
- 后端缺失必须是显式失败或显式降级,不能静默跳过。 报告里要有一行"这层没跑,因为 X 没装"。
- 不要保留跑不动的入口。 要么装上后端,要么删掉技能。二选一。
Provenance 卫生。 43 个目录里只有 2 个有 UPSTREAM-SOURCE.txt。
vendored 的第三方代码必须标出来源,否则会出现两种事故:
把别人的代码当自己的改(升级时冲突),或把自己的代码当 vendored 的删。
标记要区分两种情况:
- 整仓 clone —— git pull 可同步。
- 代码片段级摘取(例如摘了某文件的 351–421 行并做了适配)——
git pull 同步不了,必须人工比对上游那几行是否变过。这种尤其要写清楚。
最后:自己的仓库"本地落后于远端"要单独对待。 那通常意味着你在别的机器上推过东西,拉之前先确认本地没有未提交改动。
出处¶
~/Tools/TOOLING_GAP_AND_PLAN_2026-09-05.md(2026-09-05 体检)~/Tools/TOOLS.md(工具目录本身)- 同类心智:自审的失效模式不是"没发现",是"发现了没执行"(自审也是"看起来跑了"的一类)