# ai-ds-lab 的硬规则

> 中立文件名（D4）。若某 harness 只认 `CLAUDE.md` / `GEMINI.md`，用 symlink 指过来，**真源只有这一份**。

## 0. 这是什么

DS 的**体检科**，不是 DS 的一部分。设计文档：[docs/specs/2026-08-21-ai-ds-lab-design.md](docs/specs/2026-08-21-ai-ds-lab-design.md)
（⚠️ 读正文前先看文末 **§16 勘误**——第一轮实测已推翻其中若干处数字与推论）。

## 0.1 🔴 停止规则（owner 2026-09-14 拍定 —— **这条压过本文件其余全部纪律**）

owner 逐字：

> **「要有个结束的时候，不要一直优化。比如：一次性检查出有哪些可优化的地方，把它做个列表，
> 一直到做完为止，不再新增，除非有阻碍」**

**运作模式因此改了**，⛔ 不是加一条提醒：

| 旧模式（2026-08-21 起 → 2026-09-14 止） | 新模式 |
|---|---|
| 一格一格递进，**每格都可能长出新格** | **先一次性盘点 → 冻结成清单 → 照单做完 → 收工** |
| 新发现的缺陷自动进入下一格的候选 | 🔴 **新发现只登记、⛔ 不排期**（见下方铁律 2）|
| 没有终点 | **清单清零 = 这条线结束** |

**清单真源 = [`docs/frozen-worklist.md`](docs/frozen-worklist.md)**，⛔ 不在 review 的交接节、
⛔ 不在处方头栏、⛔ 不在 `decision-queue.md`（那三处继续记它们自己的账，但**排期只认冻结清单**）。

### 三条铁律

1. **⛔ 不再新增。** 清单冻结之后，任何新条目都不许进。
2. 🔴 **新发现的缺陷 ⇒ 只登记，⛔ 不排期。** 写进 `frozen-worklist.md` 末尾的
   **「冻结之后发现的（⛔ 不在本轮射程）」** 那一节，⛔ 不许挪进待做区、⛔ 不许「顺手先做一下」。
   ⚠️ **这一条最容易失守**，因为本文件 §2 / §3 整篇纪律都在奖励「查得更细、发现新缺陷」——
   那些纪律管的是**「已在清单上的那条怎么做对」**，⛔ 管不到「要不要多做一条」。
   **两者冲突时，本节赢。**
3. **例外只有「阻碍」。** 即：**清单上某条做不下去了**（前提塌了 / 依赖不存在 / owner 裁定不做）。
   ⚠️ **「我又发现一个更值得做的」⛔ 不是阻碍** —— 那是新增，走铁律 2。

### 判据（⛔ 免得下次又靠自觉）

每格收尾问一句：**「我这一格动的，是不是清单上那一条？」** 不是 ⇒ 停手，写进「冻结之后发现的」。

⚠️ **立规背景（留痕，⛔ 不删）**：owner 问「还剩下哪些任务啊？一直做不完吗」。
当时实测 18 份处方 11 份已落地，而**本格（§43）刚好是活例子** ——
去核两条旧缺口，结果又判出一条新的 ⇒ **体检科查得越细、长出的格越多，这是它的性质，不是进度问题。**
lab 当时提的建议是「按价值裁掉剩 3 条」，**owner 否决了那个形态**，要的是**先盘清再冻结**。

## 0.2 🔴 判断标准 + 「做之前先审查」（owner 2026-09-14 拍定，与 §0.1 同级）

owner 逐字三句：

> 「**可以修改判断标准**」
> 「**安排的任务做之前重新审查一下当前是否还有必要做**」
> 「**做一次优化，能看到它的效果，不要无止境的优化下去**」

### 0.2.1 判断标准换成两条（⛔ 不再看「清单还剩几条」）

**为什么换**：「剩几条」是一张**欠债表** —— 它 ⛔ 不测「系统会不会静默变坏」，
而且 2026-09-14 实测它自己的条数**数错了 3 条**（标称 21 / 我又改成 19，表里实为 24 行）。

| 标准 | 测什么 | 载体 |
|:-:|---|---|
| **①** | **不许增的量有没有真的没增**（棘轮类闸有没有破）| **[`metrics/ratchet-watch.mjs`](metrics/ratchet-watch.mjs)** —— 一条命令跑出来 |
| **②** | **闸红了多久才被人看见** | ~~🔴 目前无载体~~ ⇒ ✅ **2026-09-14 owner 拍「补上」后已有**（见 §0.2.1a）|

**标准 ① 的用法**：`node metrics/ratchet-watch.mjs --ds-root <被测仓> [--ledger <lab 侧路径>]`。
**每格起手跑一次、收尾再跑一次** —— 那两次读数的差就是「这一格的效果」。
⚠️ 现在这两次**已自动化**（§0.2.1a），⛔ 但手动跑仍然有效。

### 0.2.1a 标准 ② 的载体 —— 两个挂点 + 一个 ledger

| 半边 | 挂点 | 什么时候跑 |
|---|---|---|
| **起手** | `.claude/settings.json` 的 `SessionStart` | 每次开 session |
| **收尾** | `.githooks/pre-commit`（`git config core.hooksPath .githooks`，**每 clone 一次**）| 每次提交 lab |

两处都调同一个包装 **`.githooks/ratchet-watch.sh`**，它带 `--ledger subjects/tvu-ds/ratchet-ledger.jsonl`
⇒ 每条红都会显示「**lab 自 <ts> 起就记录到它红（连续 N 次跑）**」。

🔴 **⛔ 铁律：永远 exit 0，绝不阻塞。** 理由⛔ 不是怕麻烦 —— 那些红**多半不是 lab 的账**
（被测仓是别人的工作面）。**一个会挡我提交、而我又无权修的闸，我只会想办法绕过它
⇒ 它就退化成恒红 = 零信息**（`lab:N58`）。

🔴 **ledger 测的是「lab 第一次【记录到】它红」，⛔ 不是「它实际开始红」** ——
ledger 只知道跑过它的那些时刻 ⇒ 这个数是**发现延迟的上界**，⛔ 别报成「红了多久」。
要真起点得逐 commit 复跑（本轮对 acceptance 那条就是这么做的）。

⚠️ **如实登记的上限（⛔ 别读成「已经有人盯着了」）**：它只让 **lab 侧**看见。
**改了 DS 规则真源的那个人看不到这个输出。** ⇒ 它把发现成本从「翻仓库」降到**零操作**，
⛔ 但不是自动告警、⛔ 也不强制处理。

⚠️ **退出码是契约**（hook 靠它分流，⛔ 别改）：`0` 没破 · **`3` 有破** · `2` 用法错 ·
**`1` = 量具自己崩了**。⛔ 「有红」与「装置坏了」**不得共用一个码** —— 否则 hook 会把
装置故障显示成「系统坏了」（§3.9 那类伪装）。

🔴 **立规当天的实证（⛔ 留痕）**：第一次跑就抓到 **2 条正红着的棘轮**，其中
`audit-acceptance-gate-coverage` 从 **16:30 起红、跨 5 个 commit 已进 master**，无人发现 ——
因为它在 `pre-commit` 是**条件触发**，而那几个 commit 改的都是别的文件 ⇒ 静默 skip。
⇒ **这就是标准 ② 指的那个短板**，也是为什么它必须单列一条、⛔ 不能算进标准 ①。

⚠️ **绿 ⛔ 不等于「系统是对的」** —— 量具自己会印这句。棘轮只保证「不许增的量没增」，
⛔ 不保证判据本身对（`lab:N64` 已实证：钉子全绿 ≠ 闸是对的）。

### 0.2.2 每条任务动手前必做（⛔ 不是建议）

**⛔ 不许直接照清单条目动手。** 先跑 §2.22 那个**五行块**（那是唯一真源，⛔ 别在这里抄副本）：
登记记的 / 现取的 / 前提还成不成立 / 它还该做吗 / lab 自己验过没。

🔴 **owner 这句把它从「接手已登记待做项时的纪律」升级成「清单上每一条的前置」** ——
⛔ 没跑过五行块的条目，**不许开工**。

**实证这一条会兑现**（同日，⛔ 不是假设）：按它核了 4 条，**3 条当场销账** ——
`O4`（标的已用另一支落地）· `O5`（动作已由 agent 做掉）· `O2`（前件未到 ⇒ 挪进阻塞）·
`O1`（唯一的硬收益已被 owner 自己 09-09 的裁定消掉）。**⇒ owner 的活 6 条 → 3 条。**

### 0.2.3 「一次优化」的收敛判据

**做完一次优化就停，⛔ 别顺着它往下做第二件。** 判据：

```
这一格动的，有没有让【标准 ①】的读数变化？
  变了 ⇒ 把 before/after 两栏写进交付，收工
  没变 ⇒ 说清为什么没变（可能它结构上就测不到，见 lab:N71），收工
⛔ 「我又发现一条红」不是继续做的理由 —— 那是新发现，走 §0.1 铁律 2
```

---

## 1. 只读边界（§8）

| 层 | 允许 |
|---|---|
| DS 真源 `master` | 🔴 **可直接写**（owner 2026-09-01 裁定，见下方 §1.1）—— ⛔ 但仍受本文件其余全部纪律约束：改动前 `git pull`、逐文件 `git add`（⛔ 不 `add -A`）、闸红了按闸的判据改而不是绕过、收尾重取 HEAD |
| DS git worktree | 可改，做实验，用完即弃 |
| 处方交接 | `proposals/` 仍可用，但**不再是唯一出口**（见 §1.1） |

### 1.1 边界改判（owner 2026-09-01，⛔ 连同代价一起记）

**原规则**：DS 真源 master **永不直接写**；lab 只出 `proposals/`，由 DS 侧 session 执行。
**现规则**：**lab 直接 commit 到 DS master**。owner 逐字理由：「我老是忘记点 PR 合并，而且也没有必要坚持 PR」。

**为什么改**（读数，⛔ 不是感觉）：
- 元指标 §13.1 的采纳率实测 **7 份里 2 份已执行**（`round2-status` §4.1）；`proposals/` 现有 **14 份**，平均 20KB+、**最大 52KB**。
- 已确认未执行的至少 3 份（`meta-rules.md:975` 处方 2026-09-01 亲验仍在原位 + 两份 2026-08-28）。
- 同期 DS 侧 3 天做了 31 个 commit ⇒ **对方不缺执行力，缺的是「不用先读 52KB 再自己实现」**。

🔴 **代价（lab 提出、owner 已知悉并仍如此裁定 ⇒ 登记，⛔ 不再复议）**：
~~§13.1 元指标是 `proposal 采纳率 × 采纳后指标实际改善的命中率`。**lab 自己既写规则又自己提交 ⇒ 采纳率恒 100% ⇒ 该指标不再测任何东西。**~~
⚠️ 这与 DS 侧 [`mockup-conventions.md` §M-GATE-FALSIFIABILITY](../../tvu-design-system/docs/internal/mockup-conventions.md)（同日由本 lab 落地）是**同一个病**：一条控制在它该抓的形态上无法失败。
⇒ ~~**§13.1 的采纳率分子自 2026-09-01 起按「不可判读」处置**，⛔ 不得再引用它宣称 lab 有效；要重新获得可读的元指标，需另立一个 lab 判不了自己的量（未设计，属独立提案）。~~

🔴 **订正（2026-09-01 同日，`lab:N93`；⛔ 留痕不删上面两句 —— 上面那句划掉的推理是错的）**

**⛔ 这不是复议 owner 的边界改判**（那条不复议）。改的是 **lab 自己写的一句推理**：「采纳率恒 100% ⇒ 该指标不再测任何东西」**是反的**。

核元指标真源 —— ⚠️ **⛔ 不在本文件、⛔ 也不在 `round2-status.md`**（那里的 §13.1 讲的是「比例型指标有两个地板」，与元指标无关），真源是
[`docs/specs/2026-08-21-ai-ds-lab-design.md` §13.1](docs/specs/2026-08-21-ai-ds-lab-design.md)「lab 自己的成功标准」，**逐字**：

> **元指标**：`proposal 采纳率 × 采纳后指标实际改善的命中率`
> **若处方大多被采纳但指标没动 → 错的是 lab 的诊断模型，该改 lab 而不是改 DS。**

⇒ 这个指标要抓的形态，原文点名就是「**采纳率高 + 指标没动**」。采纳率恒 1 ⇒ **「大多被采纳」这个前件永真** ⇒ 元指标**塌缩到剩下的那个因子上**，而剩下那个（**指标到底有没有动**）**恰恰就是靶心**。恒 1 的因子不携带信息 ≠ 乘积不再测任何东西。

⇒ 🔴 **现行口径（owner 2026-09-01 拍定）**：
- **因子 1（采纳率）自 2026-09-01 起恒 1、不再携带信息** ⇒ ⛔ 不得单独引用它宣称 lab 有效（这一半原判**成立、保留**）。
- **因子 2（采纳后指标实际改善的命中率）⛔ 未作废，元指标即等于它。**
- 🔴 **因子 2 可判读的前提是「承诺的指标必须写在改动之前」** —— 否则 lab 可事后挑一个必然会动的指标，那才真是一条不能失败的控制。⇒ 与既有预注册纪律（取数前 commit、取数后一字不改）同构，**推广到处方上**：处方须在 §0 或验收节写死「这条改动承诺让哪个指标动、动到哪」。
- ⇒ **⛔ 因此「需另立一个 lab 判不了自己的量」这个独立提案不成立、不立项**（它的前提「§13.1 已全废」是假的）。

⚠️ **顺带一处登记面缺陷（`lab:N93` 新查）**：本文件 `:24`/`:29`/`:31`/`:58` 与 `round2-status.md §4.1` 均写「§13.1」而未标编号空间 ⇒ 与 `round2-status.md` 自己的 §13.1 **撞号**，两者内容毫无关系。**应写 `spec:§13.1`** —— 这正是本文件 §4 那条「两套编号空间都在长 ⇒ 撞号已实际发生」的又一例，且这次是 lab 撞自己的。
⇒ 中间路线（lab 出 PR、owner merge）已提出并被 owner 否决，理由如上。⛔ 别再自动提议它。

**所有测量都在 pin 住的 worktree 里做，不读 DS 的工作区**——工作区可能是脏的、可能已跑在 pin 之后。
（实证：`.husky/commit-msg` 在 pin 处不存在，直接读真源会拿到未来的钩子；同一批 HTML 按三种量法得 16 / 69 / 657 份。）

## 2. 度量纪律

1. 每份 baseline 记全三元组主键 `(subjectSha, modelId, promptTemplateVersion)`（§5.2），缺则作废。
   纯 T1 确定性指标可把后两项记 `n/a`，**但要显式记，不留空**。
2. 每个判据标注**裁判来源**（lab 自写 / DS gate）。
3. **新增指标前先写清「它会驱动什么决策」**，写不出来就不加。
4. **凡引用一个分母，必须带口径名。** 写「66（`scripts/` 口径）」而不是「66」。
   同一个量在不同口径下是不同的数，两者都对，并排读却像矛盾。
   （实证 N19：`audit-*.mjs` = **66**（`scripts/` 口径）= **82**（全仓 tracked 口径 = scripts 66 + figma-sync 14 + templates 2）。
   两份 lab 报告各用一个、都没标，读起来像对不上账。）
   ⇒ 推论：**扫描面本身也要写进报告**。第一轮的挂载盘点只扫 `scripts/`，漏掉 `figma-sync/` 整个目录 14 条闸，
   而「17 条未执行」这个结论就建在那个未声明的扫描面上（实为 20 条）。
   ⇒ 推论二（**编号也是一种口径**，2026-08-25 采纳 DS 的提议）：**跨仓引勘误/编号必须带仓前缀** ——
   写 `lab:E9` / `ds-adr:E9`，⛔ 不写裸 `E9`。两套编号空间都在长、都用同一个字母 ⇒ 撞号已实际发生：
   DS 引「E9 是实证」指的是 `ds-adr:E9`（一条 ADR 结论），而 lab 的 `lab:E9` 是 spec §14 排序错误，
   两者毫无关系 —— lab 按**实质主张**独立复核后采纳，但白花了一轮对不上号
   （见 `docs/ds-reply-2026-08-25.md` §1.3）。
   ⇒ 同族的一次反向实证（**这次是 DS 踩的**，`lab:E39`）：DS 说「4,199 行与 E34 的 47.7% 是同一个算式」——
   实为两个口径（4,199 = **34 份删除清单**口径；4,665 = **35 份 S2 裁定面**口径，差的正是那份判 hold 的 466 行）。
   ⇒ **两个数长得像同一个量，就是最该标口径名的时候。**
5. lab 的文档同样适用归档出口规则（§11.3）——不得只进不出。
6. lab 自身受元指标考核：`proposal 采纳率 × 采纳后指标实际改善的命中率`（**`spec:§13.1`**，⛔ 不是 `round2-status` 的 §13.1 —— 撞号，见 §1.1 订正段）。
   🔴 **自 2026-09-01 起因子 1 恒 1 ⇒ 元指标 = 因子 2**；因子 2 可判读的前提是**承诺指标写在改动之前**（§1.1 订正段）。
7. **低基数离散指标在小 N 上最容易伪装成确定性。⛔ `sd=0` 不得读作「无噪声」。**
   实证（6′ 校准档 → 放量档）：`ds-conformance.errors` 在 **N=2** 上两次都是 1 ⇒ CV **0.0%**，
   据此写下了「离散/类别型 T1 指标零变异」这条结构性观察（当时已自标「线索不是结论」）。
   **N=5 实测逐 run `[1,1,4,0,2]`，CV 94.8% —— 它是全表方差最大的那个，不是最小。**
   同一轮还在另一个量上撞到同族：`.md` 实读面在 N=2 上两次完全相同，N=4 上是 9/9/6/8、交集仅 5/10。
   ⇒ **操作口径**：连续型指标的小 N 估计可当粗略线索；**离散/低基数型的小 N 估计一律不得外推**，
   ⛔ 尤其不得用来论证「这个指标是确定性的 / 可以少跑几次」。
8. **MDE 大于效应量时，该指标在该 N 上「结构性地判不出改善」——这要显式写进报告，⛔ 不许只报 MDE 数值。**
   实证：`ds-conformance.errors` 的 MDE(2σ)=**3.03**、mean=**1.6** ⇒ 「把违反降到 0」这个改善（1.6）
   比地板还小。只报「MDE=3.03」而不说这句，读者会以为这个指标能用来验收。
   ⇒ 每个指标报 MDE 时**并排报 MDE/mean**，并对 >100% 的显式标注「该 N 下不可用于验收」。
9. **比例型指标有两个地板，必须并排报。⛔ 只报 MDE 会让读者以为「加大 N 就能用」。**
   - **噪声地板**（= MDE，抽样误差）：加大 N 会降。
   - **分辨率地板 = 1 / 分母**（量化误差）：**N 加到多大都不动**。
   - ⇒ **有效地板 = max(两者)**。
   实证（第 11 步）：规则口径的噪声地板 **0.1584** 比分辨率地板 **0.20** 还小 ——
   只报 MDE 会读成「能判出 16% 的改善」，而这个指标**根本表示不出小于 20% 的移动**。
   ⇒ 推论一（**恒真分母稀释**，勘误 E35）：**凡引用比例，先问「分母里有几格是恒真的」。**
   实证：HTML grader 5 条规则里 4 条在 N=5 上从未命中 ⇒ 它们对任何改善都不动，
   把合规率从 0.20 抬到 0.84、把分辨率从 1/1 稀释到 1/5。**恒真项要剔出来单独报有效分母。**
   与 E33 同族不同形态：E33 是**整条判据**恒真，这条是**分母里部分**恒真。
   ⇒ 推论二（勘误 E36）：**拆细分母只买分辨率，不买统计力。** 实证：把 N 个 run × K 条规则
   摊成 N·K 格，分辨率地板 0.20→0.04，**噪声地板反而 0.1584→0.2905** ——
   独立复现单位仍是 N 个 run，拆格子不产生新独立信息。
   **⇒ 与「铺新 task 买区分度不买统计力」同构：统计力只能靠增加独立复现单位来买。**
