# L3 预注册（第 5 份）—— 双写 JSX 增广在 **DS 真发出的 d.ts** 上的五版本矩阵（`lab:L3`）

> 🔴 **本文件必须在写任何取数代码之前 commit。** 依据 `AGENTS §1.1` 订正段。
> ⛔ 取数后本文件一字不改（要改只能另起一份并留痕）。

- **立项依据**：owner 2026-09-03（第三轮）在带推荐的方案中选定 **L3**（四条候选的前提核对见
  [`open-items §15`](2026-09-02-open-items.md)）。
- **被验对象**：**DS 真发出的那份类型声明** `dist-wc/tvu-web-components.d.ts`
  （DS HEAD `d1ba0505`；⚠️ `dist-wc/` 是 gitignored 的 build 产物 ⇒ 冻结物 = **文件 sha + DS HEAD**，见 §1）。
- **它回答哪个目前未知的问题**（⛔ 立项理由不得是「确定有产出」）：
  处方 [`2026-08-28-webcomponents-types-entry.md`](../proposals/2026-08-28-webcomponents-types-entry.md) §2.6
  那张「五版本 × 三写法」矩阵，是在 **lab 自搭的最小复现环境**上跑出来的 ——
  §2.0 标题逐字「**复现环境（⛔ 未碰 DS）**」。
  ⇒ 🔴 **「双写在最小片上跨 5 个版本成立」⇒「在 DS 真发出的那份 700+ 行 d.ts 上也成立」是一次外推，
  ⛔ 不是同一个读数。本份验这次外推。**
  ⚠️ 两个方向都可能：真载体多了 `TvuIntrinsicElements` / `TvuElementAttributes` 的 import 链与
  700+ 行声明，**模块解析与命名空间合并的条件都比最小片复杂** ⇒ ⛔ 不是构造保证。
- **谁消费这个读数、他在乎哪个方向的错**（🔴 `D6.2 §3` 那条教训的兑现，⛔ 不得跳过这一问）：
  消费者 = **一类会生成 React 代码的 AI 工具**（owner 2026-08-28 逐字：「Claude.ai/design 是消费 React 的
  其中一个 AI 工具之一，**不是唯一**」）⇒ 它们产出的 `@types/react` 版本**不可能统一**。
  他同时在乎两个方向：

  | 方向 | 错长什么样 | 不测它会怎样 |
  |---|---|---|
  | **假绿** | 非法值 `size="XXL"` **不报错** | 类型逃逸成 `any` ⇒ AI 生成的错代码没人拦，**闸恒绿、白挂** |
  | **假红** | 合法值 `size="M"` **报错** | 工具链在那个版本上直接不可用 |

  ⇒ 🔴 **必须正反同跑；单侧是构造保证。** 处方 §2.6 逐字已警告「⛔ 只看『不报错』会把类型逃逸成 `any` 读成通过」。

---

## 0. 接手纪律（`AGENTS §20` 四行块 + `§22` 第五行，⛔ 不许跳过）

```
登记记的：  「L3 重跑 webcomponents-types §2.6 的五版本矩阵 ⏸ 未动。闸已绿（EXEMPTIONS=[]）
            且 DS 自陈有 .d.ts ⇒ 大概率没问题，但双写是否 5 版本全覆盖本轮 ⛔ 未验」
            （open-items §2.1 L3 行逐字；连续 6 个结算节标「未动」）
现取的：    五层复核（open-items §15.5）—— 载体在、双写在、随包发：
            ① src/web-components/web-components.d.ts:707 declare module + :715 declare global
            ② 闸在（audit-exports-types-contract / check-dist-wc-freshness / audit-typecheck-scope）
            ③ package.json exports 含 web-components、files 含 dist-wc
            ④ 落地 commit 4bbbc467
            ⑤ 真产物 dist-wc/tvu-web-components.d.ts 实测 1×declare module + 1×declare global
前提还成不成立：**成立，但登记的措辞要订正**。「大概率没问题」的依据是「闸绿 + DS 自陈」——
            ⚠️ 那两样都 ⛔ 不覆盖「跨 @types/react 版本」这个维度：闸测的是导出契约与
            typecheck 范围，DS 仓自己只锁 ^19.0.0（package.json:263）⇒ 17/18 那三档
            **DS 侧结构上没人跑过**
它还该做吗：🔴 **该做，且理由比登记的更强**。DS 侧 `scripts/lib/react-binding-templates.mjs:420`
            逐字自陈双写的理由（「@types/react moved …」），:524/:532 是生成双写的模板 ——
            但那是**作者的理由**，⛔ 不是 lab 侧独立可取的读数（AGENTS §20 推论一：
            核别人的判断时，每一条都要有一个 lab 侧独立可取的读数，
            「对方写了理由、听起来对」⛔ 不构成证据）
lab 自己验过没：🔴 **验过，但验的是另一个载体。** §2.6 那张表跑在 lab 最小复现上
            （§2.0 逐字「⛔ 未碰 DS」）⇒ 对**真发出的 d.ts** 而言，lab 从未验过
            ⇒ ⛔ 不是 lab:N56（我已经干过了），是「干过的是隔壁那件」
```

