# INFRA-F62 — 延迟验证（claim → verified）：设计 + 自审 **⛔ 结论 = 当前不实施**

> **状态：🔴 已自审否决，⛔ 不要照 §3–§7 动手。** 本文件的用途已从「实施计划」改为**否决记录（封路理由）**。
> 保留全文不删的理由：删掉就只剩「F62 ③ 没做」，下一个人会把同一套 `void` 判据再设计一遍。
> 本仓规矩是**封路理由必须写在产物里**，且[「封路理由」正是最贵的一类二手源](../../../docs/meta-rules.md) —— 所以下面 §0 的四条**必须连证据一起读**，别只读结论。
>
> 真源关系：缺陷历史与现取判据命令在 [backlog [[INFRA-F62]]](../../internal/backlog.md)。
> ⛔ 原先这里写的「落地后把入站指针放进 `scripts/lib/conformance-claim.mjs` …」**作废** —— 那两个文件不该被创建。
>
> **⚠️ 保留一条仍然成立的诚实边界**（它不因否决而失效）：F62-a 原本要的是「交付那一刻机器拦截」。
> 在 owner 2026-08-31 给定的约束下（§2）**消费侧结构上不可能变红** ⇒ 任何 ③ 形态都只能是「后验」，
> 且 **claim 本身防伪强度 = 0**。F98 spec:180 那句「③ 不降防伪强度」**说满了**。

---

## 0. ⛔ 自审：本设计经不起推敲的四处（2026-08-31，owner 追问后逐条实测）

> 前两条是**纯设计错误**（与活源新旧无关），后两条是**没验证就写下的前提 / 空转**。
> 起手对 entry 跑了触发器 S，却没对**自己的设计**跑同一套自审 —— 这是本轮最该记的教训。

### Flaw 1（致命）· `void` 恰好吞掉这套机制唯一存在的理由

§6.2 把对账锚定在「`figmaLastModified` 没变」，变了即 `void`。但**任何一次编辑都会让它变**，而 mockup 工作本来就是反复改的 ⇒ **`void` 是压倒性的常态**，且**系统性偏向**：设计越活跃越必然 void，而那恰恰是最该验的文件。

根因 = 混了两个问题：

| 问题 | `void` 答得对吗 |
|---|---|
| 这个 conformance 结论还适用于当前设计吗 | ✅ 对 |
| 这个人当初到底跑没跑那个机检 | ❌ **完全没答** |

**F62-a 的目的是第二个。**「当初有没有跑」是一个**不会过期的事实**，而我给它配了一条会过期的判据。

### Flaw 2（承重前提未验证，可能不可实现）· §4.3 的 `figmaLastModified` 必填

§4.3 写「无 token 端可从 `use_figma` 的文件元数据取（in-file 插件 API 可读，不需要 REST）」——**这句没有任何证据**。
**现取**：`docs/internal/figma-technical-reference.md` 与 `docs/internal/mockup-conventions.md` 两份 Figma 参考文档里 `lastModified` **零命中**。
⇒ 若插件 API 拿不到它，§6 的对账**没有可比对的锚**，整条链塌。**这是任何重启前必须先证伪的第一件事**，⛔ 别再把它当既成事实。

### Flaw 3（空转 · 且这是本轮最该独立处理的发现）· §5 坐在一个本来就空过的闸上

| 现取（2026-08-31） | 结果 |
|---|---|
| `audit-mockup-handoff-evidence --all` 的交付物清单 | `['templates/consumer-product/docs/handoffs/_handoff.template.md']` —— **1 份，是模板** |
| 该模板喂进 `checkHandoffEvidence()` | `isHandoff=false` · `ok=true`（标记在引用块里：`> <!-- mockup-handoff -->`）|
| DS 仓有真 handoff 吗 | `git grep -l '^<!-- mockup-handoff -->' -- '*.md'` → **空** |
| `TVU Pack` | githooks 未装，owner 2026-08-31 拍定不装 ⚠️ **2026-09-11：已装，但装的是支柱④ upstream-gate、不是本闸 —— 见 §1.2 订正注** |

⇒ **该闸今天在 CI 上的绿，是评估一个「不是 handoff 的模板」得来的空过；它当前守着零个对象。**
⇒ 在它上面加 claim 分支，**在它跑到的每一个环境里都不可达**。
⇒ **这一条不属于本 spec 的否决理由，它是 F62 真正的下一个问题**，已搬进 backlog entry。

### Flaw 4 · §7.2/§7.3 就是我自己批评过的橡皮图章

