# DS 健康度缺口清单 —— 从 30 格活读数反推的待优化项

> 立于 2026-09-16 12:2x，owner 看完体检报告后要求「把欠缺的填进待优化任务列表，分批并行处理，
> 做完再出一份更完善的健康报告」。
>
> **读数出处**：`node metrics/ds-sweep.mjs --ds <DS 仓> --out /tmp/sweep.json` @ `388d2737`
> —— ⛔ 本文件里每个数都出自那次输出，**不是从报告 HTML 抄的**。
> 报告侧的数由 `metrics/verify-report-numbers.mjs` 机械核过（62 项全过）。
>
> ⚠️ **这是第二条线**，与 `docs/frozen-worklist.md` 那条冻结线**互不相干**
> （同 `2026-09-16-dim-wiring-plan.md` 开头那句）。⛔ 别把这里的条目算进冻结清单。

---

## 0. 🔴 先看这个：缺口落在**三个不同的工作面**上，⛔ 不能一起并行

这是本清单最该先读的一节 —— 「分批并行」的真正约束在这里，⛔ 不在任务数量上。

| 面 | 在哪 | lab 能不能直接动 | 当前状态（2026-09-16 12:2x 实测） |
|:-:|---|---|---|
| **① DS 代码仓** | `tvu-design-system` @ `master` | ✅ **能**（owner 2026-09-01 裁定，`AGENTS §1.1`） | HEAD `388d2737` · 工作树脏 **6 项**，⛔ 均非本轮所改 ⇒ **有并行 session 在动** |
| **② 消费产品仓** | `MicroApps/{vue-app,graphics-insertion-app}` | 🔴 **未登记过授权** | 在 **feature 分支 `mc-44-graphics-insertion-code`** 上，⛔ 不是 master ⇒ **别人正在做的工作分支** |
| **③ Figma 设计文件** | Figma（6 个产品文件） | ⛔ **不是代码** | 拿错库 / 孤儿组件都在这里，要**设计师在 Figma 里改**，⛔ 写代码改不了 |

🔴 **推论（这决定了怎么分批）**：

- **面 ① 内部可以并行**（不同文件互不冲突），但**必须每条都 `git commit --only <具体文件>`**，
  ⛔ 不 `add -A` —— 那 6 项脏文件是别人的账。
- **面 ② 需要 owner 先拍两件事**：lab 能不能改消费产品代码 · 改到哪个分支。
  ⛔ 在 `mc-44-*` 这个别人的 feature 分支上直接改，会被同事拉到本地 / 可能触发 CI 失败。
- **面 ③ 根本不是「做任务」能解决的** —— 它要设计师打开 Figma 逐个换组件来源。
  lab 能做的只有**把清单列准**（哪几个文件、哪几个组件、各多少实例），⛔ 不能代做。

⚠️ ⇒ **owner 说的「都做完之后再出报告」，面 ③ 的完成时间不由 lab 控制。**
⛔ 别把新报告的产出时间挂在它后面。

---

## 1. 清单（按工作面分组 · 每条都带读数）

### 1.0 🔴 **A1 动手前被五行块拦下 —— 那 19 处里 15 处是量具假阳**

**这一条要先读**，因为它同时推翻了**体检报告里的一句话**和 **DIM-U17 的一半读数**。

**怎么发现的**：按 §2.22 五行块核「前提还成不成立」时，去查 playground 到底 import 的是哪个组件
—— 发现它引的是 `src/components/*`（legacy Vue SFC），而量具的契约真源
`src/web-components/components.config.ts` 描述的是 `src/canonical/*`（web-component）。
🔴 **仓里同名组件有两套 API，量具拿后者的契约去判前者的用法。**

| 量具报的 | playground 引的实现的真实签名 | 判定 |
|---|---|:-:|
| `Input.size="l"` ×8 | `src/components/Input/Input.vue:7` `type Size = 's' \| 'm' \| 'l' \| 'xl'` | 🟢 **假阳** |
| `Progress.size="s"` ×1 | `Progress.vue:5` `type Size = 'M' \| 'S' \| 'm' \| 's'`（大小写都收，`:23` 还做了归一） | 🟢 **假阳** |
| `Slider.size="s"` ×1 | `Slider.vue` `size?: 'm' \| 's'` | 🟢 **假阳** |
| `Badge.type="brand"/"orange"/"blue"` ×3 | `Badge.vue:21` `type?: 'brand' \| 'red' \| 'orange' \| 'blue'`，且 `:4-5` **自称 legacy** 并逐字写明「npm 导出的是 `src/canonical/Badge.vue`，**API 不同**」 | 🟢 **假阳** |
| `Switch :loading="true"` ×2 | `Switch.vue` `loading?: boolean` ⇒ `:loading="true"` 是 Vue 里的正确写法（`yes\|no` 是 web-component 口径） | 🟢 **假阳** |
| **`Button.size="s"` ×4** | 🔴 Button **只有 8 个 `canonical*` prop，⛔ 根本没有 `size`**（真名 `canonicalSize`） | 🔴 **真缺陷** |