10. **二值 / 低基数比例口径走精确检验，⛔ 不走 2σ；且「落在判定边界」必须显式写，它比「判不出」更需要写清。**
   实证（勘误 E37）：`ds-conformance.exitCode` 按 2σ 出的地板是 0.8944 ⇒ 读作「判不出」；
   改走 **Fisher 精确检验**后，「完全修复」（1/5 → 5/5）的 p = **0.0476** —— **距 0.05 只差 0.0024**，
   而 4/5 时 p 跳到 **0.2063**。⇒ 正确读法是「**只能判出完全修复，且刚好过线**」。
   ⇒ 结论仍是「不得用作主验收」，但理由从「地板远大于效应量」变成
   「**结论对口径选择与单个 run 的结果极度敏感**」——后者最容易被人拿去当「我们能测出来」。
   ⇒ 操作口径：① Bernoulli 变量不得用样本 sd 派生地板（n 小、p 靠边界时正态近似很差）；
   ② 把这条**内建成 must-not-hit**（实例：`first-shot.mjs` 的 MN3 断言二值口径产物里
   不得出现任何 sd 派生字段）；③ 换口径时两个都报，⛔ 不悄悄换。
   ⇒ 反向的一条（**背书不是勘误**）：`MDE = 2·sd` 这个启发式与正式两样本公式
   `(z_{α/2}+z_β)·sd·√(2/n)`（n=5 ⇒ 系数 1.771）相差 13%，**方向在安全的那一侧**，结论不翻。

11. **「谁主导地板」是口径级事实，⛔ 不得跨口径外推；「分布形状」也不算具名事实。**
   实证一（`lab:E40`）：同一份报告的同一张表里，规则口径是**分辨率主导**（加 N 无用）、
   主验收口径 `unmatchedDistinct` 是**噪声主导**（N 加到 58 之前一直有效），
   而 `round2-status.md` §13.2 把前者写成了通用结论「加大 N 过不去分辨率地板」。
   ⇒ **操作口径**：报双地板时**每个口径都要显式标注「谁主导」**；
   写「加大 N 有没有用」这类跨口径判断前，先问「我说的是哪个口径」。
   ⇒ 实证二（`lab:E43`，是 §3.2 推论二的补充）：`first-shot` 的 MH2 钉「exitCode 分布 = 4 个 1 + 1 个 0」，
   GT-002 实测 `[1,1,1,0,1]` **巧合通过** ⇒ **一条本该在被测对象换代时炸的控制没炸**。
   ⇒ **「分布形状」不算具名事实** —— 它在另一个被测对象上可能恰好相同，
   而那正是控制最该响的时刻。⇒ 钉**逐 run 序列**，不钉分布的统计摘要。
   ⇒ 实证三（`lab:E42` 与 §3.14 同族）：`convergence-probe` 的 MH3 把「0 命中」
   钉成单一解释「**检测器坏了不是产物变了**」，被 GT-002 的 r007/r011 推翻 ——
   那两个 run **真的手搓了整套 BEM**（82/68 个自有 class token、零动态绑定迹象、零 DS 根 class）。
   ⇒ **同一个观测值可能有多种解释时，判据要把解释拆开分支**（0 命中 ∧ class 面非空 ⇒ 真手搓；
   0 命中 ∧ class 面塌了 ⇒ 装置坏），⛔ 不是放松成「允许 0 命中」。
   ⇒ 推论（造故障 F-E / F-E′ 的对照）：**同一个失效概念可能有多种发射形态，每种都要有自己的控制。**
   实证：闸「计数假绿」由双向夹逼 MH5 抓、闸「规则行假绿」由曝光矩阵 MH7 抓，**两者互不覆盖**。

12. **「改了被测对象」和「改了它的说明文字」是两件事，⛔ 冻结物只存整文件 sha 就分不开。**
   实证（`lab:E44`，2026-08-26 re-pin 第一批）：`manifest.json` 原本只存整文件 `sha256` ⇒
   「换引文出处」与「改 prompt」在校验器眼里**完全不可区分**，两者都只表现为 sha 变了；
   而后果天差地别 —— 前者可比性不变，后者按 spec §7.5 要**新旧 set 各跑一遍桥接**（≈85 M token）。
   ⇒ **操作口径**：冻结物按「身份」分别存 sha —— 被测对象（`{prompt, outputContract}`）、
   判定口径（`graders[]` 的 `{id,kind,judgeSource,script,caliper}`）、其余（provenance / 立论 / 边界）。
   判据按三档**分支断言**（`provenance-only` / `grader-changed` / `subject-changed`），
   ⛔ 不合并成一个「变了」，也⛔ 不放松成「允许 sha 变」。这是 §2.11「同一观测值多解释要分支」的又一实例。
   ⇒ **序列化必须 canonical**（递归按键名排序）—— `JSON.stringify` 的键序依赖插入序，
   不规范化的话「只调整字段顺序」会伪装成「内容变了」。
   （反向实证：本轮造故障时用 `JSON.stringify` 重写文件导致整文件 sha 变了，
   而 `subjectSha256` **纹丝不动** ⇒ canonical 口径正确地忽略了格式差异。）
   ⇒ 推论一：**「预测」不是「判定口径」，要逐字排除在 grader sha 之外。**
   `expectedDiscrimination` 是预注册预测，改它不改变任何判定；不排除的话
   「重写一句预测的理由」会被错归成「grader 变了 ⇒ 读数不可并池」（造故障 F-4 专门验了这一格）。
   ⇒ 推论二（`lab:E45`，§2.11 的第四例）：**控制少钉一维 = 换代时不炸。**
   `golden-set-freeze` 的 `hitFor` 原本只比 `mustContain`、⛔ 不比 `path` ⇒
   出处换了文件而引文串不变时，MH2 **照样报绿**，还带着一句已不成立的 detail。
   ⇒ 钉引文要 `path` + `mustContain` **一起**钉。
   ⇒ 推论三（`lab:N47`，取证工具造假象）：**管道会吞掉退出码。**
   `node x.mjs | tail` 之后 `$?` 拿到的是 `tail` 的、不是 node 的 ——
   本轮实测把一次真实的 `exit 1` 读成了 `EXIT=0`。⇒ **验 fail-closed 必须不带管道单跑。**
   与 DS 同日登记的「后台通知的 exit code 是 wrapper 的不是 vitest 的」同族。
   ⇒ 推论四（`lab:N48`，§3.9 的加强）：**当装置故障的返回值恰好是一个合法读数时，
   「先证装置再归因」最容易被跳过。**
   实证（2026-08-26 re-pin 预演）：提取 DS 的 `KNOWN_SILENT` 表条数，**连续三次拿到 `0`**
   （sed 范围没框住 / macOS `grep -E` 不支持 `\s` / 函数内 `git show` 少了 `-C`）——
   而 `0` 在那个位置**完全合理**：该表头注释逐字写着「表只会缩…**表空 = 终态**」。
   ⇒ 不实看表体就会把「装置坏了」写成「DS 已达终态」，**而那是一条会被写进报告的结论**。
   实看后修正得 **36 条**。
   ⇒ **操作口径**：凡判据可能返回 `0` / 空集，且 `0` / 空集**本身是一个有意义的结论**时，
   **必须先用一次独立方式确认判定面非空**，再解释那个 `0`。
   ⇒ 推论五（`lab:N48` 的加强，2026-08-26 真 re-pin 一轮内**自己踩了五次**）：
   引号数当条数（10 vs **2**，容器是对象数组不是字符串数组）/ 跨节计数（B=8 vs **5**，正则没框节边界）/
   假设标签形态被原样搬运（D 组 0 vs **11**，对方把 `D1–D11` 重编号成了 `1.–11.`）/
   **`head -6` 截断当成全集**（workflow 调用点 2 vs **4**）/ 字段路径写错（契约计数 0 vs **11**）。
   **五次全部返回了一个「看起来合理」的值。** 其中截断那次差点被写成
   **与对方自称对立的发现**（我数 2、对方称 4 —— 错的是我）。
   ⇒ **操作口径**：**凡要把自己的计数与对方的自称对立起来之前，先证自己的计数器口径** ——
   截断 / 标签形态 / 节边界 / 字段路径 / 容器类型，**五项各查一遍**。
   ⛔ 「我数出 X，他说 Y，所以他错了」在证完自己的装置之前**不是一条发现**。

   ⇒ 推论七（`lab:N48` 第 7 例，2026-08-26 A 格 —— **首次由产物自带的控制抓到，⛔ 不靠人工警觉**）：
   **读数与同一份产物里的控制结论矛盾时，先疑自己的取数装置，⛔ 不先疑被测对象。**
   实证：取 `ds-gate-chain-run` 产物时字段路径写错（`s.ms`/`s.findings`/`s.exit`，
   真实是 `warmMedianMs`/`contract.findings`/`exitCode`），拿到
   「0 ms 全链总 / 0 条契约步 / **39 个非 0 退出步**」—— 三个都是「看起来合理」的值。
   而同一份 JSON 里 `controls` 是 **18/18 全绿**、进程 `EXIT=0` ⇒ **矛盾本身暴露了装置故障**。
   ⇒ **操作口径**：产物自带控制时，**把控制结论与自己算出的读数并排打印** ——
   比事后人工复核便宜得多，且不依赖警觉。

   ⇒ 推论八（`lab:N48` 第 10 例，同轮）：**两个独立方法得到同一个数，⛔ 不等于那个数对 ——
   如果两者共享同一个错误假设。**
   实证：核处方 2 单测覆盖时，`grep -cE "^\s*(it|test)\("` = **27**，自写解析器也 = **27**，
   于是自查 `if (cases.length !== 27) throw` **通过了**；而 `vitest run` 实跑是 **34**。
   差额 **7 = (5−1)+(4−1)** —— 两个**表驱动**块 `for` 展开的差。
   两把尺共享同一个错误假设（把 `it(` **字面量**数当测试数）⇒ **互相印证成假绿**。
   ⇒ **与 §3.8「DS 的收割器与发射端同源 ⇒ 测不出自己那套约定的盲区」同构，
   只是这次是 lab 自己踩的。**
   ⇒ **操作口径**：**交叉验证必须换「实现范式」，⛔ 不只是换「实现」。**
   静态解析 × 静态解析 = 同一范式；正确的第二把尺是**运行时**（实跑计数）。
   ⇒ 同轮还有一例**结果对但装置错**（比结果错更危险，因为不会被结果暴露）：
   判控制全绿时写了 `c.pass ?? c.ok ?? true` —— 真实字段是 `ok`，`c.pass` 恒 `undefined`
   于是碰巧取对，但 `?? true` 的兜底意味着**字段一改名就假绿**。⇒ 判定一律 fail closed
   （`typeof c.ok !== "boolean"` 即抛），⛔ 不写 `?? true` 这类兜底。
   ⇒ 🔴 **`?? ""` 是同一个坑，且更隐蔽**（2026-09-11 §29 实测）：
   `"*+?{".includes(pat[i] ?? "")` —— 越界时 `pat[i]` 是 `undefined`，`?? ""` 变空串，
   而 **`String.includes("")` 恒为 `true`** ⇒ 整条判据恒真、读数塌成 `0`，
   而那个 `0` 在它出现的位置「看起来完全合理」。
   ⇒ **口径：判定式里的越界取值一律显式判 `undefined`，⛔ 不给任何默认值** ——
   `?? ""` / `?? 0` / `?? []` 在包含、匹配、求和、遍历语义下各自都会造出一条恒真或恒假的判据。
   ⇒ **反向的一条（`lab:N48` 里第一条被验证有效的做法，⛔ 不只记教训）**：
   **取数脚本一律 fail-closed 起手，这次直接兑现了价值。** 逐步表表体里有一条 `───` 分隔线，
   初版解析器**抛错而非静默跳过** ⇒ 改成**显式**排除分隔线、其余仍抛。
   若当初写成「解析不出就跳过」，行数会变成 **38** 而不自知。

   ⇒ 推论六（`lab:E46`，2026-08-26 真 re-pin 当场暴露 —— §2.12 主条的又一实例）：
   **`golden-set-freeze` 的 `frozenAgainstSha` 同时承担了两种身份，于是 re-pin 后它永远不更新。**
   它逐字取自 `tasks[0].task.provenance.pinnedSha`（= **引文取证时的 sha**，一个历史事实），
   **⛔ 不是 `--pin` 参数**（= 本次校验用的 pin）。两者在第一次 re-pin 之前恰好相等，
   于是「一个字段两种身份」一直没暴露；re-pin 之后 manifest 永久停在旧 pin 上，
   而**没有任何判据会炸**（`lab:E45` 同族：控制少钉一维 = 换代时不炸）。
   ⚠️ 还有第三个身份混在附近：run 的 §5.2 主键 `subjectSha` 实测取自
   `context-manifest.mjs` 的 **`cwdFacts.head`**，⛔ **不是** task JSON 的 `provenance.pinnedSha` ——
   判据 E 却把后者标成 `subjectSha`。**三个事实，三个位置，⛔ 别互相顶替。**
   ⇒ **操作口径**：① 冻结物要**分别记**「取证 sha」与「校验 pin 的真 HEAD」；
   ② ⛔ **不改 `provenance.pinnedSha` 去「跟上」新 pin** —— 那是伪造历史取证事实
   （与「⛔ 不自动迁移旧读数到新档」同源）；
   ③ 老冻结物缺该字段 ⇒ **fail closed 报错**，⛔ 不得拿另一个字段顶替；
   ④ 本次 pin ≠ 冻结时 pin ⇒ **显式报「跨 pin 读取」但⛔ 不判失败** ——
   用旧 pin 复现旧读数是合法动作，与 `chainEra` / `injectionEra` / `graderSha` 分档同构；
   ⑤ 从**单个元素**取集合属性（原实现只取 `tasks[0]`）会**静默吞掉**其余元素的分歧 ⇒ 不一致就抛。

13. **协议只规定「什么时候做」是不够的，还要规定「做到哪个目标」——两处都会出错。**
   实证（2026-08-26）：`subject.json` 的 `repinProtocol` 只写了「自然 re-pin 时机 =
   DS 侧执行完某份 proposal 之后」，**没写「pin 到哪个 sha」**。结果两处各错一次：
   ⇒ **时机判错**：把「执行完某份 proposal 之后」读成「**DS 空闲**」——
   而那是**一个已经发生过的时点，不是一个要等的状态**。实测 lab 处方线 21 小时前就收尾了。
   ⇒ **目标会错**：pin 到 DS 当前 HEAD 会把处方线之后 12 个**无关 commit** 的漂移记到处方账上。
   量化实测：`tests/` 口径下处方 delta **+1**、无关漂移 **+13** ⇒ **93% 是别人的账**。
   （这与 `whyKeep` 当初选 P1 而非 P0 的理由**同源**，本轮给了它第二个量化实证。）
   ⇒ **操作口径**：pin 目标 = **本轮处方线的最后一个 commit**，⛔ 不是「对方当前 HEAD」。
   ⇒ 推论（§2.11 同族）：**「pin 到哪」的影响是逐口径不同的，⛔ 不得跨口径外推。**
   同一次对比里 `tests/` 是 93% 污染，而 `_archive` 是处方 −52 / 无关 −1 ⇒ **pin 到哪都差不多**。
   ⛔ 别写「pin 到 HEAD 会污染读数」这种不带口径名的句子。
   ⇒ 推论二：**协议里写死数量会过期。** `dsMustReport` 逐字写「**两份**处方验收标准」，
   而实际已是 **7 份** ⇒ 照原文执行会漏 5 份。**写「本轮的全部 X」，⛔ 不写死份数。**
   ⚠️ 2026-08-26 真 re-pin 时发现**同一形态在同一份 `subject.json` 里出现了四次**：
   写死份数「两份处方」/ 写死 key 名「`prepublishOnly`」（DS 已挪进 `gate-chain`）/
   写死份数「三个 worktree」（已是四个）/ 写死代号「对 P1 而不是 P0」。
   ⇒ **协议里凡出现会漂的量（份数、key 名、代号、路径），一律改成判法而不是值。**

14. **性能自称必须带环境名 —— 同一条闸在不同环境可以差一个数量级，⛔ 不得跨环境搬读数。**
   实证（`lab:E47`，2026-08-26 真 re-pin 的 `dsMustReport` ④）：DS 在 commit subject 逐字写
   「plan-lifecycle 扫描面收窄 **-73.8% 全链耗时**」。lab 在 pin 上交替 N=3 实测，
   delta **+33 ms（+0.5%）**，落在噪声地板 2σ=526 ms 以下，**方向还相反**。
   ⇒ **⛔ 但这不是「对方的数假」。** 四个环境的读数完全自洽，机制唯一：
   被排除的 `figma-data/mockup` 是 **gitignored 的 1.1 GB**，只在开发者主工作树在场；
   `git worktree` 只 checkout tracked 文件、CI 走 `actions/checkout` 新鲜 checkout
   ⇒ **lab pin 与 CI 上那个目录从来就不存在**，排除一个不存在的目录省不出时间。
   ⇒ **操作口径**：① 引用对方的性能读数前，先问「**这个收益在哪个环境成立**」，
   并把环境名写进句子；② 自己报性能 delta 时同样带环境名；
   ③ ⚠️ 对方的 **commit body 里写清了环境限定词、subject 里没有** 是常见形态 ——
   **传播的是 subject**，所以差异要显式登记，⛔ 别默认读者会去看 body。
   ⇒ 推论：**「治好了 X 的成本」与「治好了 X 的不确定性」是两件事，⛔ 别合并。**
   本例中 DS 治的是**扫描面在本机与 CI 上不一致**（一个真缺陷），
   ⛔ 不是 lab 处方指出的那 6.2 s ——后者由 **tracked 的 67 MB** 主导，本次修复没动它，
   ⇒ lab 那条处方的前提**未被动摇**。
   ⇒ 推论二（`lab:E48`，2026-08-26 A 格实测 —— **同族的第二个实例，且更强**）：
   **闸链读数还依赖「构建产物是否在场」，那也是一个环境维度。**
   `dist/` 与 `figma-data/mockup` 完全同形态（gitignored、`git ls-files` = 0、只在跑过 build 的
   工作树在场），但后者只影响**耗时**，`dist/` 直接改变 **exit code** ——
   新建 `git worktree` 首跑全链 `EXIT=1`，第 27/28 步逐字报 `dist/tokens/tokens.json 不存在`。
   ⇒ **上轮「两 pin 39 步全 exit 0」是在「dist 已构建」的环境上取的**，而那个维度**从未被登记**。
   ⇒ **操作口径**：`chainEra` / `injectionEra` / `graderSha` 之外，**闸链读数须并记「构建产物是否在场」**；
   ⛔ 换机器 / 新 worktree 上复现 lab 读数，不先 build 会拿到 `EXIT=1` 而误读成「闸炸了」。
   ⇒ 连带（**给「⛔ 不得在 pin 上跑 build」一个机制理由**，此前它只是个不变式）：
   `pnpm build` 会弄脏 **tracked** 面 **292** 条 —— `playground-dist/` 与 `react-pilot/dist/` 是
   **刻意 tracked**，且内容哈希后缀每次都变 ⇒ **构建产物不可复现**。
   复现姿势：`build` → `git checkout -- .` + `git clean -fd <那两个目录>`
   ⇒ tracked 回 `dirty=0`、gitignored 的 `dist/` 保留。
   ⇒ 推论三（**第三个实例，且后果最远 —— 前两个是单次读数，这个是会被反复引用的约定**）：
   **耗时类的 MDE / 噪声地板约定必须带环境名，否则它会被跨环境裸用。**
   实证（2026-08-26 B 格结 `71ac2711` 读数账）：第一轮基线报告在「实测 `@71ac2711`」标题下给出
   gate 总时长 **13.8s**、N=5 均值 **13.82s**(σ0.18)、冷启 **46.9s**，并据此立了一条**至今仍在用**的约定：
   「**MDE = 2σ ≈ 0.35s（约 2.5%），低于此的耗时改善不算数**」。
   而机制实证：那条最贵的闸 `smoke-consumer-treeshake.mjs` 逐字跑 `npm pack` + `npm install` + `npx vite build`
   ⇒ **必然需要 `node_modules`**，而 `71ac2711` 的 `dist/` 与 `node_modules` **都不在**
   ⇒ 那组读数**必然取自另一个环境**，报告**只标了 pin、没标环境名**（本纪律 2026-08-26 才立，报告是 08-24）。
   ⇒ **操作口径**：① 立 MDE / 噪声地板时，**环境名与 pin 同等必填**；
   ② 老约定缺环境名 ⇒ **要么补环境名重取，要么降级为「历史参考」，⛔ 不得继续裸用**；
   ③ ⚠️ **数值接近最危险**：那 13.82s 与另一口径的 13,465 ms（39 步全链）**只差 2.6%**，
   而口径是「55 条可离线跑」vs「39 步全链」⇒ **⛔ 严禁并池**，尤其严禁据此说「性能没变化」。
   ④ 同族提醒：**静态解析得到的数与实跑得到的数同值时，引用必须带限定词** ——
   本轮实测「`prepublishOnly` 顶层 **39** 步」（静态读 `package.json`）与
   「逐步表 **39** 行全 exit 0」（实跑）同值，读者极易把前者读成后者。