两种命运二选一：按 Flaw 1 `refuted` 几乎不发生 ⇒ 闸是装饰；若发生 ⇒ **拿一件设计走查的事去挡 DS 仓里毫不相干的 commit**，直到写满 4 字段处置 ⇒ 这正是把表逼成橡皮图章的机制。
且我拿 F86 那张表做类比给自己背书 —— **类比是坏的**：F86 的 69 行是 owner **已经做过的裁定**的记录，这里的行是**打断**。

### 还剩下什么是真的（若将来重启，从这里起）

- ✅ **§4 schema**，但**去掉 `figmaLastModified` 必填**（Flaw 2）
- ✅ **§6 对账器当「测量」**（它产出今天不存在的信息）
- ✅ **§7.1 台账当时间序列**
- ❌ **§5 claim 分支** · ❌ **§7.2 处置表** · ❌ **§7.3 台账闸** —— 都不该建
- 🔑 **重启的前置顺序**：先答 Flaw 3（那个闸到底在守谁）→ 再证伪 Flaw 2 → 才谈要不要做测量档。⛔ 反了就是在空转的闸上加东西。

---

## 1. 缺陷 —— 先订正 entry 里三条已过期的转述（2026-08-31 全部活源实测）

接手时 entry 与交接单给的四条前提，**三条经实测已不成立**。三条都不是措辞问题，都改变了要建的东西。

### 1.1 无 token 环境**不产出**任何 report（entry 说的是「产出一份 subAudits 全 2 的 report」）

- entry 逐字（2026-07-30 实证）：「`FIGMA_PERSONAL_ACCESS_TOKEN` 实测 UNSET → 9/9 could-not-run、`subAudits` 全非 0，`reportPassed` 恒 false」。
- **现取**：[`audit-mockup-conformance.mjs:515`](../../../scripts/audit-mockup-conformance.mjs) 是 `const TOKEN = requireFigmaToken()`，位置在**跑任何一条规则之前**；[`figma-env.mjs:158`](../../../scripts/lib/figma-env.mjs) 直接 `process.exit(2)`。
- **实测（空目录 + `env -u` 两个变量名）**：`EXIT=2`，stdout 只有 `FIGMA_PERSONAL_ACCESS_TOKEN is not configured`，**`--report` 指的文件根本没被创建**。
- **成因**：`4a68e02d`（2026-08-25「合成单进程引擎」）把子审计从 spawn 独立进程改成单进程，凭据检查随之上移到引擎入口。entry 的实证打在此前 26 天。

⇒ **「先有一份 report 可以标 claim」这个起点不存在。** ③ 必须是 F98 spec §8 逐字说的那件事 —— **给 conformance report 立第二个合法生产者**，不是给既有 report 加两态。
⇒ 交接单转抄的「`exitCode=2`（缺 token）在任何档都硬失败，那正是要治的点」**同时作废**：今天的 `exitCode=2` 只来自「离线缓存过期被跳过」与「规则抛异常」两条路径（[`:585`](../../../scripts/audit-mockup-conformance.mjs) / [`:608`](../../../scripts/audit-mockup-conformance.mjs)），与缺 token 无关。

### 1.2 `TVU Pack` **是** git 仓（entry 说「不是 git 仓库 → 无机器拦截」）

| 项 | 现取 |
|---|---|
| `git rev-parse --show-toplevel` | `TVU Pack` 自身；有自己的 `.git` 目录 |
| 首个 commit | `2c4ecd5` **2026-08-11 13:12**「Initial commit: TVU Pack UX design deliverables」（13 个 commit） |
| `core.hooksPath` | 空 |
| `.git/hooks` | 只有 `*.sample` |

⇒ 「无机器拦截」**是真的，但成因不是结构性的**：是 `templates/consumer-product/.githooks/` 没部署。
⇒ entry 那句转述**已过期 20 天**，且它把「一条安装命令」写成了「结构性缺口」。
⇒ ⚠️ **本设计仍不装它** —— owner 2026-08-31 明确不批（§2）。此处只是把事实记正，供将来重开时用。

> 🔴 **2026-09-11 订正 —— 上面这张表是 2026-08-31 的现取，其中三格今天已经不成立**：`core.hooksPath` 现为 **`.githooks`** · `.githooks/pre-commit` 是一份活着的零依赖闸（不再只有 `*.sample`）· commit 数 13 → **32**。
> **装它的是 2026-09-09 的支柱④ upstream-gate 线**（commit `e9da70a`，owner 拍 ai-ds-lab decision-queue Q13），它只扫 staged `docs/specs/upstream-gate.*.md`，**不是本 spec 的 claim 机制**。
> ⇒ **§10 非目标 1 的两条重开条件仍未触发**（没有非 owner 的 claim 生产者，§8.4 也没失效），「本设计仍不装它」那句**不变**。
> ⇒ 变的只有一点，但重开时必须知道：**`.githooks/pre-commit` 这个位置已被占用** —— ⛔ 别照 `templates/consumer-product/.githooks/` 原样部署，那会整份覆盖掉 upstream-gate 那份闸。详见 backlog [[INFRA-F62]] 判据 ③。

