# ai-ds-lab

TVU 设计系统的**外部评测台 + 方法论仓库**——分析「AI 消费 / AI 维护的产品设计系统」。
**它是 DS 的体检科，不是 DS 的一部分。**

- **当前进度与谁在等谁：[docs/round2-status.md](docs/round2-status.md)** ← 续跑先读这份
- 设计文档：[docs/specs/2026-08-21-ai-ds-lab-design.md](docs/specs/2026-08-21-ai-ds-lab-design.md)（⚠️ 先读文末 §16 勘误）
- lab 自己的硬规则：[AGENTS.md](AGENTS.md)
- 被测对象与 pin：[subjects/tvu-ds/subject.json](subjects/tvu-ds/subject.json)

## 常驻装置（2026-09-04 起，owner 拍定 A+B 档自动 / C 档排队）

| 装置 | 是什么 | 落点 |
|---|---|---|
| `com.claude.ds-sweep`（launchd） | 每日 **09:17**（⚠️ **名义值** —— 机器那时在睡就唤醒后补跑，2026-09-07 实测三轮落在 09:58 / 09:22 / 10:01）跑 A 档巡检，**⛔ report-only**（不修不提交） | 产物 `~/.claude/ds-sweep/sweep-<日期>.json` + `.env.json`（环境名）+ `ds-sweep.log` |
| [`metrics/ds-sweep.mjs`](metrics/ds-sweep.mjs) | 采集器：6 条文档面闸 + 3 个度量账本新鲜度 + **1 条「此刻能不能提交」探针**（2026-09-07 加，owner 拍 Q9）+ **1 条迭代趋势活体测量**（2026-09-07 加，owner 拍 Q3）+ **DS 健康度那 8 格**（2026-09-08 加，Q4 立格后接线）。退出码 **0 全清 / 1 被测对象要人看 / 2 装置自己坏了**（⛔ 2 不得读作「DS 没问题」） | 迭代序列 `~/.claude/ds-metrics/iteration-ledger.jsonl` + 维度序列 `~/.claude/ds-metrics/ds-dimensions.jsonl`（⛔ 两者都不落任何 git 仓） |
| `com.claude.ds-autofix`（launchd） | 每日 **10:17**（同样是名义值）跑 **A 档自动修** —— 2026-09-07 起放开：拉取 → 取数 → 唤起 headless agent → 收尾核查 → push（只走 ff） | 产物 `~/.claude/ds-autofix/run-<时间戳>/`（run-report.json + sweep 前后 + agent 输出 + guard 日志） |
| [`bin/ds-autofix.sh`](bin/ds-autofix.sh) | 上面那个装置的入口。退出码 **0 全清 / 1 要人看 / 2 采集器自称装置故障 / 3 前置不成立 / 4 并行冲突已停手 / 5 提交纪律违例** | — |
| [`bin/ds-autofix-guard.mjs`](bin/ds-autofix-guard.mjs) | PreToolUse hook：**机械**拦 `add -A` · `--no-verify` · `force` · `merge` · `rebase` · `reset --hard` · `stash` · `core.hooksPath`/`HUSKY=0` 绕法 · 开工前就脏的文件。自证 **25 必拦 / 20 必放** | `node bin/ds-autofix-guard.mjs --self-test` |
| [`docs/decision-queue.md`](docs/decision-queue.md) | **C 档唯一落点**。四类才进：C1 值不值上闸 · C2 频次痛感 · C3 文档与活体产物冲突 · C4 放宽闸 | 每条附起草好的判据，owner 拍一个分支即降 A/B 档 |

⚠️ **launchd 的 node 与交互 shell 的不是同一个**（`bash -l` → ServBay v22.21.1；交互 → nvm v24.15.0）。
两者读数已于 2026-09-04 实测一致，但 ⛔ 别假设永远一致 —— 每次的真实版本写在 `.env.json` 里。