15. **造故障取证之前，先问「这个装置在故障存在与不存在时会给出不同的读数吗」——
   答不出「会」，装置就不成立。**
   实证（`lab:N48` 第 6 例，2026-08-26 A 格**起草计划时**）：初稿打算用 lab 的
   `adapters/ds-gate-chain-run.mjs` 去验处方 1 §5.1「第 1 步失败后第 2…39 步是否仍执行」——
   而它头注释逐字写着「⛔ 为什么逐步独立跑，而不是 `pnpm run prepublishOnly`」，
   **每步各起一个进程、必然全部执行** ⇒ 它在任何情况下都会打出 39 行。
   ⇒ **拿一个「必然全跑」的装置去证「是不是全跑了」，返回的 39 是装置的属性，不是被测对象的属性。**
   ⇒ 与 `lab:N48` 前五例的差别：**前五例是计数器口径错（数错了），这一例是装置与命题不匹配
   （数对了，但数的不是那个东西）。**
   ⇒ 推论一（**独立旁证**）：处方逐字要求「⛔ 证据不是『runner 说它跑了』」时，
   要找一个**不经过被测对象自述**的量。本例用**墙钟**：失败 run 13,530 ms ≈ 全绿 13,465 ms
   （差 +65 < 合并 2σ=177），而「失败即停」等价口径只有 **157 ms**（差 86.2 倍）
   ⇒ 后 38 步确实跑了，**该结论不依赖逐步表**。
   ⇒ 推论二（**must-not-hit 的空判**，同轮实证）：**几个 must-not-hit 看起来在测不同的东西，
   可能全被同一条前置条件挡住 ⇒ 一格都没测到。**
   实证：处方 3 判据 4/5/6 三格期望结果全对（`exit 0`），但闸的真实判据是
   `① 显式相对 ∧ ② 段边界后缀匹配 ∧ ③ 完整路径不存在`，而那四个形态**无一以 `./`/`../` 开头**
   ⇒ **② 根本没被触发**，而判据 6 的意图正是测 ②。补一格 `../tion/…`（①过②失败 ⇒ 不报）
   并配阳性对照 `../retrospection/nope…`（①②都过 ⇒ 报了）才真正验到。
   ⇒ **写 must-not-hit 要问「这个用例会走到我想测的那条规则吗」，⛔ 不只是「期望结果对不对」。**
   ⇒ 推论三（**阳性对照是 must-not-hit 的前置**，同轮实证）：
   **`exit 0` 在证明「判定面覆盖到我造的这个点」之前，⛔ 不算 must-not-hit 通过。**
   实证：用**仓根形态**做阳性对照 ⇒ `EXIT=0` 不报 ⇒ 无法区分「这些形态确实不该报」与
   「我插入的行根本没进扫描面」；换**显式相对形态**同位置重做 ⇒ `EXIT=1` 报在我插入的那一行
   ⇒ 三条 must-not-hit 的 `exit 0` 才有意义。**⛔ 少这一步就是三条假绿。**

16. **写「X 不得变」类判据之前，先问「达成 X 的那个动作，本身会不会改变 X 的载体」——
   答「会」是恒假判据，答「载体压根不覆盖那个动作」是恒真空判。两头都测不出东西。**
   实证（`lab:N49`，2026-08-26 B 格 —— **lab 自己写的**处方 4 验收表第 3 行「`L1Fingerprint` 不得变」）：
   同一采集器、同一口径、变量隔离的造故障（环境名 `wt-l1fp`）：

   | 态 | 指纹 | 变的分量 |
   |---|---|---:|
   | 基线 | `ec0f228c…` | — |
   | 删 11 份桶三归档·**不 commit** | `ec0f228c…` | **0** |
   | 建 11 个**与归档无关**的文件 | `ec0f228c…` | **0** |
   | 删 11 份桶三归档·**已 commit** | `0c730b95…` | 1（`subjectSha`） |
   | 改 `AGENTS.md`（**阳性对照**） | `79d04b79…` | 1（`entry`） |

   ⇒ 口径「不 commit」：指纹**恒不变**，且**分不清「删 11 个归档」/「建 11 个无关文件」/「什么都不做」**
     ⇒ **恒真空判**，**与 `lab:N43` 同族且落在同一个字段上**（N43 修的是「注入是否投递」，这次漏的是「载体选谁」）。
   ⇒ 口径「已 commit」（处方安全网逐字「git 可逆」⇒ **删除必然 commit**，这是**现实口径**）：
     `subjectSha` 必变 ⇒ **恒假**，而失败原因与命题**毫无关系**。
   ⇒ ✅ **阳性对照不可省**：改 `entry` 面 ⇒ 指纹立刻变 ⇒ 前三行的「不变」才不是装置死值（§2.15 推论三）。

   ⇒ **操作口径**：① 判据的**载体**要与「达成命题的动作」**正交** —— 载体里混进「随任何 commit 必变的量」
   （`HEAD` / 时间戳 / 自增号）就恒假；② 落判据时**逐分量列出载体吃了哪些量**，
   对每一个问「这个量会被我要验的动作改变吗」；③ **恒真与恒假都要查，别只防恒真** ——
   `lab:N43`/§3.2 推论二此前只警告了恒真那一侧。

   ⇒ 推论一（**建设性那一半，⛔ 别只报「判据坏了」**）：**「命题错」与「量具错」是两件事，必须分开报。**
   本例 8 分量中**7 个守恒** ⇒ 处方的命题「确定性注入层结构上不该动」**实测成立**，
   坏的只是载体 ⇒ 报告要给**可选修法方向**（去掉那一维 / 改逐分量比），**⛔ 但不替对方选**（同 §19.3 第 2 条纪律）。

   ⇒ 推论二（**`EXIT` ≠ 判据**）：造故障态下 `EXIT=1` 失败的是**另一条无关控制**（`MN4` 禁 dirty），
   而**那条被验的判据本身是「通过」的**（空判通过）。
   ⇒ **⛔ 别把进程退出码当成「验收结论」** —— 逐条对齐「哪条控制失败了」，否则会把空判通过记成验收失败。

   ⇒ 推论三（**同一量具的两个采集档不可并池**）：同一个 pin 上
   L1-only 采集的指纹 = `f2dc3040…`，真 run（有 transcript）= `87517baf…`，
   差在 `sessionStartDelivered` 分量（**刻意设计**，`MH6`）。
   ⇒ 比对任何指纹类判据前，**先对齐采集档**（有没有 transcript / 有没有 L2），
   否则拿到的「变了」纯粹是口径造成的。

   ⇒ 推论四（**登记面纪律**）：**「未覆盖」清单必须区分「lab 没验」与「对方没做」。**
   实证：lab 把处方 4 整条登记为「未覆盖」，而实测桶三**已被 DS 执行 4/5 项**
   （份数与清单 8/7/2/1 **逐行吻合**，归因 commit subject 逐字含「归档桶三」）。
   ⇒ 写成「未覆盖」会让读者以为**对方没做**，而真实情况是**我没验**。
   与 §19.1「漏登 5 格」同族：**都是 lab 自己的登记面缺陷，⛔ 不是对方的问题。**

17. **「X 面守恒」类判据落地前，先量**载体覆盖率**——「X 面不得变」的前提是「X 面**碰得到**那个动作」，
   而不同面的覆盖率可以差一个数量级。⛔ 覆盖率不量，判据就是在一个自己选小了的面上做守恒。**
   实证（`lab:N50`，2026-08-26 C 格 —— **又是 lab 自己写的**处方 4 验收表第 2 行
   「实读面守恒：删前删后各跑 N=5，比较两组 L2 实读 `.md` 的并集」）：
   量具 `metrics/delete-surface-coverage.mjs`，精确删/移清单 **52** 个文件、N=15 既有 run（**0 个新 run**）：

   | 面 | 命中 | 占比 |
   |---|---:|---:|
   | **实读面**（判据逐字用的载体） | **2** | **3.8%** |
   | 尝试面 | 0 | 0% |
   | **检索面**（Grep/Glob 行首命中，**处方没枚举、采集器不采**） | **33** | **63.5%** |
   | 三个面都没进 | 19 | 36.5% |

   ⇒ 检索面**严格包含**实读面，倍数 **16.5x** ⇒ 判据选了包含关系里**更小**的那个。
   ⇒ 与 `lab:N49` 的两头（恒假 / 恒真空判）是**第三种形态**：**载体覆盖了，但只覆盖 3.8%** ——
     即**载体与作用通道之间存在数量级的口径落差**。
   ⇒ **操作口径**：落「X 不得变 / X 不得少」类判据时，**先算 `|清单 ∩ X 面| / |清单|`**，
     并把这个比值写进判据旁边。⛔ 比值不到 1 就不能说「这条判据管住了那个动作」。

   ⇒ 推论一（**面的枚举必须穷举**）：**「三个面都不在」这类断言，先证面枚举完整。**
   处方 §5.1 逐字「删的东西本来就不在任何一个上下文面里（自动注入面 / 声明面 / 实读面，**三个都不在**）」——
   漏了**检索面**，而它的覆盖率是实读面的 16.5 倍。
   ⚠️ 且这条漏不是没线索：`metrics/context-manifest.mjs` 的口径说明**逐字登记**了
   「⚠️ 仍不含 Grep/Glob 带回的内容」⇒ **量具自己写明的边界，被拿它当验收载体的人没读**。
   ⇒ **拿别人（或自己早先）的量具当验收载体前，先把它的「覆盖边界」逐条与被验动作对一遍。**

   ⇒ 推论二（**事前交集判据 > 事后守恒判据**）：**能改写成「事前交集」的，⛔ 别写成「事后守恒」。**
   | 判法 | 成本 | 覆盖 | 性质 |
   |---|---|---|---|
   | 事前交集「清单 ∩ 删前（实读∪检索）= ∅」 | **0 个新 run**，确定性无噪声 | 63.5% | **事前、可否决** |
   | 事后守恒「删前删后各 N=5 比并集」 | **N=15**（删前 5 + 删后 5 + **建地板 5**） | 3.8% | 事后、只能追认 |
   ⇒ ⚠️ 两者**⛔ 不等价**，别当成同一判据的两种实现。
   ⇒ ⚠️ 还有一条成本陷阱：处方写的是 **N=10**，而守恒判据要判「并集少了一份」**必须先有并集自己的噪声地板**，
     那需要**第三组不重叠的 N=5** ⇒ 真实成本 **N=15**。**⛔ 立守恒判据时把地板那一组一起算进预算。**

   ⇒ 推论三（**随机层上的判据，真阳性自己也有频次**）：**检出功率 = 真阳性在 N 个 run 里的出现频次，⛔ 不是 1。**
   实证：被误删的那份归档只被 **2/5** 个 run 读到 ⇒ 换一组 N=5 很可能一次都碰不到 ⇒ 检出功率 **< 1/2**；
   而同一并集里 freq==1 的成员有 **1–2 份**（不删任何东西、只换一组 N=5 就会「少一份」）
   ⇒ **真阳性淹在假阳性里，报警时分不清是真删错还是随机层抖动。**
   ⇒ **口径**：判据落在随机层上时，**真阳性频次与假阳性面要一起报**，⛔ 只报「能不能测到」是不够的。

   ⇒ 推论四（`lab:E49`，**登记面的陈旧值会被下一格原样抄走**）：
   **「未覆盖」清单里写的**边界**也会过期 —— 抄之前先实测一遍。**
   实证：处方 §5.2 登记边界「GT-002 / GT-003 **一次没跑过**」，而 status §15 标题逐字
   「GT-002 / GT-003 **各铺到 N=5**」（08-25 夜就跑完了）—— **B 格报告 §7 第 1 条把那条边界原样抄了下来**，
   过期约 20 小时。⇒ 与 `lab:N49` 推论四同族，但那条是「lab 没验 vs 对方没做」，
   这条是**「边界本身已经不成立了」** ⇒ **⛔ 引用自己上一格的「未覆盖 / 边界」清单前，先核一遍它还成不成立。**

18. **判「删除 / 移出 / 改路径会不会断」时，⛔ 别只问「会不会断」——那是四个不同的问题，
   而最危险的三个都不会当场报错。且「文档规定的通道」≠「模型实际走的通道」。**
   实证（`lab:N51`，2026-08-26 D 格，被验动作 = 处方 4 桶二「`product-pattern-index.json` 移出 docs 树」）：

   | 问题 | 实测机制（逐字取自 pin `c1db57b8`） | 会报错吗 |
   |---|---|:---:|
   | ① 会不会**当场断** | — | 否 |
   | ② 会不会**静默降级** | `release.mjs:226` `.filter((p) => existsSync(p))` ⇒ 路径被静默过滤，`git add` 不报错、tag 照推；`:172-174` step 1e 逐字「**NON-blocking observer**, NOT a gate」「**不拦发版**，继续」；`scan-mockups.mjs:419` `existsSync(…) ? JSON.parse(…) : {}` ⇒ 累积快照的**历史基线静默丢失**，`:431` 仍印「✓ 已写」+ 一个变小的数 | **否** |
   | ③ 会不会**被写回**（= 移出等于没移出） | `scan-mockups.mjs:430` `writeFileSync(PATTERN_INDEX, …)` **无条件写**，路径来自 `:58`；而每次发版 step 1e 都跑 `health:snapshot` ⇒ 不改 `:58` 就**每次发版把它写回 docs 树** | **否** |
   | ④ 会不会**延迟到下一周期** | 改了写入方路径、没改 `release.mjs:224` ⇒ 新产物不进 `git add` ⇒ 发完版工作树留脏 ⇒ **下一次** release 的 preflight「Working tree not clean」才拦住 | **延迟一整个发版周期** |

   ⇒ **操作口径**：落「移出 / 改路径」类结论前，四个问题**逐个问一遍并分别给证据**。
   ⛔ 只答「不会当场断」就写成「不会断」，会把 ②③④ 全漏掉 —— 而它们比 ① 危险。
   ⇒ ⚠️ ④ 的暴露点与根因**相隔一个周期** ⇒ 所有写死同一路径的地方**必须同 commit 改**，
     且**「同 commit 改」这件事本身要写进处方**（实证：处方 §2 对 `plans` 目录逐字写了
     「**是配置项，必须同 commit 改，否则该闸语义当场破**」，对 `_generated` 那一行**没写**
     ⇒ **登记了依赖、未登记同步性要求**）。

   ⇒ 推论一（**规定通道 ≠ 实际通道**）：**量依赖面时必须量模型**实际**走的通道，
   ⛔ 不能拿文档里规定的通道当依据 —— 哪怕那条规定是 owner 拍定、且模型确实读到了。**
   实证：`AGENTS.md:139` 有一条 owner **2026-08-14 拍定**的编号纪律，逐字
   「11. **跑一次 `pnpm pattern:lookup <本次的 figma URL>`**」；**15/15 run 都 `Read` 了 AGENTS.md 全文
   （33,056 B）⇒ 全部读到了这条纪律，而执行它的是 0 个。**
   实际走的是完全另一条链：`Glob docs/internal/_generated/*` **发现** → 定向 `Grep` 进正文 → 分片 `Read`。
   ⇒ **移出后真正断掉的是「发现」那一步（`Glob` 列不到它），⛔ 不是断在读取。**
   ⇒ ⚠️ 反过来也成立：那条 CLI 旁路移出后**只需改一处**（`pattern-index-lookup.mjs:79`）即恢复，
     且 `AGENTS.md` 因为指的是**命令而非路径**、**根本不需要改** ——
     **「旁路可用」⛔ 不等于「旁路会被用」**（15/15 实测没人走）。

   ⇒ 推论二（`lab:E50`，**主语窄化**）：**引用上一格的登记时，⛔ 别只搬数，先核那个数的**主语**。**
   实证：处方 §2 桶二那一行的「**7 个脚本硬编码了路径**」，主语是
   **整批 `docs/internal/_generated/*.json` `*.jsonl`**（实测那 8 个点名脚本**全部**确实硬编码了
   `_generated/` 下的产物 ⇒ **⛔ 处方没错**）；而 status §21.6 第 3 条 / C 格报告 §9 第 3 条
   把它转述成 **`product-pattern-index.json`（…… + 7 个脚本硬编码）** —— **主语从整批窄化成单个文件**，
   数跟着搬了过来。**实测硬编码该单文件的是 3 个**（写入方 `scan-mockups:58` / 读取方 `lookup:79` /
   发布链 `release:224`），差 2.3 倍。
   ⇒ 与 `lab:N49` 推论四（「lab 没验 vs 对方没做」）、`lab:E49`（「边界本身已过期」）**同族第三种**：
     那两条是**谓语**错和**时效**错，这条是**主语**错。⇒ **三种都是 lab 自己的登记面缺陷，⛔ 不是对方的问题。**

   ⇒ **操作格式（采纳 DS 侧 `docs/meta-rules.md` 触发器 S 的三行块，`cee7265c`，2026-08-26 14:59）**：
   **接手任一已登记待做项前**（§X.Y 的「未覆盖」条目 / 上一轮交接 prompt 的清单 / plan 的某一步，**都算**），
   动手前先输出**三行**：

   ```
   登记记的：  <原文逐字，含主语>
   现取的：    <实测命令 + 读数>
   前提还成不成立：<成立 / 不成立 —— 不成立就说清哪一半没了>
   ```

   ⚠️ **DS 那条把层次分得比 `lab:E49` 更清，照它的分法**：
   「读活源」治的是**事实**过期；触发器 S 治的是**决策前提**过期 ——
   逐字「**活源可以全读对，而那条待做项的存在理由已不成立**」。
   ⇒ 按这个分法：`lab:E49`（边界值过期）属**事实**那一类；**本条（主语窄化）属决策前提那一类** ——
     我 grep 读得完全对（12 个引用文件），错的是那条待做项的**问法**建立在对处方主语的误解上，
     发现它靠的是**多读了一层**（处方 §2 那一行的原文 + 8 个脚本各自硬编码什么）。
   ⚠️ ⛔ **别把两边写成「独立收敛」** —— 两个仓库的 owner 是同一个人，⛔ 也不推断谁先谁后、谁影响谁。
   ✅ **本格实证这个动作有效**：起手在**问用户做哪一格之前**先跑了两次只读 grep 核候选格的前提，
     当场就抓到了「7 个脚本」的主语问题 ⇒ **以后接手「未覆盖清单」里的条目，先做这一步再开工。**

   ⇒ 推论三（**第 17 条推论一的第二次命中，这次栽在 lab 自己上一格新造的量具上**）：
   C 格量具 `metrics/delete-surface-coverage.mjs` 的检索面口径逐字是「Grep/Glob 的 **`tool_result` 里行首**
   出现的路径」，而实测存在**第四种通道**——**定向 Grep 进文件正文**
   （`Grep {"path": "<该 json>", "output_mode": "content"}`，`r007` 3 次 / `r009` 2 次）：
   路径在 **`tool_use` 的 `input.path`** 里、`tool_result` 返回的是**文件正文** ⇒ **它扫的地方根本没有路径。**
   ⇒ 🔴 **C 格正是靠「面的枚举必须穷举」推翻处方 §5.1 的那一格，而它自己新造的量具漏了第四面。**
   ⇒ **口径**：新造一个「面」的量具时，**把已知的工具调用形态逐个过一遍**
     （`Read` / `Grep files` / `Grep content` / `Grep --path <单文件>` / `Glob` / `Bash` 间接），
     并把**扫的是 `tool_use.input` 还是 `tool_result`** 写进边界表。⛔ 只写「扫哪些工具」不够。