### 1.3 claim 语义**已经被手工实践了近一个月**（entry 说「唯一存在的 report 是手写 schema」）

- `TVU Pack/docs/handoffs/.conformance/` 下现有 **≥5 份** JSON。
- `TVU Pack/docs/handoffs/2026-07-21-v4-1827-ndi-into-ipsource-handoff.md:119` 引用其中一份，括号里逐字写着：
  **`（in-file 机检结构化落盘；REST 五闸仍待 token 补跑）`**

⇒ 这就是 claim + 待复跑，**只是没 schema、没对账、闸不认**。本设计要做的是把已经在跑的东西规范化，不是引入新概念。

### 1.4 仍然成立的那一条

`TVU Pack` **无 `.env`**，且其 `.gitignore:8` 忽略 `.env` ⇒ **无 REST token 是真的**，F62 的病灶本体未变。

### 1.5 entry 自身不合规（顺带修）

`INFRA-F62` entry **没有「现取判据命令」字段**，而 [`meta-rules.md` 触发器 S](../../meta-rules.md) 逐字要求每条 entry 结构性地带它、「没有那个字段 = 它本身不合规，先补再动手」。本轮正是因此只能现编命令，也正是因此才撞上 §1.1–1.3 三条过期转述。⇒ 落地时一并补该字段（§5.5）。

---

## 2. owner 裁定（2026-08-31 当轮，逐条）

| # | 裁定 | 依据 |
|---|---|---|
| 1 | **走 ③ 延迟验证**，不走 ①（降级通道）| ① 放宽防伪强度；② 已于 2026-08-06 被排除（F98 spec:180）|
| 2 | ⛔ **不设时间型有效期** | claim 不会因为「放久了」变假 —— 它要么当初就真跑过，要么当初就是编的；天数不区分这两者，只会某天把两者一起判红。且必然走向「把日期往后挪」的橡皮图章 |
| 3 | ⛔ **不写 Figma**（含把 claim 落 `setSharedPluginData`）—— 除非 owner 主动要求 | owner 逐字：「不要修改 Figma 里面的内容，除非我主动让你写」。**作为机制副作用的自动写入尤其不行** |
| 4 | ⛔ **不写回 consumer 仓** | 同 3 的同类动作 |
| 5 | ⛔ **不装 `.githooks` 到 `TVU Pack`** | owner 判「没有必要的原因」 |
| 6 | **不限制 dev 工作方式**；消费路径**不保证**经过有 token 的环境 | owner 逐字：「不一定经过，不限制开发的工作方式」 |

**裁定 6 的直接后果（本设计的形状全由它决定）**：任何「dev 消费时自动对账」的触发点全部出局。对账只能挂在 **owner 侧定期会跑的东西**上。
**裁定 3+4+5 的直接后果**：牙齿只能长在 **DS 仓自己**身上（§7）。

### 2.1 被排除的三条路线（连理由一起留档，防止下轮重提）

1. **claim 落 Figma `sharedPluginData`** —— 技术上两半都现成（写：`mockup-conventions.md:568` 已有 `ux_annotation` 先例；读：[`audit-mockup-conformance.mjs:370`](../../../scripts/audit-mockup-conformance.mjs) 已在请求 `?plugin_data=`，`connector` 规则已在消费）。**被裁定 3 否决。**
2. **producer 把 claim 推进 DS 仓台账** —— 无 token 环境（claude.ai/Design）没有本仓写权限 ⇒ 需要人手工搬运。把机制押在「有人记得贴」，正是本仓「规则别继续往 L1 prose 加」要治的病。
3. **handoff 直接标「未验证」+ 记进豁免表放行** —— 这就是候选 ①，换了个名字。

---

## 3. 形态总览