⇒ **15 假阳 · 4 真**。而且**真的那 4 处，量具的归因也是错的**：
它报「`size` 的值 `s` 不在 `XS\|S\|M\|L` 里」，真相是 **`size` 这个 prop 压根不存在**
⇒ 它连同 `variant="ghost-gray"` 一起落进 `$attrs` 变成 DOM 属性，**那几个按钮的样式根本没生效**。
⚠️ 而 `variant` 被量具归进了 312 个 `unknownProp`（那一档刻意不进违规率）⇒ **更严重的那一半反而没报**。

#### 这条发现连带的三件事

1. 🔴 **体检报告里那句「连设计系统自己的演示页都把属性写错，别人照着抄一定会错」⛔ 不成立**
   —— 15/19 是假阳。⚠️ 但**别反过来读成「示范页没问题」**：Button 那 4 处是真的，
   而且是「写了不生效」这种**更难发现**的形态。⇒ 报告要改，但方向不是删掉这段，是**换归因**。
2. **DIM-U17 的 `demos` 组读数（0.8%）是假阳率，⛔ 不是违规率。**
   `consumers` 组（0%）不受影响 —— 消费仓引的是 npm 包 = canonical，口径对得上。
3. **量具缺一条口径边界登记**：它的头注释登记了 4 条边界，**⛔ 没有一条说「本量具只对 canonical
   API 成立，对 `src/components/*` 的 legacy SFC 会假阳」**。⇒ 这是个 fail-open：
   假阳会被当成真缺陷去"修"，而**那会把正确的 legacy 用法改成对 legacy 无效的值**。

#### 由此拆出的新条目（替代原 A1）

| # | 事 | 档 | 说明 |
|:-:|---|:-:|---|
| **A1a** | 修 Button 那 4 处（`size`→`canonicalSize`，`variant`→对应 canonical prop） | **A** | ⚠️ 改完样式会变 ⇒ 必须跑 render-drift 闸看 952 条 manifest 有没有漂 |
| **A1b** | 给量具补口径边界：按 **import 路径**分辨该用哪套契约，或至少在头注释登记这条假阳 | **C** | 修法不唯一（真判 / 只登记 / 只扫 canonical 面），要 owner 拍 |
| **A1c** | 改体检报告那句话（换归因，⛔ 不是删掉） | **A** | 等 A1a/A1b 定了再改，免得改两次 |

⚠️ **这一整格是 §2.22 五行块救下来的**：差一步就去"修"那 15 处正确代码了。
⇒ 下面每一条动手前**照样要跑五行块**，⛔ 别因为「读数是我自己取的」就跳过。

---

### 面 ① · DS 代码仓 —— lab 可直接做

分档沿用 `AGENTS §4`：**A 档** = 机械判据 + 修法唯一 ⇒ 直接修 + 阳性对照 + 提交；
**C 档** = 价值取舍 / 要定阈值或定人 ⇒ ⛔ 不动手，写进 `docs/decision-queue.md`。