19. **同一个目录下的写入方，对「目标目录不在」可以有相反的处置 —— 移出/删除的失效形态由
   `mkdirSync(recursive)` 在不在决定，⛔ 不由目录名决定。且判「会不会断」时，
   四问之外还有第五问：**指着它的文档链接会不会被闸判红**。**
   实证（`lab:N52`，2026-08-26 E 格，被验动作 = 桶二剩余 `_generated` 产物移出）：

   隔离实测：`appendFileSync` / `writeFileSync` 在父目录不在时**都 THROW ENOENT**（目录在则 OK）。
   而同一个 `docs/internal/_generated/` 下的写入方分成两派：

   | 派别 | 谁 | 移出后 |
   |---|---|---|
   | **`mkdirSync(dirname, {recursive:true})` 派** | `f129-…probe.mjs:836` · `a11y-contrast-inspector.mjs:317` · `a11y-token-contrast.mjs:146` · 两个 render spec | **自愈** —— 目录和文件都自己长回来 ⇒ 「移出等于没移出」 |
   | **裸 `append/writeFileSync` 派** | `ds-health-scan-mockups` · `ds-health-scan-consumers` · `release.mjs`（只读不写） | 目录在 ⇒ 静默重建一个**空白**文件；目录不在 ⇒ **ENOENT** |

   ⇒ **操作口径**：判「移出会不会断」时，先分两问 —— **文件不在**与**目录不在**是两种输入，
     ⛔ 别只测前者。目录能不能存活，看的是**有没有别的文件留在里面**（git 不跟踪空目录）
     + **有没有人 `mkdirSync` 它**。
   ⚠️ **⛔ 但别停在单个脚本的控制流上**（本条自己栽过一次，见推论一）。

   ⇒ 推论一（**第 18 条推论一「规定通道 ≠ 实际通道」的变体：单脚本控制流 ≠ 系统实际执行顺序**）：
   我据 ENOENT 推断「发版时快照当场死」，**被自己推翻** —— `release.mjs:79` 的 render 测试
   **先于** `:172` 的 `health:snapshot` 跑，而它的 spec 里那句 `mkdirSync(recursive)`
   已经把目录建回来了 ⇒ ENOENT 到不了 health 那一步。
   ⇒ **量一个 throw 会不会真的发生，要沿着调用方的实际执行顺序走一遍，
     ⛔ 不能只看抛它的那个脚本自己。**
   ⚠️ 同族还有一条：`&&` 链（`health:snapshot` = `A --write && B --write && C`）里
     **第一个抛会把后两个全带掉** ⇒ 「移出产物 X」可以连带打掉「产物 Y 的写入」。

   ⇒ 推论二（**第五问：文档链接**）：第 18 条的四问（当场断 / 静默降级 / 被写回 / 延迟一周期）
   **全都答不了「指着它的文档链接会不会被闸判红」**，而实测这才是整批动作里**唯一当场断**的那一步。
   隔离实测（`git archive` 导出临时目录，pin 与活源 HEAD **各跑一遍**）：
   **移 json/jsonl ⇒ `audit:stale-anchors` `EXIT=0`；再移 4 份 `.md` ⇒ `EXIT=1`、5 条孤儿。**
   ⇒ **口径**：凡「移出/改名/删除**文件**」类动作，四问之后必须加第五问 ——
     **`grep` 现行文档树里指向它的链接，并确认哪道闸在守这些链接**。
   ⚠️ 且实证：**处方对会红的那一步零前置登记，对不会红的那一步写满了前置** ——
     ⇒ 前置登记的密度 ⛔ 不能当风险的代理指标。

   ⇒ 推论三（`lab:N53`，**已经防住一半的 fail-open 最难看见**）：
   `ds-health-delta.mjs:75-85` 的 `criterionChangesBetween` 在 `catch` 里逐字写了
   「git 不可用 / 不在仓库里 ⇒ 如实说『没检查』，⛔ 别静默当成『没动过』」并返回 `null` ——
   **作者明确想过这件事**。但只读实测 `git log … -- '<不存在的 pathspec>'` = **EXIT 0 + 空输出**
   ⇒ 「pathspec 指向的文件被搬走了」这个原因**根本走不到 catch**，函数返回 `[]`（= 没动过）
   ⇒ 判据变更检查静默失效。
   ⇒ **口径**：看到一处 `try/catch` 或 `existsSync` 守卫，**⛔ 别因为「作者写了注释、显然想过」就跳过**
     —— 恰恰要问：**它想到的是哪几个原因？还有哪个原因走的是另一条路却落进了同一个返回值？**
     本例里「git 挂了」进 catch、「路径被搬走」进 try 的空结果，**两者共享同一个下游语义**。

   ⇒ 推论四（**造故障是用来推翻自己的，不只是用来确认判据**）：本格三次判断反转里有两次
   靠自己造的故障翻掉（「表格行进不了候选」被双探针推翻 · 「闸有盲点」被逐字克隆探针定位到
   fenced code block 而推翻）。⚠️ 第二次的入口是**静态枚举 6 行 vs 实测 5 条孤儿差 1** ——
   ⇒ **静态数与实测数不同值时，那个差就是线索，⛔ 别抹平也别只加个限定词了事**
     （与第 16 条「同值时必须带限定词」是同一条纪律的两面）。

   ⇒ 推论五（**知道纪律 ≠ 执行纪律，要单独记**）：本格预注册 §3 开头**专门写了**
   「判定规则必须无空档」并引用了 D 格 H2 落空档的教训，**结果 H5 与 H6 又各落一处空档**
   （H5 没定义「可逆」是否含「需人工合并」；H6 没定义 `r` 取哪个面）。
   ⇒ 与第 18 条推论一「15/15 读到、0 执行」**同构，但这次主语是 lab 自己**。
   ⇒ **口径**：预注册写完判定规则后，**逐条把可能的读数取值列出来**，指着每一个值问
     「它落在哪一档」——⛔ 光写一句「必须无空档」不构成执行。

   ⇒ 推论六（**为善意场景写的守卫会吞掉语义不同的另一个动作**）
   〔🔴 **2026-08-26 A′ 格订正撞号**：本条原编号也是「推论四」，与上一条撞号；
   且它的实证（`§22.2a` / D 格）属**第 18 条**，⛔ 不属本条 —— 只改编号、⛔ 不搬正文，
   免得引它的地方全断。形态正是 §2.4 推论二「编号也是一种口径」那条纪律。〕：
   **`existsSync` / `try-catch` 这类守卫，判的是「东西不在」这个**状态**，
   ⛔ 而它分不清造成这个状态的两件事 ——「**还没生成**」和「**被搬走了**」。
   这两件事该有完全不同的下场，被同一个守卫吞成同一个「跳过」。**
   实证（隔离实测，临时 git repo 内，⛔ 未碰 pin、⛔ 未跑 release）：

   | 动作 | `git add` 收到 | **实测 EXIT** | `run = execSync` 后果 |
   |---|---|:---:|---|
   | 整目录 **gitignore**（文件仍在磁盘 ⇒ `existsSync=true`） | 被 ignore 的路径 | **1** | 抛 ⇒ **当场断** |
   | **移出** docs 树（`.filter(existsSync)` 生效） | 仅剩存在的路径 | **0** | **静默跳过、照常发版** |
   | 移出但假设无 `.filter`（阳性对照） | 混入缺失路径 | **128** | 抛 ⇒ 会断 |

   ⇒ EXIT 取到 **0 / 1 / 128** 三种值 ⇒ 装置活着，那个 `0` ⛔ 不是死值（`lab:N48`）。
   ⇒ `release.mjs:220` 那条注释逐字写明了守卫的**本意**：「`existsSync` 过滤：**首次发版时派生产物
     可能还不存在**，`git add` 一个不存在的路径会直接报错。」—— 本意正当，**吞掉的是另一个动作**。
   ⇒ 这是 §3.1 铁律「**fail closed，不 fail open**」的一个真实反例实例。
   ⇒ **操作口径**：看到 `existsSync(x) ? … : <默认值>` 或 `try/catch` 吞异常时，
     **列出所有能让 `x` 不在的原因**，逐个问「这个原因该走同一个分支吗」。
     ⛔ 只要有两个原因该有不同下场，这个守卫就是个 fail-open。
   ⇒ ⚠️ 附带：**「会当场断」的方案反而更安全**（立刻被发现）。⛔ 但选哪个方案是对方的事，
     lab 只负责把两种动作的失效形态**分别**算出来交出去（本格 gitignore 那条处方**实测成立**，
     ⛔ 不是错的 —— 它只是说的不是同一个动作）。

20. **接手一条已登记的待做项时，「事实还对不对」和「它还该做吗」是两个独立的问题 ——
   而**第二个问题的答案常常就写在被测对象自己的源码注释里**，⛔ 不在任何交接文档里。**
   实证（`lab:N54`，2026-08-26 A′ 格，被验对象 = 处方 §2 桶二整条工作线）：

   DS 侧 `scripts/audit-plan-lifecycle.mjs:103-125` 有一段 📌 注释，逐字自称
   「**这一段是那条决定的唯一真源**」，内容是这两个目录「**为什么刻意留在 docs 树里**」，
   起因**逐字点名 lab 自己的处方 §2 桶二**，并写了三条理由 + **重开条件**。
   ⇒ 即：**桶二已被裁定不做。**
   而实测：那个裁定块的引入 commit **就是 `c1db57b8` 本身** —— C/D/E **三格**测量所用的那个 pin，
   即它**从第一格起就在手里**；lab 全仓 `grep "刻意留在|重开条件"` = **0 命中**，
   只从该文件取过两样东西（耗时 6.2 s、`archiveDir` 是配置项）。
   ⇒ **9 处**提及桶二处置状态、**0 处**知道它是已裁 hold。

   ⇒ **这是第四种登记面缺陷**，与前三种并列（**四种都是 lab 自己的**）：

   | 种 | 错在哪 | 编号 |
   |---|---|---|
   | 谓语错 | 「lab 没验」vs「对方没做」混写 | `lab:N49` 推论四 |
   | 时效错 | 边界值本身已过期 | `lab:E49` |
   | 主语错 | 数搬对了、主语窄化了 | `lab:E50` |
   | **存在理由错** | 事实全读对了，**那条待做项已经不该做了** | **`lab:N54`** |

   ⇒ **操作口径**：§2.18 推论二那个三行块**不够** —— 它只治「登记记的数还对不对」。
     接手前必须再加**第四行**：

   ```
   登记记的：  <原文逐字，含主语>
   现取的：    <实测命令 + 读数>
   前提还成不成立：<成立 / 不成立 —— 不成立就说清哪一半没了>
   它还该做吗：<被测对象的源码注释 / 该动作的 owner 侧真源怎么说 —— grep 「刻意 / 为什么 /
              重开条件 / hold / 不改」这类词，⛔ 别只 grep 那个待做项自己的名字>
   ```

   ⇒ 推论一（**核对方的理由时，最大的风险是变成给它背书**）：本格三条理由核出「两条成立、
   一条的一半被实测推翻」，而**推翻那一半靠的是造故障** —— 我在预注册里已经**接受了** DS 的表述
   （把「`archiveDir` 漏改 ⇒ 当场破」预测成成立），臂 A 实测 `EXIT=0` + ✓ PASS 才翻掉。
   ⇒ **口径**：核别人的判断时，**每一条都要有一个 lab 侧独立可取的读数**，
     ⛔ 「对方写了理由、听起来对」不构成证据 —— 这与 §2.19 推论三「⛔ 别因为作者写了注释就跳过」同源，
     但那条治的是**代码**，这条治的是**决策**。
   ⚠️ 同族第二个形态（**条件化的闸 = 延迟一周期，⛔ 不是当场断**）：
     `audit-plan-lifecycle.mjs:511` 逐字 `if (!archiveExists && expiring > 0)`，注释逐字
     「归档落点**只在本轮真有文件要归档时**才必须存在」⇒ 配置漏改在 `expiring = 0` 的轮次里
     **静默通过**，降级形态是「**✓ PASS + 一个变小的数**」（`已归档 25 份` → `0 份`）。
     ⇒ 归入第 18 条四问的第 ④ 格。⚠️ 且**基线自己就现形过**（`handoffs` 那行印着「（归档落点未建）」
     却没判红）⇒ **看到「守卫在基线上就静默」时，⛔ 别当成自己注入的故障。**

   ⇒ 推论二（**⛔ 别把一个目录的暴露面外推到另一个目录 —— 散文与数据的检索命中率不是一回事**）：
   E 格实测 `_generated/*.json` 三产物在 15 个 run 上 `tool_use.input` **零命中**，
   我据此预测 `_archive/superpowers/plans` 更没人碰。**实测 3/15 命中，其中 2 个 run 拿到正文行** ——
   机制是 **agent 为完成任务对 `<pin>/docs` 做的全树 `Grep`**（逐字
   `Grep {"path":"…/docs","output_mode":"content","-n":true,"head_limit":60}`），
   而 `docs/_archive/` 就在 `docs/` 下 ⇒ **凡 Grep `docs/`，归档必在检索面内。**
   ⇒ **口径**：量「AI 会不会碰到某个目录」时，**分文件形态量** ——
     **散文**（.md、大量自然语言）对域名词查询的命中率远高于**数据**（.json、结构化）；
     ⛔ 别用一类的读数替另一类作答。
   ⚠️ 附带订正一处口径缺口：E 格「这 3 个产物从来没有任何 run **Grep 过**」那句，
     口径是「**返回窗口**」⛔ 不是「**检索面**」—— 同一次 Grep 不截断跑，277 行命中里
     **包含**那几个 `_generated` 产物。⇒ **「Grep 过」必须标取哪个面。**

   ⇒ 推论三（`lab:N47` 的第二个形态：**复现工具的返回序 ≠ 被测通道的返回序**）：
   真实 run 的 `head_limit: 60` 窗口里归档物占 **56/60（93.3%）**，而同一查询不截断时
   归档只占总命中的 **91/277（32.9%）**⇒ 我提「归档挤占了检索窗口配额」。
   **用 `grep -rn` 复现：前 60 行里归档只占 1/60（1.7%）** ⇒ 两个工具**返回序不同**
   ⇒ **「被挤掉的是哪些现行行」这一问答不了，如实记未证。**
   ⇒ **口径**：凡拿一个本地命令去复现 harness 工具的行为，**先问「顺序、截断、去重这三样一样吗」**；
     ⛔ 不一样就只能报「两个读数不同值」这个事实本身，⛔ 不许据此推因果。
   ✅ **而发现它靠的正是 §2.19 推论四**（静态/复现数与实测数不同值 ⇒ 那个差就是线索）：
     1.7% vs 93.3% 那个差，指向的不是被测对象，**是我的量法**。

   ⇒ 推论四（**「判定规则无空档」之外还有第二种规则缺陷：一档里塞了两个不同的判定**）：
   本格五条假设的取值**全部落在预注册的逐值表预先指到的档里**（§2.19 推论五的纪律**这次执行到了**），
   但 H2 那一档写的是「`g_read ≥ 1` ⇒ 推翻 = **重开条件后半句达成**」——
   实测二者**分离**：论据（「没有任何机制引向」）被推翻，而重开条件（「进了某条 onboarding 注入面」）
   按其字面**未达成**。
   ⇒ **口径**：写判定档时，**一档只许绑一个判定**。凡档的措辞里出现「= / 即 / 也就是」把两件事等同起来，
     就要问「这两件事会不会分开发生」——会，就拆成两档。
   ⇒ ⚠️ 并由此立一条交付纪律：**「对方的论据被推翻」与「对方写的重开/复议条件达成」是两件事，
     lab 只交出两句话的差，⛔ 不裁哪个算。**

21. **「档内自查」不能靠找措辞里的『= / 即 / 也就是』—— 焊接常常不在措辞里，在命题本身。**
   实证（`lab:N55`，2026-08-26 A′′ 格）：本格预注册**执行了**第 20 条推论四那条自查、并逐档写了
   「本档绑几个判定」、程序化数过 **53 档 / 52 档单判定**，**仍然漏了一处** ——
   `H1b` 那一档写「`d = 0` ⇒ 推翻」，措辞里**没有任何等号**，但它把
   **技术强制**（闸拦不拦，lab 可实测）与**规范应然**（该不该造新落点，lab ⛔ 不裁）焊在了一起。
   实测二者**分离**：技术上 `d = 0`（删掉落点，闸照跑照 FAIL 照印文案），
   而「该造新落点」这个结论反被**加强**（不造 ⇒ FAIL 文案成为**无守卫的死指针**）。

   ⇒ **改用这个判据**（⛔ 不再只看措辞）：

   ```
   对每一档问：落这一档时，被验命题的【哪些部分】被判了？【哪一部分】没被判？
   ⛔ 凡命题里同时含【可实测的事实】与【应然 / 价值判断】，必须拆档 ——
      前者 lab 判，后者 lab ⛔ 不裁，二者天然不能共用一个档。
   ```

   ⇒ 推论一（**同族裁定块不止一个，且可能在同一个 commit 里**）：A′ 格找到 `audit-plan-lifecycle.mjs:103-125`
   之后，**⛔ 不该停**。A′′ 格按措辞 grep（`唯一真源` / `刻意` / `重开条件` / `20XX-XX-XX 评估`）
   在 DS 侧查到 **3 个**同族块，其中**两个的引入 commit 就是同一个 `c1db57b8`**，
   而 lab 对第二个「9 处提及 0 处知情」升级成「**13 处明文登记为『未追问』、0 处知情**」。
   ⇒ **口径**：第 20 条第四行 grep 到**一个**裁定块后，**把那次 grep 跑完**（穷举同措辞的全部命中），
     ⛔ 别拿第一个命中就收工；**并如实标『按措辞 grep，⛔ 不保证穷尽』。**

   ⇒ 推论二（`lab:N47` 的第三、第四个形态：**取证工具的判定面被自己污染 / 关键词假阳**）：
   本格连中两次，**两次都靠「读数太整齐或太大 ⇒ 先追查再采信」抓到** ——
   ① **判定面自污染**：算「lab 登记面有多少处知情」时，把**本格自己刚写的预注册**算了进去
     ⇒ `q = 14` 全部来自那一个文件，排除后 `q = 0`。
     **⇒ 口径：量『lab 自己的登记面』时，判定面必须排除本格自己的产物。**
   ② **关键词假阳**：查「有没有 run 报告工具截断」时，正则 `截断` 在 16 个 run 上**各命中恰好 1 次**
     —— 精查发现 16 次全是**同一段 DS 文档正文**里讲 UI 表格三状态的「正常 / 截断 / hover tooltip」，
     与工具截断毫无关系 ⇒ **真值 0**。
     **⇒ 口径：读数出现『每个样本恰好 N 次』这类不自然的整齐，先当假阳查，⛔ 别直接采信。**
   ⚠️ 附带第三条：**两次 grep 撑爆输出**（未排 `runs/*/transcript.jsonl` = 799 KB、
     未排 DS 侧 `.claude/worktrees/` 整份工作树副本 = 517 KB）
     ⇒ **口径写死在命令里，⛔ 不靠事后过滤**（与 §2「批量输出走 subagent」同源）。

   ⇒ 推论三（**「无空档」与「档写得对」是两回事** —— 第二次实证）：
   A′ 格五条取值全落在预先指到的档里、仍有一档焊了两个判定；A′′ 格 **14 条**取值全落在预先指到的档里、
   **仍有一档焊接 + 一档定义落空**（`k` 只定义了 `§`/`#` 锚点，实测命中的却是**行号形式** `:384`）。
   ⇒ **口径**：逐值表交付时除了「有没有空档」，还要逐档答**两问** ——
     「**这一档绑了几个判定**」与「**这个读数的取值域，我的定义覆盖全了吗**」。