```
[无 token 端]  use_figma in-file 机检
                    │ 写
                    ▼
     <consumer>/docs/handoffs/.conformance/*.json      ← claim（已存在的落点，本设计只给它 schema §4）
              │                          │
   被 handoff │ 用既有那行引用            │ 只读（不回写 —— 裁定 4）
              ▼                          ▼
   audit-mockup-handoff-evidence     ds-reconcile-conformance-claims   [owner 端 · 有 token]
   §5 认 claim → 放行 + 显式印        §6 按 DS_CONSUMER_ROOTS 扫 → 复跑 → 判定
      「未验证」；refuted/void 判红                    │
              ▲                                       │ append（只写 DS 仓）
              │ 下一次跑到时读到新 mode                ▼
              └───────── docs/internal/_generated/conformance-claim-ledger.jsonl   §7 台账
                                        │ 只读（+ 只读处置表）
                                        ▼
                          audit-conformance-claim-ledger   §7 台账闸（L4+L5 —— 唯一的牙齿）
```

⚠️ 图里左下那条回边**不是自动的**：handoff-evidence 读的是 claim 文件本身，而对账结论落在 DS 台账里。
消费侧的 claim 文件**不会被改写**（裁定 4）⇒ 那边下次跑仍读到 `mode:"claim"`。
**`refuted` 的实际生效点只有台账闸**（§8.4 逐字说明红为什么落在 DS 仓）。§5.1 表里的 `refuted` / `void` 两行，
是给「将来若允许回写、或 claim 由有 token 端产出」预留的判定，**当前约束下走不到**。

三个面**全部是现存的**，新增只有一份 schema + 一个只读脚本 + 一条只读 DS 仓的闸：

| 要什么 | 已经有了什么 |
|---|---|
| claim 的落点 | `<consumer>/docs/handoffs/.conformance/*.json`（§1.3 实证在用）|
| handoff 的引用形态 | `REPORT_REF_RE = /Conformance report:\s*(\S+\.json)/i`（[`audit-mockup-handoff-evidence.mjs:87`](../../../scripts/audit-mockup-handoff-evidence.mjs)）—— claim 复用同一行，不新增语法 |
| 发现面 | `ROOTS = process.env.DS_CONSUMER_ROOTS \|\| mainWorktreeParent()`（[`ds-health-scan-consumers.mjs:61`](../../../scripts/ds-health-scan-consumers.mjs)）。`TVU Pack` 正是主工作树父目录下与 DS 平级的目录 |
| 对账的 token | owner 本机 DS 仓 `.env`（`figma-env.mjs` 单一 parser）|
| 观测器范式 | `ds-health-scan-*` 两只：**L0 · 手动/定期 · always exit 0 · 刻意零挂载**（各自头注释自陈）|

---

## 4. claim schema

落点 `scripts/lib/conformance-claim.mjs`（**判据与 schema 的唯一真源**，闸与对账器共 import，⛔ 不许任一侧再写一份）。

与真 report（[`buildReport()`](../../../scripts/audit-mockup-conformance.mjs) 的返回，字段 = `fileKey` / `nodeIds` / `subAudits` / `nodeFindings` / `timestamp` / `figmaLastModified` / `nonBlocking` / `ok`）**同形**，加三个字段：

```jsonc
{
  "mode": "claim",                    // 新增。缺省 = 真 report（见 §4.1 向后兼容）
  "producedBy": "use_figma-in-file",  // 新增。生产者标识
  "claimedAt": "2026-08-31T03:00:00Z",// 新增。= 机检发生的时刻（≠ timestamp 的语义，见 §4.2）

  "fileKey": "rJJjWWs51n2iFOlCIC7aYG",
  "nodeIds": ["1408:17152"],
  "figmaLastModified": "2026-08-30T11:02:31Z",   // ⛔ 必填，否则 claim 不可对账（§4.3）
  "timestamp": "2026-08-31T03:00:00Z",
  "subAudits": [ { "key": "integrity", "exitCode": 0 }, … ],
  "nonBlocking": false,
  "ok": true
}
```

**`subAudits[].key` 必须取自现行 10 条规则的 id**（真源 = `scripts/mockup-rules/index.mjs` 的 `RULES`，现取 `pnpm audit:mockup-conformance --list-rules`）：
`integrity` · `colors` · `typography-icon` · `library-origin` · `binding-fidelity` · `bilingual-spacing` · `overlap` · `connector` · `library-binding` · `geometry-consistency`。
⛔ **别在 claim 里自创 key** —— 对账靠 key 对齐，自创 key 只会被记成 `unverifiable`。

### 4.1 向后兼容与 fail-closed 方向

- **缺 `mode`** → 按**真 report** 处理（= 今天的判据，全 `exitCode===0`）。**缺字段不会变宽松**，与既有 `nonBlocking` 的处理同向（[`:140`](../../../scripts/audit-mockup-handoff-evidence.mjs) 逐字「老 report 无 `nonBlocking` 字段 → 走严档」）。
- `mode` 取值集 = `claim` / `verified` / `refuted` / `void`，**其余值一律拒（抛错）**，⛔ 不静默当 claim。

