# INFRA-F149 ② 取证预注册 —— 「产品帧显式约定」可行性（B 路线）

> **本文件在取任何一个读数之前 commit。** 先例 = `ai-ds-lab/docs/2026-09-10-delivery-surface-denominator-preregistration.md`。
> 理由很实在：本轮要回答的是「有没有一个约定能罩住真实产品帧」，而**看完数据再去定约定形态、再宣布它罩得住**，
> 是一个无法被事后排除的循环。⇒ 描述性读数与评价性读数分两阶段，第二阶段的判据在看到第一阶段结果之后、
> 评价之前**另行预注册**。

## 0 · 这一步在整条线的哪儿

- `INFRA-F149` ① **档位**已拍并落地（`3bb612e4`，移出默认规则集，新增「隔离」档）。
- `INFRA-F149` ② **路线**已拍（`98d3e0b8`）：先取证 → 再改 §M33 → 最后改闸。
  ⚠️ 拍的是路线，**⛔ 不是判据本身**。
- 本文件 = 路线的第一步「取证」，**纯读数**，backlog 逐字「⛔ 不需要再拍即可开工」。

### 🔴 本轮开工前 owner 追加拍定的一次方向修正（2026-09-15）

owner 逐字追问：「LCD 和 config-T 是消费产品，不属于设计系统的真源，为什么从它这里着手」。

该问推翻了取证的**默认前提**。原计划（记作 **A 路线**）是量「闸能不能从结构**推断**出产品帧」——
即 backlog ② 逐字写的「每帧 `WebUI/*` INSTANCE 数分布 × 人工标注 → 分离度 + N 区间」。

开工前的一条实测让 A 路线的前提当场变脆（读数见 §4「已知量具陷阱」，同一条命令踩过一次 grep 陷阱并已修正）：

| 离线缓存 | `WebUI/*` 命名数 | 该文件主力命名前缀 |
|---|--:|---|
| `rJJjWWs…`（Config-T） | 大量（`WebUI/Form/Item/Input` 2590…） | WebUI |
| `0054ib0…`（LCD） | **1810** | WebUI · Icon · TouchScreen |
| `DtZcMkh…`（MicroApps） | **0** | icon · Button · input box · Box |
| `xu7H3pp…`（TPC） | **1** | icon · Table · Box · Menu |

⇒ 上一轮那个「分离度好（286 / 88 vs 0）」的读数**取自 Config-T 一个文件**。
推到 17 个文件上，`≥N 个 WebUI/*` 在 MicroApps / TPC / Producer 族上**结构性恒 0**
⇒ 那些文件的所有帧都判「非产品」⇒ 闸在那里恒绿。**这正是 owner 说「样本只有 7 页、⛔ 别据此直接上闸」要防的事，只是缺口比预想大一档。**

owner 当轮拍定改走 **B 路线**：

> **B = DS 规定一个显式的产品帧标记约定，闸只认显式标记；⛔ 不从结构去猜。**

B 的立论不是「A 测不出来」，而是**判据真源该在哪**：§M33 是 DS 的规则，让 DS 去逆向猜测消费稿
碰巧长什么样，方向本身是反的。**且本仓已有同闸上的成功先例**——`REFERENCE — …` section 就是显式约定，
上一轮 7 页实测合计 61 个 reference **逐个落对**，STATUS ④ 逐字「区域三分本身是对的，⛔ 别去收窄它」。
⇒ 该闸在「读显式标记」上是准的，塌掉的恰恰是「反向兜底猜」那一半。

⛔ **A 路线未被证伪，只是不先跑。** 上表只说明 `WebUI/*` 这一个信号不通用，
⛔ 不等于「任何结构信号都不通用」。若 B 的可行性读数不支持 B，A 仍在台面上。

## 1 · 取证面（17 个真实产品文件，分层，⛔ 不并池）

口径与成员数来自 `INFRA-F146` 已发表的四口径表（lab `runs/delivery-surface/ds-figma-face-registration.json`）。
⛔ 本轮**不重做**那次枚举，只复用其成员清单。

| 层 | 口径 | 成员数 |
|---|---|--:|
| L1 | `targets`（DIM-U12 登记测量目标） | 6 |
| L2 | L1 + `pattern-index`（实际采集过） | 7 |
| L3 | L1 + `sourceLabels` 里 owner 亲笔 `kind=product-file` | 14 |
| L4 | L3 + `repo-ref ∩ figma-face`（机检新立） | **17** |

**逐个 fileKey（本轮取数面 = L4 全部 17 个）：**

L1（6）：
`DtZcMkhNy6qh6jbQQnhreQ` Micro-Apps-20250923 ·
`rJJjWWs51n2iFOlCIC7aYG` Config-T ·
`0054ib0nLmt27bC3QlGDl7` LCD ·
`tmVCFjx1BCfb7EP5OPD1AP` PP-2025-2026 ·
`BvqvqRXPEBlWFbl1jOC6mh` MH-2026 ·
`HvU7TXVvJGQ8AoS9Z1Jd10` Media Service UR