22. **第 20 条那个四行块**不够用 —— **必须加第五行：「这活我自己是不是已经干过了」。**
   实证（`lab:N56`，2026-08-27 A″′ 格）：起手核候选格前提，四行块**四行全做了**
   （查了 DS 侧源码注释、按第 21 条推论一把裁定词 grep 跑完、撞出归因 commit `483e3feb`
   subject 逐字含「归档桶三」），据此报出「桶三已被 DS 执行而 **lab 零处知情** ⇒ `lab:N54` 第三次命中」。
   **实测 `q = 30` 处知情** —— `docs/round2-status.md` §20.4 与 `AGENTS.md:314`（**本文件自己**）
   早已逐字写着同一结论，含同一个归因 sha 与同样的 8/7/2/1 逐行吻合，
   另有 `ds-reply-2026-08-25.md` 的**逐份列表**及三份报告独立复述。
   ⇒ **不是「lab 不知情」，是「我不知道 lab 已经知情」**，整格 H1–H4 把已交付结论重跑一遍、读数完全相同。

   ⇒ **口径**：接手一条已登记的待做项时，第 20 条四行块后再加一行：

   ```
   lab 自己验过没：<grep 该待做项的【关键读数 / 归因 sha / 结论措辞】在 lab 仓内的命中
                  ⛔ 别只 grep 待做项自己的名字，⛔ 也别只 grep owner 侧>
   ```

   ⇒ **三条纪律互不覆盖**：第 20 条治「**对方**还该不该做」· 第 21 条推论一治「**对方**的裁定不止一个」·
     本条治「**我自己**是不是已经干过了」。本格起手若 `grep -rn "483e3feb" .` 就会立刻命中 30 处。

   ⇒ 推论一（**第五种登记面缺陷：知情面与登记面分叉**）：与前四种并列 ——

   | 种 | 错在哪 | 编号 |
   |---|---|---|
   | 谓语错 | 「lab 没验」vs「对方没做」混写 | `lab:N49` 推论四 |
   | 时效错 | 边界值本身已过期 | `lab:E49` |
   | 主语错 | 数搬对了、主语窄化了 | `lab:E50` |
   | 存在理由错 | 事实全读对了，那条待做项已经不该做了 | `lab:N54` |
   | **知情面分叉** | **lab 已在某格验过并写下正确结论，但那条待做项的登记面没跟着改** | **`lab:N56`** |

   **后果不是「白记一笔」，是后续格在过期的登记面上继续加注、继续排期** ——
   A″ 格就在一条 §20.4 早已判定「已执行」的待做项上，又加了一条前置加注（其前提本格实测两半都不成立）。
   ⇒ **口径：某格判出「对方已做 / 已裁」时，必须当场回改那条待做项的登记面本身（处方正文），
     ⛔ 不能只写进当格报告和 status —— 后者不是下一格的入口，处方正文才是。**

   ⇒ 推论二（**`lab:N47` 第五个形态：`git show --stat` 的路径列会截断**）：
   本格起手按 `--stat` 显示出来的目录名归类，把 `_archive/_archive/translation-md-pre-schema/…` 那份
   算进了 `_design-kickoffs` ⇒ 报出「实删 3 份 / 529 行 vs 登记 2 份 / 210 行」。
   改用 `--name-only` 取全路径后 = **2 份 / 210 行，与登记逐位相同**。
   ⇒ **口径：凡按路径归类，必须用 `--name-only`（全路径），⛔ 不许从 `--stat` 的显示列读目录名。**

   ⇒ 推论三（**同一读数的两个正交维度也会焊接 —— 第 21 条新判据仍拦不住**）：
   本格 H4 的 `q` 逐档写了取值域，但只有「知情 / 不知情」二值，**没有「状态知情但归因错」第三态** ——
   而 `round2-status.md` §25.5 第 6 条正落此态（知道那个目录不在了，却把原因读成「登记的名字写错了」）。
   ⇒ **焊接既不在措辞里、也不在「可实测事实 vs 应然判断」这条轴上，而在
     「同一个读数的两个正交维度」（**状态** / **归因**）。**
   ⇒ **口径：取值域自查时，除了「值域覆盖全没有」，还要问「这个读数是不是其实是两个维度压成一个」。**

   ⇒ 推论四（**换一道闸，结论可能反号 —— 「技术阻断成不成立」必须标是哪道闸**）：
   A″ 格实测删 `STATUS-CHANGELOG.md` ⇒ `audit:doc-shape` **EXIT=0 ✓ PASS 空 diff**，判「技术阻断读法不成立」；
   本格同 pin 同副本换 `audit:stale-anchors` ⇒ **EXIT=1，24 个孤儿当场断**。
   ⇒ **两道闸给出相反答案**，那句在它自己的口径内对，但「删不了」在另一条路径上**是成立的**。
   ⇒ **口径：报「删得掉 / 删不掉」「拦不拦得住」这类结论时，必须标是在哪道闸上测的；
     ⛔ 一道闸绿不等于这个动作没有技术代价**（`§2.19` 推论四同族：口径不同 ⇒ 落不同档）。

   ⇒ 推论五（🔴 **`§2.21` 推论二①那条「排除本格自己的产物」不够 —— 文件级 `--exclude` 拦不住
     「追加进既有判定面文件的段落」**）：本格**交付前自核**时 `p` / `q` 从 `68 / 30` 涨到 `77 / 41`，
     差值正是刚写进 `docs/round2-status.md` §26 与**本文件第 22 条**的内容 ——
     而这两个文件**本身就是判定面的一部分**，`--exclude <本格产物文件名>` 对它们**结构性无效**。
   ⇒ **口径：量「lab 自己的登记面」时，判定面取【跑前那个 commit 的树】** ——
     `git archive <预注册 commit> | tar -x -C "$(mktemp -d)"` 后在导出树上 grep，
     ⛔ **不在工作树当前状态上量**。这样文件级与段落级污染一次排干净。
   ⚠️ 本格靠它把假阳挡在交付之前；⚠️ 同时**又一次印证「自核脚本自己的期望值也要核」** ——
     那两条红是**假阳**（口径错在脚本，不在报告），而同一次自核里 §25.5 行号那条是**真红**。
     ⇒ **口径：自核报红时，先判「红在被核对象还是红在自核脚本的口径」，⛔ 别把它的红直接当结论。**

## 3. 写判据脚本的铁律（第一轮踩出来的）

1. **fail closed，不 fail open。** 输入面塌了要抛，不要静默降级成「干净 / 不存活 / 0 命中」。
   ⛔ 尤其禁止用 `try/catch` 把异常吞成 `false`——第一轮的 `resolveRuleRef` 就这么让一条判据对 53 份**全部恒假**，
   而脚本照常输出「分类完成」。
2. **每条判据配 must-hit + must-not-hit 控制，并内建进脚本**，签名一变就当场抛。
   **这条已有四次独立实证，不是形式主义**：① CI 收割器的矩阵双腿重复计数（408 vs 真实 382）；
   ② 写输出契约盘点时，我用单行 `grep 'console.log(JSON.stringify'` 把**跨行发射**的
   `audit-tokenized-diff` 判成「无结构化发射」，并把这个错判写成了 must-not-hit ——
   **是那条控制自己失败，把我的假设打回来的**。
   ③ 被测对象换了发射形态（`console.log(JSON.stringify(x))` → `emitGateOutput(buildGateOutput({…}))`），
   9 条 `json-only` 在旧判据下**全部塌成 `silent`** —— 不拦就会报出「7b 把结构化输出从 9 条干到 0 条」
   这个**反向的假读数**（N28）；④ 函数体切片吃进下一个函数的 JSDoc，把纯构造器判成发射器（N29）。
   ⇒ 推论一：**控制也要写「我认为它不该命中」的那一侧**，只写 must-hit 抓不到这类。
   ⇒ 推论二（③ 的教训）：**量具的形态枚举会随被测对象演化而过期。**
   控制要钉在「我认为**这条闸**应该是什么形态」这种**具名事实**上，
   ⛔ 不能钉「解析器跑通了没有 / 有没有抛异常」—— 后者在形态换代时恒真。
   ⇒ 推论三：控制**必须走真代码路径**，不能测它的副本。测副本的控制在真路径改了之后照样绿。
   ⇒ 推论四：**控制集可以按被测对象的形态分档**（如「契约前 / 契约后」），
   但那是**两档都断言**，⛔ 不是在新形态上把控制放松。
3. **判据是「调用位置 / 结构匹配」，不是「文件里提到过」。** 放宽成提到过 ⇒ 注释与散文被算成命中。
   （实证：`§Sprint` / `§Pre-Phase` 被当成规则号，把「提到 §规则」虚高成 30 份，实际 11 份。）
   ⇒ **操作口径：凡文本切片判据，先去注释再切。** 注释是这条铁律最容易复发的形态 ——
   而且**不只判据面，送出面同样适用**（6′ 实证）：给他厂 juror 送产物切片做黑盒判时，
   切片里模型自己写的注释 `<!-- …（Popup Box）-->` **就是答案本身**，送出去 juror 抄一遍就"答对"，
   交叉校验整个失效。⇒ **凡要送出去被独立判定的材料，先剥注释。**
   同一轮还栽了配套的一跤：泄题判据第一版写成 `/PopupBox/`，对**带空格的 `Popup Box`** 判 0 命中。
   ⇒ **判据要钉形态不钉字面**（`/popup\s*box/i`），否则「太字面」这条错误会从判据面平移到送出面。
   实证 N29：反解「哪些导出会写 stdout」时，函数体切片的右界取「下一个 `export function`」，
   于是**下一个函数的 JSDoc** 落进了上一个的体内，而那段注释逐字写着 `process.stdout.write`
   ⇒ 一个纯构造器被判成了发射器。是 must-not-hit 抓回来的。
4. **登记覆盖边界，写在头注释里，标明「这是边界不是 TODO」。** 范式抄 DS 的 `audit-gate-ci-parity.mjs`。
5. **计数与归因分开说。** 计数可靠不代表归因可靠（实证：逃逸值按原始值反查 token 会跨语义类别碰撞）。
6. **耗时测量丢弃第一次**（实证：冷启动 3.4 倍）。
7. **同一个量做上下两个方向的口径，再对差集逐条解释。**
   must-hit/must-not-hit 验的是「判据自身没塌」，**验不出「我压根没想到还有这种形态」**——
   那要靠**双向夹逼**：一个刻意从宽（上界）、一个刻意从严（下界），差集必须能逐条说清。
   差集里出现真命中 ⇒ 严的那侧漏了形态；两侧**收敛**才是「形态枚举穷尽」的证据。
   （实证 E20：`path 口径`（下界）漏了行内代码 span 里的相对路径，靠 `basename 口径`（上界）
   的 3 份差集炸出来 —— 其中 2 份是核心现行文档给**存活规则**举的证据出处，
   按补漏前读数会被判成「0 引用、可无人审核删除」。补漏后两口径收敛。）
8. **别人的闸不等于你的安全网 —— 先量它的覆盖面，再依赖它。**
   spec 曾把「删完跑 DS 自己的 gate，删错立刻红」当安全网。实测那两条闸对归档删除
   **近乎零覆盖**（删 34 份，锚点读数一字未变）：一条闸的扫描面只有 3 个文件，且行内代码 span 里的
   路径**刻意不校验**。⇒ 依赖外部闸做验收前，必须先**造故障验证它会拦**（这条 DS 自己也立过：
   `working-principles.md`「新增闸必须造故障验证它会拦，跑一遍绿不算验证」）。见勘误 E19。
   **§3.8 与 §3.2 不可互相替代 —— 已有干净实证（N27）**：DS 收割器的 6 条内建控制全绿，
   造故障却发现它对 `findings>0 ∧ checkedUnits=0` 这种自相矛盾读数**不报、照样 exit 0**。
   原因是控制测的是「判据按真值表跑对了没有」，而缺的是**真值表本身少了一格**。
   ⇒ **控制验判据没塌；双向夹逼（§3.7）验形态枚举穷尽；造故障验「表/判据集本身有没有漏一格」。三件事。**
   ⇒ **造故障时优先造「格式合法但内容有毒」那一种。** 实证（第 10 步 5 次注入）：篡改字节 / 删文件 /
   多文件 / 引文失效 4 种都能被 sha 校验或双向夹逼兜住，**只有「重新冻结过、sha 完全对得上、
   但 prompt 里泄漏了答案」那一次是唯有 must-not-hit 拦得住的** —— 结构校验对它完全无感。
   造故障的操作纪律：① **先证故障态成立**（贴出被改对象的实际输出，⛔ 别改完直接跑闸）；
   ② 用完 `git checkout` 还原并核 `git status` 为空；③ **注入本身也要验**——
   实证：本轮第一次注入的 `perl -0pi -e 's/^emitGateOutput…/'` 因锚了行首而没生效，
   闸「照常绿」，差点被读成「收割器不会拦」。**marker 计数没涨就不算注入成功。**

9. **测量装置的失败会伪装成被测对象的行为。** 已三次实证，且三次都长得像「被测对象坏了」：
   ① `sh -c` 缺 `node_modules/.bin` 的 PATH ⇒ `lint:ds` 报 exit 127，读起来像「lint 挂了」（N30）；
   ② 取被测进程 exit code 时接了管道 ⇒ 读到的是 `tail` 的退出码，一条本该 exit 1 的闸显示成 **exit 0**，
   读起来像「这条闸不拦」（N38）；③ markdown 表按 `split('|')` 切列，遇到单元格内嵌竖线静默错列（N37 同批）。
   ⇒ **操作口径：读到一个「被测对象表现异常」的读数时，先证自己的装置没坏，再归因。**
   尤其 exit code —— 确认没在读管道末端那一节的。
   ⚠️ **zsh 下 `${PIPESTATUS[0]}` 是空的**（zsh 用 `$pipestatus[1]`）⇒ 这条在 6′ 又复发一次。
   量具里取被测进程退出码一律用 `spawnSync(...).status`，**⛔ 不经 shell**。

   ⚠️ 🔴 **zsh 第三个坑（`lab:N68`，2026-09-14 §40.6 实测）：`MULTIOS` 会让
   `cmd 2>&1 >/dev/null | wc -c` 静默变成「量两条流之和」。**
   zsh **默认开 `MULTIOS`** ⇒ 同一个 fd 被多次重定向时它**同时**发到多个目标，
   于是 `>/dev/null` ⛔ 不像 bash 那样把 stdout 从管道里摘走。
   实测同一条命令：纯 stderr **280** · 纯 stdout **209** · 该写法 **489**（= 两者之和）·
   加 `setopt NO_MULTIOS` 后回到 **280**。
   ⇒ 🔴 **489 在它出现的位置「看起来完全合理」**（一个比 280 大的数，读者会归因成
   「换了棵树所以多打了点东西」）—— 正是本条主文说的「装置故障伪装成被测对象的行为」。
   ⇒ **口径：zsh 下量单条流，一律 `2> file` / `> file` 分开重定向再 `wc`**，
   ⛔ 不用任何「靠重定向顺序」的写法（它在 bash 下对、在 zsh 下错，而且不报错）。
   ✅ 抓到它靠的是 §2.19 推论四（实测数与预期数不同值 ⇒ **那个差就是线索**），⛔ 不是复盘想出来的。

   ⚠️ 🔴 **批量注入的第二道验证（`lab:N69`，2026-09-14 §41.5 实测）：marker 计数只证明
   「字节写进去了」，⛔ 不证明「文件还能解析」⇒ 批量注入后必须逐个 `node --check`。**
   实证：给 7 条闸批量插一行 `globalThis.console.warn = () => {}`，插在**文件第一行之前** ——
   而其中 **4 条以 `#!/usr/bin/env node` 开头** ⇒ shebang 不再是第一行 ⇒ `SyntaxError`。
   marker 计数 **7/7 通过**（字节确实写进去了），全量 vitest 却读到 **28 failed**。
   ⇒ 🔴 **28 在它出现的位置「看起来完全合理」** —— 它比上一格同一指标的 **6** 大，
   而两格之间被测仓确实提过 3 个 commit ⇒ 极易归因成「测试集长大了所以红得多」。
   ✅ **抓到它靠的是第二个读数对不上**（仍是 §2.19 推论四）：
   **total test 数 3427 vs 基线 3491 —— 那个数该相等**，差 64 ⇒ 有整个文件没被收集。
   ⇒ **口径**：① 批量注入后逐个 `node --check`；② **注入位置要按文件形态分档**
   （有 shebang 插第 2 行 / 无则插第 1 行），⛔ 别用一个位置套所有文件；
   ③ 造故障的全量读数必须**与零注入基线并排报 total**，⛔ 只报 failed 数会漏掉这一整类。
   ⚠️ 🔴 **第三道验证（`lab:N73`，2026-09-14 §43.5 实测 —— 上面那两道**都过了**，注入仍是坏的）：
   `node --check` 只验语法，⛔ 不验「注入的代码是不是我写的那句」。**
   实证：用 `node -e '…'` 做注入，内嵌的 `'MARKER\n'` 里又有单引号 ⇒ **shell 提前闭合**
   ⇒ 写进文件的是 `process.stdout.write(MARKER_TOPLEVEL\n)`（**引号没了**）。
   marker 计数 **3/3 通过**、`node --check` **OK** —— 因为它**语法完全合法**（一个未定义标识符），
   真跑才 `ReferenceError`。⇒ 两道现成的验证**一道都没拦住**。
   ⇒ **口径**：① 注入后**把注入行原文打出来肉眼核**（`grep -n <marker> <file>`），这是第三道；
   ② **注入脚本一律写成文件**（`heredoc <<'EOF'` 阻止展开）再 `node <file>`，
   ⛔ 不用 `node -e` / `perl -e` 内嵌带引号的代码 —— 那条路上 shell 与 JS 抢同一批引号；
   ③ **锚必须唯一**（`s.split(a).length-1 !== 1` 即抛），⛔ 不用 `replace` 的默认「换第一个」。
   ⇒ ⚠️ **同轮附带一条口径**：查残留 marker 用**宽前缀**（`MARKER_`）得 2 个文件，
   精查全是被测对象**自带**的标识符（`HANDOFF_MARKER_RE` / `SOURCE_MARKER_RE`）
   ⇒ **残留检查只认自己那几个具名 marker，⛔ 不用宽前缀**（同 §2.21 推论二②关键词假阳）。
   ✅ 选一个不像被测对象会有的前缀（本格用 `ZZPROBE_`）可以一起解决这件事。

   ⚠️ 与 §40.8 第 2 条已登记的边界同族但更进一步：那条说 marker 不证明「那行代码被求值」，
   这条说它连「文件能不能解析」都不证明。

   ⇒ **第二种形态（6′ 新增，N42）：装置不是「坏了」，是「根本没被验证过就用来下结论」。**
   实证：临时 `grep` 冒充受控量具，一轮内连出两个假读数 ——
   ① 拿 `--tvu-` 当 DS 的 token 前缀（实际是 `--text-*`/`--sp-*`…）⇒ 误得「模型自造 token 体系」；
   ② `grep -c` 数的是**行**不是**出现次数** ⇒ `<tr>`/`<nav>` 计数全错。
   前四次同族都是装置**坏了**（PATH / 管道 / 分列），这两次是**装置从未被校准**。
   ⇒ **凡要写进报告的数，必须出自带 must-hit/must-not-hit 的量具；
   一次性 grep 只能用来找线索，⛔ 不能用来下结论。**

11. **「X 不可得」这类否定结论，必须用多层判据复核后才能写进报告。**
   实证 N41/N44：`command -v` 对 `claude` 报 absent，实为 npm 的 bin symlink 被挪走
   + VSCode 扩展里另有一份完好的；同一个判据还让第 10 步写下「7 个他厂 CLI **全 absent**」——
   而 `codex-cli` 就藏在 `~/.vscode/extensions/openai.chatgpt-*/bin/` 里，**可执行且已鉴权**。
   ⇒ **最少四层**：① PATH ② 包管理器全局目录（含被挪走/改名的 bin）
   ③ brew / pipx / `/Applications` ④ **编辑器扩展捆绑的二进制**。
   ⇒ 与 §3.10 同源但方向相反：§3.10 是「0 命中 ⇒ 可删」，这条是「0 命中 ⇒ 不可得」——
   **两者都是拿一个未声明扫描面的空集当结论。**