### 4.2 `claimedAt` 与 `timestamp` 为什么都要

`timestamp` 被既有时效窗口消费（[`:153-159`](../../../scripts/audit-mockup-handoff-evidence.mjs)，`0 ≤ age ≤ maxAge`）。`claimedAt` 是**语义锚**：对账器据它排序、判「同一 claim 的多次记录哪条最新」。二者初始相同，但 `timestamp` 的语义归闸、`claimedAt` 的语义归台账，**不许合并成一个字段**——合并等于让两个消费方共享一个会被对方改变含义的值。

### 4.3 `figmaLastModified` 必填 —— 且它是**对账的唯一锚**

真 report 里它可空（无 token 时 `null`，gate 降级 `unverified`）。**claim 里它不可空**：没有它就无法判断「复跑时的文件」是不是「机检时的那个文件」，对账结论没有意义。
无 token 端可从 `use_figma` 的文件元数据取（in-file 插件 API 可读，不需要 REST）。**取不到就不要产 claim** —— 产一份不可对账的 claim 比不产更坏（它会以 `unverifiable` 永久占着台账）。

---

## 5. 闸侧改动 —— `scripts/audit-mockup-handoff-evidence.mjs` ⛔ **不建（§0 Flaw 3：空转不可达）**

判据函数现行终判是 [`:175`](../../../scripts/audit-mockup-handoff-evidence.mjs)：
`ok = reportFound && reportPassed && fresh && live !== 'stale'`

### 5.1 按 `mode` 分支（缺省保持今天的判定不变，另四个是新增）

| `mode` | 判定 | 输出 |
|---|---|---|
| 缺省 / 无 `mode` | **不变**（今天的两档：blocking 全 0 / non-blocking 允许 1 但必须点名；`exitCode===2` 两档硬失败）| 不变 |
| `claim` | **放行**（`ok = true`，前提是 schema 合法 + `fresh` + `live !== 'stale'`）| **必须显式印**一行：`⚠️ 这是 claim（<producedBy>，未经 REST 验证）—— 对账前它不构成 conformance 证据` |
| `refuted` | **判红**（`ok = false`）| 印出被推翻的规则 key + 台账记录位置 |
| `void` | **判红**（`ok = false`）| 印「Figma 文件在机检后被改过，该 claim 已作废，需重跑机检」|
| `verified` | 按真 report 判（全 `exitCode===0`）| 印对账时刻 |

### 5.2 ⛔ 那行「未验证」提示不是装饰，是本设计仅有的交付面信号

消费侧不会变红（裁定 3+4+5），所以**读到那一行的人**是唯一会在交付当下知情的人。⇒ 它必须是 `console.error` 级、必须每次都印、⛔ 不许加 `--quiet` 一类开关把它关掉。

### 5.3 ⛔ consumer 镜像必须同步改，而钉它的那条测试**当前看不见这一层**

`templates/consumer-product/.githooks/audit-mockup-handoff-evidence.mjs` 是真源的**自包含零依赖镜像**（109 行 vs 真源 281 行，只 import node 内置；头注释逐字「改逻辑先改真源再同步这里」）。消费仓无 npm/husky 生态，镜像**不能 import 兄弟脚本**。

⇒ **§4 的 schema 判据在镜像里必须再实现一份**。`scripts/lib/conformance-claim.mjs` **不会进 npm 包** —— `files[]` 的 `scripts/lib/` 白名单实测只有 6 个模块（`figma-env` / `figma-file-chunked` / `figma-payload-limit` / `gate-output-contract` / `is-cli-entry` / `mockup-library-origin`），且 `audit-mockup-handoff-evidence.mjs` 本身被 `!` 显式排除出包。
⇒ 这与 §11「schema 只此一份」**不矛盾**：DS 侧只此一份；镜像是**刻意的形态差异**，走既有「真源 + 同步」约定，由下面那条测试钉。

🔴 **但那条测试现在钉不住这一层（2026-08-31 实测）**：

- `tests/consumer-hook-mirror-parity.test.ts:97-102` 的 **4 条 fixture 全部落在 `reportFound: false`**（没引用 report / report 不存在 / 只有手打 Integrity 行 / 根本不是 handoff）⇒ **一条都走不到 `subAudits` 判定层**。
- 后果已经发生：镜像里 `nonBlocking` **grep 0 命中**（2026-08-14 落地的场景 2 档位），`figmaLastModified` 也 0 命中 —— **镜像落后真源一个完整档位，而测试是绿的**。（`live` 那半是测试注释里显式声明的「设计差异，不比」，属已登记；`nonBlocking` 不是。）

