# 复盘 2026-08-27 —— 新建闸要过的不只是「它自己的判据」，还有**仓库横向契约**；以及派生产物不该承载人的判定状态

> **范围**：只记本轮学到的**两条可复用 pattern**。本轮的逐项实证（读数 / 注入清单 / 存量表）已在
> [STATUS-CHANGELOG](../STATUS-CHANGELOG.md) 第四十九 + 第五十二轮、[tracker](./design-spec-canonical-alignment-tracker.md)
> 轨道 C §已完成末两行、以及 [[CANONICAL-F104]] / [[INFRA-F142]] 两条 entry 里，**本文刻意不复述**。

---

## 一 · 新 pattern：新建闸的验收清单里少了「仓库横向契约」这一格

memory `new-gate-acceptance-three-questions` 记的三问 + 第 5 问都是**朝内**的：空/畸形输入、输入形态错要 fail closed、判据有几个调用面、这条推荐达成的是它声称的目的吗。本轮暴露的是**朝外**的一格：

**这条闸有没有过仓库对「一条闸」的横向要求？**

实证：新建的 `audit-acceptance-gate-coverage.mjs` 判据写全了、26 条整脚本回归面全绿、L4/L5 都挂了 —— 然后被**另一条闸** `gate-output-harvest` 判 `unexcused`：上 `gate-chain` 的闸**必须无条件发结构化 stdout**（`scripts/lib/gate-output-contract.mjs`，`checkedUnits` 是硬要求）。我一格都没想到去查。

⚠️ **它不是"锦上添花"**：那条契约存在的理由逐字是「`findings: 0` 有两种成因 —— 真干净，还是**分母是空的**」。一条不发 `checkedUnits` 的新闸，正是它要消灭的那种不可解读的绿。

本仓当前对「一条闸」的横向要求，实测有三条，**各由一条元闸守着**：

| 横向契约 | 元闸 | 漏了会怎样 |
|---|---|---|
| 头注释里有挂载层自声明 | `audit:gate-mount-declaration` | 沉默脚本，没人知道它挂第几层 |
| 无条件发**契约 v1** 的 stdout JSON（含 `checkedUnits`）| `gate-output-harvest` | 收割不到 ⇒ 它的绿不可解读 |
| blocking 闸的**接线**有回归面（不只判据）| `audit:gate-regression-ratchet` | 摘掉 `main()` 全绿，棘轮 +1 |

⇒ **新建闸时把这三条元闸各跑一遍**，别等 `pnpm test` 全量替你抓（本轮就是全量抓到的 —— 而全量跑一次 29s，比逐条跑三条元闸贵）。

🔴 **这一格与「朝内三问」性质不同，别合并**：三问问的是「我的判据可靠吗」，本格问的是「我这条闸在这个仓库里合法吗」。前者靠想，后者**只能靠跑那几条元闸**——因为契约本身写在别处，你不去读就不知道它存在。

**顺带一个真 bug 的成因也在这**：接输出契约时 `--json` 分支把人类摘要一起打进了 stdout ⇒ 下游 `JSON.parse` 当场炸。**是那 26 条回归面里的一条测试抓到的，不是我先想到的** —— 整脚本 harness 的又一次兑现（只 import 判据函数的测试结构上看不见 stdout 形态）。

---

## 二 · 新 pattern：**派生产物不该承载人的判定状态**

本轮给 owner/designer 生成了一份「rows 存量逐条判真假」的清单（28 个决策点），初版给每条放了：

```
- 判定：☐ 真缺陷（修）　☐ 有意（进 allow 表，写理由）
```

**这是个真缺陷，我自己造的**：那份文件是机械生成的、每次重跑**整份覆盖** ⇒ owner 在上面打的勾会被下一次重跑抹掉。

⇒ **判据**：一份产物只要标了「机械生成，别手改」，它就**不能**同时是判定状态的载体。两者互斥。

**修法不是"重跑时保留勾选"**（那要 merge 逻辑，脆弱且会产生第二份真源），而是**把判定的落点移到不会被覆盖的地方**，并在文件头显式禁止在报告上记判定：

- 判「真缺陷」→ 在 Figma 里改掉
- 判「有意」→ 进 `--config` 的 `allow` 表，带具名理由（闸每次运行会把 allow 掉的每条连同理由打出来，禁静默 cap）
- ⇒ **判过的条目会因为「已修」或「已被 allow 命中」而自然从报告里消失** —— 那才是进度的可核信号

🔑 **推广形态**：派生产物的正确角色是**事实清单**（每次重算、可弃）；人的决定必须落在**契约面**（代码 / 豁免表 / Figma），那里有 git diff 和闸看着。把决定写进会被重算的东西 = 决定会静默消失。

⚠️ 同族但**不是**同一条：`foreign-library-cleanup.md` 那类产物也标「别手改」，但它从来没打算承载判定 ⇒ 没这个冲突。本条要治的是「顺手给清单加个勾选框方便人用」这个直觉。

---

## 三 · 一条已登记规则的第三次实证（不是新 pattern，但值得记次数）

memory `worktree-lacks-node-modules-and-uses-main-hooks` 的第 3 坑（worktree 里 `hooksPath` 解析到**主仓**绝对路径 ⇒ 跑的是主仓那份 hook）**本轮又救了一次假声明**：

新闸头注释声明了 `L4 = .husky/pre-commit 的 … 条件块`，而首次 commit 打出 48 个 `▶ pre-commit` 块、exit 0 —— 看起来验过了。实测 `grep -c 'acceptance-gate-coverage'` 在**主仓那份** hook 里 = **0** ⇒ 我加的块**从未执行**。

⇒ 复验用 memory 记的配方（`git -c core.hooksPath=.husky/_`），并补了**三级证明**：

1. 块被执行（输出里有那行 `▶`）
2. 触发面命中时**真调闸**（打出闸的完整自印）
3. 造真违例（往规则真源加一个新 Acceptance 段）⇒ **hook EXIT=1，真拦住了**

🔴 **只有第 3 级是「闸在守」的凭据**。第 1 级只证明「hook 文件被读了」，第 2 级只证明「命令被调了」—— 本轮第一次复验拿到的是「块被执行但 `skipped`」（amend 时 staged 为空），若停在那里就会把「接线在」误报成「闸在守」。

⚠️ 同族教训在 memory `verification-criterion-must-be-terminal-state`：**判据必须取终态事实**。「hook 里有那一行」不是终态，「造了违例它会红」才是。