✅ **「A 档自动修」2026-09-07 已放开** —— owner 拍的 `open-after-checks` 把授权前置成了成文判据，
清单 6 条全部拿到「造故障时它红 / 还原后它绿」两侧读数后，agent 自行放开（⛔ 未再问 owner，那正是那个分支的含义）。
判据先写死在 [`docs/2026-09-07-q7-autofix-release-preregistration.md`](docs/2026-09-07-q7-autofix-release-preregistration.md)、
证据表在 `decision-queue.md` **Q7**。

⚠️ **纪律靠机械层，⛔ 不靠 agent 自觉**：`pull --ff-only` 前置由 wrapper 做（agent 无从跳过）·
禁用命令由 PreToolUse hook 拦（`bypassPermissions` 模式下**实测仍生效**）· 收尾由 wrapper
**独立复跑采集器 + 独立查 git 状态**，⛔ 不采信 agent 自陈。

⚠️ **登记在案的残余风险**：LLM 那一层每条只实测 1–2 次（owner 清单字面就是「实测一次」），
⛔ 不是分布证据；且验证在 DS 的沙箱克隆里做（`~/.ai-ds-lab/sandbox/`），另补了一次 live 监督 run。

⚠️ **verify 环境的两条事实**（⛔ 别假设两边一样）：`bash -l` 解析到的 `claude` 是
`/Applications/ServBay/package/node/current/bin/claude` **2.1.89**，而交互 shell 是
`~/.nvm/.../bin/claude` **2.1.251** —— **两个不同的二进制**。真实版本每次写进 `run-report.json`。

🔴 **首次无人值守 run 的真读数（2026-09-08 10:40）：`exitCode 3`，零改动。**
`run-2026-09-08T104037/run-report.json` 逐字 `phase: "pull"` · `agent.ran: "no"` · `pushed: "no"`，
日志根因逐字 `Could not resolve host: product-demo.tvustream.com` ——
**`origin` 是内网主机**，那一刻解析不了。⛔ 这**不是装置缺陷**：它正确地拒绝了
「在不知道有没有并行改动时唤起一个有写权的 agent」。
⚠️ 但它更正了昨日那句登记：「亲验 origin 此刻可达 ⇒『天天 exit 3』不成立」
**只对那一刻成立** —— 同一天 14:xx 单跑 `git fetch origin` 又是 `EXIT=0`
⇒ **可达性是间歇的**，取决于当时在不在公司网络。
⇒ 无人值守的**有效 run 率取决于一个 lab 控制不了的外部条件**，
且到此刻**仍没有一次成功的无人值守 run**（⛔ 不许把「装置装上了」读成「它在干活」）。

🔴 **⛔ 别把这个采集器的「闸红 0 条」读成「DS 仓可用」** —— 2026-09-07 实证：它连报 3 天绿，
而那 3 天 DS 仓**一次提交都提不了**（`audit:plan-lifecycle` 存量红 + `pre-commit` 跑全量 vitest，
其中有测试断言「真仓库此刻是绿的」）。采集器的闸清单是手写的 6 条，那条不在里面。

✅ **已修（owner 2026-09-07 拍 Q9 的 `add-committability-probe`）**：采集器现在**先印**一条
「此刻能不能提交」读数 —— 跑 `pre-commit` 里**无条件**那一段（`pnpm test`），只记
`EXIT` + 红掉的测试文件名，⛔ 不修不提交；超时记作 `canCommit: null`（**不知道** ≠ 能）。
阳性对照：把那份 plan 挪回 live 重建原故障 ⇒ 同一次输出里印出「**闸红 0 条 · 提交被拦**」
并点名 `tests/audit-plan-lifecycle.test.ts`；还原后零残留。

⛔ **它绿 ≠ 任意一次提交都能过** —— `pre-commit` 还有一批按 staged 文件触发的条件块
（typecheck 作用面 / render check / claim-vs-livesource 等），那些的红取决于你改了什么。
这是如实登记的边界，不是 TODO。

