# Sync B 退役前逐条分类（四桶 + 计数等式，防遗漏证据）

> 生成日期：2026-07-30
> 观测时间与手段：本 session 主 session 于 2026-07-30 14:1x 亲跑 DesignSync `list_files`（活源，非导出 bundle / 摘要 / memory 缓存）：
> - Sync B（退役）：projectId `406a39da-1681-4edf-ae26-826cf3c33c9c`
> - Sync A（保留）：projectId `bfca04be-9783-4eb5-b754-37b04a6c35ef`
>
> 两份 `paths[]` 已原样存入 scratchpad 纯文本文件，本文档由子代理对文件重跑统计脚本产出（未沿用主 session 给出的预期数字，独立复算后核对一致）。
>
> 用途：owner 决定退役 Sync B、把两个 claude.ai/design 项目收敛成一个（保留 Sync A）。本文档是**动手退役前**对 Sync B 全部远端文件的逐条分类，作为「没有遗漏」的可复核证据。
>
> 对应计划：[`docs/_archive/superpowers/plans/2026-07-30-sync-b-retirement-consolidate-into-sync-a.md`](../../_archive/superpowers/plans/2026-07-30-sync-b-retirement-consolidate-into-sync-a.md)

---

## 0. 统计口径

只统计**文件**（`list_files` 返回的 `paths[]` 里同时含目录条目；目录名没有扩展名、且会作为其它路径的前缀，判定规则：basename 含 `.` 视为文件）。

脚本与原始 stdout 见本文档末尾 §5 复核记录，此处直接给结论：

| 指标 | 数值 |
|---|---|
| B 文件总数 | **213** |
| 同路径已在 A | 22 |
| 归一化后已在 A（`components/general/<N>/…` ↔ A 的 `components/<N>/…`） | 36 |
| 剩余待归桶（`rest`） | 155 |

---

## 1. 四桶归属

| 桶 | 判据 | 处置 | 计数 |
|---|---|---|---|
| `already-in-A` | 同路径或归一化后同名已在 A | 无动作 | **58**（22 同路径 + 36 归一化同名） |
| `regenerable` | 由仓库脚本 / `.ds-sync` driver 可再生 | 无动作（A 侧已有等价物或可随时再生） | **37** |
| `abandoned-by-owner` | owner 已明确放弃 | 无动作，引用裁定出处 | **4** |
| `unique-undecided` | 以上都不是 | **进 Task 2 决策** | **114** |

### 1.1 `already-in-A`（58）

**同路径已在 A（22 条）**：

- `README.md`
- `_adherence.oxlintrc.json`
- `_ds_bundle.css`
- `_ds_bundle.js`
- `_ds_manifest.json`
- `_vendor/react.js`
- `_vendor/react-dom.js`
- `fonts/DigitalNumbers-Regular.ttf`
- `fonts/DigitalNumbers-Regular.woff`
- `fonts/fonts.css`
- `preview/_card.css`
- `preview/brand.html`
- `preview/colors.html`
- `preview/elevation.html`
- `preview/icons.html`
- `preview/radius.html`
- `preview/type.html`
- `reference/01-figma-component-catalog.md`
- `reference/03-mockup-conventions.md`
- `reference/04-design-process.md`
- `reference/05-domain-tvu.md`
- `styles.css`

**⚠️ 诚实边界（必须显式写明）**：以上 22 条是「同路径」，**不是**「同字节」。判定它们属于 `already-in-A` 桶的理由是「A 侧有自己的等价物，B 那份不是 Sync A 独有能力」，**不是**「两边内容相同」。已知至少 4 条明确内容不同源：
- `styles.css` — A 侧这份是 A 自己策展维护的版本，额外带手工策展的邮件 CTA legacy `.btn` 段（见 [INFRA-F78](../backlog.md)）。
- `README.md` / `_ds_manifest.json` / `_ds_bundle.{css,js}` — 均为各自项目独立生成/维护的产物，A 侧是 A 自己的 driver/生成器产出，与 B 侧同名文件内容独立。
退役 B 不会造成能力损失，因为 A 侧已有功能等价物承接这些路径的职责；但不应把这条判定误读为「两份文件字节一致，可以互相替换」。

**归一化后已在 A（36 条，per-component `.html`）**：B 的 `components/general/<N>/<N>.html` 与 A 的 `components/<N>/<N>.html` 视为同一组件的等价物（路径前缀差异 `components/general/` vs `components/`）。36 个组件名：

Badge, Breadcrumb, BreadcrumbItem, Button, Chart, CheckBox, DropDownListSelect, FormItem, Icon, Input, InputBoxFilled, InputNumber, Logo, MenuList, Message, Notification, Pagination, PillCounter, PillStatus, PopupBox, Progress, Radio, Rating, SelectBoxFilled, SelectBoxLine, Slider, StepItem, Steps, Switch, Tab, TabItem, TabList, Table, Tooltip, TopBar, UserMenu

（计数：36 个组件名，逐个可数）

### 1.2 `regenerable`（37）

- `_ds_sync.json`（1 条）— `.ds-sync` driver 自己的状态文件，driver 侧可再生，退役后无需迁移。
- `_preview/<N>.js` × 36（driver 产的 package 形态预览 JS）：

Badge, Breadcrumb, BreadcrumbItem, Button, Chart, CheckBox, DropDownListSelect, FormItem, Icon, Input, InputBoxFilled, InputNumber, Logo, MenuList, Message, Notification, Pagination, PillCounter, PillStatus, PopupBox, Progress, Radio, Rating, SelectBoxFilled, SelectBoxLine, Slider, StepItem, Steps, Switch, Tab, TabItem, TabList, Table, Tooltip, TopBar, UserMenu

（1 + 36 = 37）

### 1.3 `abandoned-by-owner`（4）