12. **一次工具调用 ≠ 一次成功的观测。反解 transcript 的采集器必须看 `tool_result` 的成败。**
   实证 **N46**：`context-manifest.mjs` 只数 `tool_use` 不看 `tool_result.is_error`，
   于是把「模型试了但工具拒了」的读当成成功读。两种形态、两种损害：
   ① **文件不存在** ⇒ 幽灵进实读面（份数虚高）——这个被 `MN6` **偶然**拦到（它钉的是「文件必须存在」）；
   ② **整文件超 256 KB 被拒** ⇒ 文件**存在**，`MN6` 一声没吭，却被按 `coverage: whole-file`
      **计满 327,571 B** ⇒ 该 run 的 L2 字节**虚高 2.18 倍**。
   ⇒ **② 才是真损害，而拦住 ① 的那条控制对 ② 完全无感** —— 又一个 §3.8「真值表本身少一格」：
   控制集当时缺的不是一条判据，是**「读失败」这整个类别**。
   ⇒ **操作口径**：① `tool_use` 配不到 `tool_result` 直接抛（⛔ 不默认它成功）；
   ② 成功面与失败面**分两层记**，失败面字节恒 0；
   ③ 「模型尝试过」与「内容真进了上下文」是**两个口径**，按 §3.7 并排记、差集逐条解释；
   ④ 同一路径可以**同时**在两层（实证：一份文档 3 次读 = 1 次整文件被拒 + 2 次分片成功），
      判据要写「**从未成功过**的路径不得入实读面」，⛔ 不是「出现在失败面就不许在成功面」。
   ⇒ 与 §3.9 同源但方向相反：§3.9 是**装置的失败**伪装成被测对象的行为；
   这条是**被测对象的正常失败**被装置记成了成功。

13. **量具的缺省值不得让主键留空 —— 那是 fail open。**
   实证：`context-manifest.mjs` 的 `--model-id` 缺省是 `null`，注释写着「真 run 必给」却**没有控制强制**
   ⇒ 一次忘给参数就静默产出 `modelId: null` 的 manifest，直接违反 §2.1「缺则作废」。
   ⇒ 凡 §5.2 三元组主键字段，都要有一条 must-hit 在「这是真 run」的前提下断言它非空。

14. **否定结论的扫描面要覆盖「能力通道的种类」，不只是「实现载体」。**
   实证 **E38**：「T2 陪审团开不了」被定义成「他厂 **CLI** 在不在」，扫了四层载体（PATH / 包管理器 /
   brew·Applications / 编辑器扩展）都没找到第三家 ⇒ 写进报告的是「不可得」。
   **但 §6.1 铁律 1 要的是「不同厂商的模型」，不是「不同的 CLI」—— 一个 API key 就够，不需要装 CLI。**
   ⇒ 补上第五层（**模型访问权**：环境变量 / shell 配置里声明过的 key）与第六层
   （**登录态 / 本地推理宿主**：`~/.ollama` `~/.gemini` `~/.config/gcloud` `~/.lmstudio` `~/.cache/huggingface`）
   之后，结论才站得住：可得**两家**厂商，缺的是**第三家**，不是「一家都没有」。
   ⇒ 与 §3.11 同源但更深一层：§3.11 漏的是**一个目录**，这条漏的是**一整类通道**。
   ⇒ **操作口径**：写「X 不可得」之前，先把 X 的定义摊开 ——
   问「我扫的是 X 本身，还是 X 的某一种实现形态？」⛔ 只扫载体就下否定结论，是把口径当结论。
   ⇒ **活量具的头注释里尤其要清理这类 stale 否定结论** —— 它是下一个读者的入口，
   比报告里的同一句话更危险（实证：`noise-floor.mjs` 边界 ① 逐字写着「7 个他厂 CLI 全 absent」，
   而 N41/N44 早已推翻它）。改完必须证明**读数 no-op**（逐字段 diff = 0 行）。

10. **判「0 引用 / 0 命中 ⇒ 可删」之前，先问「有没有扫描面之外的消费者」。**
   实证 N37：DS 的入站引用图只扫 DS 仓内，而 lab 的 golden set 冻结物引着
   `_archive/_design-kickoffs/` —— 那个目录正因「外部入站 = 0」被列进真删清单。
   ⇒ 引用图的**扫描面边界**本身就是一类系统性盲区，与 E20（形态漏了一类）不同：
   E20 是同一个面里少看了一种形态，这一条是**整个消费者所在的仓不在面里**。

15. **措辞匹配类量具只判到【规则名】那一层 —— ⛔ 不许拿它的读数回答「删得不得 / 重不重复」。
   它给的是**分母**（哪几处载体、各有哪几条），⛔ 不是**丰度**（同名那条正文里有没有对方没有的句子）。**
   实证（`lab:N65`，2026-09-10 §24.3）：`metrics/style-rule-carriers.mjs` 判出
   lab `AGENTS.md §4.1` 有 **3 条规则名**与 DS 七条重合 ⇒ 按量具读数可以写成「3 条纯重复、收成指针」。
   **逐条把两边正文摊开人工比，翻掉了这个结论** —— 那 3 条里只有 1 条（R5「清晰优先」）可无损去重；
   另 2 条各带**一句 DS 三份副本里一个字都没有的具体化**
   （R6 那条的「不假设读者记得上一轮的编号 / 读数 / 文件名」· R7 那条的「⛔ 不为显得严谨堆叠订正史」）
   ⇒ 照量具读数去收指针，会**静默丢掉那 2 句**。
   ⇒ 与 [[dedupe-check-which-copy-is-richer]]（真源可能是更薄的那份）同族，
   但那条治的是**选哪份当真源**，这条治的是**量具结构上测不到的那一层**。
   ⇒ **操作口径**：① 量具报「某条在 N 处都有」时，**必须同时报该条在各处的正文字节数**；
   ② 凡结论形如「可删 / 可收成指针 / 纯重复」，**逐条比正文这一步机器代不了，必须人工做并在报告里留痕**；
   ③ 把这件事**钉成量具自己的一条控制**（⛔ 别只写在报告里）——
   `style-rule-carriers.mjs` 的 `MN5` 即此：断言「名字相同的那条，两处正文长度**不同**」，
   于是任何人跑量具都会看到「同名 ≠ 同内容」这个事实，⛔ 而不是靠下次还记得（同 §3.2 推论一）。
   ⚠️ **边界**：`MN5` 钉的是「量具知道自己测不到丰度」，⛔ **它不能替人做那次逐条正文比**。

16. **写「A ⇒ B」这类因果句之前，把 A 与 B 之间那个【连接】单独跑一次。
   ⛔ 「我跑了 A、A 是红的」⛔ 不构成「A 会在 B 这个场景里发生」。**
   实证（`lab:N66`，2026-09-11 一轮内**同一个毛病三种形态**，⛔ 不是三条独立的错）：

   | # | 我推的 | 缺的那个连接 | 实测 |
   |---|---|---|---|
   | 1 | 「`stale-anchors` 跑出来是红的」+「我要改 `docs/` 下的 `.md`」⇒「提交会被挡」 | **触发面** | hook 的触发条件逐字只含**五份**文档 + 闸脚本 ⇒ `backlog.md` **不在里面** ⇒ 那次提交本来就做得了 |
   | 2 | 「`grep "stale-anchors" pr-checks.yml` = 0 命中」⇒「CI 不跑它」 | **调用链** | 它**在** CI 里 —— 经 `pnpm run prepublishOnly` → `run-gate-chain.mjs` **间接调用**，workflow 的字面只有一行 `run: pnpm run prepublishOnly` |
   | 3 | 「`git archive` 导出的是同一棵树」⇒「等价于 CI 的 checkout」 | **装置与被测环境的差异** | 导出树**没有 `.git`**，而其中一条断言逐字是「marker 当前被 **git 跟踪**」⇒ 6 个文件假红。换 `git clone` + checkout 后才可用 |

   ⇒ 🔴 **代价是叠加的**：第 2 条让我**把一个自己起手就已经跑出来的正确读数**
   （`stale-anchors EXIT=1`）**排除出了候选**，于是第 3 条又造了一个坏装置去找「别的红因」——
   **两次错误串起来，比单独一次远得多。**
   ⇒ **操作口径**：因果句里的每个箭头都要有自己的读数。
   典型的三种连接：**触发面**（这条规则什么时候才跑）· **调用链**（它是不是被别的入口间接调用）·
   **装置差异**（我的复现环境与真实环境差哪几个维度）。
   ⇒ ✅ **抓到它的动作是固定的一条，⛔ 不是「再想一遍」**：
   **拿一个独立读数去撞它**（实测触发条件 / 实跑那条链 / 换一种装置重做）。
   本轮三次**全部**由此抓到，⛔ 零次靠复盘想出来。
   ⇒ 与 §3.14 同源但不同层：§3.14 治「否定结论的**扫描面**漏了一类通道」，
   本条治「**推理链**里有一环没验过」——⛔ 前者漏的是面，后者漏的是箭头。

   ⇒ 推论一（**第四种连接：命令的输出面**，`lab:N67`，2026-09-11 §28 实证）：
   **「我跑了这条命令、它没报错」⛔ 不构成「我要的那个事实已经读到了」——
   先问「这个命令的输出面里到底有没有那个字段」。**
   实证：起手核 DS 仓状态用的是 `git status --porcelain`，而它（不带 `-b`）
   **结构上就不输出 branch header** ⇒ 全程以为在 `master` 上，`git commit` 落到了
   并行 session 的 feature 分支上。⛔ 命令跑通了、读数也对，**缺的字段压根没进输出**。
   ⇒ **操作口径**：① 核仓库状态一律 `git status -sb`，或显式
   `git rev-parse --abbrev-ref HEAD`；② 更一般地 —— 凡把某条命令的**沉默**当成一个事实的
   确认（「没报错 ⇒ 在对的分支 / 没冲突 / 没别人在改」），先把该命令的**输出面字段表**过一遍。
   ⇒ 与前三种连接的差别：触发面 / 调用链 / 装置差异漏的都是**被测对象那一侧**，
   这一条漏的是**量具的输出契约**。
   ⇒ ⚠️ 同轮另一个同族（**判定面为空的 0**）：造故障探针 `git add` 了一个**未修改**的文件
   ⇒ `git diff --cached` 为空 ⇒ 五臂**全阴（含两个对照臂）**。命令全部 `exit 0`、
   ⛔ 不是「命令失败的 0」，是**第五种 0：命令跑通了、判定面是空的**。
   ⇒ **口径**：造故障探针必须**断言判定面非空**（本例 `staged ≥ 1 否则抛`），
   ⛔ 不许只断言「注入生效」（同 `lab:N48`，但那条治判据、这条治**探针**）。

   ⇒ 推论二（**第五种连接：别人给的取数口径缺了一维**，`lab:N72`，2026-09-14 §42.6 实证）：
   **交接单 / 文档里写死的取数口径，要逐维核它有没有写全 —— 缺的那一维会让判据恒不成立，
   而那个「一直没到终态」看起来完全合理。**
   实证：交接单逐字写「Gitea `statuses/<sha>` 取 **id 最大**那条」——**没写字段名**。
   我按 `state` 取，实测字段名是 **`status`** ⇒ `state` 恒 `undefined`
   ⇒ 轮询的终态判据 `*state=success*` **永远匹配不到** ⇒ 会跑满 40 次 / 20 分钟然后退出，
   而那**会被读成「CI 一直没出终态」** —— 即把**装置故障**读成**被测对象的状态**（§3.9 主文）。
   ✅ **抓到它靠的是「一条记录不可能只坏一半」**（§2.19 推论四）：同一条 JSON 里
   `description` 读到了「Successful in 7m16s」、`state` 却是 `undefined`
   ⇒ **两个字段的读数不该有这种落差**。
   ⇒ **口径**：① 照别人的取数口径动手前，**先拿一个已知终态的样本做阳性对照**，
   并**把每个要用的字段都打印出来**（⛔ 不只打印最终判定）；
   ② 判定式依赖的字段，**逐个确认它在真实响应里存在** ——
   ⛔ `undefined` 不会报错，它只会让判据恒假。
   ⚠️ 与推论一的差别：那条漏的是**命令的输出面有没有那个字段**，
   这条漏的是**我以为的字段名与真实字段名不同** —— 前者字段不存在，后者**存在但叫别的名字**。

## 4. 不接受文字总结（§6.1 铁律 3）

agent 判定只输出结构化 JSON（`verdict` + 证据定位 + `confidence`）。
禁止「通过 / 完成 / N 项 pass」式断言——**包括 lab 自己写给用户的结论**：
凡「完成声明」会驱动下一步动作（提交、删除、告知已解决），必须先拿到可复核证据。

### 4.1 给 owner 的表达（2026-09-09 加）

⛔ **真源已上移，本条只留指针**（owner 2026-09-11 拍板）——
走 **DS 仓 `AGENTS.md` §AI 表达风格 → 小节「对 owner 的输出（额外）」**
（七条本体 + 那四条额外要求 + 语言分层表 + 违反信号，都在那一节）。

**为什么搬**：owner 2026-09-10 在 DS 立了「本节是表达风格的**唯一真源**，作用面 = 任何 AI 工具 ×
任何场合的任何输出」。而本节当时有 **2 条规则 + 2 句具体化**是那份真源里一个字都没有的
（「先结论、再依据」·「代号出现时必须跟一句它指的是什么」·「不假设读者记得上一轮的编号 / 读数 /
文件名」·「⛔ 不为显得严谨堆叠订正史」）⇒ 「唯一真源」那句当时**不成立**。
2026-09-11 owner 拍「加子节」⇒ 四处已逐字搬进 DS，本节收成指针 ⇒ 那句自称现在成立了。

**立规实证（⛔ 不随内容搬走，它是 lab 侧的账）**：
owner 2026-09-09 13:34 逐字「12 是代号，没讲清楚什么冲突」；同日下午逐字
「ai-ds-lab……目前不知道结果如何」——当时报告 66 份、处方 16 份，owner 一份结论都没读进去
⇒ **问题不在量，在表达**。此前这条只活在 session memory（`ask-owner-with-source-text-not-jargon`）里，
⇒ 违反「纪律下沉到机制不是 prompt」，2026-09-09 迁入本文件，2026-09-11 再上移到跨工具真源。
读数与逐条正文比 ⇒ [`docs/2026-09-09-ds-slim-optimize-review.md` §24.3 / §25 / §27](docs/2026-09-09-ds-slim-optimize-review.md)。

⚠️ 与 [`docs/decision-queue.md`](docs/decision-queue.md) §1 的写法上限是同一条纪律的两半：
那条管**多长**，DS 那节管**怎么写**。
⚠️ **⛔ 别在这里重新维护一份副本** —— 本节收成指针的全部意义就是不再有第二份会漂的正文；
量具 `metrics/style-rule-carriers.mjs` 的 `MN5` 钉着这件事（本节再出现七条/四条的本体就红）。

## 5. AI 中立（D4）

`metrics/` 与 `adapters/` 必须是纯 Node、零依赖、不依赖任何 AI harness 的特有能力。
lab 可以被任何 AI 驱动，也可以被人手工驱动。

23. **「引用 ≠ 定义」，且「覆没覆盖到」必须标【路径口径】—— 判定面的边界比措辞更能决定结论。**
   实证（`lab:N57`，2026-08-27 A⁗ 格）：核 `Ruling-N` 编号裁定体系，三条互不覆盖的口径各中一次。

   ⇒ **口径一（引用 ≠ 定义）**：判某处是不是真源，要问「它是在**用**这个编号，还是在**定义**它」。
     本格三个载体各含 1–2 个编号，**全部是「用编号 + 顺带描述效果」**，⛔ 无一是定义面。
     ⚠️ 而我起手把 `criteria-that-never-fire.md` 的表末列读成「处置」，实测表头逐字是
     「**谁发现的**」⇒ **状态对（知道它在那儿）、归因错（读错了它是什么）**，正是第 22 条推论三那条轴。
     ⇒ **判据**：定义面 = **≥2 个不同编号 + 各自的裁定正文**；只给后果 / 只给溯源的，一律算引用。
     ⚠️ 宽严两个口径都报，⛔ 别只报一个。

   ⇒ **口径二（「某次 grep 覆没覆盖到」必须标路径口径）**：§26.7#6 写「A″ 格的措辞 grep
     没覆盖到这一族」。实测**三套措辞集**（A″ `plan:52` 六个 / `plan:73` 四个 / 我预注册的四个）
     在同一口径下读数**完全相同**；而**换路径口径就反号** ——
     A″ 自己的口径（`scripts/*.mjs` + `docs/meta-rules/`）⇒ `h=0` ✅ 成立；
     全仓口径 ⇒ `h=1`（`pr-checks.yml:263` 的「刻意」）⇒ 🔴 不成立。
     ⇒ **决定结论的是判定面的边界，⛔ 不是措辞集。** 与第 22 条推论四「必须标是哪道闸」同族。
     ⚠️ **同一份 plan 里还记了两套互不相同的措辞集**（`:52` vs `:73`）⇒ 「我当时用了什么口径」
       这一问，**在自己的登记面上就可能有两个答案** ⇒ **引自己过去的口径也要标出处行号。**
     🔴 **并撞出 `lab:N48` 由 lab 自己踩的一次**：`plan:52` 登记的 `docs/meta-rules/`（**目录**）
       三 sha 均为 0 份，真身是 `docs/meta-rules.md`（**文件**，`W6` 措辞本可命中 3 行）
       ⇒ **判定面一半是空的而当时没察觉**。⚠️ 诚实边界：只能读到**登记**的命令，
       ⛔ 无法确认**实际**跑的是哪个 ⇒ 「登记面笔误」与「判定面塌」两种可能都要报。

   ⇒ **口径三（🔴 第 22 条推论五对「新建文件型产物」反向失效）**：那条写「判定面取【跑前 commit 的树】」，
     用意是拦「**追加进既有判定面文件**的段落」（文件级 `--exclude` 拦不住）。
     但本格预注册是**新建文件** ⇒ 跑前 commit 树**包含它自己** ⇒ `p_reg = 18` vs `p_pre = 5`，**虚高 13**。
     ⇒ **修正**：

     ```
     量「lab 自己的登记面」时，判定面取【接手时那个 commit 的树】= 上一格交付 commit
     ⛔ 不是【跑前 commit（含本格预注册）】—— 两者之差正是本格自己写的内容
     ```

   ⇒ 推论一（**「取值域覆盖全没有」反复漏的那一格是「措辞变体」**，第三次）：本格 `q_attr`
     只用 `疑似真源` 得 **2**，补上变体 `真源疑在` 才是 **3**。
     ⇒ 与 A″ 格 `k` 只定义 `§`/`#` 锚点、A″′ 格 H1 名集无档可落**同型** ——
     **⇒ 口径：凡按措辞取数，先列出该措辞的【同义变体表】再跑，⛔ 别用单一写法当全集。**

   ⇒ 推论二（**副本膨胀会把「一个定义面」读成「十六个」**）：DS `.claude/` 下 `Ruling-N` 命中 **16 处**，
     按 basename 归并后**只有 3 种**，全是主树那三个文件的 worktree 副本。
     ⇒ **口径：跨 `worktrees/` / 归档副本面取数，必须按 basename（或内容哈希）归并后再报处数。**
     与 §2.21 推论二⚠️（口径写死在命令里）同源，但那条治**输出撑爆**，这条治**读数虚高**。

   ⇒ 推论三（**§18.7 那条「先证自己的计数器」第 6 次生效，且这次差点反向冤枉对方**）：
     `pr-checks.yml:260` 称「`--all` 已整条删除」，而 `grep -c -- "--all"` 三 sha 各 **2 行**。
     精查：那 2 行**全是注释**，逐字「所以**不留** `--all`」，argv 判定使用 **0 处**，
     另有 `708f84ea` subject 逐字「删 `--all` 死 flag」⇒ **对方说对，错的是我的计数器。**
     ⇒ **⛔ 「我数出 X、他说 Y、所以他错了」在证完自己的装置之前不是一条发现** —— 原话仍逐字有效。

   ⇒ 推论四（**「悬空」这个词要分两层说**）：本格起手预期「定义面到处都没有」，
     实测**定义面存在，只是在仓外**（`~/.claude/sdd-archives/…`，40 个文件、17 个编号）。
     ⇒ **⛔ 别把「我够不到」写成「它不存在」** —— 正确表述是
     「**定义面存在，但不在任何 <该仓读者> 能到达的面上**」，两句话的后果完全不同。
     ⚠️ 且**规模读数本身也要防假阳**：全面数出 18 个编号，多出的 `Ruling-8` 只出现 1 次，
     逐字查是一句元说明「**编号跳过 8（当时没记过 Ruling-8，不是丢了）**」⇒ **真值 17，体系刻意跳号。**

   ⇒ 推论五（**口径一的第二个形态：把对方登记面的「行号 / 读数」转引成自己的实测**）：
     实证（2026-08-27 G 格复核）：处方 §3.1 写 `DEFAULT_CONFIG.controlPatterns`（`:54-61`），
     措辞是「同 entry 另一条**已实测**」。DS 回报订正为 `:66-75`，而 lab 现取
     @`8183a1c6` 是 **`:68-75`** / @`8a341f46` 是 **`:97`** —— **三个值互不相同**。
     追查：`:54-61` 的**真源是 DS 自己的 `backlog.md:633`**（写于 2026-08-06，此后文件漂了），
     lab 只是**转引**。
     ⇒ **⛔ 「对方 entry 里写着的行号 / 计数」不是 lab 的读数** —— 引它就必须
       ① 自己重取一次、② 标 sha、③ 措辞写「转引自 <出处>」而**⛔ 不写「已实测」**。
     ⚠️ **行号尤其危险**：凡引用的文件被任何一方改过，行号必漂 ⇒ **引行号不标 sha 等于没引**。
       本例中**订正方自己也没标 sha**，而漂的正是它自己 +495 行改的那个文件。