| # | 缺口 | 活读数 | 档 | 改哪 | 能否与别条并行 |
|:-:|---|---|:-:|---|:-:|
| **A1** | ~~DS 自己的示范代码属性写错~~ 🔴 **前提已塌，见下方 §1.0** | `U17` playground 报 19 处 —— **实测 15 处是量具假阳**，真缺陷 4 处且归因不同 | **改判** | 见 §1.0 | — |
| **A2** | 图标闸有一条没挂上链 | `X5` `audit:icon-canonical-names` **不在** `gate-chain`（4 条里在链 3 条） | **A** | `package.json` 的 `gate-chain` | ⚠️ 与 A3/A6 撞同一文件 |
| **A3** | 发布产物的溯源引用断了 | `X18` **2 / 5** 悬空（`ux-team/tvu-design-system/icons/manifest.json` · `figma-data/render-verification-manifest.json` 不被 `files[]` 覆盖） | **A** | `package.json` 的 `files[]` 或 `llms.txt` | ⚠️ 与 A2/A6 撞同一文件 |
| **A4** | 没有回滚手册 | `X8` **标题级 0**（行级搜到的 2 处逐条看全是 npm registry 的备用端点，与发版回滚无关） | **A** | `docs/RELEASING.md` 加一节 | ✅ |
| **A5** | 治理文档 9 份只有 1 份 | `X12` **1 / 9**（仅 `CONTRIBUTING.md`；缺 CODEOWNERS · SUPPORT · ACCESSIBILITY · SECURITY · CODE_OF_CONDUCT · GOVERNANCE · issue 模板 · PR 模板） | **C** | 仓根 / `.github/` | ⚠️ **CODEOWNERS 要 owner 定人**，其余可写 |
| **A6** | 没有任何包体积闸 | `X1` dist **12.6 MB** / 939 份，`hasSizeGate = false` | **C** | 新增一条闸 + `package.json` | ⚠️ **阈值是取舍**，撞 A2/A3 |
| **A7** | 供应链一项都没有 | `X6` 信号 **0**（无 dependabot / renovate / SBOM / 漏洞扫描，四种找法都零命中） | **C** | `.github/` | ✅ |
| **A8** | 8 条闸只报告不拦 | `Q6` **8 / 93** `blocking=false` | **C** | 逐条判该不该改成 blocking | ✅ |
| **A9** | 近一半的闸没做过故障注入 | `Q8` 带故障注入 **49 / 93 = 52.7%**；**3 条零测试面**（face=NONE） | **A**（补测试）| `tests/` | ✅ |
| **A10** | 组件清单没有成熟度字段 | `X11` render manifest **无** maturity/stability/tier 任一字段（docs-site 侧有 approved 17/25） | **C** | 要先定分级语义 | ✅ |
| **A11** | 没有中央微文案规范 | `X15` 文件名命中 **0**（扫了 323 份 .md；内容命中的 3 份全是讨论该缺口的评估报告） | **C** | `docs/` 新建 | ✅ |
| **A12** | motion / density 两族 token 一个都没有 | `X19` motion **0** · density **0** · z-index 4（且那 4 个前 3 个值都是 1000，是命名不是标度） | **C** | `src/tokens/variables.css` | ✅ |
| **A13** | 三视图覆盖极低 | `X13` useCases **0%** · designSpec **4%** · statusMatrix **40%**（分母 25 个组件页） | **C**（工作量大）| `docs-site` | ✅ |
| **A14** | 登记表 base 列有过期信息 | `X16` 逐字写「无跨产品索引」，而索引**实际存在**（7 份文件 / 5 个真产品 / 82 KB） | **A** | `docs/internal/ds-health-dimensions.md` | ✅ |

### 面 ② · 消费产品仓 —— 🔴 **要 owner 先拍授权，⛔ 本轮不动手**

| # | 缺口 | 活读数 | 为什么卡住 |
|:-:|---|---|---|
| **B1** | 组件该用没用 | `U1.component` **6.1%**（3 / 49）；vue-app **2.7%**（1 个组件 / 36 处该用没用）· graphics-insertion-app **16.7%**（2 / 10）。裸 `<button>` **38** 个 · 裸输入框 5 · 裸下拉 2 | 要改两个产品的 `.vue` 源码 |
| **B2** | 图标没用 DS 的 | `U1.icon` 内联 SVG **2.6%**（1 / 38）⇒ **37 处**用的是别的图标 | 同上 |
| **B3** | 用了的组件还在被大量改写 | `U5` **2.0×**（3 次使用配 6 处 `:deep()` 覆盖）；vue-app 是 1 次使用配 4 处覆盖 | 同上 —— ⚠️ 且**覆盖多通常意味着组件本身不满足需求**，⛔ 不一定是消费方的错，见下 |

🔴 **B3 有一个必须先答的问题，⛔ 别直接去删覆盖**：
覆盖比使用还多，两种解释 —— ①消费方乱改 ②**DS 的变体不够 / 文档没说清有哪些变体**。
**这两种的修法完全相反**（前者改消费仓、后者改 DS）。
⇒ 先做一件面 ① 的事：**逐条看那 6 处覆盖改的是什么属性**，再判归谁。这件事 lab 现在就能做。

### 面 ③ · Figma 设计文件 —— ⛔ 不是代码，lab 只能出清单

| # | 缺口 | 活读数 |
|:-:|---|---|
| **C1** | 拿错设计库 | `U12` **10.4%**（10,602 / 101,662，6 个产品文件加权）。⚠️ **逐产品差两个数量级**：LCD 21.4% · MicroApps 20.7% · Config-T 14.4% · MH 6.3% · Media Service UR 3.2% · PP **0.14%** ⇒ ⛔ 别用加权值当行动依据，按产品看 |
| **C2** | 孤儿 master（做好了没挂进组件集） | `U15` 孤儿 master **28 / 123 = 22.8%** · 孤儿实例 **728 / 13,264 = 5.5%** |