L2 增（1）：`xu7H3ppLyQfa3fOmU8M7iO` TPC 20220519

L3 增（8）：
`5VVlCTtQ0WRcJdvwUA6bJ5` Config T (Local UI) V7.7&v8.0 20210909 ·
`ZXm4ClRDgGm2M3pU64NC4A` MH-Lora ·
`lqo3mopIoEs27YcJ6R4a0I` PP-Lora ·
`nhZkYb9qQdEngal7iOa5CL` Sandra-TVU One 20210526 ·
`qkxgyVfbPDB9fc2rdbeXOh` PL_3 ·
`daLUTwSPemAbE0bMpn9s8n` Producer Admin ·
`HAL8gzATJx58kynXesipEb` Producer 2.0 ·
`G9JxiOc3V4fVq0DH3GjfTw` TVU Drive

L4 增（2）：
`4nDKKBlQHvkBslebJsQu9o` A cloud TV Station NOC 20240511 ·
`pUE6UakxCpU6Dw9vUCtBBe` TVU RPS 20220302

⚠️ **两个 Config-T 别看混**（`INFRA-F146` 已登记的坑）：L1 里是 `rJJjWWs…`（20240220），
L3 里是 `5VVlCTtQ…`（20210909）—— 同一产品的两代文件。

⚠️ **`targets` 的 `label` ⛔ 不是 Figma 真名** ⇒ 一切比对按 fileKey，⛔ 不按名字。

**取数方式**：`GET /v1/files/:key?depth=3` **REST 现取**，⛔ 不用 `figma-data/mockup/` 离线缓存
（缓存只有 5 份、最旧落后 26 天，且本轮面是 17）。`depth=3` 足以拿到 CANVAS → SECTION → topFrame 三层，
⛔ 不拉全树（全树 17 份约数 GB，本轮的问题不需要它）。

## 2 · Stage 1 —— 描述性读数（本文件即预注册，内容固定）

**⛔ Stage 1 不评价任何候选约定，只清点现状。** 描述性读数改不动结论方向，因此不存在「看了再定」的风险。

每个文件逐帧记录，单位定义先钉死：

- **topFrame** = `type === 'FRAME'` 且其父节点 `type` ∈ {`CANVAS`, `SECTION`}。
  ⚠️ **允许挂在 SECTION 下**——`INFRA-F146` 实测某份缓存里 FRAME 父类型分布是 `{SECTION:1, FRAME:12}`、
  `CANVAS` 直接子 FRAME **一个都没有**，若按「CANVAS 直接子」定义，严口径恒 0，而那个 0 长得像「存量 0」。
- 每个 topFrame 记：`id` · `name` · `parentType` · `parentName`（SECTION 名或 CANVAS 名） · `absoluteBoundingBox` 的 `width`/`height`。
- 每个 CANVAS 记：`id` · `name` · 其下 SECTION 数 · topFrame 数。

产出四张表：

1. **S1-a SECTION 名字清单** —— 全 17 文件的 SECTION 名及出现次数，按文件分列。
2. **S1-b topFrame 名字形态清单** —— 名字按分隔符（`·` `—` `/` `|` 空格）切词后的高频词与前缀分布。
3. **S1-c 挂载结构分布** —— topFrame 有多少挂在 SECTION 下、多少直接挂 CANVAS 下，按文件分列。
4. **S1-d 现有 `REFERENCE` 约定的覆盖计数** —— 作为「显式约定在本仓行得通」的**对照锚**：
   现有 `REFERENCE_SECTION_RE` 在 17 个文件上命中多少 SECTION、罩住多少 topFrame。

## 3 · Stage 2 —— 评价性读数（判据**另行预注册**，⛔ 本文件不预设）

Stage 1 交付后，**在看任何 Stage 2 读数之前**，另写一份预注册，钉死：

- 候选约定形态 C1…Ck（从 S1-a/S1-b 的现状里选，⛔ 不凭想象造）；
- 每个候选的**判定表达式**（可机检，逐字写死）；
- 三个待答量：
  - **Q2 补标记工作量** —— 多少 topFrame 现在不命中 Ck、需要改名或挪位，按文件分层；
  - **Q3 覆盖面影响** —— 在已付过钱的 7 页上，「未标记 ⇒ 不判」会把判过的 product TEXT 分母
    从现值 **2661**（565+327+547+300+242+635+45）降到多少；
  - **Q4 罩不罩得住** —— Ck 是否罩住已知的真设备屏幕帧（见 §4 的 V1）。