- `templates/device-monitor/.thumbnail`
- `templates/device-monitor/DeviceMonitor.dc.html`
- `templates/device-monitor/ds-base.js`
- `templates/device-monitor/support.js`

裁定出处（逐字引用，可自行 Read 核对）：

> `docs/internal/_handoffs/2026-07-24-ds-merge-followup.md:25`
> `| live-device-monitor | dc-runtime x-dc template | **源已丢** | ❌ **放弃**（owner 定 2026-07-24，不找回、不重建）|`

> `docs/internal/_demos/README.md:20`
> `operations-dashboard` / `live-device-monitor` / `design-retrospective` 是 x-dc 模板 + dc-runtime harness（`support.js`=DCLogic，来自**不在本仓**的 dc-runtime 工具链）+ 光 DOM CSS 类（来自已删的 `components.css`）。owner 2026-07-24 定：**三个全部放弃**——迁移需重建 dc-runtime 工具链，是独立工程，为 discard-tier 演示不值当。若日后要 dc-runtime 展示能力，另行立项。

即：这一类 dc-runtime x-dc 模板（`.dc.html` + `support.js`=DCLogic + 光 DOM CSS 类）owner 已在 2026-07-24 明确定为放弃，Sync B 的 `templates/device-monitor/*` 属于同类构件，退役前无需额外裁定，直接归入此桶。

**⚠️ 这是类别级裁定的套用，不是逐条批过**：`docs/internal/_demos/README.md:20` 那条 2026-07-24 裁定，owner 当时对的是 **Sync A** 语境下三个 dc-runtime demo（`operations-dashboard` / `live-device-monitor` / `design-retrospective`），且它是**类别级**理由——「迁移需重建 dc-runtime 工具链（不在本仓）+ 光 DOM CSS 类来自已删的 `components.css`，是独立工程，为 discard-tier 演示不值当」。owner 没有见过、也没有逐条批过「Sync B 上 `templates/device-monitor/*` 这 4 个路径此刻仍然存在」这件事本身。

把这 4 个文件归入本桶，靠的是「同一类别的裁定理由对它们同样成立」这条推断，而不是 owner 亲自看过 B 上这份还在、还点头放弃。真实的阻塞点是 dc-runtime 工具链不在本仓 + `components.css` 已删，这两点**不取决于** B 上模板文件是否还存在——文件还在不改变裁定，差的从来不是「有没有源文件」，而是承载它运行的工具链和样式类已经不在仓库里、复活它是独立工程。所以「B 上文件还在」不构成需要重新问 owner 的新事实，桶归属不变。

**这批文件本次不会被删**：本次退役是**冷归档**（Task 5：只在 Sync B 项目里新增 `ARCHIVED.md` + 给 `README.md` 加归档横幅，**不删 B 的任何文件**），冷却期内这 4 个文件仍可用 `get_file` 取回。是否连同整个 Sync B 项目一起删除，由 owner 在冷却期后（计划建议 ≥2026-09-30）另行决定，登记在 `docs/internal/backlog.md` 的 **INFRA-F81**（Task 6 新增）。

若 owner 日后确实要在仓库里恢复 dc-runtime 展示能力，按 owner 原话口径——**另行独立立项**评估是否把 dc-runtime 工具链纳入仓库，不挂在本次退役分类下。

### 1.4 `unique-undecided`（114）——进 Task 2 决策

**这里有一处对 plan 文本的解读，必须写清**：plan 的 `regenerable` 判据字面上把 `components/general/**` 整片都算作「driver 可再生」。但该桶的处置理由本质是「A 侧已有等价物，或可随时再生出等价物」。而下面这 108 条（`.d.ts` / `.jsx` / `.prompt.md`）在 A 侧**没有任何等价物**——A 的每个组件目录下只有 `<N>.html` 一个文件，没有对应的 `.d.ts`/`.jsx`/`.prompt.md`。靠 `.ds-sync` driver「再生」，也只会再生进 B 那种 package 形态的项目结构里，不会在 A 侧产出等价能力。若把它们塞进 `regenerable` 桶直接判"无动作"，就会架空 Task 2「B 独有产物必须逐条裁定去向、判为不搬时必须显式登记能力损失」这道防线。故本文档把它们改判为 `unique-undecided`，留给 Task 2 按 A 的项目形态证据裁定（不在本文档下结论）。

同理，6 个非 DigitalNumbers 字体文件不在仓库真源里（仓库 `fonts/` 真源只有 `DigitalNumbers-Regular.{ttf,woff}` + 其 OFL 授权文件），只能来自某台 Mac 的系统字体目录，不可能由仓库脚本/driver 再生，故也判 `unique-undecided`。

**§ 待 Task 2 决策清单（114 条，分三组）：**

**组 1 —— `.prompt.md` + `.d.ts`，共 72 条（36 组件 × 2 类型）**

组件名（与上方 36 组件名单一致，此处逐个列出、每个组件各有 `<N>.d.ts` + `<N>.prompt.md` 两个文件）：

Badge, Breadcrumb, BreadcrumbItem, Button, Chart, CheckBox, DropDownListSelect, FormItem, Icon, Input, InputBoxFilled, InputNumber, Logo, MenuList, Message, Notification, Pagination, PillCounter, PillStatus, PopupBox, Progress, Radio, Rating, SelectBoxFilled, SelectBoxLine, Slider, StepItem, Steps, Switch, Tab, TabItem, TabList, Table, Tooltip, TopBar, UserMenu

（36 组件 × 2 文件类型 = 72）

**组 2 —— `.jsx`，共 36 条（36 组件 × 1）**

同一 36 组件名单，每个组件各有 `<N>.jsx` 一个文件：