⚠️ **2026-09-07 补漏（Q7 验放行清单时撞出）**：探针 v1 **只覆盖了无条件段的一半** ——
`.husky/pre-commit` 第 **5–6 行** `pnpm exec vue-tsc --noEmit` 同样无条件，而 v1 只跑了第 8–9 行的
`pnpm test` ⇒ `canCommit: true` 可能假绿。现在探针跑 **2 步**，并加了一条 claim-vs-livesource 对账：
声明的步骤与从活源 `.husky/pre-commit` 抠出的无条件命令逐条对账，**少覆盖 ⇒ exit 2**（装置故障）。
⚠️ 以后有人往 hook 的无条件段加步骤，探针会红 —— 那是**想要的**红，含义是「探针不再知道自己覆盖全了」。

✅ **迭代趋势 2026-09-07 救活（owner 拍 Q3 的 `revive`）** —— 采集器每轮读活体产物
`figma-data/normalized/{,react-}render-verification.report.json`，追一行到
`~/.claude/ds-metrics/iteration-ledger.jsonl`（同日同指纹去重；⛔ **不落任何 git 仓** ——
往 DS 写破坏 report-only，往 lab 写每天造脏文件）。
⛔ **刻意不用**账本正文声明的 `component-attributes.audit.json`：它 110 天未重生成，
且账本自 row #12 起那些数字列全是 `—` ⇒ **账本自己早就弃用了它**。

🔴 **空转治掉了，但要说清是怎么治的**：`audit-iteration-ledger` 那条「人多久没写新一波」
**⛔ 不再进 needsHuman** —— 它断了 102 天，每轮让采集器 `EXIT=1`，于是 autofix 每天被唤起、
无事可做、退出（实证 `run-2026-09-07T170354`：`classification: none` · 改动为零）。
「多久没有新的一波」是**人的节奏**，不是装置故障。报警换成**产物年龄**（阈值 30 天）。
⛔ 关掉的只有这一条，同轮里 6 条闸 / 提交探针 / 另两个账本全部照常判，那 102 天也**照常印**
（标成 `〔读数·⛔ 不叫人〕`）。

⚠️ **第一版实现被自己的判据推翻**（值得记）：报警原本接在**序列最后一行的年龄**上，
而那一行是**读它的那一轮自己写的** ⇒ 恒等于今天 ⇒ **永远不会红**。
等于把「每天都响的无信息报警」换成「永远不响的无信息报警」，同属本仓「恒真 ⇒ 零信息」族。
判据（P2「真断的时候它仍然红」）**先于实现钉死** ⇒ 一跑就抓到。
口径与两侧读数：[`docs/2026-09-07-q3-iteration-ledger-revive-preregistration.md`](docs/2026-09-07-q3-iteration-ledger-revive-preregistration.md)。

⛔ **不许说「账本救活了」** —— 救活的是**测量**。DS 侧 markdown 账本本轮**一行未追加**
（那一步需 DS 写权 ⇒ 归 `ds-autofix`，且要等序列有第二个指纹才算得出第一个 Δ）。
序列此刻 1 个点 ⇒ **「趋势」这个词还不可用**。

✅ **DS 健康度那 8 格 2026-09-08 接进采集器** —— 此前它们只是 DS
`docs/internal/ds-health-dimensions.md` §3 里的「活源算法 + 当日基线」，**没有任何东西每天去算**。
现在每轮从活源现算（DS §0 的 **G4**：⛔ 不引用任何既有报告的数）并追一行到
`~/.claude/ds-metrics/ds-dimensions.jsonl`。**7 格接线 · `DIM-Q14` 明确不接**（三条闸都没有
`--json`，分母只在散文里 ⇒ 取数要靠正则解析散文；已印 `null` + 理由 + 重开条件，⛔ 不是省略）。

