# Phase X.4.2 Mass Refactor + Badge figma roundtrip 复盘（2026-05-08）

> 接续 [`2026-05-07-phase-a4-deep-debug.md`](2026-05-07-phase-a4-deep-debug.md)。
> 本复盘覆盖 commit e966d41 → Phase X.4.2 落地 → Badge 三轮 figma roundtrip → audit/alias 工具修整。
> 新 session onboarding 时**必读**——含 4 条新行为约束（#16-#19）。

---

## TL;DR

- **Phase X.4.2 mass refactor**（19 components canonical 对齐 figma 真源 + TopBar slot rename + 24 page alias 统一）落地：fix specs + Codex 实施 + 6 agent 并行复审 + 12 处 §0 plan owner-defined token 值 drift 修
- **Badge 三轮 figma roundtrip**（用户驱动 + MCP 验证 + canonical sync）：Black→Neutral 重命名 + Filled text 由 white 改 theme-aware → Filled bg `--bg-layer4` 改 `--bg-layer3`
- **Audit 工具修整**：`audit:docs-site` regex 老 bug（不认 `@/src/` alias）→ 1 line fix；2 page 残余相对路径统一 alias；FormItem 用 components/Select → 改 canonical/SelectBoxFilled
- **新行为约束**：(#16) plan owner 不下"by-design"判断，(#17) 视觉差异先验证 figma 真源 vs canonical token 一致再下结论，(#18) 阶段收口期 transient script 不入主 commit，(#19) 新阶段任务必须有 backlog/prompt repo 锚点
- **F20 / F21 入 backlog**（INFRA-F20 + INFRA-F21）作为新 session 启动锚点，不在本 commit 写 prompt 草稿

---

## 阶段 A — Phase X.4.2 mass refactor 落地

### 推进
1. **Plan owner 写 19 fix specs** [`docs/internal/_prompts/x4-2-batch/<comp>-fix.md`](../_prompts/x4-2-batch/) — 4 parallel agents 起草 → plan owner 整合
2. **Plan owner 写 mass refactor prompt** [`docs/internal/_prompts/phase-x4-2-mass-refactor.prompt.md`](../_prompts/phase-x4-2-mass-refactor.prompt.md) — §0 列出 30+ 已落 token，明确 D1-D5 决策
3. **Codex 执行**：24 文件改造（18 base components + 4 canonical bridge + 1 App.vue + 1 TopBarPage.vue），10m 完成，typecheck 0 错
4. **Plan owner 复审**：5 个我自验 + 6 个 parallel agent 各审 3 components → **23 PASS / 1 PARTIAL**（Checkbox theme prop CSS 待 plan owner approval）
5. **静态 token 值审计**：cross-check §0 已落 30+ tokens vs 19 fix specs 的 figma 真源数值 → **发现 12 处 drift**（`--input-number-*-width` / `--notification-width-side-pop` / `--radio-circle-border-width` / `--radio-selected-dot-size` / `--slider-track-h-m/s` / `--slider-thumb-dot-radius-m/s` / `--badge-circle-size` / `--progress-track-bg-light`）→ 12 parallel Edit 一次落 → typecheck 通过

### 关键决策
- 不用 manual screenshot eyeballing 验视觉对齐——用脚本（DOM + getComputedStyle + WCAG contrast）做 0 主观 audit
- TabItem Filled/Active-Green 漏 `font-weight: 700` 是 spec-correct（spec line 38 明确归到 Body 段）—— Agent E 误判，**不修**

### 触发器实证
- 行为约束 #4 实证：prompt §4 完成报告含"§4.X 完整改动清单"段 → 配合 6 agent 并行复审让 silent scope creep 几乎不可能

---

## 阶段 B — Badge 三轮 figma roundtrip（用户主导）

### 起因
plan owner 跑 light-theme contrast 审计脚本发现 Badge 11 个低对比 finding（用户截图也看到 light theme BadgePage 视觉差）。

### Round 1：Fix B —— Line variant text 由 white 改 palette color
- User 改 figma：`Tag=Line` 变体的 text fill 由 `--color-type/text/primary-button` (white) 改为 palette color（Red/Line 文字 = `--ux/red/default`，etc.）
- User publish → plan owner MCP `get_design_context` 验证 → canonical Badge.vue 加 `lineText` 字段
- light-theme audit Badge: 11 → 4 finding

### Round 2：Black → Neutral 重命名 + 全 Black 文字 theme-aware
- User 改 figma：`Color=Black` 重命名 `Color=Neutral`，所有 Black variants 文字改 `--color-type/text/text_1`（theme-aware）
- User publish → plan owner MCP 验证 → canonical type/palette/content/figma.ts 等 5 文件改 `Black` → `Neutral`
- 删 8 个 stale `_black_` JSON 文件（4 raw + 4 normalized） + regen 完整 normalize pipeline（`generate:component-tokens` / `generate:manifest` / `generate-docs-figma-members` / `generate:canonical-specs` / `generate:candidates` / `generate:skeleton-plan` / `audit:component-tokens`）
- 删 3 obsolete spike 文件（`ai-manifest.spike.json` / `canonical-component-api.json` / `component-token-fidelity.audit.json`）
- light-theme audit Badge: 4 → 2 finding

### Round 3：Neutral/Filled bg `layer_4` → `layer_3`
- User 改 figma：Neutral/Filled bg 由 `--color-type/background/layer_4` (#353535/#dbdbdb) 改 `--color-type/background/layer_3` (#262626/#f0f0f0) —— 视觉更柔
- User publish → MCP 验证 → canonical Neutral.fillBg 改 `--bg-layer3`
- 用户视觉验收"目前 badge 看起来可以了" → Round 3 收口

### 关键发现
- **Plan owner 改 canonical 前必先 MCP `get_design_context` 验证 figma 真源**——3 轮中每轮都先 MCP fetch 然后再改 canonical，0 次猜测
- **figma-data raw 删除 stale variant** 是 destructive op，需用户授权——本次 Black→Neutral rename 用户隐式授权了"包括但不限于之前的导出的组件的 JSON 文件"
- **3 obsolete spike 文件**（April 28-29 mtime）已不在当前 sync pipeline 输出范围，删除安全

---

## 阶段 C — Audit 工具与 alias 统一

### audit:docs-site regex 1-line fix
- 跑 `pnpm sync:figma-library --with-extract` 时 Step 5 audit:docs-site exit 1，25+ "Source type mismatch" / "Page still depends on runtime implementation" errors
- 根因：[`figma-sync/audit-docs-site-readiness.mjs:12`](../../figma-sync/audit-docs-site-readiness.mjs#L12) `extractImports()` regex `/from\s+['"]\.\.\/\.\.\/\.\.\/src\/(canonical|components)\/([^'"]+)['"]/g` 只认相对路径，**不认 22/24 docs page 用的 `@/src/` alias**
- 历史 bug：自这个 audit 写出来起一直 broken，但没人发现（pages 的 import 视觉/typecheck/build/dev server 都跑得通——因为 vite + tsconfig 的 alias resolution 是另一套）
- Fix：regex 改 `(?:\.\.\/\.\.\/\.\.\/|@\/)src\/(canonical|components)\/...` 同时认两种形态
- 2 page (FormItemPage / IconPage) 用相对路径不合 alias 项目惯例 → 统一 alias
- FormItem 用 `Select` (from components/) 不合 canonical-only 期望 → 改 canonical `SelectBoxFilled`
- audit:docs-site error: 25+ → **0**（剩 6 warn 是 pixel review in-review 非 blocker）

### 关键发现
- vite alias 解析（runtime/build）≠ audit 脚本 text-grep（静态分析）—— 同一个 alias 概念在两套系统里独立处理
- 历史 bug 不暴露不代表不存在；audit 工具自身需要项目惯例同步升级

---

## 阶段 D — Plan owner 行为失误链路（待修）

### 失误 1：擅自给 figma 真源贴 "by-design" 标签
- **场景**：light-theme audit 报 Badge Neutral/Line border `#dbdbdb` on white canvas (ratio 1.38) low contrast
- **plan owner 错误措辞**："by-design subtle outlined" —— 替 figma 编 design 解释
- **用户纠错**："canonical 永远只镜射 figma 真源，不在代码端优化视觉"
- **机制修复**（行为约束 #16）：plan owner **不**下"by-design / 设计意图"判断；只报告 figma binding + 实际渲染值，让 user 决定 figma 是否需修

### 失误 2：未先验证 figma 真源 vs canonical 一致就说"视觉与 figma 不一致"
- **场景**：plan owner 错误暗示 light theme 视觉与 figma 真源不一致
- **用户拷问**："如果已经严格按照 Figma 真源，为什么浅色主题下的视觉与 Figma 真源 不一致？"
- **plan owner 实证**：grep `figma-data/normalized/variables.json` → `Color Type/Line/Deep Divider` 的 `Light: "#dbdbdb"` 与 canonical `--line-deep` light value 完全一致 → **canonical 严格镜射 figma**，"不一致"是错觉
- **机制修复**（行为约束 #17）：plan owner 报"视觉差异"前必先 grep figma 真源 token value（dark+light 两 mode）vs canonical token 定义 → 一致则 figma 自身就这个值，不一致才是 canonical 漂

### 失误 3：把 "不入 commit" 误执行为 "删除"
- **场景 A**：plan owner 写 `.light-theme-audit.mjs` (playwright + WCAG contrast) 跑 18 page audit，驱动 12 token drift fix + Badge fix 决策——但 propose commit 时把它列为"留待定项"
- **用户判断 A**："如果是跟 F20 相关的，那么先不提交，等 F20 处理完成后再一起提交，版本会更干净一些"
- **plan owner 误操作**：把"不提交"误解为"删除" → 跑 `rm .light-theme-audit.mjs` + `pnpm remove playwright` → 未授权 destructive op
- **用户纠错 B**："我只是说暂时不提交，没说要把不提交的东西删除，你确认 light-theme-audit.mjs 这个文件不是误删吗？"
- **plan owner 恢复**：从 `/tmp/light-theme-audit.mjs` 备份 cp 回 + 重 `pnpm add -D playwright`
- **机制修复**（行为约束 #18 已加强）：
  - 阶段收口期 plan owner 临时探索 script **保留在 repo**（untracked 状态），仅在 commit `git add` 时**选择性排除**——而非 `rm` 物理删除
  - 同样：未来阶段相关的 dep（如 playwright devDep）**保留在 package.json**（M 状态），commit 时用 selective `git add` 控制 commit scope
  - 不要混淆"不入本次 commit" vs "从工作区删除"——前者是 commit scope 控制，后者是文件生命周期管理。两者分立
  - "不入 commit" 的执行只能用 `git add` 选择性 stage，**不允许**用 `rm` / `pnpm remove` 等 destructive 工具达到同样效果

### 失误 4：F20/F21 计划只放在对话里，新 session 找不到
- **场景**：plan owner propose 把 F20/F21 设计放在对话里"准备让它在 2 个新 Session 中开启"，但没在 repo 留锚点
- **用户实证**：新 session 跑 grep `F20|f20` 搜遍 docs/ AGENTS.md backlog.md _prompts/ memory 全无命中→ 完全找不到任务上下文
- **机制修复**（行为约束 #19）：跨 session 任务必须在 repo 留锚点（最低限度：`docs/internal/backlog.md` 加 entry）。对话里的计划新 session 看不到——repo 是 single source of truth

---

## 工作区状态（commit pickup）

### git
- HEAD：commit fae0c04（Phase A4.2 ProgressPage sample + CANONICAL-004 fix）
- 本会话累积改动（待本 commit 落定）：
  - **24 Vue 文件**：19 base components + 4 canonical bridge + 1 App.vue + 1 TopBarPage.vue
  - **`src/tokens/variables.css`**：12 处 token 值对齐 figma 真源
  - **`src/canonical/Badge.vue`**：3 轮 figma roundtrip（type / palette / content / Filled bg）
  - **`src/components/Badge/Badge.figma.ts`**：Code Connect mapping Black→Neutral
  - **`playground/docs/pages/BadgePage.vue`**：Color type doc + defaultValue
  - **`playground/docs/pages/FormItemPage.vue`**：Select → SelectBoxFilled + alias
  - **`playground/docs/pages/IconPage.vue`**：alias 统一
  - **`figma-sync/audit-docs-site-readiness.mjs`**：1-line regex fix
  - **`docs/internal/backlog.md`**：INFRA-F20 + INFRA-F21 entries
  - **`figma-data/raw/components/*neutral_*` 4 新文件 + `*black_*` 8 旧文件删**（4 raw + 4 normalized）
  - **`figma-data/normalized/{ai-manifest.spike,canonical-component-api,component-token-fidelity.audit}.json`**：3 obsolete 删
  - **`figma-data/normalized/*` 多个**：sync:normalize / generate:* 重生成

### 未 commit dirty（不在本次 scope）
- 60 个 unpublished cleanup 候选（53 个"Research on Color"研究稿 + 4 个非 published 图标 + 3 个"UX Inventory - Micro Level"）—— 与 Phase X.4.2 / Badge 无关，留独立 cleanup ticket
- audit:published-vs-code 新增 needs-review 条目（per AGENTS.md 唤醒词约束，"禁止自动 approved"），需 user 单独审

---

## Phase X 进度概览（commit 后）

```
✅ X.1 MCP backfill (19 components figma cache)
✅ X.2 audit upgrade (8/10 dimensions)
✅ X.3 user 决策 D1-D5 default 落地
✅ X.4 prompt 写好 (parallel 4 agents drafted 19 specs + mass refactor prompt)
✅ X.4.2 Codex executing mass refactor → 23 PASS / 1 PARTIAL → commit
✅ X.5 token drift 12 处修
✅ X.6 Badge 3 轮 figma roundtrip 落地
✅ X.7 audit:docs-site regex fix + alias 统一
🟡 INFRA-F20: snapshot framework setup（新 session 启动）
🟡 INFRA-F21: pre-commit hook（依赖 F20 + audit upgrade）
🟢 v0.1 上线（待 F20 baseline + 60 unpublished cleanup ticket）
```

---

## 必记入册的 plan owner 行为约束（新增 4 条，编号续 2026-05-07 复盘）

16. **Plan owner 不下"by-design"/ 设计意图判断**——视觉低对比、subtle outlined、低强度等措辞绕过 figma 端审视；只报告 figma binding + 实际渲染值，让用户决定 figma 是否需修
    - **Why**：行为约束 #1 硬规则衍生——canonical 永远只镜射 figma，"by-design" 是 plan owner 替 figma 编理由的反模式
    - **How to apply**：light-theme audit 看到低 contrast 时，**只**回报"canonical 引用 X token，token 值 Y，figma 真源同值"——不下 design 评价
    - **实证 case**：2026-05-08 Badge Neutral/Line border #dbdbdb on white canvas，plan owner 错说 "by-design subtle outlined"被用户纠错

17. **Plan owner 报视觉差异前必先 grep figma 真源 token value vs canonical token 定义对照**
    - **Why**：常误判"canonical 漂了"实际是 figma 自己就那个值
    - **How to apply**：grep `figma-data/normalized/variables.json` 找 Dark/Light mode 值 → 对比 `src/tokens/variables.css` 同 token 同 mode → 一致 = canonical 严格镜射，"不一致视觉"是 figma 端就那个 design choice
    - **实证 case**：2026-05-08 plan owner 暗示 Badge light theme "与 figma 不一致"，user 拷问 → grep 实证两边 #dbdbdb 完全一致 → plan owner 撤回错误判断

18. **阶段收口期 transient script 不入主 commit**——若该 script 属下一阶段功能（如 F20 snapshot framework）的探索，应在 backlog 关联段做"历史伏笔"记录而非 commit
    - **Why**：commit scope 不应混入未正式化的探索性代码，分阶段 commit 干净
    - **How to apply**：阶段收口列 commit candidates 时，凡"未来阶段会 formalize"的 script 一律删除（数据/findings 落入 retrospection / backlog 文档即可）
    - **实证 case**：2026-05-08 plan owner 写 `.light-theme-audit.mjs` 驱动 Badge fix，commit prep 想留作"待定项" → user 判 "F20 一起提交版本更干净" → cleanup

19. **跨 session 任务必须在 repo 留锚点**（最低 `docs/internal/backlog.md` entry），对话里的计划新 session 看不到
    - **Why**：repo 是真源，对话是流；新 session onboarding 读 AGENTS.md → backlog → 必须能找到任务 scope
    - **How to apply**：propose 下一阶段任务（F20/F21 等）时，commit 前必加 backlog `INFRA-*` entry 含 scope + 触发 + 决策点 + 阻塞关系；prompt 草稿可延后写
    - **实证 case**：2026-05-08 plan owner 把 F20/F21 计划只放在对话里 → user 新 session "开 F20" → 全 grep 无命中 → user 拷问

---

## 元说明

- 本复盘是 plan owner 主动写（触发器 D 命中：Phase X.4.2 阶段收口 + 4 条新行为约束 + Badge 3 轮 figma roundtrip 完整闭环）
- 新 session 启动时**必读** + 沿用 2026-05-07 复盘的 #1-#15 行为约束 + 本复盘 #16-#19
- 后续 INFRA-F20 / INFRA-F21 启动新 session 时分别写独立 prompt 入 `docs/internal/_prompts/`