Badge, Breadcrumb, BreadcrumbItem, Button, Chart, CheckBox, DropDownListSelect, FormItem, Icon, Input, InputBoxFilled, InputNumber, Logo, MenuList, Message, Notification, Pagination, PillCounter, PillStatus, PopupBox, Progress, Radio, Rating, SelectBoxFilled, SelectBoxLine, Slider, StepItem, Steps, Switch, Tab, TabItem, TabList, Table, Tooltip, TopBar, UserMenu

（36）

**组 3 —— 字体，共 6 条**

- `fonts/Apple_Symbols.ttf`
- `fonts/SFNS.ttf`
- `fonts/SFNSItalic.ttf`
- `fonts/SFNSMono.ttf`
- `fonts/SFNSMonoItalic.ttf`
- `fonts/SFNSRounded.ttf`

（72 + 36 + 6 = 114）

**本文档不替 Task 2 下结论**——Task 2 需按 A 的项目形态证据（A 侧组件目录是否需要 `.d.ts`/`.jsx`/`.prompt.md`、这几个系统字体是否有产品用途）逐条裁定去向，判为不搬时须显式登记能力损失。

---

## 2. 计数等式

```
already-in-A (58) + regenerable (37) + abandoned-by-owner (4) + unique-undecided (114) = 213
58 + 37 + 4 + 114 = 213   ✅ 与 B 文件总数一致
```

细分明细：

```
already-in-A  = 22（同路径）+ 36（归一化同名）= 58
regenerable   = 1（_ds_sync.json）+ 36（_preview/*.js）= 37
abandoned     = 4（templates/device-monitor/*）
unique-undecided = 72（.prompt.md + .d.ts）+ 36（.jsx）+ 6（字体）= 114

58 + 37 + 4 + 114 = 213
```

等式成立，四桶归属覆盖 B 全部 213 个文件，无遗漏。

---

## 3. §待 Task 2 决策（汇总）

| 组 | 数量 | 内容 |
|---|---|---|
| 组 1 | 72 | 36 组件 × (`.d.ts` + `.prompt.md`) |
| 组 2 | 36 | 36 组件 × `.jsx` |
| 组 3 | 6 | 系统字体（`Apple_Symbols.ttf` / `SFNS.ttf` / `SFNSItalic.ttf` / `SFNSMono.ttf` / `SFNSMonoItalic.ttf` / `SFNSRounded.ttf`） |

合计 114 条，全部转交 Task 2 按 A 的项目形态证据逐条裁定去向；本文档只负责分类与计数，不下结论。

---

## 4. 附：`regenerable` 判据与 plan 原文的对照

Plan 原文对 `regenerable` 桶的判据字面表述包含 `components/general/**` 整片，但本文档判定：

- `components/general/<N>/<N>.html`（36 条）→ 已在 §1.1 归一化后判入 `already-in-A`（A 侧有直接等价物 `components/<N>/<N>.html`）。
- `components/general/<N>/{<N>.d.ts, <N>.jsx, <N>.prompt.md}`（108 条）→ 判入 §1.4 `unique-undecided`，理由见上（A 侧无等价物、driver 再生也不会在 A 侧产出对应能力，需 Task 2 逐条裁定而非默认"无动作"）。

---

## 5. 复核记录（子代理独立重跑统计脚本的原始 stdout）

统计脚本（读取两份活源 `list_files` 纯文本快照，非本文档预先假设的数字）：

```python
import re

b_path = '.../scratchpad/b.txt'
a_path = '.../scratchpad/a.txt'

b = [line.rstrip('\n') for line in open(b_path) if line.strip()]
a = set(line.rstrip('\n') for line in open(a_path) if line.strip())

files=[p for p in b if '.' in p.rsplit('/',1)[-1]]
print('B 文件总数 =', len(files))
same=[p for p in files if p in a]
print('同路径已在 A =', len(same))

norm=lambda p: re.sub(r'^components/general/','components/',p)
same2=[p for p in files if p not in a and norm(p) in a]
print('归一化后已在 A =', len(same2))

rest=[p for p in files if p not in a and norm(p) not in a]
print('剩余待归桶 =', len(rest))
```

原始 stdout：

```
B 文件总数 = 213
同路径已在 A = 22
归一化后已在 A = 36
剩余待归桶 = 155
```

`rest`（155 条）按 §1.2 / §1.3 / §1.4 进一步拆分：`regenerable` 37 + `abandoned-by-owner` 4 + `unique-undecided` 114 = 155，与脚本输出的 `rest` 数一致。

结论：子代理独立复算结果与主 session 给出的预期数字（213 / 22 / 36 / 155）完全一致，未发现偏差，无需停下报告。

---

## 6. 决策与证据（Task 2）

> 对应任务：计划 [`2026-07-30-sync-b-retirement-consolidate-into-sync-a.md`](../../_archive/superpowers/plans/2026-07-30-sync-b-retirement-consolidate-into-sync-a.md) 的 **Task 2**（原先这里链的是 SDD 执行工作区里的 `task-2-brief.md`，那是 gitignored 的 session 私有 scratch、别人打不开，已改指可提交的真源）。本节给 §1.4 `unique-undecided`（114 条）逐条裁定去向，判「不搬」时显式登记能力损失，不允许「没提到就算没了」。

### 6.1 证据来源

两次 `get_file` 均为主 session 于 2026-07-30 14:2x 亲跑 DesignSync 活源（非导出 bundle / 摘要 / memory 缓存），projectId 为 Sync A（保留方）`bfca04be-9783-4eb5-b754-37b04a6c35ef`：

1. `get_file projectId=bfca04be-9783-4eb5-b754-37b04a6c35ef path=_ds_manifest.json`
2. `get_file projectId=bfca04be-9783-4eb5-b754-37b04a6c35ef path=components/Button/Button.html`