### 0.1 ⛔ 本份不做什么

- ⛔ **不改 DS 一个字节、⛔ 不跑任何 DS 闸、⛔ 不跑 DS 的 build**（`dist-wc/` 用它**现有**的产物，见 §1）。
- ⛔ **不测 `react-pilot/src/wrappers/jsx.d.ts`** —— 该文件第 3 行逐字
  `Repo-internal JSX augmentation for react-pilot. Not shipped.` ⇒ **不在射程内**（§6 边界⑤）。
  ⚠️ 它只写了 `declare module`、无 `declare global`，**看着像一条缺陷** ——
  `open-items §15.5 ②` 已登记：只看 grep 会把它报成假缺陷。
- ⛔ **不测 d.ts 的其它任何契约**（props 类型正确性、事件、slot、导出面）—— 本份只测 **JSX 增广这一条**。
- ⛔ **不换版本集** —— 用 §2.6 原表那 5 个。换了就不是对同一张表的复核。
- ⛔ **不出处方、不改 DS 模板** —— 即便读出「有洞」，本份只交读数（`AGENTS §8`）。

---

## 1. 被测对象与冻结（`AGENTS §2.1` 三元组 / `§2.12` 冻结物存整文件 sha）

| 对象 | 处置 |
|---|---|
| `<DS>/dist-wc/tvu-web-components.d.ts` | 🔴 **被验对象。取数前记 `sha256` + 字节数 + DS HEAD，⛔ 取数中不得重建** |
| `<DS>` 工作树其余一切 | ⛔ **只读，一个字节不写** |
| `proposals/2026-08-28-webcomponents-types-entry.md` §2.6 | 🔴 **参照基线（⛔ 不是被验对象）** —— 它是最小复现上的读数 |
| **量具（新）** `probes/wc-types-jsx-matrix/run-matrix.mjs` | 建 5 个隔离环境 + 正反同跑 + 内建控制 |
| **量具（新）** `probes/wc-types-jsx-matrix/fixtures/` | 正例 / 反例 / 基线 / 阴性对照四类 fixture |

🔴 **三元组主键**（`AGENTS §2.1`，纯 T1 确定性指标后两项记 `n/a` 但**显式记**）：

```
subjectSha            = sha256(dist-wc/tvu-web-components.d.ts)   ← 取数前落盘
dsHead                = d1ba0505
modelId               = n/a（本份无模型参与）
promptTemplateVersion = n/a（同上）
```

⚠️ **`dist-wc/` 是 gitignored 的 build 产物** ⇒ 它 ⛔ 不能由 DS HEAD 唯一确定
⇒ **必须存整文件 sha**，否则本份读数不可复核（`AGENTS §2.12` 逐字）。

---

## 2. 🔴 产出与判读规则（⛔ 取数后不得增删、不得换）

### 2.1 面与分母（🔴 带口径名，`AGENTS §2.4`）

**面 =【`@types/react` 五版本 × 正反两向】= 10 格**，口径名 **`§2.6 原版本集 · 真载体口径`**：

| `@types/react` | §2.6 在**最小复现**上的读数（双写 `B` 列）|
|---|:-:|
| `17.0.2` | ✅ |
| `18.0.0` | ✅ |
| `18.2.0` | ✅ |
| `18.3.31` | ✅ |
| `19.2.17` | ✅ |

⇒ **本份在真载体上重取这 5 格，每格拆成正反两向。**
⚠️ **⛔ 不得把「§2.6 全绿」当成本份的预期而只跑反例** —— 那就是拿基线给自己背书。

### 2.2 🔴 承诺（⛔ 取数前写死，⛔ 取数后不得调）