🔴 **两条口径别读错**：
- **默认不叫人**。判据是「**有没有别的闸已经在守它**」（逐格实测）——
  `Q12`/`Q14`/`S9` 各自已有闸在守 ⇒ 只记读数（标〔读数·⛔ 不叫人〕）；
  `Q13`/`U16`/`X17`/`X18`/`X19` **零闸在守** ⇒ 它们退步才叫人。
  ⚠️ 其中 `U16`/`X17` 的量具 `audit:docs-site` **在 `gate-chain` 里**（阻塞面）却单跑 `EXIT=0`
  而 `threeViewPending` 非零 ⇒ **在链上 ≠ 守这个数**（与 Q2 那条「报 20 条 fail 却 EXIT=0」同族）。
- **触发条件是退步、不是绝对值**，且比的是**比例**（G5）。⛔ 不许「pending > 0 就叫人」——
  U16 此刻 pending 就是非零，那会恒红，而恒红 = 零信息。
  ⚠️ 序列只有 1 个点时印的是「**趋势不可用**」，⛔ 不是「无退步」。

🔴 **G4 在 `DIM-Q13` 上兑现了**：我第一版的两个算式**都算出 0**，而登记基线是「闸级 1 · 规则级 13」
—— 一个被**否定句**污染（`⛔ 刻意不挂 .husky` 让「提到 .husky 就排除」的判据假阴性），
一个把 import 进来的裸标识符列表当成了对象字面量。**照基线抄就会把这两个错完整掩盖。**
口径与两侧读数：[`docs/2026-09-08-dim-8-cells-sweep-preregistration.md`](docs/2026-09-08-dim-8-cells-sweep-preregistration.md)。

停掉巡检 / 停掉自动修：

```bash
launchctl bootout gui/$(id -u)/com.claude.ds-sweep
launchctl bootout gui/$(id -u)/com.claude.ds-autofix     # 只停自动修，检测仍在跑
```

也可以只关 push（保留检测 + 本地修）：在 `com.claude.ds-autofix.plist` 的
`EnvironmentVariables` 里加 `DS_AUTOFIX_PUSH=0`。⛔ 默认是**开**的 ——
Q7 小节已登记过一次「我主动收窄 owner 授权」的错，不重蹈；控制放在 ff-only + 冲突停手上，
而不是放在「少做一步」上。

## 怎么跑一轮

> 第 1–4 步在 pin 住的 worktree 里做；第 5 步打 GitHub API，与 pin 无关。

### 0. 建 pin 住的只读 worktree（必须，不要读 DS 工作区）

```bash
DS=~/Documents/AICoding/VS_Code/tvu-design-system
SHA=$(node -p "require('./subjects/tvu-ds/subject.json').pinnedShaShort")
W=~/.ai-ds-lab/pins/tvu-ds-$SHA          # ⚠️ 在 DS 仓外面，见下
mkdir -p "$(dirname "$W")"
git -C "$DS" worktree add --detach "$W" "$SHA"
```

⚠️ **worktree 必须落在 DS 工作树之外**（曾经建在 `$DS/.claude/worktrees/`，已改）。
理由是 lab 自己查出来的：DS 有一批脚本会 glob 进仓内目录，**worktree 会被算成重影** ——
第一轮「625 份存量 HTML」里 588 份就是 30 个 worktree 的重影（勘误 E3），
DS 侧 2026-08-24 也刚因同一类问题把测试面分母从 195 涨成 5499（DS commit `410cd11b`）。
⇒ 只要有 DS session 在并行跑它自己的量具，**仓内 worktree 就是污染源**。
放到仓外则 DS 的 glob 完全看不见它，`git worktree` 的元数据仍在 DS 的 `.git` 里（对 glob 无害）。

⛔ **re-pin 时新建，不要拆旧的。** 旧 pin 是既有读数的主键（§5.2），拆了就不可复现；
而且 delta 要对着**落地 commit 的父提交**算，不是对着旧 pin ——
两者之间可能夹着一堆无关 commit（本轮实测 17 个）。
现存的 pin 与各自用途见 `subjects/tvu-ds/subject.json` 的 `pinHistory`。

**要跑闸（成本画像 / 契约运行时读数）时**，worktree 里得先装依赖：

