# Codex Prompt: T1a Fix v2 — Round 1 (Plan Only)

> 这是一个**只产实现计划，不写代码**的任务。30 分钟工作量。
>
> 目标：让 audit 脚本理解 CSS 间接变量链 + Vue computed palette，机械区分"间接变量假阳性 / 命名差 / 真错位"三类 token-mismatch。
>
> **本轮不修脚本、不安装依赖、不写代码、不 commit。** 只产出一份计划 `.md`。

---

## 必读前置

1. **`AGENTS.md`** — 项目级 AI 协作入口
2. **`docs/meta-rules.md`** — **元规则真源**（必读，含反模式清单 + Audit 子规则）。本任务所有设计必须符合反模式清单
3. **`src/design-system/translation/prop-aliases.md`** + **`divergences.md`** — 现有翻译层真源（plan 阶段需扩展）
4. **`docs/internal/_prompts/t1a-audit-component-token-fidelity.prompt.md`** — T1a 原 prompt
5. **`docs/internal/_prompts/t1a-fix-patch.prompt.md`** — fix patch v1 prompt
6. **`figma-sync/audit-component-token-fidelity.mjs`** — 当前脚本（829 行，含 evidenceLevel）
7. **`docs/internal/component-token-fidelity-report.md`** — v1 报告（1558 行）
8. **`figma-data/normalized/component-token-fidelity.audit.json`** — v1 机读 JSON
9. **`src/components/Button/Button.vue`** — 间接变量模式的样板（line 365-460）
10. **`src/canonical/SelectBoxLine.vue`** + **`SelectBoxFilled.vue`** — prop-axis 模式的样板（feature prop 实现 figma feature axis）
11. **`playground/docs/pages/DateTimePage.vue`** — 拓扑映射的样板（figma `Select.feature=date` 在 code 端用 SelectBox 组件渲染 docs 页）

---

## 上下文：当前 audit 的 3 类结构性盲区

主 session 审 v1 报告时发现 audit 算法在 3 个层面存在结构性盲区。每类盲区的根源和示例：

### 盲区 1：Vue computed palette + CSS 间接变量

Button 段 15977 条 `⚠️ token-mismatch | direct` 大多数是假阳性。code 用的设计是：

```js
// Button.vue:365
const buttonVars = computed(() => ({
  '--btn-bg': palette.value.bg,  // 按 props 算出 --brand / --brand-hover / --red 等
}))
```

```css
.btn { --btn-bg: transparent; background: var(--btn-bg); }
```

audit 只比字符串字面量（`var(--btn-bg)` ≠ figma `--brand-hover`），不追间接变量链 → 全判 token-mismatch。

### 盲区 2：axis 用 prop 实现而非 CSS class

```ts
// src/canonical/SelectBoxLine.vue:9
type Feature = 'default' | 'time' | 'date'
// :feature="feature" 透传给子组件
```

figma `Select.feature=[date|default|time]` axis 在 code 端用 **prop 实现**（不是 CSS class modifier）。audit 当前只查 `*--feature-date` selector → 全判 axis-branch-missing。

### 盲区 3：figma↔code 拓扑错位

figma `Select.feature=date` variant → code 端的"DateTime"实际由 `SelectBoxLine[feature='date']` + `SelectBoxFilled[feature='date']` + `playground/docs/pages/DateTimePage.vue` 共同呈现，**不在 Select.vue 内部**。

audit 假设 figma 一个组件 ↔ code 一个组件，认不出这种拓扑映射。

预期还有其它组件存在类似情况：Steps/StepItem、Tabs/TabList/TabItem、Breadcrumb/BreadcrumbItem、DropDownListSelect 等——plan 阶段需扫全库识别。

---

## 设计原则（必须遵守，违反 = plan 重写）

按 `docs/meta-rules.md` 反模式清单：

- **#1 不在脚本里硬编码"项目级规则"**——所有拓扑映射 / axis 别名 / 实现层级映射必须登记到 `.md` 真源，audit 读真源，不 hardcode 组件名
- **#2 不打补丁**——不能为 DateTime / Button / Steps 各加一个 if-else 分支；必须抽象成统一机制，让所有这类组件成为机制的实例
- **#3 产出契约思维**——v2 报告必须保留并扩展 `evidenceLevel` schema
- **#5 扩展只改一处**——后续新增类似拓扑/prop-axis 组件，只改 `.md` 真源，不改脚本

---

## 你的任务（唯一产出）

写一份计划文档：

**`docs/internal/_plans/t1a-fix-v2-plan.md`**

文档必须覆盖以下 10 个章节（章节 0 新加），每节都要落到**具体可执行**而非抽象描述。

### 章节 0：真源机制设计（先于一切，必须先做）