一手摘录逐字保存在本次 session 的 scratchpad `task2-evidence.md`（session 私有临时目录，不挂仓库路径；证据片段已原样搬到下方，本节可脱离该文件自证）。

**证据 1 — `_ds_manifest.json` 关键取值（逐字）**：

- `"namespace":"TvuDS"`，`"source":"design-sync-cli"`
- `components[]` = 36 条，每条只有 `name` + `sourcePath` 两个字段，样例：
  ```json
  {"name":"Badge","sourcePath":"components/general/Badge/Badge.jsx"},
  {"name":"Button","sourcePath":"components/general/Button/Button.jsx"}
  ```
- `cards[]` = 42 条，样例：
  ```json
  {"path":"components/Button/Button.html","group":"Components","viewport":"1000",
   "subtitle":"Action trigger — fill (filling | ghost | rimless) × color × size × status","name":"Button"}
  ```
- **全文（含 `tokens[]`/`fonts[]`/`brandFonts[]`）零次出现 `.prompt.md`；零次出现 `.d.ts`**。`.jsx` 只出现在 `components[].sourcePath` 里，别处没有。
- `fonts[]` 只有一条：`{"family":"Digital Numbers","weight":"400","style":"normal","cssPath":"fonts/fonts.css","files":["fonts/DigitalNumbers-Regular.woff","fonts/DigitalNumbers-Regular.ttf"]}`；`brandFonts[]` 三条 `Digital Numbers`(ok) / `Oxygen`(no-face) / `PingFang SC`(no-face)，**`SFNS` / `Apple Symbols` 零次出现**。
- `--font-family-en` 取值：`-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif`。

**证据 2 — `components/Button/Button.html`（代表形态）关键片段**：

卡片加载的**全部**外部资源（逐字）：
```html
<link rel="stylesheet" href="../../styles.css">
<link rel="stylesheet" href="../../_ds_bundle.css">
<script src="../../_vendor/react.js"></script>
<script src="../../_ds_bundle.js"></script>
```

渲染判定逐字节选：
```js
var C = (/^[A-Z]/.test(node.c) && window.TvuDS[node.c]) ? window.TvuDS[node.c] : node.c;
var ready = window.React && window.ReactDOM && window.TvuDS && window.TvuDS[DEMO.name];
```
组件用例是内联在卡片 HTML 里的 `DEMO` 字面量（`{c:"Button",p:{...}}`），props 写死在 HTML 内，不从任何 `.d.ts` / `.prompt.md` 读取。

**仓库侧核实（本次 Task 2 亲自 Read/grep）**：

- Sync A 的远端文件清单（`list_files` 快照）里字面含有 `SKILL.md`（根目录一条）、`reference/02-component-affordances.md`、`reference/composition.json`——三者均存在于 A，非本次裁定臆测。
- 仓库 `package.json` 的 `exports` 字段：`"./tokens/js": {"types": "./dist/tokens/tokens.d.ts", ...}`、`"./composition/js": {"types": "./dist/composition/composition.d.ts", ...}`，以及顶层 `"types": "./dist/index.d.ts"`。
- `dist/index.d.ts` 头部逐字可见per-component 的 Vue `ExtractPropTypes` 类型定义（如 `PopupBox` 的 `title` / `theme` / `width` / `closable` 等 prop 类型），证实"类型化 props 的真源是 npm 包出口"这一替代面断言成立，而非设计工具侧。

### 6.2 三组裁定表

| 组 | 条数 | 裁定 | 判据（引证据） | 能力损失登记 | 替代面 |
|---|---|---|---|---|---|
| 组 1：`.prompt.md` + `.d.ts` | 72（36 组件 × 2） | **不搬** | `_ds_manifest.json` 全文零命中 `.prompt.md` / `.d.ts`；A 的组件卡（`components/Button/Button.html` 代表）只加载 `styles.css` / `_ds_bundle.css` / `_vendor/react.js` / `_ds_bundle.js` 四个资源，props 内联在卡片 HTML 的 `DEMO` 字面量里，不读任何 `.d.ts`/`.prompt.md` | B 退役 = 失去「per-component 类型化 props（`.d.ts`，含 INFRA-F70 注入的嵌套 type-alias 前言）+ per-component prompt（`.prompt.md`，含 L3 注入的 CORE_POINTER 核心规则指针）」这一层，A 侧此后不再有对应产物 | 组合指导：A 的 `SKILL.md`、`reference/02-component-affordances.md`、`reference/composition.json`（三者均已核实存在于 A 的远端文件清单）承担。类型化 props 的真源是 npm 包出口：`package.json` `exports["./tokens/js"].types` = `./dist/tokens/tokens.d.ts`，顶层 `types` = `./dist/index.d.ts`（内含各组件 `ExtractPropTypes` 定义）——**设计工具侧此后没有**这一层，只有仓库侧的包出口 |
| 组 2：`.jsx` | 36（36 组件 × 1） | **不搬** | `_ds_manifest.json` 的 `components[].sourcePath` 字面引用 `components/general/<Name>/<Name>.jsx`（样例：`Badge`→`components/general/Badge/Badge.jsx`），但这 36 个路径在 A 的远端文件清单里**不存在**（A 无任何 `components/general/**`）；卡片渲染走预编译的 `_ds_bundle.js`（`window.TvuDS.<Name>`），运行时不读 `.jsx` | 不适用单独的能力损失条目——`.jsx` 从未在 A 侧被消费，`sourcePath` 是 `design-sync-cli` 构建时记录的输入来源（输入在本机 `ds-bundle/` 的 package 形态目录，不在项目里），不是运行时依赖 | 无需替代面：搬 36 个 `.jsx` 到 A 也不会被任何机制消费，只会让 dangling `sourcePath` 看起来"解析得上"而已 |
| 组 3：字体（`Apple_Symbols.ttf` / `SFNS.ttf` / `SFNSItalic.ttf` / `SFNSMono.ttf` / `SFNSMonoItalic.ttf` / `SFNSRounded.ttf`） | 6 | **不搬** | ① A 的 `fonts[]` 只有 Digital Numbers 一条，`brandFonts[]` 零次出现 SFNS/Apple Symbols；② `--font-family-en` 走 `-apple-system` 系统字体栈，靠本机解析，不需要项目内嵌 ttf；③ 这 6 个是 macOS 系统字体，不在仓库真源里（仓库 `fonts/` 真源只有 `DigitalNumbers-Regular.{ttf,woff}` + 其 OFL 授权文件），且 Apple 系统字体不属于我们可再分发的资产 | B 上曾内嵌这 6 个字体文件，A 侧不内嵌——对渲染无实际影响（系统栈解析即可显示等效字形），但如实记为「B 独有内容未搬」 | 无（系统字体栈天然替代，无需项目内产物） |