```bash
cd "$W" && pnpm install --frozen-lockfile --prefer-offline   # node_modules 被 gitignore，不污染 pin
```

⚠️ 自己用 `sh -c` 跑 npm script 时，**必须把 `$W/node_modules/.bin` 塞进 PATH** ——
pnpm 会做这件事，`sh` 不会。少了它 `eslint` 类步骤报 **exit 127**，长得像被测对象失败（N30）。

### 1. 闸挂载盘点 —— 哪些 gate 从没上过场

```bash
node adapters/ds-gate-mount-inventory.mjs --ds "$W" --out subjects/tvu-ds/inventory/gate-mount-$SHA.json
```

### 1b. 闸的 stdout 输出契约盘点（第 7b 步的前置读数）

```bash
node adapters/ds-gate-output-contract.mjs --ds "$W" \
  --ci-history subjects/tvu-ds/inventory/ci-gate-history-2026-08-24.json \
  --out subjects/tvu-ds/inventory/gate-output-contract-$SHA.json
```

⚠️ 扫描面是 `scripts/` **+ `figma-sync/`** 两个目录（第 1 步的挂载盘点只扫前者，见 N16）。
`--ci-history` 可选；给了才做「源码形态 × CI 运行时观测」的跨源对账。

### 2. 文档入站引用索引（归档处置 / retrospection 分类的共同前置）

```bash
node adapters/ds-doc-graph.mjs --ds "$W" --under docs/_archive --out subjects/tvu-ds/inventory/doc-graph-archive-$SHA.json
```

### 3. retrospection S1 脚本分类（零 AI）

```bash
node metrics/retrospection-s1.mjs --ds "$W" \
  --graph subjects/tvu-ds/inventory/doc-graph-archive-$SHA.json \
  --out subjects/tvu-ds/inventory/retrospection-s1-$SHA.json
```

### 3b. retrospection S2 前置：上界口径 + 证据候选（零 AI）

```bash
node metrics/retrospection-s2-prep.mjs --ds "$W" \
  --s1 subjects/tvu-ds/inventory/retrospection-s1-$SHA.json \
  --graph subjects/tvu-ds/inventory/doc-graph-archive-$SHA.json \
  --out subjects/tvu-ds/inventory/retrospection-s2-prep-$SHA.json
```

先用 `basename 口径`（**上界**）把「S1 判 0 引用但其实有人用文件名指着」的摘出 S2
——能脚本判的就不交 AI（§11.4）。内建「上界 ≥ 下界」不变量 + 与 doc-graph 的扫描面总数对账，
任一不成立当场抛。⚠️ 上界的用途是**反向**的：`>0 ⇒ 不放行`，不是 `>0 ⇒ 是现行资产`。

### 3c. 复盘自述的回流落点核对（零 AI）

```bash
node metrics/retrospection-s2-claims.mjs --ds "$W" \
  --out subjects/tvu-ds/inventory/retrospection-s2-claims-$SHA.json
```

复盘写「结论已回流到 X」是**自述不是事实**。本器逐条到现行文档核，三种结局：
`as-claimed` / **`relocated`（在册但落点搬了）** / `CLAIM-FAILED`。
⚠️ 没有 `relocated` 这一档会把「已固化、可删」误判成「会丢结论、不可删」——实测 7/30 是这一档。

### 3d. S2 裁决的机械复核（零 AI，⛔ 出数前必跑）

```bash
node metrics/retrospection-s2-verify.mjs --ds "$W" \
  --prep subjects/tvu-ds/inventory/retrospection-s2-prep-$SHA.json \
  --verdicts subjects/tvu-ds/inventory/retrospection-s2-verdicts-$SHA.json \
  --out subjects/tvu-ds/inventory/retrospection-s2-verify-$SHA.json
```

