# INFRA-F66 CE `:host` 尺寸 — live 复现判定 — 2026-07-29
> **扫描面**：docs 站 **React(CE) 态**下的 **19 个候选 canonical CE**（候选集从活源重建、逐实例实测；确认复现 2 个、未动 17 个）

> backlog INFRA-F66 明写这条是 **live-repro 驱动、未证实前不批量改动**（静态 grep 只给候选：grid 容器会掩盖，
> 纯 flex 无 `flex-grow` 才暴露）。本报告按此执行：候选集从活源重建，逐实例在 docs 站 **React(CE) 态**实测，
> **只给确认复现的两个组件加 `:host`**，其余 17 个候选 CE 一个没动。
>
> 探针（随本报告入库，均不入 `testMatch: '**/*.spec.ts'`）：
> `tests/docs-overflow/_f66-parity-probe.mjs`（Vue↔React 同槽位宽度对照）·
> `tests/docs-overflow/_f66-ab-probe.mjs`（原位 A/B：当场施加候选修法看渲染是否实质变化）。
> 原始数据 `/tmp/f66-parity.json` · `/tmp/f66-ab.json`（未入库，可用探针重生）。

## 方法学：两个「显而易见但会给出错误答案」的判据，先排除掉

| ❌ 不能用的判据 | 为什么错（本轮实测） |
|---|---|
| **`getComputedStyle(host).display === 'inline'`** | 320+ 个实例里**只有 1 个**读到 `inline`。原因：这些 demo 预览容器几乎都是 flex，**flex item 会被 blockify**，host 的 computed display 因此一律显示 `block` —— 但那是 blockify 的结果、不是有人声明了 block，而 blockify **只 stretch 交叉轴**，主轴（宽度）照旧收缩。所以 `display: block` 什么也不能证明。已用活源核实：`tvu-message` 的 shadow root 内无任何 `:host` 规则、文档层也无规则命中该标签，computed 仍是 `block`。 |
| **「host 比父容器窄」** | 会把每一个**本该**是内容宽度的 badge / pill / button 都报成缺陷。 |

实际采用的两条判据，**必须同时成立**才算复现：

1. **框架 parity 对照**（Vue 作参照）：同一 demo 槽位下，plain-Vue SFC（无 shadow host）填满容器而 CE host 明显更窄 → host 塌陷。
   两侧宽度相等 = 该组件本来就是内容宽度，不是缺陷。
2. **原位 A/B**（同时验证修法本身）：对候选 host 当场施加 `display: block; width: 100%`，
   要求 **host 变宽 且 shadow 内容随之变宽**。只有 host 变宽、内容不动 → 只是「能被拉宽」，不是塌陷。

**对照组验证了探针灵敏度**：已修的 `tvu-logo` / `tvu-progress` 在 A/B 里都是 `no change`
（它们的 `:host` 已声明同一组值，再施加是 no-op）—— 正是「已修」应有的签名。

## 候选集重建（活源，2026-07-29，不信 backlog 那份 2026-07-14 快照）

```
base 组件内部靠 width:100% 撑满（grep src/components/）：16 个
  Checkbox · FormItem · Icon · Input · Logo · Message · Notification · Progress
  · Select · Slider · StepItem · Steps · Switch · Table · TopBar · UserMenu
canonical 已声明 :host 的：2 个（Logo.vue / Progress.vue）
→ 真候选 = 14 个 base，映射到 20 个 CE 标签（其中 tvu-logo / tvu-progress 作对照组）
```

**覆盖面**：docs 站 25 个组件页 × React(CE) 态，**实测 323 个 CE 实例 / 19 个标签**。
唯一未覆盖：**`tvu-drop-down-list-select`** —— docs 的 React demo 里零个渲染实例，本轮无法判定（见 §残余）。

## 逐候选判定