24. **复现别人的读数时，「用不用对方的装置」决定了这次复核能证什么 —— 两者⛔ 不可互相冒充。**
   实证（2026-08-27 G 格复核）：为独立核 DS 报的存量表，lab `git archive` 导出对方的闸，
   把对方 tracked 的三份快照喂给它**导出的纯函数**，三列 **18 个数逐项吻合**。
   ⚠️ 但这**只**证明了「**对方报的数确实是那套装置在那份快照上的真实输出**」
   —— ⛔ **不证明判据本身正确**，因为量具是对方写的。

   ⇒ **口径（复核报告里必须分两栏写）**：

   ```
   用对方装置复现  ⇒ 只能证「报的数没编」（防伪造 / 防抄错 / 防口径漂）
   用自己独立路径  ⇒ 才能证「判据对不对」（读源码逐条核不变量 / 造故障 / 换量具）
   ⛔ 凡只做了前者就写「已验证该闸正确」= 把可复现性冒充成正确性
   ```

   ⇒ 推论一（**「读数太整齐先当假阳」这条纪律有一个例外，要显式排除**）：`§2.21` 推论二②立的是
     「读数出现不自然的整齐 ⇒ 先当假阳查」。本格 18 个数全中，按纪律追查后结论是
     **这里的整齐是预期的** —— 同 commit / 同函数 / 同快照 / 同默认 config 是**确定性计算**，
     **不同才是问题**。
     ⇒ **口径：先问「这个读数是确定性复算还是独立测量」** —— 确定性复算全中不是假阳信号，
       ⛔ 但也因此**不构成独立证据**（回到本条正文）。

   ⇒ 推论二（**对方的量具会在自己的输出里留下「从没看」冒充「扫了零个」的坑，⛔ 别拿它当读数用**）：
     本格原想拿自己 rows-only 跑法印出的 `scanned.controls: 0` 去印证对方「默认 config 扫出 0 control」，
     **不能用** —— 该跑法结构上根本没调用采集函数，那个 `0` 是「**从没看**」。
     ⚠️ 而**该闸自己的注释逐字立过这条纪律、却只守了一半**（rows 侧守了、controls 侧没守）。
     ⇒ **口径：引用任何闸的 `scanned` / 分母类计数前，先看该跑法有没有真的采集过那一类**
       —— 与 `lab:N48`（判据返回 0/空集先证判定面非空）同族，但那条治**自己的**判据，
       这条治**引用别人的分母**。

25. **判一个「断言 / 探测装置」有没有用，必须在【故障臂】和【对照臂】上都跑 —— 只在故障臂报红的才是
   判别器；两臂都报红的是【恒红】，信息量 0，且它长得像 fail-closed。**
   实证（`lab:N58`，2026-08-27 H 格，被验对象 = DS `audit-mockup-geometry-consistency.mjs` 的 `--probe`）：
   预注册 H8 只问了「拿被丢弃的帧 id 当探针，会不会触发 `:797`」，取值域写的是**二值**（触发 / 不触发）。
   实测**触发**，据此本可写成「存在一条能报红的通道 ⇒ 半个对策」。
   **但同一次跑的对照臂推翻了这个读法** —— `--probe <帧 id>` 在**五臂全部** `exit 2`，
   **包括 G2 成组成功、命中、正确 FAIL 的那两臂** ⇒ 它**⛔ 不能区分故障态与正常态**
   ⇒ **不是半个对策，是 0 个**。
   ⚠️ 二阶后果比一阶更重：运维试一次帧 id 得到红 ⇒ 得出「帧不能当探针」这个**正确**经验
   ⇒ 退回去探 control ⇒ 落进**给绿**的那条路径。**恒红把人推向假绿。**

   ⇒ **口径**：凡报「某通道能 / 不能拦住 X」，报告里必须同时给出
     **该通道在无故障对照臂上的读数**；⛔ 缺这一栏的结论不成立。

   ⇒ 与 `lab:N33`（闸退化成**恒绿**）是**镜像形态**：恒绿说「永远没问题」、恒红说「永远装置坏了」，
     **两者都不携带被测对象的信息**；⚠️ 但恒红更隐蔽 —— 它长得像 fail-closed，
     而 `AGENTS.md` 全篇的纪律都在奖励 fail-closed。

   ⇒ 推论一（**第 22 条推论三那条轴第 3 次生效，这次的两个正交维度是「报红了没」vs「报红有没有区分力」**）：
     取值域自查已经问过「值域覆盖全没有」（二值确实覆盖全了）**仍然漏**，因为漏的不在值域里，
     在**维度**里。⇒ **口径：设计一个「装置有没有效」的判据时，取值域必须是
     【故障臂读数 × 对照臂读数】的笛卡尔积，⛔ 不是单臂读数的值域。**

   ⇒ 推论二（🔴 **`§18.7` 第 9 次生效，第 2 次犯在自己的推理上 —— 且这次是「窗口截断」造的假阳**）：
     本格顺手核「lab 知不知道 DS 已证伪 `^Item/`」时，第一次 grep 报 **0 处知情**，
     据此差点写成「`lab:N56` 反向形态：对方已证伪而 lab 零处知情」。
     **重跑后是 4 处知情**（`docs/round2-status.md:2074-2077` / `:2169` 逐字），两个成因**并存**：
     ① **措辞变体没列全** —— DS 写「**18 control**」，我搜的是「**18 个**」（第 23 条推论一第 4 次）；
     ② 🔴 **我给 grep 加了 `head -6`，真命中被截在窗口外** —— 与 `lab:N47` 推论三
        「复现工具的**返回窗口** ≠ **检索面**」同族，但那次是量别人，**这次是量自己**。
     ⇒ **口径：量「lab 自己知不知情」这类【判否】结论时，⛔ 不许给 grep 加 `head` / `-m`**
       —— 判「有没有」可以截断（命中一条即成立），判「**没有**」**必须跑完**。

   ⇒ 推论三（**真实缺口往往不在「知不知情」，而在「知情写到哪儿了」**）：本格纠正后的真实状态是
     §28.6 **已判出**「DS 已 live 证伪 `^Item/`」，却**只写进 `docs/round2-status.md`，⛔ 没回改处方正文**
     —— 而 `proposals/2026-08-27-designqa-gate-gap.md` 才是**交给 DS 执行的入口文件**，
     它至今仍在推荐那条已被证伪的路。
   ⇒ **这正是第 22 条推论一那条口径（判出对方已做 / 已裁 ⇒ 当场回改处方正文）在 §28.6 未被执行**
     ⇒ **口径升级：那条口径要在【交付自核清单】里固化成一行 ——
       「本格判出的每一条『对方已做 / 已裁 / 已证伪』，有没有回改到对方会读的那份文件？」**

   ⇒ 推论四（**起手基线是「起手时」的读数，⛔ 不是整格结论 —— 收尾必须重取**）：
     本格起手实测 DS HEAD 未漂，据此在报告与 status 初稿里写下「**本格 DS 未漂**，交接 prompt 的
     『必然又漂』本轮不成立」。**收尾重取：`1cc95824` → `6a78faa4`（+4 commit）** ——
     「格内也会漂」**第 5 次实证**，且这次是**首次漂到被验文件本身**（前四次都没碰该族）。
   ⇒ **口径**：凡起手基线类读数（对方 HEAD / dirty / 落后多少），**报告里必须写成「起手 X → 止 Y」两栏**；
     ⛔ 不许只写一个值，⛔ 更不许把起手值写成「本格没发生 Z」这种整格断言。
   ✅ **而这次能救回来靠的是一条可复用动作**：被验文件在格内被改时，**把装置在新 sha 上原样重跑一遍**，
     `diff` 两次 stdout —— 空 diff 就是「结论仍成立」的程序化证据，
     ⛔ 比「读 diff 觉得没影响」强得多（本格 `+7 行` 那次，肉眼判断与实跑结论一致，但**只有实跑能作证**）。

26. **一条纪律如果没有【承载它的栏位】，它就只会靠自觉执行 —— 而自觉的方差是一个数量级。
   ⇒ 立完口径要接着问：「对方会读的那份文件里，有没有地方写这件事？」没有 ⇒ 先建栏位，再谈遵守。**
   实证（`lab:N59`，2026-08-27 I 格，被验对象 = **lab 自己**）：第 25 条推论三（「判出对方已做 / 已裁 /
   已证伪 ⇒ 必须回改到对方会读的那份文件」）在存量上反查 —— `docs/round2-status.md` 里 18 条同类命题、
   15 条有处方对应物，**11 条已回改、4 条未回改 + 1 处半回改**。
   🔴 **但真正的读数不是那 4 条，是这三个数**（⚠️ **测量时点 = lab `01b6589`，交付前** ——
   本格交付本身会改变它们，**自指污染必须标时点**）：
   `status` 里「待 DS 执行」**7 处** · `proposals/` 全 9 份含「待 DS 执行」**0 份文件** ·
   `proposals/` 全 9 份含「执行状态」**0 份文件**（⚠️ 预注册那条 regex 锚了行首、抓不到
   `- **执行状态**：`，已改纯字符串口径逐份复测，**两种口径同得 0**；⛔ 但窄口径的 0 不能自动读成宽口径的 0）。
   ⇒ **「对方已做」这类判定在处方里结构性无处可写** ⇒ 只能靠散落在正文的订正块
   ⇒ 做到的（`retrospection-adr.md` 用 `~~删除线~~` + 标 sha + 标口径名，11 条里占 3 条）
     与做不到的（`gate-output-contract.md` **整份零登记**）**差一个数量级，而差别只在当轮 session 的自觉**。

   ⇒ **口径**：凡「某类信息必须回写到某份文件」的纪律，**落地动作是先在那份文件里建一个固定栏位**
     （本格建的是处方的「**执行状态**」头栏 + `archive-triage.md` 的 §0.1 逐步状态表），
     ⛔ 不是反复提醒「记得回改」。**没有栏位的纪律 = 每轮重新赌一次自觉。**

   ⇒ 推论一（**分项回改会把「文件级总述」留在原地** —— §26.4「知情面与登记面分叉」第 6 个实例，
     且**首次发生在同一个文件内部**）：`archive-triage.md:26`@`01b6589` 逐字「**本处方尚未执行**」，
     而同文件 `:188`/`:198`/`:300`/`:330` 已各自写着「已被 DS 裁定不执行」。
     成因是**改分项的人只看那一段**。⇒ **口径：改完分项，回到文件头核一遍总述句。**

   ⇒ 推论二（🔴 **`§18.7` 第 10 次生效 —— 「行号标了 sha」和「sha 贴着行号」是两件事**）：
     本格核 `archive-triage.md:301` 引的 `audit-doc-shape.mjs:48-73`，按处方头部声明的 `71ac2711` 取读数
     **得到 `import` + JSDoc**，差点写成「悬空行号引用」这条新缺陷。
     **实为下一行 `:302` 逐字标了「引入 commit = `c1db57b8`」** ⇒ 判断不成立，已撤。
     ⇒ **口径：sha 要贴着行号写，⛔ 不要隔行** —— 隔行的读者会回退到文件头那个 sha。
     ⚠️ 同族第二处：起手报「§28.8 的 `probeG1:316` 与我现取的差 4 行」，追到底是
     **交接单锚在「分组键那一行」、我 grep 的是 `export function` 声明行** ⇒ **两个面差 4/2 行，谁都没错。**
     ⇒ **口径：引函数内行号时写明锚的是哪一行（声明行 / 某个判据行），⛔ 只写函数名 + 行号会撞面。**

   ⇒ 推论三（**报「缺口」时必须并排报「已做到的那一栏」，⛔ 否则读成「从来没做过」**）：
     本格 `a = 11`（已回改）比 `b + c = 5`（未回改）**多一倍**，且 🔴 **重档 = 0**
     —— 存量里**没有**「处方仍在推荐一条已被证伪的路」这种雷（唯一那条 `^Item/` 已由 §28.8 当格补掉）。
     只报 4 条未回改，会把一个「机制缺栏位、但人基本补上了」的状态读成「纪律全面失效」。
     ⇒ 与第 25 条「恒红=零信息」同一条轴：**单栏读数不携带判别力，⛔ 分档计数必须给全档。**

27. **「只登记基数、不逐条裁定」这个降级动作，损失的是【基数面】，⛔ 不是【缺口面】——
   而这两个量互相独立，可以一个低估两成、另一个精确为零。
   ⇒ 立「未覆盖」登记时必须写明**降级损失的是哪个量**；⛔ 只写「未逐条裁定」，
   读者（= 下一格的自己）**无法判断本格结论还能不能用**。**
   实证（`lab:N60`，2026-08-27 J 格，被验对象 = **lab 自己**）：I 格对次判定面 S（`reports/` 34 行候选）
   声明「只登记基数 + 定向抽样，⛔ 不承诺逐条裁定」。本格**全量补跑 34 行**：
   归并 **12 处**命题，其中 🔴 **5 处是 P 面 18 条没有的** ⇒ **基数低估 5/23 = 21.7%**；
   🔴 **但回改缺口零变化** —— 那 5 条里 **4 条在 `proposals/` 全 9 份零对应物**
   （纯 lab 内部账 / DS 仓内部 owner 裁定，处方本就不该有它们）· **1 条已回改** ⇒ **`b = 0 · c = 0`**。
   ⇒ **两个量方向完全不同**：一个被低估两成，另一个精确为 0。
   ⇒ 若 I 格当时写的是「未逐条裁定 ⇒ **可能低估基数，⛔ 但不影响三态计数**」，本格价值就只剩「确认」；
   而它写的是笼统的「只登记基数」⇒ **下一格必须整格重跑才能知道结论受不受影响。**
   ⚠️ 同格第二例：**跨行档**（§28.9 未覆盖第 2 条）补跑后真跨行结构 **5 处**、**新命题 0**
   ⇒ **该档可关闭**（k ≤ 3）。**同一节的两条未覆盖，一条真有损失、一条纯属虚惊 ——
   ⛔ 而原登记的措辞让它们看起来同级。**

   ⇒ 推论一（🔴 **判据脚本必须有【交叉验证锚】，⛔ 否则「跑出来有数」≠「数是对的」**）：
     本格跨行判据先跑出 **79 / 175**，靠**与 I 格已知读数对齐**（`both` 必须 = **29**）逐一揪出两条 bug：
     ① `comm -12` 要**字典序**，喂 `sort -n` ⇒ 交集**恒 0**（被 `lab:N48` 拦住）
     ② awk **引用即创建** —— 写 `p[j]` 会凭空在 `p` 里建出 key `j` ⇒ 第二个 `for(i in p)` 遍历到幽灵 key
     ⇒ 读数虚高 **4.4× / 5.3×**，真值 **18 / 33**。
     🔴 **抓到 ② 的线头是「输出里有一对的行号落在空行上」** —— 空行不可能命中谓语。
     ⇒ **口径：新判据先在一个【已有读数的面】上跑，对上了才用它产新读数。**
     ⛔ 没有锚的脚本，**虚高 5 倍和正确一样「看起来有数」**。

   ⇒ 推论二（**同名编号可能属两个体系 —— 按名字 grep 到的「对应物」必须先证同体系**）：
     🔴 `§18.7` **第 11 次**生效。`A3`/`B2` 在 `retrospection-s2-s3.md:147` 指的是 **DS 仓归档文件
     `process-gap-report-2026-06-11.md` 的内部编号**（同段 `B3`/`B5`/`C2`/`C3` 是该文件的 owner-gated 待决项），
     在 `retrospection-adr.md:83`/`:97` 指的是 **lab 处方自己的 ADR 编号**。
     按名字 grep 到「对应物」后，**差点判出一条 🔴 重档缺陷**（「处方仍推荐已被 owner 砍掉的路 ⇒ DS 白干」）
     ⇒ **判断不成立，已撤。**
     ⇒ **口径：跨文件按编号名找对应物前，先证两边是同一编号体系**（⛔ 名字相同 ≠ 同一体系）。
     这是第 26 条推论二（「引函数内行号要写明锚的是哪一行」）的**同族第三例** —— 都是**面没对齐**。

   ⇒ 推论三（**「不存在的 0」≠「零命中的 0」—— 这是第三种 0**）：
     探反探针时 `git grep` 对 3 份 `.md` 返回空，实为它们在该 sha 上**根本不存在**（都是后来新增的）。
     ⇒ **口径：在历史 sha 上判「零命中」前，先用 `git ls-tree` 证该文件在那个 sha 上存在。**
     与 §28.9「**窄口径的 0 ⛔ 不能读成宽口径的 0**」同一条轴。

   ⇒ 推论四（**自指污染是【持续的】，⛔ 不是一次性的**）：
     §28.9 那张双栏表右栏原写「交付后〔**现行**〕」—— 而本格交付**又推高了它**（`reports/` 26→27 份等）。
     ⇒ **口径：自指读数的每一栏都写死时点 sha，⛔ 不许用「现行」这种会漂的词。**
     已就地回改该表表头（`交付后〔现行〕` → `@5883444〔§28.9 交付后〕`）。

28. **「证据通道非零」≠「证据独立」—— 当所有通道都落在【被验方自己的仓/文档】里时，
   判「对方真做了 X」与判「对方自称做了 X」的读数**完全相同**，⇒ 该问题**结构性不可判**，
   ⛔ 不是「再多找一条通道」能解决的。
   ⇒ 立「不可判」时必须写明成因是**「通道全零」还是「非零但同源」**；⛔ 只写「不可判」，
   下一格会去做**注定白费的第五次找通道**。**
   实证（`lab:N61`，2026-08-27 K 格，被验对象 = **DS 侧**）：复核「`bf0df7d5` 是不是 owner 亲裁」，
   四条通道**全部非零**：① git 身份（有值）② owner-gated 队列（四时点恒 5 条、无一条涉本议题）
   ③ 文本痕迹（**有鉴别力**：「已决」193 处 vs「待 owner」112 处；最强一条甚至逐字记了
   **owner 的反问**「能不能自动判定」）④ 时间线（自称由**后续** commit 写入）。
   🔴 **但四条证据全部由被验方书写** ⇒ 「亲裁」与「自称亲裁」在此证据面上不可分。
   ⚠️ **⛔ 这不是造假指控** —— 痕迹的具体程度反而更像真实往返。可判的是**结构**：
   **DS 仓没有任何机制能区分二者** —— 与该格所复核的那道闸治的病（「没有机制回答某个问题」）**同型**。
   ⇒ **口径：判「对方已裁/已做」前，先问「有没有一条证据不在对方手里？」** 没有 ⇒ 直接落
   「不可判 · 成因=同源」，把问题交回**唯一权威读数持有者**（这里是 owner 本人），⛔ 不猜、⛔ 不代答。

   ⇒ 推论一（🔴 **「第四种 0」：命令失败产生的 0**）：
     `git show "$s:scripts/audit-acc…"` 在 zsh 下**加双引号仍失败** —— `$s:s/cripts/audit-acc/` 被解析成
     **参数展开的 `:s` 替换修饰符**（⛔ **与历史扩展无关，所以引号挡不住**）⇒ `git show` fatal，
     而管道下游 `wc -l` **照吐 `0`**，差点读成「文件 0 行」。**修法：写 `${s}:path`（花括号）。**
     ⚠️ 同格内**又撞第二次**（路径猜错 `data/gate-baselines/` 实为 `figma-data/audit-allowlist/`
     ⇒ 重定向出空文件）。
     ⇒ **口径：0 有四种** —— ①真零命中 ②文件在该 sha 上不存在（第 27 条推论三）
     ③窄口径的 0（§28.9）④**命令失败的 0**。⛔ 拿 0 下结论前，先证**命令本身跑通了**
     （查 exit code / 先在必然非空的面上跑一次同一条命令）。

   ⇒ 推论二（**⛔ 写死的 `echo` 文案不许冒充读数**）：
     该格在管道后写死 `echo "(上面为空 = 这三个决策从未进 owner-gated 登记面)"`，而实际输出**非空**。
     🔴 **去复核那一行，反而挖到了整格最强的一条证据。**
     ⇒ **口径：结论性文案必须由读数生成（条件判断/计数），⛔ 不许与命令并排写死** ——
     与第 25 条「恒红 = 零信息」同一条轴：**不随输入变化的输出不携带信息**。

   ⇒ 推论三（**机制闭合 ≠ 存量闭合；⛔ 百分比下降可能全部来自分母变大**）：
     该闸把「没有闸的那些条」从不可见变成 `unclassified` 默认态（机制闭合 ✅），
     但存量 `unclassified` **绝对数 83 → 83、一段没减** —— 占比 98.8% → 70.3% **全部来自分母
     从 84 涨到 118**。且棘轮只保证「**不再增**」（余量已 = 0），**⛔ 无任何机制逼它减到 0**。
     ⇒ **口径：报「覆盖率改善」必须同时给【绝对数】与【分母】两栏**（第 26 条推论三的同族），
     并写明**收敛机制是「止增」还是「必减」** —— 两者对残余风险的含义完全不同。