| # | 承诺 | 线 | 治什么 |
|:-:|---|---|---|
| **C1** | **10 格全绿**：5 个版本上，正例 `size="M"` 必须 `exit 0`，**且**反例 `size="XXL"` 必须非零退出并给出**类型不匹配**诊断 | 10 / 10 | 「双写在真载体上是否全覆盖」——本份唯一要回答的问题 |
| **C2** | **阴性对照必须红**：删掉 `declare global` 块的**副本**在 `17.0.2` 上，正例必须**由绿转红** | 必红 | 🔴 **C1 的可失败性证据**。⛔ 不过则整份**不可判读** |

🔴 **为什么 C1 ⛔ 不是构造保证（本份成立的关键一问，`AGENTS §2.15`）**：
`§2.6` 那张表本身就有 **3 个红格**（`M` 写法在 17.0.2 / 18.0.0 / 18.2.0 上失效）
⇒ 这条线**在同一个判据下已经判否过** ⇒ ⛔ 不是恒真。
⚠️ 但那 3 个红是在**最小复现**上取的 ⇒ 本份必须在**真载体**上重新证明这条线能失败
⇒ **这就是 C2 存在的理由**：它是 C1 在真载体上的「换被验对象即判否」实证
（形制抄 `D6.3 §3.1`：同面同线换被验对象 ⇒ v1 当场判否）。

### 2.3 ⚠️ 边界读数（⛔ 不作承诺 —— 登记而不高估）

- 每格的**具体诊断码**（`TS2322` / `TS2339` / …）与首行诊断文本 —— 登记，⛔ 不作判据。
  🔴 **理由**：钉死错误码会让「写法失效」这件事因**错码换了**而假绿/假红
  ⇒ 判据只钉**方向**（该绿的绿、该红的红），⛔ 不钉码。
- 每格 `tsc` 耗时 —— 登记，⛔ 不作任何性能主张（`AGENTS §2.14`：性能自称必须带环境名）。
- `18.3.31` 与 `19.2.17` 上单写 `M` 是否仍绿（§2.6 说绿）—— **事后观察列**，⛔ 不进承诺。

### 2.4 地板（⛔ 不达则整份判「不可判读」，⛔ 不得改判成通过）

| # | 地板 | 不达时 |
|:-:|---|---|
| **F1** | 5 个版本**全部真装成功**，且 `node_modules/@types/react/package.json` 的 `version` 与声明值**逐字相同** | **不可判读** ——⛔ 不许用「相近版本」顶替，⛔ 不许只跑装上的那几个 |
| **F2** | 被测 d.ts 的 `sha256` 与 §1 冻结值**逐字相同** | **不可判读** —— 载体在取数中被重建过 ⇒ 读数不可复核 |

---

## 3. 内建控制（`AGENTS §3.2`：签名一变当场红；fail closed）

| # | 类 | 控制 | red 时的含义 |
|:-:|---|---|---|
| **MH1** | 🔴 **装置活性 / 阴性对照** | 删 `declare global` 的副本在 `17.0.2` 上，正例**必须由绿转红**（= C2） | **装置根本没在测 JSX 增广** ⇒ 全部读数作废 |
| **MH2** | 🔴 **假阳闸（已知的坑）** | `tsconfig.paths` 必须同时映射 `react` **与** `react/jsx-runtime`；控制 = **不 import DS 包**的纯 React 基线 fixture 必须 `exit 0` | **是我的 tsconfig 坏了，⛔ 不是被测对象坏了**（`AGENTS §3.9` 第一形态）|
| **MH3** | **版本隔离** | 每格跑完**当场回读** `@types/react/package.json` 的 `version`，必须等于该格声明值 | 5 个环境串味（hoisting / 缓存）⇒ 读的不是它以为的那个版本 |
| **MH4** | **载体同一性** | 每格跑前回读被测 d.ts 的 `sha256`，必须等于 §1 冻结值 | 载体在取数中变了（= F2 的逐格形态）|
| **MN1** | 🔴 **退出码取法** | 一律 `spawnSync(...).status`，**⛔ 不经 shell、⛔ 不接管道** | 读到的是管道末端那一节的码（`lab:N47`；🔴 **交接点名的那条，上一轮擦边两次**）|
| **MN2** | **正反隔离** | 正例与反例**各自独立的 fixture 文件 + 各自独立的 `tsc` 进程** | 同一次编译里一个错会掩盖另一个（继承处方 §2.2 逐字「隔离跑，每态单独确认退出码」）|
| **MH5** | 🔴 **解析控制**（**补写，见下方留痕**）| 从被测入口 `import type { ButtonSize }` 并**用掉它**的 fixture，必须 `exit 0` | **是我的 `paths` 没解析到被测 d.ts，⛔ 不是双写失效** |

