# 越守规矩越过不了的闸 —— 判据必须区分「历史出处」和「它还在飞」

> 2026-08-03（session V，[[INFRA-F96]]）。通用教训，不限本闸。

## 发生了什么

给 `docs/superpowers/plans/` 上一条**可达性闸**：一份实施计划留在 live tree 的唯一条件是「仓库里有东西指向它」，没有就归档。

闸落地前配套一条协议：归档前先做**抢救扫描**，把「只活在这份 plan 里的仍生效约束」搬到它约束的那个对象旁边（[[INFRA-F84]] 先例）。我照做了，写了三条注释，每条都注明**抢救自哪份 plan** —— 这是负责任的写法，读的人能追到出处。

重跑闸：**点名数从 18 掉到 15**。

那三条注释把它们抢救自的三份 plan 变成了「有入站引用」，于是那三份归档不掉。

## 为什么这不是「小 bug」

因为方向是反的：**越认真执行闸自己要求的前置协议，闸越通不过。** 一个惩罚合规行为的判据，最终会被绕过 —— 而最省事的绕法恰好是**别写出处**，也就是把 F84 那条教训重新丢掉一遍。

这类缺陷有个共同形状：**判据把两种语义不同的东西当成了同一种**。这里是

- **活指针** = 「这份 plan 还在飞，别动它」
- **溯源引用** = 「这条约束的历史出处是那份 plan」

字面上都是一个文件名，语义相反。

## 修法：修判据，不是回避判据

两条路：

| | 做法 | 问题 |
|---|---|---|
| ❌ | 注释里不写 plan 文件名 | 丢掉溯源，等于把 F84 的教训重犯一遍 |
| ✅ | 让判据能区分两者 —— **引用写的是归档后的真实路径（含 `_archive/`）= 溯源** | 溯源保住，且这条规则**自己可验证**：写了 `_archive/` 却没真归档 = 死链，一点就发现 |

选 ✅ 的附带好处：溯源链接指向文件**真正在的地方**，比指向一个已经不存在的 live 路径更准。

## 可迁移的三条

1. **判据在「被遵守」时也要成立，不只在「被违反」时成立。** 造故障看它变红是标配；同样该问一句：**完全按协议做完之后，它还绿得了吗？** 本轮的自锁只有在真做了抢救搬迁之后才暴露 —— 光造故障测不出来。
2. **同一个字面形态承载两种相反语义时，判据必须能分。** 分不了就会二选一地错：要么放行该拦的，要么拦住该放的。找一个**带内的、可验证的**区分位（这里是路径前缀，写错了会变死链），别靠约定俗成。
3. **闸的前置协议也是闸的一部分，要一起测。** 我把「抢救扫描」当成闸之外的人工步骤，所以没想到它会和判据打架。凡是闸要求「先做 X 再做 Y」，X 的产物就在闸的输入面里。

## 落地物

- 判据：`scripts/audit-plan-lifecycle.mjs` 的 `isProvenanceMention()`
- 钉子：`tests/audit-plan-lifecycle.test.ts` §`isProvenanceMention` —— 三向断言 + 一条**复现该自锁场景**的回归钉
- 设计记录：[`specs/2026-08-03-infra-f96-plan-spec-lifecycle-design.md`](../../superpowers/specs/2026-08-03-infra-f96-plan-spec-lifecycle-design.md) §2b-1

## 顺带记一条不同性质的

同一轮里另一个发现：F96 entry 断言「1 069 个 checkbox 是 1.4 MB 的主要构成」，实测 checkbox 行**只占 plans 的 7.3%**（代码块 42.2%、散文 50.4%），差约 6 倍。

那条断言在 entry 里读起来非常顺 —— 1 069 个条目、4% 勾选率、1.4 MB，三个数字摆在一起，"所以主要是 checkbox" 是个很自然的推论。**但它是推论，不是测量。** 一条 checkbox 平均 69 字节，1 069 条就是 73 KB，量级一算就穿。

对应既有 memory `entry-restatement-is-secondhand`：entry 里带**因果/占比**措辞的句子，动手前自己跑一次基线。本轮把「删 checkbox」这个方向整个否掉，靠的就是这一次 `awk`。