按反模式清单 #1 和 #2，本 v2 升级的核心**不是改 audit 算法**，而是**建立真源机制 + audit 读真源**。

**0.1 设计 axis-implementation-map 真源 schema**

新建一个真源 `.md` 文件（推荐路径：`src/design-system/translation/axis-implementation-map.md`，或扩展 `divergences.md`——你判断），登记格式应能描述：

```
对每条 figma (component, axis, value) 三元组，登记 code 端实现方式：
  - 实现层级：CSS class modifier / Vue prop / computed palette / docs page composition / cross-component split
  - 实现位置：哪个 .vue 文件、哪行、哪个 prop / class / palette key
  - 验证锚点：怎么机械验证这条登记仍然有效
```

给出至少 5 个实例登记草稿（包含 DateTime、Button、Steps/StepItem、Tabs、Breadcrumb 等），让用户审 schema。

**0.2 设计 audit 读真源的算法**

audit v2 不再 hardcode 任何组件名 / axis 名。算法描述：

```
对每条 figma axis-value：
  1. 查 axis-implementation-map.md，找到登记的实现层级
  2. 按登记的层级在 code 端验证（CSS class / prop / palette / 拓扑组合）
  3. 验证通过 → ✅ token-match-via-<level>
  4. 验证失败 → ⚠️ implementation-mismatch
  5. 真源没登记 → ⚠️ unmapped-axis-value（首次发现，提示登记）
```

**0.3 plan 阶段产出物**

plan 文档里必须包含：
- a) `axis-implementation-map.md` 的 schema 定义（具体字段 + 示例 5 条）
- b) Round 2 实现时 audit 读真源的伪代码
- c) 后续扩展场景：新组件出现拓扑/prop-axis 错位时，开发者只改这份真源 .md，audit 自动支持——证明这个机制能扩展

**违反检查**：如果你的 0.1 设计要求 audit 脚本里 `if (componentName === 'DateTime')` 这种分支 → 重写章节 0（违反反模式 #2）。

---

### 章节 1：问题诊断（你自己复述）

用你自己的话说清楚 v1 audit 的 3 个盲区，每个给 1-2 个 v1 报告里的具体行号引用。这一节是 sanity check——如果你诊断写错，后面整份 plan 都会跑偏。

### 章节 2：受影响组件清单（grep 全库）

跑一遍：

```bash
grep -rln 'computed.*=>.*({' src/components/ | head -50
grep -rln "'--[a-z]*-bg'\\|'--[a-z]*-color'" src/components/
```

列出**所有**使用 "computed palette + 间接变量" 模式的组件。预期至少包含 Button / Select / Input / Notification / Tooltip 这几个。每个组件给：

| 组件 | palette 文件路径 | computed 函数行号 | 涉及的间接变量名（如 `--btn-bg`/`--btn-color`） |

这一节决定 v2 升级的影响范围。

### 章节 3：新 verdict 类型 + evidenceLevel 映射

设计 5 个新 verdict（覆盖 A/B/C 三类 + 工具能力边界）：

```
✅ token-match-via-indirection   — code 间接变量解析后等于 figma cssVar (A 类正解)
⚠️  hex-equal-different-token    — 两端 cssVar 不等但解析为同 hex（B 类，改名建议）
⚠️  true-token-mismatch          — code 直写不同 var() 且 hex 不等（C 类，必修）
⚠️  true-visual-drift            — 双端都是 hex literal 且不等（C 类）
❌ palette-resolution-failed     — Vue AST 抽 palette 失败 / axis 不匹配（工具能力边界）
```

明确每个新 verdict 的：
- 触发条件（伪代码）
- evidenceLevel（direct / heuristic / semantic-inference）
- evidenceSource 字段值

并给出**旧 verdict 到新 verdict 的迁移表**——如 v1 的 `⚠️ token-mismatch | direct` 进 v2 后大多数应被升级到哪一类。

### 章节 4：Vue AST 解析方案

具体说明：

- 用什么库（推荐 `@vue/compiler-sfc` 的 `parse` + `compileScript`，**项目已是 Vue 3，依赖应已经存在或非常轻**——你需要先 `pnpm list @vue/compiler-sfc` 确认）
- 解析步骤伪代码（找到 `<script setup>` → AST walk 找 `computed(...)` → 抽 ObjectExpression → 提取 key-value 表达式）
- 怎么处理非 `computed` palette 变体（`ref`、`reactive`、直接 const object）——给降级策略
- 输入输出契约：`extractPalette(vueFilePath) → { '--btn-bg': <表达式 AST>, '--btn-color': ..., }`

### 章节 5：palette 求值算法

给定 palette 表 + axis tuple，输出该 axis 下 code 端 token 终值。