⇒ **实施 claim 档时必须先把 fixture 补到能真的读到一份 report 的那一层**（注入 `readReport`），否则新增的 `mode` 分叉会和 `nonBlocking` 一样**静默分叉**。这条写进 §9 第 11 行验收。
⚠️ 这正是本仓那条教训的又一个实例：**绿是真的，而关心的对象根本不在这条闸的扫描面里** —— 判据要读闸/测试自印的覆盖面，不是退出码。

### 5.4 为什么 claim 放行不会诱使大家都走 claim

claim 放行，但它**被记进台账、承担被 refuted 的风险**；真 report 没有这个风险。⇒ 能跑真的时候跑真的，是激励相容的。这一条成立的前提是对账真的会发生（§8.2 如实登记它的前提）。

---

## 6. 对账器 —— `scripts/ds-reconcile-conformance-claims.mjs`（新增，只读外部）

**性质 = 观测器，不是闸。always exit 0。** 与 `ds-health-scan-*` 同档（L0 · 手动/定期 · 刻意零挂载），理由同它们：要打 Figma REST（网络 + 凭据），且要读**别的仓库**，pre-commit / CI 里两者都不保证在场。

### 6.1 发现

按 `DS_CONSUMER_ROOTS`（默认 `mainWorktreeParent()`）逐个根，找 `**/.conformance/*.json`，跳过 `node_modules` / `.git` / `dist`。
**⛔ 只读**：本脚本对 DS 仓以外的任何路径**不得有写操作**（裁定 4）。落地时以「全程无 `writeFileSync`/`appendFileSync` 指向 ROOTS 下路径」为实现约束，并配一条单测锁住。

### 6.2 逐 claim 判定

```
读 claim → schema 校验（不合法 → 记 invalid，⛔ 不猜、不修）
  │
  ├─ 取该 fileKey 当前 lastModified（REST）
  │     取不到 → 记 unverifiable(reason=fetch-failed)，⛔ 不记 verified
  │
  ├─ current > claim.figmaLastModified  → verdict = void（设计已改，结论本就不描述当前设计）
  │
  └─ 相等 → 用本机 token 复跑 claim 里出现过的那些 rule key（同 fileKey / 同 nodeIds 范围）
        逐 key 比对：
          claim 说 0，复跑 0        → 该 key verified
          claim 说 0，复跑 1        → 该 key REFUTED
          复跑 2（跑不起来）        → 该 key unverifiable（⛔ 不是 refuted，也不是 verified）
          claim 里有、复跑不支持    → 该 key unverifiable
```

**claim 级终判**：任一 key `REFUTED` ⇒ `refuted`；否则若 ≥1 key `verified` 且 0 个 `REFUTED` ⇒ `verified`（`unverifiableKeys[]` 一并记下）；一个都没验成 ⇒ 维持 `claim` 并记 `unverifiableKeys`。
⛔ **不新增第五个状态**；`unverifiable` 是字段不是状态。

### 6.3 两条已知取证边界（每次运行自印，⛔ 别读成「已覆盖」）

1. **超大文件走分片抓取时 REST 拿不到 `plugin_data`** —— 既有边界，[`audit-mockup-conformance.mjs:373`](../../../scripts/audit-mockup-conformance.mjs) 逐字写着分片不带 `plugin_data` ⇒ `connector` 会如实报 missing 并 fail-closed。⇒ 该 key 记 `unverifiable`，**⛔ 不记 `verified`**。
2. **`--node` 只约束 8/10 条规则**：`connector` 与 `library-binding` 是**全文件口径**（`--list-rules` 自印）。⇒ claim 若只覆盖某个 node，这两条的对账结论是文件级的，台账里必须标出 scope，⛔ 不许把文件级结论读成「那个节点验过了」。

---

## 7. 台账 + 台账闸（唯一的牙齿）

### 7.1 台账 `docs/internal/_generated/conformance-claim-ledger.jsonl`

- **append-only**，与 `ds-health-history.jsonl` 同形同目录。
- 一行一次对账记录：`{ consumer, claimPath, fileKey, figmaLastModified, claimedAt, reconciledAt, verdict, perKey:{…}, unverifiableKeys:[…] }`
- **当前态 = 按 `(consumer, claimPath)` 取 `reconciledAt` 最新的一条**（last-write-wins）。
- 🔴 **⛔ 台账里不许放勾选框、批注、处置标记** —— 它是机械生成物，下次重跑会抹掉且没人会发现（本仓 `derived-artifact-cannot-hold-decisions` 已付过这个代价）。**判定必须落在契约面**，即下面那张表。