⚠️ **Q4 一旦需要扩到 7 页以外，就需要人工标注列**，而 topFrame 分母实测 LCD 597 / Config-T 431
⇒ 17 文件外推 **约 3000–8000**，全量人眼判不可行 ⇒ 那时需另拍抽样设计。
**本轮刻意不进到那一步**：Stage 1 + Q2/Q3 都不需要基准真值，先把这些交出来再判断要不要花那笔钱。

⛔ **backlog 那句「⛔ 不抽样」管的是那 66 项的逐项核实**（分母 66，能全核），
⛔ 不能原样搬到分母几千的标注列上——搬过去只会得到一句做不到的话。这一条是**如实登记的口径分歧**，不是放宽。

## 4 · 已知向量自证（对不上**整批作废**）

量具在报告任何读数之前，必须先通过下列全部向量。⛔ 不许「先出读数、自证稍后补」。

| 向量 | 内容 | 来源 |
|---|---|---|
| **V1** | `rJJjWWs51n2iFOlCIC7aYG` 的 `6907:2` 子树含两个真实设备屏幕帧：`BEFORE · Config-T Modem settings (baseline · …)` **1280×1438** 与 `BEFORE · Config-T Network (baseline · …) — SIM Locked` **1017×902** | `INFRA-F149` ③ |
| **V2** | `rJJjWWs51n2iFOlCIC7aYG` 的 `7687:1203` `name === 'ZH ref caption'` | 闸头注释 :130 逐字 |
| **V3** | 7 页三分计数逐页重现：product 分母 `8075:2`=565 · `7452:2`=327 · `7636:2`=547 · `6907:2`=300 · `10340:2`=242 · `9343:2`=635 · `10166:2`=45；reference 合计 **61** | STATUS ① / ④ |
| **V4** | 7 页违例 id 集合合计 **66** 项，且逐页数为 4/9/0/2/9/0/42 | STATUS ① |

⚠️ **V3/V4 用的是本闸自己的输出，这不违反「⛔ 人工标注不能拿本闸输出充当」** ——
那条纪律管的是**标注列**（基准真值），而 V3/V4 验的是**量具读的是不是同一棵树、走法一不一样**。
⇒ 前者是「判据对不对」，后者是「读数可不可复现」，两件事。本轮 Stage 1 **不产出标注列**，冲突不发生。

### 已知量具陷阱（本轮开工前已踩到一次并修正，留痕）

1. 🔴 **`figma-data/mockup/*.json` 有两种 JSON 排版** —— `rJJjWWs…` / `0054ib0…` 是紧凑（`"name":"…"`），
   `DtZcMkh…` / `xu7H3pp…` 是缩进（`"name": "…"`，带空格）。
   用 `grep -o '"name":"WebUI/…'` 扫后两份**静默返回 0**，而那个 0 长得像「这个文件没有 WebUI 组件」。
   ⇒ 改用带空格的形态复扫才得到真值（MicroApps **0**、TPC **1** —— 结论方向没变，但**论据差点是假的**）。
   ⇒ 本轮量具**一律 `JSON.parse` 后走树，⛔ 不用 grep 数结构**。
2. 🔴 **「查 X 得 0」先问「X 本来会出现吗」** —— 判据真源 `docs/internal/retrospection/2026-09-15-zero-hits-two-meanings.md`。
   本轮每一处得 0 的读数都要配一条阴性对照，⛔ 不许直接当结论。
3. 🔴 **⛔ 别 pipe 到 `head` 再取 `$?`** —— 取的是 `head` 的退出码。`INFRA-F149` 本轮已踩过一次，
   差点写下「闸报了违例却 exit 0」这个不存在的接线缺陷。

## 5 · 边界（⛔ 本轮不做的事）

- ⛔ 不动 `scripts/`（含两个 language-isolation 脚本、`mockup-rules/index.mjs` 的 `QUARANTINE`）。
- ⛔ 不动 §M33 / `mockup-conventions.md` —— 那是判据真源，owner 档。
- ⛔ 不动任何设计稿，⛔ 不写 Figma（只 REST 读）。
- ⛔ 不产出标注列、⛔ 不给 N 的取值、⛔ 不宣布任何约定「可行」——那些都要等 Stage 2 及其单独一拍。
- 量具是一次性的，落 scratchpad，**⛔ 不进本仓 `scripts/`**；只有读数与报告进仓。

## 6 · 工作树

本轮在 `.claude/worktrees/f149-evidence`（分支 `f149-evidence`，基于 `d8588c7b`）。
⚠️ 起因：并行 session 今日连推多条，且刚动过 `docs/internal/mockup-conventions.md`（§M33 所在文件）。
⚠️ `FIGMA_TOKEN` 在**主工作树**的 `.env`（gitignored，mode 600），worktree 里没有 ⇒ 取数脚本需显式指向主树。