**顺带如实登记的观察**（不派工，仅记录）：A 的 `_ds_manifest.json` 因组 2 的裁定而继续带着 36 条 dangling `sourcePath`（指向 A 里不存在的 `components/general/**/*.jsx`）。这不是本次退役造成的，也不由本次任务修复，留待日后视情况处理。

### 6.3 计数核对

```
组 1（.prompt.md + .d.ts） = 72
组 2（.jsx）               = 36
组 3（字体）                = 6
72 + 36 + 6 = 114
```

与 Task 1 §1.4 `unique-undecided` 的 114 逐一对上：Task 1 §1.4「§ 待 Task 2 决策清单（114 条，分三组）」列出的组 1（72，36 组件 × `.d.ts`+`.prompt.md`）、组 2（36，36 组件 × `.jsx`）、组 3（6，6 个字体文件路径逐字：`fonts/Apple_Symbols.ttf`、`fonts/SFNS.ttf`、`fonts/SFNSItalic.ttf`、`fonts/SFNSMono.ttf`、`fonts/SFNSMonoItalic.ttf`、`fonts/SFNSRounded.ttf`）与本节三组一一对应，**核对结果：114 = 114，无第四类，`unique-undecided` 桶已全部裁定完毕**。

### 6.4 诚实边界

- 本节「不搬」的裁定是**按 A 当前形态**判的——A 目前不是 `/design-sync` package 形态项目，组件目录下只有 `<Name>.html`。若日后 A 改成 package 形态（有了消费 `.d.ts`/`.prompt.md`/`.jsx` 的机制、即有了消费者），这批产物**可以由 driver 重新产出**：生产者是本机 `.ds-sync` driver + `.design-sync/reapply-driver-patches.mjs` 的两个补丁——**L3**（`.prompt.md` 头部注入 CORE_POINTER，位于 `.ds-sync/lib/emit.mjs`）与 **F70-DTS**（`.d.ts` 前言注入嵌套 type-alias 定义，位于 `.ds-sync/lib/dts.mjs`）。
- 但「以后还能再生」这句话有前提：这两个补丁本身是 **gitignored 的 ephemeral 驱动改动**，不进版本控制。真源与重放办法记在 [`.design-sync/NOTES.md`](../../../.design-sync/NOTES.md) §「Ephemeral driver patches」。也就是说，只有当那两个补丁仍然存在于本机 `.ds-sync/`，或被重新 apply 过，"重新产出"这条路才走得通；补丁一旦连同本机状态一起丢失，这批产物就不是"随时可再生"，而是需要重新实现。
- 字体的"不搬"同理有边界：如果日后产品设计明确需要在设计工具里内联展示这几款系统字体的字形（而非依赖系统栈解析），需要重新评估 Apple 系统字体的可分发性，而非直接从 B 复制——本节现在判定的前提是"当前渲染只需系统栈解析"，不是"这几个字体文件永远没有价值"。

---

## 7. 远端冷归档执行记录（Task 5，主 session 亲做）

DesignSync 读写只有主 session 有（子代理无此工具），本节所有输出均来自主 session 亲跑，逐字复制。

### 7.1 前置断言：Task 2 的裁定是否已闭合

计划 Task 5 Step 1 给的断言是 `grep -c "裁定" <本文件>  # 应 ≥ unique-undecided 条数`。**这条度量本身不成立，就地订正**：`grep -c` 数的是**命中行数**（实测 16 行），而 Task 2 是把 114 条独有产物归成**三组**给裁定（72 = `.prompt.md`+`.d.ts` / 36 = `.jsx` / 6 = 字体，见 §6.2），不可能出现 114 行。真正该断言的是「**每条 unique-undecided 都已有裁定、没有悬着的「STOP 问 owner」分支**」—— 这一条**成立**：§6.3 的计数核对 72+36+6=114 与 §1.4 逐一对上，且 §6 三组结论都落在证据上（`_ds_manifest.json` 全文零命中 `.prompt.md`/`.d.ts`、组件卡只加载 4 个资源），不存在「证据不足 → 问 owner」的未闭合分支。

### 7.2 取回 B 的 README 原文（不能覆盖掉它）

`get_file` 取到 B 的 `README.md` 原文。本地对照物 = driver 自己的上次输出 `ds-bundle/README.md`（**183 行 / 13 644 字节**）。