⇒ lab 能做的：**把 C1/C2 的逐产品、逐组件清单导出来给设计师**（数据已在
`docs/internal/_generated/product-pattern-index.json` 与 `ds-health-history.jsonl` 里，
`orphanMasters[]` / `bySource[]` 两个字段就是清单本体）。⛔ lab 改不了 Figma。

### 面 ④ · lab 自己 —— 还有 15 格是黑的

`2026-09-16-dim-wiring-plan.md` §3 的第 2 轮：B 档 13 格（`U7 U9 S7 Q5 Q7 Q10 E1 E2 E4 X2 X3 X4 X9`）
+ C 档 2 格（`E3` `S1`，前件未到）。

⚠️ **B 档与第 1 轮的失败模式不同**：A 档是源没了会 fail-closed，**B 档是口径写错会静默出错数**
⇒ 每格动手前必须先定口径并写进 cell。

---

## 2. 分批方案（并行的真约束是**文件热点**，⛔ 不是任务数）

| 批 | 条目 | 为什么能一起跑 | 阻塞在什么上 |
|:-:|---|---|---|
| **P1** | `A1` `A4` `A9` `A14` | 四条改四组互不相交的文件（playground / RELEASING.md / tests / 登记表），**纯 A 档、修法唯一** | 无 —— **现在就能开** |
| **P2** | `A2` `A3` `A6` | 三条都改 `package.json` ⇒ **必须串行**，且 A6 要先定阈值 | A6 的阈值要 owner 拍 |
| **P3** | `A7` `A11` `A12` `A5`(除 CODEOWNERS) | 各自新建文件，互不冲突 | 都是 C 档 ⇒ **要 owner 先拍做不做** |
| **P4** | 面 ④ B 档 13 格 | 与面 ① 完全不同的仓（改的是 lab 自己） ⇒ **可与 P1 真并行** | 注册表那 5 处仍需串行改 |
| **P5** | `B1` `B2` `B3` | — | 🔴 **卡 owner 授权**（见 §0 面 ②） |
| **P6** | `C1` `C2` | — | 🔴 **卡设计师在 Figma 里做**，lab 只出清单 |

🔴 **只有 P1 和 P4 现在就能开，且它们真的可以并行**（不同仓）。
P2/P3 卡取舍、P5 卡授权、P6 卡他人。

⚠️ **P1 与 P4 并行时的唯一冲突点**：两条线都会跑 `ds-sweep`，而它往
`~/.claude/ds-metrics/ds-dimensions.jsonl` 追加序列 —— 那是 append，⛔ 不会互相覆盖，安全。

---

## 3. 做完之后那份「更完善的健康报告」怎么出

⛔ **别等到「全做完」** —— §0 已经说清 P5/P6 的完成时间不由 lab 控制。

出报告的判据（三条都满足即可出，⛔ 不要求清单清零）：

1. **P1 全部落地**，且每条都有阳性对照（改动撤掉数字弹回去）。
2. **面 ④ B 档接完**，即在跑维度 30 → 43 —— 这样报告覆盖的面才算完整。
3. `metrics/verify-report-numbers.mjs` 在新报告上 **exit 0**，且核验项数随新读数增加。

⚠️ 报告里必须把 **P5 / P6 单列成「不由 lab 控制的那部分」**，
⛔ 别把「还没做」与「做不了」混成一栏 —— 那正是 `AGENTS §2.16 推论一`
（「命题错」与「量具错」要分开报）的同族。

---

## 4. 要 owner 拍的三件事（⛔ 不拍就动不了）

1. **lab 能不能改消费产品仓**（`MicroApps/{vue-app,graphics-insertion-app}`）？
   它现在在 feature 分支 `mc-44-graphics-insertion-code` 上，⛔ 不是 master ⇒ 改哪个分支也要一起拍。
2. **C 档那几条做不做**（`A5` 治理文档 / `A6` 体积闸阈值 / `A7` 供应链 / `A10` 成熟度分级语义 /
   `A11` 微文案 / `A12` motion·density token / `A13` 三视图补文档）—— 这些都是**要投入的工作量**，
   ⛔ 不是修 bug。
3. **面 ③ 的 Figma 清单交给谁**（拿错库 10.4% / 孤儿组件 28 个）。