核 C1–C7：行集合一致 / 枚举合法 / **每条证据的 `file:line` 逐字存在** / 至少一条证据 /
`delete` 不得推翻确定性读数 / `low` 不得配 `delete` / 提炼承诺非空。
内建 must-hit 1 条 + must-not-hit 9 条。**第一次跑真数据就判失败 6 条**（3 条行号偏一行、
3 条引文短于下限）——「证据定位」不验等于没要求。

⚠️ 它只验裁决**站不站得住**，不验裁决**对不对**。语义正确性原设计靠 §11.4 安全网第 1 层，
而那层实测无覆盖（勘误 E19）⇒ 见 `proposals/2026-08-24-stale-anchors-codespan-gap.md`。

### 4. 结果层指标

```bash
node metrics/escape-rate.mjs  --ds "$W" --out subjects/tvu-ds/inventory/escape-rate-$SHA.json
node metrics/context-cost.mjs --ds "$W" --time-gates --out subjects/tvu-ds/inventory/context-cost-$SHA.json
```

⚠️ `--time-gates` 的**第一次结果要丢弃**（冷启动约 3.4 倍）。

### 4b. golden set 冻结校验（**每次用之前跑**，不是一次性动作）

```bash
node metrics/golden-set-freeze.mjs --pin "$W" \
  --out subjects/tvu-ds/inventory/golden-set-freeze-v1-$SHA.json
```

验冻结物没被改过 + 每条 task 的真实需求出处在 pin 上**逐字可定位** + 判据脚本存在。
任一项不过 → exit 1。重新冻结用 `--freeze`（⚠️ 那是**改冻结物**，不是校验）。

⚠️ re-pin 之后这一步**很可能 fail** —— 出处被删/被搬。那不是 bug，
是 §7.5 set 升级流程该被触发的时刻（勘误 E28）。

### 5. 闸的执行史（`rule-hit` 历史读数 · 不需要 worktree）

```bash
GH_TOKEN=$(gh auth token) node adapters/ds-ci-gate-history.mjs \
  --out subjects/tvu-ds/inventory/ci-gate-history-$(date +%F).json
```

⚠️ 这是**跨 sha 的历史语料**，不是 pin 处的快照——别拿它跟第 1–4 步的产物做 diff。
⚠️ 窗口已于 **2026-08-14** 关闭（GitHub Actions 账单），重跑只会拿到同一批历史。

### 6. 收工

```bash
git -C "$DS" worktree remove "$W"
```

## 目录

| 目录 | 装什么 |
|---|---|
| `adapters/` | 桥接 DS 的只读解析层（复用 DS 自己的 gate 导出函数） |
| `metrics/` | lab 自写的结果层打分脚本（纯 Node、零依赖） |
| `tasks/tvu-ds/` | golden task set（冻结 + 版本化，§7.5）。⚠️ 改了内容必须重跑 `--freeze` |
| `subjects/tvu-ds/` | DS 路径、pin 的 sha、各轮实测 JSON |
| `reports/` | 人读报告 |
| `proposals/` | 给 DS session 执行的处方 |

## 第一轮产出（2026-08-24 @ `71ac2711`）

| 报告 | 一句话 |
|---|---|
| [未执行 gate 清单](reports/2026-08-24-gate-mount-inventory.md) | **两条 meta-gate 全绿的同时，17 条闸从未上过场** |
| [retrospection S1 分类](reports/2026-08-24-retrospection-s1.md) | 严格判据下 `superseded` = 0；S2 待判 38 份，非预估的 ~10 份 |
| [第一轮基线](reports/2026-08-24-first-round-baseline.md) | 「625 份存量 HTML」是 worktree 重影；声明规则文档面约 25.5 万 token |
| [归档三分法处方](proposals/2026-08-24-archive-triage.md) | `_generated` 不能整目录移——7 个脚本读它 |

## 第二轮前置（2026-08-24）

| 报告 | 一句话 |
|---|---|
| [第二轮前置](reports/2026-08-24-round2-preconditions.md) | **38 条在链闸里，两个半月只有 4 条拦下过东西**；mockup 合并的真收益是「350–400MB payload 抓 8 遍降到 1 遍」，不是省进程启动（那只值 0.06%） |