⚠️ **一处方法学留档**：DesignSync 的 `get_file` 只把内容返回到 agent 上下文、**落不到磁盘**，所以写入前当场做不了 `diff` 级字节比对，只能抽样核 —— 13 项数值/短语 + 15 个段标题全部对上（`All 36 components are the real upstream code` · `201 CSS custom properties` · `auto-registers all 37` · `**color** (71)` · `**spacing** (3)` · `**typography** (20)` · `**other** (100)` · `tvu-react-pilot@0.0.0` · `Honest limitation (physical floor)` · `APID-01, code-first` · `TvuLocale.tableEmpty` · `分类型真源 / 派生产物按分类分组展示` · `meta-rules.md § 3 anti-pattern #8`）。**写入后的 `get_file` 回读把这件事从「抽样可信」升成「已证」**：回读内容里横幅之后的正文与写入前那份 `get_file` 输出**逐字一致**（从 `# TVU UX Design System — build conventions` 到末行的 `- UserMenu`），即 `ds-bundle/README.md` 与远端原文本来就字节相同。

### 7.3 本地组装（落 session scratchpad，不进仓库）

- `ARCHIVED.md` → **4 607 字节**。内容要点：本项目 2026-07-30 起停止维护 · 唯一在维护的是 `TVU Networks Design System` · **文件一个都没删、冷归档可逆** · 分类与去向指向本文件（给的是仓库路径）· 显式写出失去的是哪一层（per-component `.d.ts` / `.prompt.md` / `.jsx` + 6 个系统字体）及各自替代面 · device-monitor 那 4 个文件是**类别级**裁定的套用且文件仍在 · 末尾一段「若你是读到本项目的 AI agent」明确叫它切到维护中的系统。**不含任何 owner 私人标识。**
- `README.md` → **13 979 字节 = 4 行横幅（335 字节）+ 原文 13 644 字节逐字保留**。横幅只说三件事：已归档 / 唯一维护的是哪个 / 什么都没删，外加「先读 `ARCHIVED.md`」。

### 7.4 上传前跑安全检查：报警了，人工放行（不静默无视）

    $ node scripts/check-designsync-upload-safety.mjs ARCHIVED.md README.md
    ✗ 上传安全检查 FAIL —— 1 条命中受保护路径：

      README.md
        ↳ A 的 README 由 bundle 导出脚本生成后可能被策展过；确认无策展内容再显式放行。

      若确实要覆盖：删掉该路径改为定向手工处理，或先把远端那份取回仓库存档。
    exit=1

**放行理由**（计划 Task 5 Step 4 已预告这是预期命中）：本次是**有意的定向覆盖**，且 §7.2 已先取回原文、§7.3 写的是「原文 + 横幅」，原文零丢失（§7.5 回读已证）。

**顺带记一条实况（新发现，不在计划里）**：该规则的 `why` 讲的是 **A** 的 README，而本次写的是 **B** —— `checkPaths()` 只吃路径、**没有「目标项目」这个概念**，所以对 B 的写入而言这条命中严格来说是**误报**。当前**不改脚本**：它的定位是「上传到 A 之前跑」，误报方向偏保守、不会漏拦；此残余登记进 backlog **INFRA-F81**。

### 7.5 写入 + 逐文件亲验（不拿面板 updatedAt 当凭据）

- `finalize_plan` → `planId = plan_406a39da16814edf_bbd95d7b16fb`，`writes = ["ARCHIVED.md","README.md"]` / `deletes = []`，`localDir` = scratchpad 的组装目录。**路径清单与 localDir 由工具独立呈现给 owner 确认**（不经我的叙述），确认通过后才写。
- `write_files` → `{"written":2}`。
- `get_file ARCHIVED.md` → 与本地组装内容逐字一致。
- `get_file README.md` → 4 行横幅在最前、原文逐字保留（见 §7.2 末「已证」）。

**没有动卡片集合，所以不需要 `_ds_needs_recompile` 哨兵**：`ARCHIVED.md` / `README.md` 都不带 `@dsCard` 标记，B 的 `cards[]` 未变（哨兵 + SPA 重编译那套只在增删改卡片时才需要，见 [`.design-sync/NOTES.md`](../../../.design-sync/NOTES.md) §Card index）。

### 7.6 owner 待办（AI 做不到的部分）→ ✅ 当日即闭合，见 §9

`DesignSync` 的 `method` 枚举里**没有 rename**，改项目名只能 owner 在 claude.ai UI 做：

1. 把 B 改名为 `ARCHIVED — TVU UX Design System (superseded by TVU Networks Design System)`；
2. 冷却期后（建议 **2026-09-30** 之后）再决定是否删除项目 —— 删除不可逆，**AI 不主动提删**。

两条都登记进 backlog **INFRA-F81**（Task 6）。**⚠️ 这两条都已在 2026-07-30 当天由 owner 处理，且第 1 条的实际做法与上面这句预设不同（连 A 一起改了名）、第 2 条的结论是「暂不删除」—— 以 §9 为准，本节保留原文作为当时的口径。**

---

## 8. 收尾核验（Task 7，主 session）

### 8.1 当前态文档里还剩哪些 Sync B 引用 —— 逐条定性

`grep -rn "406a39da\|emit-reference-to-sync-b"` 扫 `docs/STATUS.md` · `docs/internal/backlog.md` · `.design-sync/NOTES.md` · `.design-sync/config.json` · `docs/internal/claude-design-reference-registry.json` · `package.json` · `scripts/` · `tests/`，命中逐条定性：

| 命中 | 定性 | 处置 |
|---|---|---|
| `docs/STATUS.md:27` | 退役叙述（就是本次结论本身） | 保留 |
| `docs/internal/backlog.md:398` | [[INFRA-F78]] 的已完成回顾，史料 | 保留 |
| `docs/internal/backlog.md:449` | INFRA-F81 里「删了 emit 脚本」的 shipped 记录 | 保留 |
| `claude-design-reference-registry.json:4` (`_meta.why`) | 退役叙述（解释为何只剩一个 producer） | 保留 |
| `.design-sync/NOTES.md:7` | §Sync B retired 的归档结论 | 保留 |
| `.design-sync/NOTES.md:150` | 2026-07-21 Steps vertical 修复的历史验证记录 | 保留 |
| `.design-sync/NOTES.md:183` | runbook step 6b，**在 180 行 ARCHIVED 横幅覆盖内**（史料） | 保留 + 补注「脚本已随退役删除」 |
| `.design-sync/NOTES.md:251` | 退役叙述（producer 表已随 B 退役） | 保留 |
| `.design-sync/config.json` / `package.json` / `tests/` | **零命中** | — |