| CE 标签 | base | 实例数 | A/B 结果 | Vue 参照 | 判定 | 处置 |
|---|---|---|---|---|---|---|
| `tvu-form-item` | FormItem | 22 | **REPRO ×7**（host 与 shadow 同步变宽） | Vue 9/9 个 cell 一律 334px 填满；CE **168–317px 且随状态漂移** | ✅ **复现** | 修 `src/canonical/FormItem.vue` |
| `tvu-input-box-filled` | Input | 33 | **REPRO ×1** | Vue 侧 `.form-item__content` 内 **25/25** 个控件填满其 slot；CE 在 198.3px 的 slot 里只有 180px | ✅ **复现** | 修 `src/canonical/InputBoxFilled.vue` |
| `tvu-message` | Message | 13 | REPRO ×4（A/B 看似命中） | **Vue 与 CE 宽度逐个完全相同**：437.7 / 436.2 / 453.6 / 466.5 | ❌ **不复现** | **不改** —— A/B 只说明「能被拉宽」，Vue 参照证明这是设计宽度 |
| `tvu-switch` | Switch | 48 | host-only ×39（内容不受影响） | — | ❌ 不复现 | 不改（开关是内容宽度控件） |
| `tvu-step-item` | StepItem | 30 | host-only ×30 | — | ❌ 不复现 | 不改 |
| `tvu-check-box` | Checkbox | 19 | host-only ×9 | — | ❌ 不复现 | 不改 |
| `tvu-slider` | Slider | 4 | host-only ×2 | — | ❌ 不复现 | 不改 |
| `tvu-notification` | Notification | 37 | no change | — | ❌ 不复现 | 不改 |
| `tvu-input` | Input | 23 | no change | — | ❌ 不复现 | 不改 |
| `tvu-select-box-filled` | Select | 14 | no change | — | ❌ 不复现 | 不改 |
| `tvu-table` | Table | 14 | no change | — | ❌ 不复现 | 不改 |
| `tvu-steps` | Steps | 10 | no change | — | ❌ 不复现 | 不改 |
| `tvu-select-box-line` | Select | 8 | no change | — | ❌ 不复现 | 不改 |
| `tvu-input-number` | Input | 7 | no change | — | ❌ 不复现 | 不改 |
| `tvu-user-menu` | UserMenu | 5 | no change | — | ❌ 不复现 | 不改 |
| `tvu-top-bar` | TopBar | 4 | no change | — | ❌ 不复现 | 不改 |
| `tvu-icon` | Icon | 2 | no change | — | ❌ 不复现 | 不改 |
| `tvu-progress` | Progress（对照组） | 26 | no change | — | 已修 | — |
| `tvu-logo` | Logo（对照组） | 4 | no change | — | 已修 | — |
| `tvu-drop-down-list-select` | Select | **0** | 无实例 | — | ⚠️ **未判定** | 见 §残余 |

**结论：13 个候选里 2 个复现、11 个不复现**（backlog 原文「另 13 base 组件 Low、live-repro 驱动」的量级基本吻合，
但**具体是哪几个和原假设不同** —— 静态 grep 名单里的 Table / TopBar / UserMenu / Switch / Steps / Checkbox 全部不复现）。

## 修复内容（只动这两个文件）

范式与已修的 `Logo.vue` / `Progress.vue` 一致，写在**非 scoped** `<style>` 块里
（scoped 会给选择器加 `[data-v-*]`，`:host` 就不再匹配 shadow host）：

```vue
<style>
:host {
  display: block;
  width: 100%;
}
</style>
```

- `src/canonical/FormItem.vue` —— 注意它原本只有一个 `<style scoped>` 块，新增的是**独立的非 scoped 块**。
- `src/canonical/InputBoxFilled.vue` —— 原本无 `<style>` 块。

**Vue 侧零影响**：plain-Vue 构建没有 shadow host，`:host` 匹配不到任何东西 = no-op（这也是 Logo/Progress 当初的理由）。

**已核实不会经 light-DOM 样式注入泄漏**：`components.config.ts` 的 `lightDomStyleSources` 全部指向
`src/components/*`（base 层），**从不引 `src/canonical/*`** → 这两条 `:host` 不会被收进 Pagination / PopupBox /
SelectBoxLine / SelectBoxFilled / DropDownListSelect 那 5 个 light-DOM CE 的 head 注入里
（否则 `:host` 会错误地命中那些组件自己的 host）。

## 修后回验