## 第二轮第 7 / 7b 步（2026-08-24）

| 产出 | 一句话 |
|---|---|
| [闸的输出契约盘点](reports/2026-08-24-gate-output-contract.md) | 契约不是「38 条里散落 8 条示范」，而是**目录级分界线**：`figma-sync/` 在链 11 条里 10 条已发结构化输出，`scripts/` 在链 25 条里 **0 条** |
| [mockup 闸合并处方](proposals/2026-08-24-mockup-gate-merge.md) | 执行点方案落在 **B1**：DS 已有的 PostToolUse hook **触发点今天就是自动的**，只差从 URL 捕获 fileKey |
| [输出契约处方](proposals/2026-08-24-gate-output-contract.md) | v1 只动 `figma-sync/` 11 条、不碰一条 `scripts/` 闸；`scripts/` 那 25 条另立 shrink-only 棘轮 |

## 第二轮第 7 / 7b 步 **落地后的 delta**（2026-08-25 · DS commit `4a68e02d`）

| 产出 | 一句话 |
|---|---|
| [7 / 7b delta 实测](reports/2026-08-25-round2-step7-7b-delta.md) | 契约的分母键 `checkedUnits` 在链上 **0 → 11 条可读**，**上线当天抓出 1 条真·假绿**；但造故障发现收割器有一格漏 —— `findings>0 ∧ checkedUnits=0` 不报、exit 0 |
| [第 9 步处方（**范围已收窄**）](proposals/2026-08-25-chain-failfast-denominator.md) | 全链热态只有 **8.7 s**、单条闸占 **70%** ⇒「按成本重排 / 分组并行」ROI 不成立，**砍掉**；第 9 步只剩「解 fail-fast 让分母可比」 |
| [交叉校验缺口处方](proposals/2026-08-25-crosscheck-denominator-gap.md) | 真值表五格里三格不看 `checkedUnits` ⇒ 一条闸只要报出 findings，分母就无人校验。**must-hit/must-not-hit 抓不到，只有造故障能** |

## 设计走查闸的覆盖缺口（2026-08-27 · DS commit `8183a1c6` → `1cc95824`）

| 产出 | 一句话 |
|---|---|
| [设计走查闸覆盖缺口盘点](reports/2026-08-27-round2-designqa-gap.md) | 几何/尺寸/间距类规则 **15 条**，闸只接住 **5 条**；`domain-tvu.md` 那条 Acceptance 的 4 个核查项**实现了前 3 个**，第 ④ 个（行高与分隔线间距）**一条闸都没有** |
| [设计走查闸覆盖缺口处方](proposals/2026-08-27-designqa-gate-gap.md) | 最该先补的是 ④；⚠️ 前置是**先核「行」到底长什么样**，⛔ 不是先写闸。另交 owner 一个决策点：要不要立「Acceptance ↔ 闸」的对位登记 |
| [分母 / 计数器缺陷处方](proposals/2026-08-27-geometry-gate-denominator-defects.md) | 复核 DS 的执行时撞出两条**「没被检查」被输出成「检查过、是 0」**：`collectStateFrameGroups` 按 `WxH` 分组让 G2 分母**静默变小** · `scanned` 的纪律**只守了一半**。两条都落在该闸**自己已经立过纪律**的地方。🔴 2026-08-27 实证后拆出第三条 **A′**：`--probe` 对 G2 **全域**不可断言 |
| [`--probe` 盲区实证](reports/2026-08-27-round2-probe-blindspot.md) | 五臂对照 fixture 喂该闸导出的纯函数：假绿**实证成立但有边界条件**（同组件集时 G1 独立兜底 ⇒ 无假绿），而 `--probe` 的盲区**比处方写的更宽** —— 帧 id 在**故障臂与正常臂上恒红**。🔴 由此立「**恒红 = 零信息，且它长得像 fail-closed**」（`AGENTS.md` 第 25 条） |