29. **⛔ 「分母是对的」本身要单独证 —— 棘轮/覆盖率类判据的分母若来自一条【模式匹配】，
   那条模式漏掉的东西【不会以任何形式出现在读数里】，⇒ 闸会【假绿】。**
   ⇒ 口径：**凡结论依赖「N 段 / N 条 / N 项」这个分母，必须独立于被验方的枚举器再数一遍**
   （用更宽的模式扫同一面，把差额逐处定案），⛔ 不许直接引用对方枚举器的输出当分母。
   实证（`lab:N62`，2026-08-27 L 格，被验对象 = **DS 侧**）：那道 acceptance 对位闸的
   `ACC_RE = /^(?:\*\*Acceptance|#{2,6}\s+.*Acceptance)/` 漏收三种形态 —— `- **Acceptance**：`（4 处）·
   缩进 `**Acceptance**：`（2 处）· 中文 `#### 验收标准`（1 处），共 **7 段**。
   这 7 段全部无自陈、不在豁免表 ⇒ 语义口径下 `unclassified` **83 → 90 > BASELINE 83**
   ⇒ **棘轮 S2 本该红，实际绿**。🔴 K 格据 `83` 判出的「余量 = 0、再增一段就红」是**乐观读数**：
   **它已经超了 7 段，只是闸看不见。**
   ⚠️ ⛔ **这不是「闸错了」的断言** —— 收哪些形态是闸作者定的口径。可判的是：**该取舍零处登记**。
   ⚠️ 同族反向也要核：本例**反向核过**「闸在 ``` fence 内多收 = 0 段」⇒ 少收有、多收无，**方向单一**。

   ⇒ 推论一（**⛔ 「机检分桶」之后必须抽查「其它」桶 —— 漏网项永远躺在那个桶里**）：
     本格 v1 先把候选行分成「列表项 / 缩进 / 中文标题 / 表格行 / **其它含词**」五桶，
     结论差点只据前四桶下。**抽查「其它」那 25 行**才发现 `design-process.md:687` 是 ``` **代码块内**的
     PRD 模板示例（⇒ 闸不收它是**对的**），避免了把假阳算进「真漏」。
     ⇒ **口径：分桶判据的兜底桶（`else` / 「其它」）必须抽查，⛔ 不许当噪声丢掉。**

   ⇒ 推论二（🔴 **「第四种 0」的新变体：判据的【定位面】选错产生的 0**）：
     本格做注入实证（往文档里插一段看 id 会不会位移）**连错三次、每次都吐「0 位移」**。
     成因既不是命令失败、也不是真零命中，而是**探针落进了别的 slug**
     （`id` 的 `~N` 序号取「最近 heading」，而该文档 heading 密集）。
     ⛔ **三次「0」看起来完全一致，且都「跑通了」** —— 这正是它比命令失败更危险的地方。
     ⇒ **口径：注入/探针类实证吐 0 时，先证【探针真的落在了目标面上】**（打印探针自己的 id / 位置），
     ⛔ 不许只看「结果为 0」。停止盲试、**回读原文结构**后一次命中。

   ⇒ 推论三（**同一条判据可以在一处正确、在另一处错误 —— 而闸没有机制区分**）：
     该闸的段边界判据「撞到顶层散文就停」在 `domain-tvu.md#M17` 上是**正确收窄**
     （闸 `:68-73` 逐字登记：漏掉的 5 条是「LCD surface 注记（做法层）」，本就不是核查项），
     在 `AGENTS.md#Jira` 上却是**错误漏收**（段内逐字 7 条 `- [ ]`，中间一行实证散文截断 ⇒ 只收 4 条；
     而 DS **自己**的豁免 `reason` 逐字写「**七条**」⇒ **对方两处书写互相矛盾，⛔ 不需我方做语义裁定**）。
     ⇒ **口径：判一条判据「有没有缺陷」，⛔ 不能只找一个反例就收工，也不能因为找到一个正例就判它对**
     —— 必须给出**它在哪些面上对、哪些面上错**，以及**有没有机制区分二者**。没有 ⇒ 那才是要报的缺陷。

   ⇒ 推论四（**⛔ 「条目数」≠「被覆盖数」—— 交接单里的单位错会让下一格去找不存在的东西**）：
     交接单与 §28.11 逐字写「**30 条**豁免理由未复核」，实测豁免表只有 **14 条 entry**
     （1 条**文件级**盖 17 段 + 13 条**段级**各盖 1 段 = **30 段**）。
     ⇒ 照抄「30 条」会去找 **16 条不存在的 entry**，然后「找不到 ⇒ 记 0」。
     ⇒ **口径：既有纪律「⛔ 处数 ≠ 行数 ≠ 出现次数」补上「≠ 条目数 ≠ 被覆盖数」** ——
     写未覆盖项时**必须写清那个数的单位**，⛔ 「N 条」是最容易被下一格误读的写法。

   ⇒ 推论五（🔴 **「起手零漂」⛔ 不蕴含「格内不漂」—— 两种漂要分开记两栏**）：
     本格是这条的头一个实证：**交接基线漂**（上一格止 → 本格起）9 次交接里**首次零漂**，
     而**格内漂**（本格起 → 本格止）照样发生，且 `ce3fd7e7` 逐字「再判 13 段 gated（83→70）」
     **直接改了判定面**（闸文件 `BASELINE_UNCLASSIFIED` 83 → 70 + 16 处自陈变动）。
     ⚠️ 起手那次零漂**很容易被读成「这轮不用管漂移了」** —— 那正是最危险的时候。
     ⇒ **口径：`起手 X → 止 Y` 两栏必须【收尾时真的重取一次】才能填**，
     ⛔ 不许在格中途凭「起手核过了」把止栏写成同一个 sha。
     ⇒ 且**装置的交叉验证锚往往绑定了特定时点对**（本格装置的 3 个锚写死 `f15c8500→60d644a0`），
     换区间后会报「读数作废」—— ⛔ **那不是读数坏了，是锚用错了区间**。
     **修法：给新区间另立锚**，且锚最好**逐字取自被验方自己的 commit subject**（本格用「再判 13 段 gated（83→70）」
     立了 4 个新锚，全部对上）。
     ⇒ 🔴 **第三种形态（`lab:N70`，2026-09-14 §41 实测）：HEAD 零漂 ⛔ 不蕴含「被验环境没变」——
       工作树可以漂到把闸弄红，而 `HEAD` 一动没动。**
       前两种形态（交接基线漂 / 格内 HEAD 漂）盯的都是 **sha**。本格 DS **起手止都是 `88e09c4f`**，
       同期**工作树漂了 5 次**（脏 4 项 → 13 项，⛔ 没有一项是我的）——
       而并行 session 写进 `backlog.md` 的一条新 entry 让 `audit-status-consistency`
       读出 `active 6 vs STATUS 声明 5` ⇒ **pre-commit 红、我的提交做不成**。
       ⚠️ 🔴 **而那个非零退出码长得像「你的改动有问题」** —— 若只读退出码，会写成
       「棘轮又拦了一次，按判据改 BASELINE 就是」，**而棘轮根本没跑到**
       （§2.16 推论二的反向形态：那条是「空判通过被记成验收失败」，这条是
       **「一条与本次改动完全无关的控制失败，被退出码包装成了你的账」**）。
       ✅ **归因靠两臂，⛔ 不靠推**：真工作树跑那条测试 **1 failed** ·
       `git clone` 树 @同一 sha **22/22 绿** · 自己 `staged` 的只有 1 个无关文件。
       ⇒ **口径**：① 核漂移时 `git status -sb` 的**两半都要记** —— 分支/HEAD 那一行**与**脏项清单，
       ⛔ 只记 sha 会漏掉这一整类；② 报告的「起手 → 止」**两栏各记两个量**（sha + 脏项数）；
       ③ pre-commit 红时**先逐条对齐是哪条控制失败**，再决定是不是自己的账；
       ④ 判成「别人的账」之后 ⛔ **不许改对方的文件去凑绿**、⛔ 不许 `--no-verify` ——
       正确处置是**留 `staged` + 把提交前置写进交接**（本格即此）。

   ⇒ 推论六（**判据的【召回率】要单独报 —— 「命中的都对」⛔ 不等于「该命中的都命中了」**）：
     本格 L1 用「段内是否点名 `audit-*`」判出 11 段「本该 gated」，收尾时被 DS 的独立动作验证 **11/11 全中**
     （精确率 100%）—— **但 DS 实际判了 13 段**，⇒ **召回率只有 11/13 = 84.6%**，漏了 2 段。
     ⚠️ 只报「11 段全部被验证」会让读者以为判据是全集。
     ⇒ **口径：机检判据的产出必须写成「【至少】N 个」**，并在有外部读数时**同时给精确率与召回率**；
     ⛔ 「我判出的都对」是**下界**，不是全集。
     ⇒ ⚠️ **补（`lab:N63` M 格）：召回缺口要【按成因拆开】，⛔ 不许当同一种。**
     本例那 2 个假阴性质相反：`#M52` 是**判据定位面太窄**（闸名点在父节，判据只扫段内）= 真假阴；
     `#Acceptance~9` 是**被验方自己的判据没成立**（四面全零点名）⇒ 判据漏它**是对的**。
     ⇒ **真实缺陷只有 1 处，不是 2 处**；两栏并报：对「对方判的 N 段」的召回 vs 对「满足对方判据的 M 段」的召回。

   ⇒ 推论七（🔴 **「兑现」也有承载物 —— 棘轮降一格，先问那一格是被什么承载的**）：
     实证（`lab:N63`，2026-08-27 M 格，被验对象 = **DS 侧**）：那道闸的 `BASELINE_UNCLASSIFIED`
     两批从 `83 → 70 → 67`，而两批的 `git diff --name-only` 里落在**规则真源**（闸自己的 `SCAN_FILES` 7 份）
     上的文件都是 **0 个** —— **规则原文一个字节没改、核查项一条没增减**，
     全部兑现由**新写的 `// covers-acceptance:` 注释**（第一批 14 行、第二批 3 行）承载。
     而被验方自己写死的分类判据是「**两端各有声明才判 gated**：① 规则原文点名了闸 ② 闸头注释也声明」——
     实测第二批那 3 段 ① **四面全零点名**（段内 / 本节 / 逐级父节 / 全文兜底，三种别名形态 `grep` 各 0 次）。
     ⇒ 后果是**反直觉的**：BASELINE 跟着兑现降了 3，而语义口径的残余**一段没少**
     ⇒ **超额从 8 段扩大到 11 段 —— 兑现越多，缺口越大。**
     ⚠️ 「棘轮跟着降 = 兑现即锁定」是**正面机制**（上一格判过），
     但 ⛔ **它锁住的是【数】，不是【事实】**。
     ⇒ **口径：判「某批未答项已兑现」前，必须先答【那批兑现是由什么承载的】。
     若承载物是被验方自己写的声明，那份声明【本身就是新的未复核面】**，
     ⛔ 不许把它当成已兑现的证据，⛔ 也不许因为「对方的闸绿了」就认账 ——
     **闸绿只说明声明与声明自洽，不说明声明为真。**

     ⇒ 🔴 **推论七之二（`lab:N71`，2026-09-14 §42.5 实证 —— 上面那条的【镜像】）：
       计数型指标【没动】同样要先答「它的口径数的是什么」，⛔ 不许读成「这次改动没效果」。**
       推论七治的是「**数动了**，但承载物不是事实」；这条治的是「**数没动**，而事实动了」。
       实证：给一条闸补了 10 条整脚本回归面、造故障两臂坐实有效（全量 failed **9 → 15**），
       而棘轮 `BASELINE` **纹丝不动（38 持平）**。
       归因是**两臂 + 阳性对照**测的，⛔ 不是推的：该闸的 `face` **补前补后都是 `E-fx`**
       （补前的证据是另一份测试，**它只守 V4**），而棘轮判据逐字是
       `blocking === true 且 face ∉ {E, E-fx}` ⇒ **它数的是「有没有整脚本面」**。
       ⇒ **该指标对「补【已有面的盲区】」这类改善结构上零敏感** ——
       前两格补的闸是**零整脚本面**（`face` 从非 E 变 E-fx）⇒ 各降一格；
       这一格补的是**已有面测不到的通路** ⇒ 口径上就不该动。
       ⇒ **口径**：① 报「某计数指标没动」时，**必须并排给出该指标的判据原文**，
       并答「它数的是有没有，还是数覆盖了多少」；
       ② **改善的证据要另外给**（本例在造故障两臂 + 承诺指标），⛔ 不许拿这个指标的沉默当结论；
       ③ 反过来也⛔ 不许写成「它该降而没降 ⇒ 闸有问题」—— 按它自己的口径它是对的。
       ⚠️ 这是 `lab:N63` 推论七 / `lab:N64` **同一条轴的第三个实例**：
       「**这条闸有回归面**」⛔ 不等于「**那个面覆盖了它的哪些通路**」。

   ⇒ 推论八（**⛔ 定位面选窄不只产生假阴，同样会产生【假红】**）：
     推论二记的是「定位面选错 ⇒ 吐 0」。本格（`lab:N63`）撞到它的**镜像**：
     判「规则原文有没有点名闸」时只扫 Acceptance 段内 ⇒ 把 `#M52` 判成「原文零点名」的**红**，
     而它父节 lvl3（31 行的正常规则节）就点名了。⇒ **窄面的「零命中」既能变成漏报，也能变成误报。**
     ⇒ **口径：凡判据形如「某个面上有没有 X」，必须【逐级放宽定位面并各出一栏】**
     （本格用了四面：窄段 / 本节 / 逐级父节 / 全文兜底），⛔ 单面读数不许下结论。
     ⚠️ 同族第二处：`package.json` 实测 `audit:handoff-sections → scripts/audit-handoff-deliverable-sections.mjs`
     ⇒ **npm key 与脚本文件名不同名**，任何「按名字比对」的判据都会漏这种别名 ——
     **先建 key→文件 解析表，⛔ 不许假设同名**。

   ⇒ 推论九（**判据对「书写形态」的盲区，修一层不等于修完 —— 要逐层列出还剩哪些形态**）：
     被验方 2026-08-27 当天写过一条复盘「判据只对一种书写形态灵敏」，并据此把该闸的 S4
     从 `max(各条项数)` 改成 `Σ(段内核查项总数)` —— 修掉的是「`·` 挤一行 **vs** 一项一行」这一层。
     🔴 **但同一天落地的 4 条 `[0]` 自陈证明还有一层没修：`ITEM_RE` 只认 `^- `，
     【散文形态】的核查项一律计 0。** 那 3 段实测全都含散文形态核查项
     （其中一段用 `+` 串了 **8 条以上**），却自陈 `[0]` ⇒ **`[0]` 不是「没有核查项」，是「没写成列表」**。
     两臂注入实证：插 1 条**列表**项 ⇒ S4 **3/3 红**；插 1 条**散文**核查项 ⇒ S4 **3/3 不红**
     （对照臂：`Σ=0` 但未 gated 的段同样注入 ⇒ 不红 ⇒ 判据非恒绿）。
     ⇒ **口径：报「某形态盲区已修」时，必须【枚举该判据认得的全部形态】并逐条给读数**，
     ⛔ 「改了一版正则」不算修完 —— 形态空间是开放的，只有列出来的那几种才算被覆盖。

   ⇒ 推论十（🔴 **「这条闸有回归测试」本身要单独证 —— 钉子对【已判出的缺陷面】可以完全零敏感，
     而它的绿会被当成那条闸的背书**）：
     推论七问的是「兑现由什么承载」，本条问下一层：**那个承载物由什么守着**。
     实证（`lab:N64`，2026-08-28 N 格，被验对象 = **DS 侧**）：那道 acceptance 闸有 **34 条
     「整脚本回归」测试**（自称最强形态：spawn 整个脚本、⛔ 不 import 判据符号）。
     在导出树上做**七向注入**（⛔ 未改被验方一个字节），结果**分成三种完全不同的落档，⛔ 别混报**：
       · **零敏感 + 方向相反**：把 `ACC_RE` 放宽到收 L 格判出的漏收三形态 ⇒ 钉子 **34/34 全绿**，
         而**同一改动**在真源上让闸 `sections 118→126`、`unclassified 67→75` ⇒ **S2 破棘轮 + 3 条 S4**。
         ⇒ 钉子说「没问题」，闸说「4 条 fail」—— **修复者拿到的信号互相矛盾**，
         而唯一会红的那份会被读成「你把闸改坏了」。⇒ 这是一个**惩罚修复**的结构。
       · **已固化**：把段边界改成不因顶层散文终止 ⇒ 钉子**当场红 1 条**，且那条注释逐字写「⛔ 别删」——
         而该判据在另一个面（`AGENTS.md#Jira`）上**已被判为错误漏收**。
         ⇒ **钉子只钉了对的那一面，把「没有机制区分两面」这件事固化成了规范。**
       · **零覆盖**：散文形态的 Σ 口径，18 条自陈**全部指向列表形态段**、散文段零条自陈
         ⇒ 改对改错都不红。⛔ **「零覆盖」与「已固化」是两种病**：前者修复无阻力但也无保护，
         后者修复会被拦。**必须分开报，处方完全不同。**
       · 🟢 **同时要如实报正面档**：摘 `main()` ⇒ 32 红 · `exit(1)→(0)` ⇒ 13 红 · 换原始入口守卫 ⇒ 34 绿
         ⇒ 那句「spawn 整脚本 ⇒ 看得见接线」的自陈**为真**，⛔ 不是空话。
     ⇒ **口径：判「某条闸被回归测试守着」前，必须拿【已判出的缺陷】做注入 ——
     注入的是【修复】而不是【破坏】**，问的是「**要修这个缺陷，钉子会不会拦 / 会不会毫无反应**」。
     ⛔ 「测试全绿」不许推「闸是对的」；⛔ 「测试红了」也不许推「改错了」。
     ⚠️ 同族第二处（**形态差别，值得照抄的那一半**）：同一体系同一批次的另一份钉子
     （`audit-gate-ci-parity-cli.test.ts`）头注释**逐字登记了自己覆盖不到什么**
     （「⛔ 本面覆盖不到具名豁免表的三条分支」「**如实登记的边界，不是待补 TODO**」），
     而出问题的那份**零处登记自己的形态覆盖边界**（它头 40 行里那两处「边界」，
     一处说的是**另一条闸**的缺口、一处说的是常量写死会漂）。
     ⇒ **报一份钉子的强度时，先看它有没有登记自己的边界 —— 没登记的那份，绿得最不可信。**