### 7.2 处置表 `docs/internal/conformance-claim-dispositions.json` ⛔ **不建（§0 Flaw 4：橡皮图章）**

形态照搬 owner 2026-08-31 刚接受的 `tests/a11y/color-contrast-exemptions.json`：**具名 + 带日期 + 带修法方向 + shrink-only**。

```jsonc
{ "dispositions": [
  { "consumer": "TVU Pack", "claimPath": "docs/handoffs/.conformance/xxx.json",
    "decidedAt": "2026-09-01", "decidedBy": "owner",
    "reason": "…", "fixDirection": "…" }
]}
```

**shrink-only 判据**：某条 disposition 已不再匹配任何 `refuted` 的当前态 ⇒ **闸判红并要求删行**。⇒ 表由闸维护，不靠记忆；**表空着是终态不是待办**。

### 7.3 台账闸 `scripts/audit-conformance-claim-ledger.mjs` ⛔ **不建（§0 Flaw 1 + 4）**

**只读 DS 仓自己的两份文件**（台账 jsonl + 处置表 json）⇒ 不依赖任何外部仓在场 ⇒ **可以正常挂 L4（pre-commit）+ L5（`pr-checks.yml`）**。

判据（全部 fail closed）：

| # | 判据 |
|---|---|
| **[L1]** | 当前态里存在 `verdict === "refuted"` 且处置表无匹配项 → **红** |
| **[L2]** | 处置表有行不匹配任何当前 `refuted` → **红**，要求删行（shrink-only）|
| **[L3]** | 台账 / 处置表读不了或畸形 → **抛错**，⛔ 绝不降级成「什么都不红」或「全都放行」|
| **[L4]** | 处置表条目缺 `decidedAt` / `decidedBy` / `reason` / `fixDirection` 任一 → **红**（防退化成橡皮图章）|
| **[S1]** | **覆盖面自印**（report-only）：台账条数 · 各 verdict 计数 · `unverifiable` 计数 · **最近一次对账时刻**。⚠️ 见 §8.3 |

---

## 8. ⛔ 诚实边界（四条，逐条必须留在实现的头注释里）

### 8.1 claim 本身防伪强度 = 0

in-file 机检的输出没有 REST 证据。**同一个 AI 可以不跑机检、直接手写一份合法 claim JSON**，编造成本与被 F62-a 淘汰掉的手打 `Integrity audit: I1=pass` 一样低。
③ 买到的**不是**交付时的防伪，是**后验对账**。⛔ 别把 F98 spec:180 那句「不降防伪强度」照抄进实现——**那句话说满了**，本设计如实收窄它。

### 8.2 对账频率 = owner 跑扫描的频率

裁定 6 之后没有任何自动触发点。owner 不跑，claim 就一直是 claim。**这是约束的必然代价，不是实现缺陷，⛔ 不要为它加定时器或往 CI 引凭据。**

### 8.3 台账闸在「从没对账过」时是**空过**的

台账为空 ⇒ [L1]/[L2] 恒真 ⇒ 绿。这是 fail-open 形态，**如实登记**。
**不修法**（要修就得引入「上次对账距今 N 天 → 红」，那是裁定 2 否掉的时间型判据换了个对象）。**代偿 = [S1] 每次运行自印「最近一次对账时刻」**，让空过这件事**可见**。
⛔ 判据是**读闸自印的覆盖面**，不是退出码 —— 绿而台账为空，说明的是「没测过」，不是「没问题」。

### 8.4 红落在 DS 仓，而不是落在出问题的那个仓

裁定 3+4+5 之后消费侧结构上不可能变红。链条是：
`消费侧照常放行 → owner 定期对账 → refuted 进 DS 台账 → DS 仓的 commit / CI 红`
位置是别扭的。它成立只因为**两边要动手处理的是同一个人**。⚠️ 若将来有非 owner 的贡献者产 claim，本条即失效，需重新设计。

---

## 9. 验证矩阵（实施时逐条跑，全部要有原始输出）