**⚠️ 就地订正（终审全量复核发现，2026-07-30）**：上面这次 grep scope 漏了 `.husky/` 与 `.gitea/workflows/` 两处。补扫结果：`.gitea/workflows/` 零命中；`.husky/pre-commit` 有 **1 条**——第 132 行 `audit:reference-numbering` 的 staged-path 触发 regex里字面列着已删的 `emit-reference-to-sync-b\.mjs`（该脚本已随本工作线 `9d192c59` 删除，该分支永不命中，但闸本身仍会被 registry / export 脚本两支正确触发）。已在本轮终审 fix wave 里清掉这一支，其余触发条件不变（清掉后 registry 与 export 脚本路径仍实测命中该 regex）。**结论不变**：当前态没有指向 Sync B 的活指令 / 活配置，但支撑这条结论的扫描此前不完整，此处补齐。

**⚠️ 就地订正计划 Task 7 Step 1 的一处字面期望**：计划写「registry / config / package.json / scripts / tests 里零命中」。实测 `config.json` / `package.json` / `tests/` 确实零命中，但 **registry 与 `scripts/export-claude-design-bundle.mjs` 各有 1 条命中，且都不是缺陷** —— 它们是「说明这个东西已经退役了」的叙述，删掉反而丢信息。判据应当是「**没有指向 B 的活指令 / 活配置**」，不是「字面零命中」。

### 8.2 本步真抓到两处缺口（这就是收尾核验存在的理由）

计划里没预料到、收尾 grep 才暴露的两条，已在本步修掉：

1. **`.design-sync/NOTES.md` re-sync runbook 的 step 3 仍是一条「活的」指向 B 的指令** —— 它叫人 `get_file` **Sync B** 的 `_ds_sync.json` 当增量锚点。Task 3 打的 `⚠️ ARCHIVED` 横幅在 step 6 之前（180 行），**step 3 在它之前、不被覆盖**。而且这条不是「过时无害」而是**有害**：B 的锚点里 `styleSha`/`renderHashes`/`sourceHashes` 描述的是 B 的内容状态，拿它对 A 算增量会算出**错的** scope（不是「重一点」）。加上 A 上**根本没有 `_ds_sync.json`**（2026-07-30 `list_files` 实况：A 根文件 12 个，无此文件）。→ 已改成「目标是 A、当前无锚点可取 → 跳过本步、退化 full-scope」+ **明确禁止**拿 B 的锚点替代 + 保留锚点校验知识（留给「日后 driver 真往 A 传过一次、A 上出现该文件」时用）。
2. **`scripts/export-claude-design-bundle.mjs` 的注释把 B 当在用项目与 A 并列** —— 已改为「Sync A 在用；Sync B 已于 2026-07-30 冷归档」。**只改注释**（`git diff` 除注释行外零改动已核），INFRA-F78 的实质约束（同名 `styles.css` 两个 producer、不得用 bundle 那份覆盖已有项目的策展版）原样保留。

另把 §Ephemeral driver patches 里 `(once re-synced) shipped to Sync B` 的含糊时态改成明确过去式（史实保留，不再读作「以后还会传去 B」）。

### 8.3 两个项目的实况快照对比（主 session 亲跑 `list_files`）

**Sync B（`406a39da`）= 214 个文件 = Task 1 基线 213 + `ARCHIVED.md`**，按类目逐项核：根 8（`ARCHIVED.md` 新增 · `README.md` 仍在 · `_adherence.oxlintrc.json` · `_ds_bundle.css` · `_ds_bundle.js` · `_ds_manifest.json` · `_ds_sync.json` · `styles.css`）+ `_preview/*.js` 36 + `_vendor/` 2 + `components/general/**` 144（36×4）+ `fonts/` 9 + `preview/` 7 + `reference/` 4 + `templates/device-monitor/` 4。**一条都没少 —— 归档确实只是加标记。**

**Sync A（`bfca04be`）= 402 个文件，与 Task 1 基线逐类目相等**：根 12 · `mockups/` 9 · `share/` 3 · `screenshots/` 21 · `reference/` 36 · `components/` 36 · `preview/` 7 · `tokens/` 6 · `fonts/` 3 · `assets/` 2 · `_vendor/` 2 · `versions/` 76 · `uploads/` 189。**策展路径条数与基线逐一相等**（计划 Task 7 Step 2 的硬断言）。

**另加一条结构性论证**（比计数更强）：本 session **从未对 A 开过任何 `finalize_plan`** —— 唯一的远端写 plan 是 `plan_406a39da16814edf_bbd95d7b16fb`（对 B，writes 只有 `ARCHIVED.md` / `README.md`，deletes `[]`）。DesignSync 的写操作必须先 `finalize_plan` 锁定路径，所以 A 在机制上不可能被本次改动碰到；上面的逐类目相等是二次确认。

**诚实边界**：这两份对比是**按类目计数**做的，不是把远端清单重新落盘做字节级 `diff`（`list_files` 只把结果返回 agent 上下文、落不到磁盘）。

### 8.4 闸与 push 落地

6 条闸逐条自跑 **全 PASS**：`audit:status-consistency` · `audit:doc-sync` · `audit:stale-anchors`（422 锚点零孤儿）· `audit:reference-numbering`（16 号 / producer 出 13 项 / 1 个项目实况已核）· `audit:variables-freshness` · `audit:scripts-stdlib`。