```
_f66-ab-probe   tvu-form-item        : REPRO ×7 → no change（转为与 Logo/Progress 对照组同签名）
_f66-parity     form-item 9 个 cell  : 168–317px 漂移 → 一律 317px = 恰好填满 offered
_f66-input-check .form-item__content : React 侧「未填满 slot」的控件 1 → 0
pnpm test                            : 857 passed | 10 skipped（exit 0，与基线一致）
pnpm audit:demo-slot-boolean         : in-scope=30 side-failures=0 PASS
pnpm audit:demo-framework-parity     : components=25 fails=0 PASS
pnpm audit:binding-config-parity     : 37/37 PASS
pnpm test:framework-parity（真机）   : 41 passed
```

**残余 Δ17 的正确解读**：修后 CE cell 是 317px、Vue cell 是 334px，两边**各自都恰好填满自己的容器**——
差的是两侧 StatusMatrix cell 自身的 offered 宽度（317 vs 334），属 demo 网格几何的小差异，**不是 host 塌陷**，
不在 F66 scope（若要收口，归 demo parity 侧）。

## ⚠️ render-drift-gate：本轮**未能取得绿灯**，且原因不在本改动（如实记录）

`pnpm test:render-verification` + `pnpm audit:render-drift-gate` 跑出
`A_TRUE_DRIFT_CANDIDATE=4 > baseline 0`，**4 条全是 `TopBar [placeholder] textFillHex`**
（expected `#f8f8f8`，actual `#ffffff` dark / `#000000` light）。归因证据：

1. 逐条查 report：`A_*` 分类按组件计数 = `{TopBar: 4}`，**触及 FormItem / InputBox* 的 A_* 条目 = 0**。
2. 期望值 `#f8f8f8` 是**本轮工作树里另一条并行 session 的产物**：
   `git diff figma-data/normalized/components-tokenized/top_bar__4771_7173.json` 显示该节点新增了
   `"hex": "#f8f8f8"` fill（原先 `"fills": []`）；同时那条线正在改
   `scripts/generate-render-verification-manifest.mjs` / `audit-render-verification-coverage.mjs` /
   `RenderHarnessPage.vue`，manifest 条目数因此 930 → **936**、`B_RESIDUAL_SCHEMA_GAP` 285 → **309**。
3. 且 render-verification 跑的是 **Vue** harness，而 `:host` 在 plain-Vue 构建里匹配不到任何东西。

**所以：这 4 条 drift 属那条并行线的 in-flight 改动，交由它判定**（要么按新 Figma 值把 placeholder 文本改绑
`--text-placeholder`，要么核 extract 是否需要 composite —— 注意 expected 是 theme-invariant 而 actual 随主题变，
这个形态本身值得查）。本报告不代它下结论、也不动它的文件。

**我这次跑造成的副作用已全部还原**：`test:render-verification` 会重写三个 **tracked 生成物**
（`figma-data/render-verification-manifest.json` · `figma-data/normalized/render-verification.report.json` ·
`docs/internal/_generated/render-verification-report.md`），已逐个 `git checkout --` 还原到 HEAD
（确认三者的 dirty 只来自我这次跑：那份 md 的 `Generated:` 时间戳是 `2026-07-29T08:55:48Z`，
而 HEAD 里那份是 `2026-07-28T02:25:52Z`）。若那条并行线在我跑之前自己生成过这三个文件，请重跑一次它们的生成器。

## 残余

- **`tvu-drop-down-list-select` 未判定**：docs 的 React demo 里没有它的渲染实例，本轮 0 覆盖。
  它是 5 个 **light-DOM（`shadowRoot: false`）** CE 之一，机制上 `:host` 语义与 shadow CE 不同，
  不能照搬本轮结论。**触发条件** = 给它补 React demo 时（也正好是硬规则 #8 双框架 demo 覆盖的要求）一并判。
- 11 个判定为「不复现」的候选**没有被顺手改**。若将来某个 consumer 把它们放进纯 flex 无 grow 的容器并报塌陷，
  按本报告的两条判据先复现、再决定，不要凭静态 grep 批量加 `:host`。