- 算法伪代码：palette 里的 value 经常是 `palette.value.bg`，需要再追到 `palette` 这个 ref 的定义、看里面三元/switch 怎么按 props 分支
- 怎么穷举或精确匹配 axis tuple → 推荐**精确匹配**（按当前 variant 的 axis tuple 走分支），不穷举
- 工具能力边界：palette 内含动态 JS 表达式（如调用函数、运行时计算）→ 标 `❌ palette-resolution-failed`，不强行 eval
- 输入输出契约：`resolvePaletteVar('--btn-bg', { color: 'green', status: 'hover', ... }, paletteAst) → '--brand-hover' 或 null`

### 章节 6：双端 hex 比对算法

```
figma cssVar="--brand-hover" → variables.json → "#41c760"
code "--btn-bg" → resolvePaletteVar → "--brand-hover" → variables.css → "#41c760"
→ hex 相等 → ✅ token-match-via-indirection
```

明确 hex 解析路径（用现有 `figma-data/normalized/variables.json` 还是另起 variables.css 解析）+ fallback 顺序。

### 章节 7：边界 case 列表

至少枚举 8 个，每个给应对策略：

1. palette 是 `ref(...)` 而不是 `computed`
2. palette 是直接 const object
3. palette 引用其它 module 的常量
4. palette 用了三元嵌套（`color === 'red' ? (status === 'hover' ? '--red-hover' : '--red') : ...`）
5. palette 用了 switch / Map 查表
6. palette 调用了函数 `getColor(props)`
7. axis tuple 不在 palette 分支覆盖里（如 figma 有 `color=cyan` 但 palette 没处理）
8. 同一个间接变量在不同 selector 下有不同 fallback（如 `.btn` 跟 `.btn--ghost` 都设 `--btn-bg`）

### 章节 8：自验 sanity check（带预期数字）

跑完 v2 后报告应该满足的条件，每条给具体数字或 grep 命令：

- Button 段 `✅ token-match-via-indirection` 应 > N（你估算）
- Button 段 `⚠️ true-token-mismatch | direct` 应 < M（你估算）
- 总 finding 数 vs v1 (36089) 的预期变化（应不变，只是 verdict 重新分布）
- direct 类 vs heuristic 类的新分布（你估算）
- 推荐处置段 Button 行的描述应从"复核组件 CSS token"变成更精确的话

如果你估不出数字，写"主 session 审 plan 时给参考"——不要乱填。

### 章节 9：工程量分解 + 风险点

把实现拆成可独立验证的 sub-tasks，每个估时：

| sub-task | 估时 | 风险 |
|---|---|---|
| 安装/确认 @vue/compiler-sfc 依赖 | 5min | 低 |
| 写 extractPalette 函数（章节 4）+ 单测 | 1h | 中 (AST 边界) |
| ... | ... | ... |

总估时应在 4-6h 区间。每个 sub-task 标"low / medium / high" 风险。**high 风险的 sub-task 必须给降级方案**（如果做不到怎么办、能不能用 fallback verdict 标 `❌ palette-resolution-failed`）。

---

## 不要做的事

- ❌ 不写任何 `.mjs` 代码
- ❌ 不改 `figma-sync/audit-component-token-fidelity.mjs`
- ❌ 不安装依赖（`pnpm install` 留到 Round 2）
- ❌ 不跑 audit 脚本
- ❌ 不改 src/、不改 figma-data/、不改任何报告
- ❌ 不 commit / push

允许的：
- ✅ 读项目内任何文件
- ✅ 跑 grep / find / `pnpm list`（只查不改）
- ✅ 新增 1 个文件：`docs/internal/_plans/t1a-fix-v2-plan.md`

---

## 自验

```bash
# 唯一新增文件
ls -la docs/internal/_plans/t1a-fix-v2-plan.md
wc -l docs/internal/_plans/t1a-fix-v2-plan.md   # 期望 ~200-400 行

# 工作区只增 1 个文件
git status --short | grep -v '^??' | wc -l   # 应为 0（无 modified）
git status --short | grep '??' | wc -l        # 应增加 1（新 plan）

# 没 commit
git log --oneline -1   # HEAD 应仍是 c9032ad
```

---

## 完成后 STOP

输出给主 session：

```
plan 路径：docs/internal/_plans/t1a-fix-v2-plan.md
plan 行数：N
受影响组件数（章节 2 grep 结果）：N
总估时（章节 9）：N 小时
high 风险 sub-task 数：N

工作区状态：1 untracked (plan)，0 modified，0 commits
```

主 session 会审 plan，找漏的 spec / 不清楚的算法 / 不合理的估时，让你补。**plan 通过后才会有 Round 2 implementation prompt。**

**STOP。不要写代码。不要进 Round 2。**