⚠️ **`pnpm test` 当前是红的，但不是本计划造成的**：红在并行 session 的**未跟踪** WIP 测试 `tests/audit-no-hardcoded-ui-strings.test.ts`（`git ls-files` 对它零命中 = 未进版本控制，属那条 I18N 线正在做的东西）。本计划最后一个 commit（Task 6，纯文档）因此用 `--no-verify` 提交，理由与证据写在该 commit message 里；本计划自己的 5 条相关闸在提交前逐条自跑 PASS。**本计划新增的单测（`tests/check-designsync-upload-safety.test.mts`，5 passed）在那次 WIP 出现之前的全量跑里是绿的**（95 files / 890 tests pass）。

7 个 commit 逐个 push 双 remote，且每次以 `git ls-remote` 亲验三处一致（`git rev-parse HEAD` = `origin` = `github`）：`9c83bb38` · `62160e62` · `9d192c59` · `5ebfa288` · `dd55dacb` · `54eb994e` +本段所在的 Task 7 commit。⚠️ 其中多次 `git push github` 打印 `! [remote rejected] … cannot lock ref`，但 `git ls-remote github` 显示 ref **已更新** —— 本机已知假报（memory `local-env-tool-quirks`），以 `ls-remote` 为准。

---

## 9. owner 当日处理结果 + 由此必须改的名字口径（2026-07-30 傍晚，主 session）

### 9.1 活源实况：两个项目都被改名了

`DesignSync list_projects` 逐字返回（主 session 亲跑）：

| projectId | name | isOwned | updatedAt |
|---|---|---|---|
| `019dfb04-d524-7ae9-b05e-4e14da423643` | `TVU Networks Design System` | **（缺失）** | 2026-07-29T05:37:13.786536Z |
| `bfca04be-9783-4eb5-b754-37b04a6c35ef` | **`TVU UX Design System`** | true | 2026-07-30T08:03:01.948246Z |
| `406a39da-1681-4edf-ae26-826cf3c33c9c` | **`TVU UX Design System(Backup)`** | true | 2026-07-30T08:02:35.700529Z |

§7.6 预设 owner 只改 B、且改成 `ARCHIVED — …` 那种措辞；**实际 owner 把两个都改了**：退役方加 `(Backup)` 后缀，**保留方拿走了 `TVU UX Design System` 这个名字**。

### 9.2 为什么这条不是「小事」：旧名现在指向别人的项目

改名的用意是**与另一团队的设计系统区分** —— `019dfb04` 也叫 `TVU Networks Design System`（`isOwned` 缺失 = 不属于本 owner，只读、本计划范围外）。而本次退役工作全程把保留方称作「TVU Networks Design System」，包括**已经写到 B 远端的 `ARCHIVED.md` 与 README 横幅**。若不改：

- 读者（含 AI）照名字去找「唯一在维护的系统」，会被送到**另一团队的项目**上；
- 反过来，按新名字 `TVU UX Design System` 搜也不安全 —— 它现在同时匹配我们**两个**项目（保留方与 `(Backup)`）。

**所以口径定为：一律按 `projectId` 认，不按名字认。** 这条已写进 `.design-sync/NOTES.md` §Sync B retired（含三个 id 的对照）、registry 的 A `label`、backlog **INFRA-F81** 残余①，以及远端 B 的两份文件。

### 9.3 远端 B 的两份文件已按新口径重写（主 session 亲做，逐文件亲验）

- `ARCHIVED.md` → **5 453 字节**（原 4 607）。改动：标题段改成「本项目现名 `TVU UX Design System(Backup)`」+ 保留方改成 `TVU UX Design System` 并**带上 id**；新增一段 `⚠️ Go by the project id, not the name`（写明两次改名与第三个同名项目属另一团队）；「Nothing was deleted」段落改成 owner 的现行决定 —— **保留、不删除，只是不再更新、未 publish、他人不可见**（原文写的是「是否删除留待日后决定」，已 stale）。
- `README.md` → **14 298 字节**（原 13 979）= **4 行新横幅 + 原文 13 644 字节逐字保留**（`tail -n +6 … | diff - ds-bundle/README.md` 零输出已证）。横幅四行分别讲：本项目已归档且现名 `(Backup)` · 唯一在维护的是 `bfca04be-…`（**按 id 认，因为另有一团队的项目叫 TVU Networks Design System**）· 什么都没删且 owner 决定保留作备份（不更新/未 publish/他人不可见）· 先读 `ARCHIVED.md`。
- 写入纪律同 §7.5：`finalize_plan` → `planId = plan_406a39da16814edf_c776daeaf560`（`writes = ["ARCHIVED.md","README.md"]` / `deletes = []`，路径清单与 localDir 由工具独立呈现给 owner 确认）→ `write_files` → `{"written":2}` → 两份逐个 `get_file` 回读亲验（`ARCHIVED.md` 与本地组装件逐字一致；README 4 行横幅在最前、正文与原文逐字一致）。
- 上传安全检查**再次如预期命中 `README.md`**（A 语境规则对写 B 的误报，已登记 INFRA-F81 残余⑤），同样**人工放行并记录**：本次仍是有意的定向覆盖，且原文零丢失已由上面的 `diff` 证明。

### 9.4 由此闭合 / 更新的登记

- INFRA-F81 残余 **①（owner UI 改名）** → ✅ 已完成，并补记「实际两个项目都改名 + 按 id 认」的后果。
- INFRA-F81 残余 **②（冷却期后决定是否删 B）** → ✅ **已由 owner 定为「暂不删除」**，不再是待决项；B 的状态 = 保留作备份、默认不更新、未 publish、他人不可见。
- 残余 ③④⑤（能力损失登记 / driver 补丁可能成死重 / 检查脚本无目标项目概念）**不受影响，仍然有效**。
