# Prompt — INFRA-F22: Generator theme axis case-insensitive fix

> **角色**：executor
> **范围**：修复 `figma-sync/generate-docs-figma-members.mjs` 对 figma axis name "Theme" / value "Dark" / "Light"（首字母大写）派生失败的 bug。让 generator 大小写不敏感地识别 theme axis，让 FormItem 这类大写命名的 figma component variants 顶层正确得到 `theme: 'dark' | 'light'` field。
>
> ⚠️ **不要 commit / 不要 git add**——dirty 累积到 plan owner 验证通过后 commit。
> ⚠️ 完成后 **STOP**，按 §4 完成报告格式回报。
> ⚠️ **不扩范围**：仅改 [`figma-sync/generate-docs-figma-members.mjs`](../../../figma-sync/generate-docs-figma-members.mjs) + 重跑 generator 输出 [`figma-data/normalized/docs-figma-members/`](../../../figma-data/normalized/docs-figma-members/)。**不改 figma 真源 / 不改 docs page / 不改 audit script**。

---

## §0 — Plan owner 已定裁定

### 现状根因（plan owner 已定位）

generator 大小写敏感，FormItem figma 真源派生失败：

| 层 | 行号 | 现状代码 | 问题 |
|---|---|---|---|
| axis 识别 | [`generate-docs-figma-members.mjs:278`](../../../figma-sync/generate-docs-figma-members.mjs#L278) | `?? (figmaAxis === 'theme' ? 'theme' : undefined)` | "Theme" 匹配失败 |
| value 识别 | [`generate-docs-figma-members.mjs:298`](../../../figma-sync/generate-docs-figma-members.mjs#L298) | `axisValues.every((value) => value === 'dark' \|\| value === 'light')` | "Dark" / "Light" 匹配失败 |

下游：

- FormItem figma 真源 axis name = `Theme`（首字母大写），values = `Dark` / `Light`
- generator fallback 不识别 → variant 顶层无 derived `theme` field
- [`FigmaMembersGrid.vue:22-24`](../../../playground/docs/components/FigmaMembersGrid.vue#L22) 检查 `Object.prototype.hasOwnProperty.call(variant, 'theme')` → false → 走"无 theme axis" fallback 显示全部
- [`audit-page-t2-sample.mjs`](../../../figma-sync/audit-page-t2-sample.mjs) 报"has-theme=true 但 dark=0 light=0" 自相矛盾——`has-theme` 走 axes 列表识别 axis name（识别），`dark/light count` 走顶层 variant.theme field（不识别）

### F22 目标

- generator 大小写不敏感识别 axis name `theme` 和 values `dark` / `light`
- 派生写入 `variant.theme` field 时**统一小写化**，下游 grid filter 不区分大小写也能 match
- 重跑 generator → FormItem normalized data 顶层应有 `theme: 'dark' | 'light'` field 出现
- audit 后 FormItem α verdict 应从 N/A 变 pass + dark/light variant count 应非 0

### 改造文件清单（**不可超出**）

| 文件 | 操作 |
|---|---|
| [`figma-sync/generate-docs-figma-members.mjs`](../../../figma-sync/generate-docs-figma-members.mjs) | 改 line 278 / 298 + 派生写入处 toLowerCase |
| [`figma-data/normalized/docs-figma-members/`](../../../figma-data/normalized/docs-figma-members/) | 重跑 generator 输出（不要手改） |

**不动**：[figma-data 真源](../../../figma-data/raw/) / [docs page](../../../playground/docs/pages/) / [FigmaMembersGrid.vue](../../../playground/docs/components/FigmaMembersGrid.vue) / [audit script](../../../figma-sync/audit-page-t2-sample.mjs) / canonical 组件 / backlog.md / retrospection / package.json。

### §0.1 — generator 改动精确 hunk

```diff
   const derivedAxis = aliases.globalAxisAliases.get(figmaAxis)
     ?? aliases.componentPropAliases.get(canonicalName)?.get(figmaAxis)
-    ?? (figmaAxis === 'theme' ? 'theme' : undefined)
+    ?? (figmaAxis.toLowerCase() === 'theme' ? 'theme' : undefined)
```

```diff
     if (derivedAxis === 'theme') {
       const axisValues = allAxisValues.get(figmaAxis) ?? []
       const valueAliases = aliases.globalValueAliases.get(derivedAxis)
       const hasValueAlias = axisValues.every((value) => valueAliases?.has(value))
-      const hasCanonicalThemeValues = axisValues.every((value) => value === 'dark' || value === 'light')
+      const hasCanonicalThemeValues = axisValues.every(
+        (value) => value.toLowerCase() === 'dark' || value.toLowerCase() === 'light',
+      )
       if (!hasValueAlias && !hasCanonicalThemeValues) {
         continue
       }
       themeAxisByFigmaAxis[figmaAxis] = {
         derivedAxis,
         hasValueAlias,
       }
     }
```

### §0.2 — variant 派生写入 toLowerCase

generator 在 build variants 时把 figma axis value 写入 variant 的派生字段。**写入 theme field 时必须 toLowerCase**——不然 normalized data 里仍是 `theme: 'Dark'`，下游 `variant.theme === 'dark'` filter 失败。

需要找到 generator 里实际写 `variant.theme = ...` 的地方（搜索 `theme:` 或 `themeAxis` 相关赋值），在赋值时 `.toLowerCase()`。**executor 在改 line 278/298 后 grep `derivedAxis === 'theme'` / `themeAxisByFigmaAxis` 找下游写入位置**，确认派生字段是否需要小写化。

### §0.3 — alias 表扩展（建议，不强制）

如果 [`mockup-conventions.md`](../../mockup-conventions.md) 或类似 alias 表机制能加 globalValueAliases 项 `'Dark' → 'dark'` / `'Light' → 'light'`，更长期可维护（设计师未来用 "dArK" 也照样过）。**优先级**：核心 toLowerCase 改完即可；alias 表是 nice-to-have，executor 看代码组织判断是否要加，§4 报告说明。

---

## §1 — 必读输入

按顺序：

1. [`AGENTS.md`](../../../AGENTS.md) — 项目硬规则
2. [`docs/internal/backlog.md`](../backlog.md) — INFRA-F22 entry 上下文
3. [`figma-sync/generate-docs-figma-members.mjs`](../../../figma-sync/generate-docs-figma-members.mjs) — 整个文件读一遍找派生写入位置
4. [`figma-data/normalized/docs-figma-members/formitem.ts`](../../../figma-data/normalized/docs-figma-members/formitem.ts)（或类似）— 看当前派生输出形态（应该缺 theme field）
5. [`figma-data/normalized/docs-figma-members/notification.ts`](../../../figma-data/normalized/docs-figma-members/notification.ts) — 看正常派生形态作对照（应该有 theme field）

---

## §2 — 任务清单

### 任务 2.1 — Read 当前 FormItem normalized 输出

```bash
grep -A2 "theme:" figma-data/normalized/docs-figma-members/formitem.ts | head -20
```

→ 确认当前 variants **没有** theme field（基线证据，§4 report before/after 用）

### 任务 2.2 — Read 正常派生形态对照

```bash
grep -A2 "theme:" figma-data/normalized/docs-figma-members/notification.ts | head -20
```

→ 应该看到 `theme: 'dark'` / `theme: 'light'` field（small case）

### 任务 2.3 — 改 generator line 278

按 §0.1 第一段 hunk。

### 任务 2.4 — 改 generator line 298

按 §0.1 第二段 hunk。

### 任务 2.5 — grep 派生写入位置 + 加 toLowerCase

```bash
grep -n "derivedAxis === 'theme'\|themeAxisByFigmaAxis" figma-sync/generate-docs-figma-members.mjs
```

找到 variant.theme 字段写入的代码段，在 figma value → variant.theme 赋值时 `.toLowerCase()`。

### 任务 2.6 — 重跑 generator

```bash
pnpm exec node figma-sync/generate-docs-figma-members.mjs
# 或 pnpm 已有的 generator script，看 package.json
```

### 任务 2.7 — 验证 FormItem 派生输出

```bash
grep -A2 "theme:" figma-data/normalized/docs-figma-members/formitem.ts | head -20
```

→ 现在应该有 `theme: 'dark'` / `theme: 'light'` field（小写）。

### 任务 2.8 — 跑全 audit

```bash
pnpm exec vue-tsc --noEmit
node figma-sync/audit-page-t2-sample.mjs
pnpm audit:figma-conformance
pnpm audit:docs-site
```

→ 全过；FormItemPage α verdict 应从 N/A 变 **direct + finding 数有变化**（具体是 pass 还是其它由审计逻辑定，executor 报告实际值）。

### 任务 2.9 — 扫其它 page 是否被波及

```bash
git diff --stat figma-data/normalized/docs-figma-members/
```

→ 应该只有 formitem.ts 文件改了；其它 page（小写 theme 已 OK）应保持不变。如果其它 page 也变了，§4 报告里逐一解释（理论上不应该，因为派生现在加了 toLowerCase 容错而非改变小写场景行为）。

### 任务 2.10 — STOP 等 plan owner

不要 commit。

---

## §3 — 验收清单

- [ ] generator line 278 + 298 改完 toLowerCase
- [ ] grep 找到 variant.theme 派生写入位置 + 加 toLowerCase
- [ ] generator 重跑成功
- [ ] FormItem normalized 输出现在含 `theme: 'dark' | 'light'` field
- [ ] vue-tsc 0 错误
- [ ] audit-page-t2-sample 18 page：FormItem α verdict 不再是 N/A（dark/light variant count 应非 0）
- [ ] 其它 page normalized data 未受影响（diff 只动 formitem.ts）
- [ ] **不动**：figma-data/raw / docs page / FigmaMembersGrid / audit script / canonical / backlog.md / retrospection / package.json
- [ ] 未 commit / 未 git add

---

## §4 — 完成报告

```
## INFRA-F22 generator theme axis case-insensitive fix 完成报告

### 改动文件
- figma-sync/generate-docs-figma-members.mjs (改 +X/-Y 行)
- figma-data/normalized/docs-figma-members/formitem.ts (重生)
- [其它 normalized 文件] (理论上不变，如有变化标 ⚠️ 解释)

### §4.X 完整改动清单
[git status --short 全列表]
[如有范围外改动，标 ⚠️ 解释]

### Before/After 派生输出对比
- 任务 2.1 FormItem variants before: 无 theme field
- 任务 2.7 FormItem variants after: theme: 'dark' (N variants) / theme: 'light' (M variants)

### generator hunk
[贴 line 278 / 298 改后 diff]
[贴 variant.theme 派生写入处 diff]

### audit 结果
- vue-tsc: 0 错误
- audit-page-t2-sample FormItem α verdict: <before N/A → after [实际值]>
- audit-page-t2-sample 其它 page α verdict: 无变化
- audit:figma-conformance: pass
- audit:docs-site: 仅历史 in-review warn

### Alias 表扩展（§0.3）
- <已加 globalValueAliases / 未加，理由：...>

### 未解决项 / blocker
- 无则写"无"

STOP — 等 plan owner 复审 → 通过后 plan owner 自己写 retrospection + commit F22。F22 done 后才能开 F23 FormItemPage 重写。
```

---

## §5 — 严守约束

- ⚠️ **不要 commit / 不要 git add**
- ⚠️ §0 文件清单**不可超出**——只改 generate-docs-figma-members.mjs + generator 重跑输出
- ⚠️ **不动 figma-data/raw**（figma 真源不归 generator 改）
- ⚠️ **不动 docs page**（FormItem 重写是 F23 范围）
- ⚠️ **不动 audit script**（audit gate 已是 F19 落定的版本）
- ⚠️ §4 完成报告**必须含 §4.X 完整改动清单段**