| # | 验的什么 | 手段 | 期望 |
|---|---|---|---|
| 1 | claim 被放行 | 造合法 claim + handoff 引用 → 跑 handoff-evidence | `EXIT=0` **且** stdout 含那行「未验证」提示 |
| 2 | 缺 `mode` 不变宽松 | 拿今天的真 report 原样跑 | 判定与改动前逐字相同 |
| 3 | `mode` 非法值 | 塞 `mode:"whatever"` | **抛错**，⛔ 不静默当 claim |
| 4 | **故障注入 A** | claim 声称全过、实际该 fileKey 有 findings → 跑对账 | `verdict=refuted` **且**台账闸 `EXIT=1` 点名该 claim |
| 5 | **故障注入 B** | 处置表塞一条永不匹配的行 | [L2] 报红并要求删行；还原后文件 sha256 与注入前逐字相等 |
| 6 | 阴性对照 | 一条 `verified` 的 claim | 台账闸 `EXIT=0`，且**不是**因为台账为空（[S1] 自印条数 > 0）|
| 7 | fail-closed | 台账文件写成畸形 JSON | **抛错**，⛔ 不是绿 |
| 8 | **接线覆盖** | 摘掉 [L1] 的判据整块 | 必须有测试转红 —— 走**整脚本 fixture-root harness**，⛔ 别抽纯函数单测（抽 lib 覆盖不到接线，`gate-regression-face` 纪律）|
| 9 | 只读约束 | 对账器全程 | ROOTS 下路径零写操作（单测锁）|
| 10 | CI 平权 | `pnpm audit:gate-ci-parity` | 差集 0（新闸挂了 pre-commit 就必须同时在 CI 可达面）|
| 11 | **镜像分叉可见性**（§5.3）| 先给 `consumer-hook-mirror-parity` 补能读到真 report 的 fixture（注入 `readReport`），**再**改两边 | ① 补完 fixture、**未**改镜像时 → 该测试**必须红**（证明它现在够得到那一层）② 两边都改完 → 绿 ③ 顺带把已存在的 `nonBlocking` 分叉一并暴露出来并修掉 |

⚠️ **第 4 条造故障前先确认故障态成立**（`regression-pass-needs-fault-proof`）：先断言注入前该 claim 判 `verified`，再注入，再断言 `refuted`。
⚠️ **探针名/探针值必须全仓无命中**（`fault-probe-name-must-be-absent-from-repo`），且注入前若目标文件有未提交改动，⛔ 别用 `git checkout --` 复原。

---

## 10. 非目标（本轮不做，各自独立登记）

1. **把 `.githooks` 装到 `TVU Pack`** —— 技术上可行（§1.2 实测它是 git 仓），owner 2026-08-31 判「没有必要的原因」。**重开条件**：出现非 owner 的 claim 生产者，或 §8.4 失效时。
2. **对账结果写回 consumer 仓** —— 裁定 4。重开条件同上。
3. **claim 落 Figma `sharedPluginData`** —— 裁定 3。⛔ 重开必须由 owner 主动提出，AI 不得再提。
4. **变体 B produce 侧（纯设计仓库 sibling clone 的 chokepoint 排期）** —— entry 里另一条待做，与本设计正交，不并入。
5. **给 `--node` 的文件级规则做节点级化**（`connector` / `library-binding`）—— §6.3 边界 2 的根治，是独立的判据设计问题。

---

## 11. ⛔ 清单（实施时逐条守）

- **起手先跑 `pnpm report:gate-regression-face` + `pnpm audit:gate-regression-ratchet` 取基线**，⛔ 别抄任何既有的数
- 新闸头注释必须写 **`covers-acceptance:` 自陈**（`audit:acceptance-gate-coverage` / INFRA-F142 的要求），并写清**挂载层**——头注释是挂载真源，⛔ 别让人去 grep 调用点推断
- schema 只此一份（`scripts/lib/conformance-claim.mjs`），DS 侧的闸与对账器共 import，⛔ 不许任一侧复制一份判据。**唯一例外 = consumer 镜像**（§5.3，形态刻意不同、走「真源 + 同步」+ parity 测试钉）
- **⛔ 改镜像之前先补 parity fixture 并确认它会红**（§5.3 / §9 第 11 行）—— 顺序反了就等于又加一层看不见的分叉
- ⛔ 别把台账做成「可勾选」的（§7.1）
- ⛔ 别给对账器加退出码语义 —— 它是观测器，always exit 0；牙齿在台账闸
- ⛔ 别为 §8.3 的空过加时间型判据（裁定 2）
- ⛔ 别在本仓维护第二份「消费产品清单」——发现面复用 `DS_CONSUMER_ROOTS`
- **changeset 判据 = `package.json` 的 `files[]`**：本设计涉及的 `scripts/` 新文件若不在白名单内则**不写** changeset；落地时以 `npm pack --dry-run` 现算，⛔ 别凭印象
- 全程零 `.vue` / `.css` ⇒ 不触发 `VISUAL_COMMIT_APPROVED`
- 无 token 端的 claim 产出规则要同步写进 `mockup-conventions.md` §M-DISCIPLINE.SYNC 与 claude-design bundle 的规则面（producer 读不到 `scripts/`），⛔ 但那里只放**指针 + 形态**，判据真源仍在 §4 的 schema 模块