### 3.1 ⚠️ MH5 的补写留痕（🔴 **补于取数之前**，`AGENTS §1.1`：取数后一字不改）

写量具时发现 MH1–MH4 有一个**结构性缺口**：若 `paths` 对
`@ux-team/tvu-design-system/web-components` 的映射写错，被测 d.ts **根本不会进 program**
⇒ 正例在**全部 5 个版本上一起红** ⇒ 读起来像一条 🔴 重大发现（「双写完全没生效」），
**实际是我的装置没接上**。而 MH2 只证「react 那半边的映射是好的」，⛔ 不证「DS 那半边」。

⇒ 这正是 `AGENTS §3.9`「**测量装置的失败会伪装成被测对象的行为**」的第六个形态
⇒ 补 **MH5**：一条只证「入口解析得到」的控制，与 MH2 分治两半映射。
⚠️ **⛔ 未取任何读数即补**（形制同 `D6.3 预注册 §3.4`）。

⚠️ **MH2 是本份最该防的那个坑**：处方 §2.6 逐字留痕「**本 session 在这个坑上栽了两次**」——
`paths` 只映射包名、漏映射 `jsx-runtime` 子路径，会让 **JSX 相关判据整片假阳**。
⇒ 本份把它做成**内建控制**，⛔ 不是靠记得。

---

## 4. 🔴 判读规则（取数后按此逐字执行，⛔ 不得另行解释）

| 情形 | 判定 |
|---|---|
| F1 或 F2 不达 | **不可判读** —— ⛔ 不报 C1，⛔ 不得写成「双写没问题」 |
| F 全达 ∧ **MH1（C2）不红** | **不可判读** —— 装置没在测东西，⛔ 10 格全绿也不算数 |
| F 全达 ∧ 控制全过 ∧ **10 格全绿** | **`L3_VERDICT = 双写在真载体上全覆盖`** |
| F 全达 ∧ 控制全过 ∧ **任一格红** | **`L3_VERDICT = 有洞`** —— 逐格登记「哪个版本 / 哪个方向 / 什么诊断」 |

🔴 **它会驱动什么决策**（`AGENTS §2.3`：写不出来就不加）——**两个结果都改变某件事**：

- **`全覆盖`** ⇒ 处方 §2.6 那张表**升级为「已在真载体上验证」**，`open-items` 的 **L3 这条登记项关闭**
  （连续 6 个结算节标「未动」的那条）。
- **`有洞`** ⇒ DS `scripts/lib/react-binding-templates.mjs` 的模板要改；**lab 出处方、⛔ 不直接改 DS**
  （本份 §0.1）。⚠️ 且要**同时**订正处方 §2.6 那张表 —— 它当时的「✅」只对最小复现成立。

---

## 5. 覆盖边界（`AGENTS §3.4`：这是边界，⛔ 不是 TODO）

1. **射程 = JSX 增广这一条**（`JSX.IntrinsicElements` 上的自定义元素与其 props）。
   ⛔ 不测 d.ts 的其它任何契约（事件、slot、导出面、props 语义正确性）。
2. **只测 §2.6 原表那 5 个版本**。⛔ 不外推到未测点 —— 尤其 ⛔ 不得读成「所有 17.x/18.x/19.x 都行」。
   分界点 `18.3`（§2.6 逐字）意味着**版本间不连续** ⇒ 未测版本 ⛔ 不可插值。
3. **被测物是 build 产物**：`dist-wc/` gitignored ⇒ 冻结靠文件 sha（§1）。
   ⚠️ 本份 ⛔ 不重建它 ⇒ 读数绑的是「DS HEAD `d1ba0505` 工作树当时构建出的那一份」，
   ⛔ 不是「DS HEAD `d1ba0505` 必然构建出的那一份」——**这两句不是一回事**。
4. **单次读数**：一个载体上的一次取数，⛔ 不是重复实验。
5. ⛔ **不覆盖 `react-pilot/src/wrappers/jsx.d.ts`**（逐字 `Not shipped`，§0.1）。
6. ⛔ **不覆盖非 React consumer**（处方 §2.6 那三格 Vue 对照）—— 那是**另一个面**，本份未取。
7. **环境名**（`AGENTS §2.14`）：本机 `darwin 24.5.0` / Node `v24.15.0`。
   ⚠️ `node --test <目录>` 在 v24.15.0 上不通 ⇒ 测试文件必须显式逐个列出。
