# Prompt — INFRA-F25: SVG / Icon / token / contrast design-conformance audit suite

> **角色**：executor（被 master-overnight 调用 / 或单独跑）
> **范围**：3 个 phase 顺序执行 — A) 写 4 audit scripts + 跑 baseline / B) 改 export-icons.mjs 写 currentColor / C) batch tokenize exact-match
> **决策**：Plan owner 已在 §0 写定
> ⚠️ **不要 commit 不要 push**——交给 master orchestrator 的 Plan owner role 做
> ⚠️ 完成各 phase **STOP**，按 §4 报告格式写 `docs/internal/_reports/f25-{phase}-report-{date}.md`

---

## §0 — Plan owner 已定决策

### F25 整体目标
- 把 figma 真源 ↔ 代码视觉一致性的回归保护从"靠肉眼"升到"靠 audit script"
- mark/star fill `#DBDBDB` 硬编码 / Progress 容器撞色 / 散落 hardcoded spacing—— 这类历史 bug **autonomous 检出**

### Phase A — 4 audit scripts（read-only）

#### A1: `figma-sync/audit-icon-fill-currentcolor.mjs`
扫 `src/icons/catalog/generated/*.ts`：
- 解析每个 inline SVG 字符串
- 命中 `<path[^>]*fill="#[0-9a-fA-F]{3,6}"[^>]*/>` （path 上显式 hex fill）即 finding
- **白名单豁免**：multi-color icon（path 数 ≥ 2 且 fill hex 不同）→ warn 而非 error，列入 `figma-sync/audit-allowlist/icon-multicolor.json`（如不存在则创建空数组）
- 输出：finding 数 / 命中 file 清单 / suggest "应改 fill=\"currentColor\""

#### A2: `figma-sync/audit-component-no-inline-svg.mjs`
扫 `src/components/**/*.vue` + `src/canonical/**/*.vue` 的 `<template>` 段：
- 命中 `<svg>` 标签即 finding（Icon 组件用 `<Icon :name="..." />` 引用，不应在组件 template 内直接画 svg）
- 例外：Icon 组件本身（`src/components/Icon/Icon.vue`）的 `v-html` 渲染不算
- 输出：finding 数 / 命中 file:行号 / suggest "应改 `<Icon :name="..." />` 引用 catalog"

#### A3: `figma-sync/audit-no-hardcoded-design-tokens.mjs`
扫 `src/components/**/*.vue` + `src/canonical/**/*.vue` + `playground/docs/pages/**/*.vue` 的 `<style>` 段：
- 三类 finding：
  - **color**: `#[0-9a-fA-F]{3,6}` hex 字面量（属性 `background` / `color` / `border-color` / `fill` 等内）
  - **spacing**: `(padding|margin|gap)` 内的 `Npx` 字面量
  - **radius**: `border-radius` 内的 `Npx` 字面量
- 每条 finding 含：file / 行号 / 属性名 / 值 / suggest（如有 exact-match token）
- exact-match 查询：从 `src/tokens/variables.css` 解析 `--sp-*` / `--r-*` / `--bg-layer*` / `--color-grey-*` / `--text-*` / `--icon-*` / `--orange|red|brand|blue` 等 token 表，建 `value → token-name` 字典；finding 值若在字典里 → suggest 替换 token；不在字典里 → suggest "no exact match, may need new token or accept custom"
- 例外白名单：`min-height: 32px` 等控件尺寸字面量（已在 [`src/tokens/variables.css`](../../../src/tokens/variables.css) 内 domain-specific 段表达）→ `figma-sync/audit-allowlist/dimension-tokens.json`

#### A4: `figma-sync/audit-docs-page-bg-contrast.mjs`
扫 18 个 `playground/docs/pages/*Page.vue`：
- 解析每个 page 内 `<article class="docs-demo-card ...">` 嵌套链
- 查最外层 `.docs-demo-card` 默认 bg 实际 token 值（从 [`playground/docs/docs.css:445-453`](../../../playground/docs/docs.css#L445)，是 `var(--bg-layer3)` = #262626 dark）
- 对 page 内每个 component instance（`<Progress />` / `<Switch />` / `<Slider />` 等），查其 critical visual element token（如 Progress track-bg 用 `var(--progress-track-bg-dark)` = #262626）
- 比对：critical token hex == card bg hex → **error**（视觉撞色 100% invisible）
- ΔE 色差 < threshold（建议 ΔE < 5） → warn（low contrast）
- 输出：finding file:行号 + 撞色 token pair + suggest "外层加 `var(--bg-layer1)` 内 cell wrapper 形成层级（参考 FigmaMembersGrid `__cell` pattern）"
- 实证 baseline：ProgressPage Family Matrix `family-matrix__cell` 已在 commit 596acb05 修了；audit 应该不再 finding 它，但应找到其它 page 的潜在撞色

### Phase A 收口
- `package.json` 加 4 个 `audit:*` script 行（与现有 `audit:figma-conformance` 等同款式）
- 每个 audit 跑一次 → baseline 报告 `docs/internal/_reports/f25-audit-{name}-baseline-2026-05-09.md`
- 各 audit 跑通（exit 0），即使 finding 数 > 0 也算成功（baseline 就是用来记录现状的）

### Phase B — export-icons.mjs `currentColor` 治本

改 [`figma-sync/export-icons.mjs`](../../../figma-sync/export-icons.mjs)：
- 拉到 figma SVG 后，在写入 catalog 前做 path 分析
- **mono-color**（所有 `<path>` 元素的 fill 同色 / 或仅 1 个 path）→ 全部 fill 替换为 `currentColor`
- **multi-color**（path 间 fill 不同色）→ 保留 hex（为多色 icon 设计意图）
- 重生 `src/icons/catalog/generated/*.ts`（跑 `pnpm sync:icons && pnpm generate:icons-catalog`）
- 验证：phase A 的 `audit:icon-fill-currentcolor` 重跑，findings 数应大幅下降（mono-color icon 占多数）

### Phase C — batch tokenize exact-match（auto-fix）

写 `figma-sync/auto-tokenize-exact-match.mjs`：
- 输入：phase A 的 `audit:no-hardcoded-design-tokens` 结果（或重跑取最新）
- 对每条带 "exact-match suggest" 的 finding 自动替换：file 行号位置的 `#hex` / `Npx` → `var(--token-name)`
- **绝不**替换 "no exact match" 的 finding（留 hex/px 不动，加 `/* TODO F25-followup */` 注释）
- 跑后立 vue-tsc 验证（exact token 替换不应触发 type 错；如错说明 token 被错误识别 → STOP，rollback）
- 跑后再跑 `audit:no-hardcoded-design-tokens` → finding 数应下降

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

**Phase A**:
- 新建 `figma-sync/audit-icon-fill-currentcolor.mjs`
- 新建 `figma-sync/audit-component-no-inline-svg.mjs`
- 新建 `figma-sync/audit-no-hardcoded-design-tokens.mjs`
- 新建 `figma-sync/audit-docs-page-bg-contrast.mjs`
- 新建 `figma-sync/audit-allowlist/icon-multicolor.json`（空数组初始化）
- 新建 `figma-sync/audit-allowlist/dimension-tokens.json`（空数组初始化）
- 改 `package.json`（加 4 个 npm script 行）
- 新建 4 个 baseline 报告 `docs/internal/_reports/f25-audit-*.md`

**Phase B**:
- 改 `figma-sync/export-icons.mjs`
- 重生 `src/icons/catalog/generated/*.ts`（generate-icons-catalog 输出）
- 报告 `docs/internal/_reports/f25-phase-b-icon-fill-fix-report.md`

**Phase C**:
- 新建 `figma-sync/auto-tokenize-exact-match.mjs`
- 改 `playground/docs/pages/*Page.vue`（受 audit 命中的）
- 报告 `docs/internal/_reports/f25-phase-c-tokenize-report.md`

**绝不动**：
- `AGENTS.md` / `docs/meta-rules.md` / `docs/internal/backlog.md` / `docs/internal/mockup-conventions.md`
- `src/tokens/variables.css`（手工 token 真源）
- `figma-data/raw/`
- `playground/docs/pages/FormItemPage.vue`（F23 范围）
- `src/components/**/*.vue` 和 `src/canonical/**/*.vue`（phase C 仅动 docs page；其它属于"产品组件"层 token 化要更谨慎，不在 phase C 范围）

---

## §1 — 必读输入

按顺序：
1. [`AGENTS.md`](../../../AGENTS.md) — 项目硬规则
2. [`docs/internal/backlog.md`](../backlog.md) — INFRA-F25 entry 上下文
3. [`docs/meta-rules.md`](../../meta-rules.md) — meta-rules 反模式
4. [`src/tokens/variables.css`](../../../src/tokens/variables.css) — token 真源（建 audit 字典源）
5. [`playground/docs/docs.css`](../../../playground/docs/docs.css) — `.docs-demo-card` base styles
6. [`playground/docs/pages/ProgressPage.vue`](../../../playground/docs/pages/ProgressPage.vue) — F19 P1 已修的对照样本（audit 应该不再 finding 它的 family-matrix__cell）
7. [`src/components/Rating/Rating.vue`](../../../src/components/Rating/Rating.vue) — currentColor patch 对照
8. [`src/icons/catalog/generated/mark.ts`](../../../src/icons/catalog/generated/mark.ts) — mark/star + star-on 已修过；其它 mark/* icons 没修过

---

## §2 — 任务清单

### 任务 2.A1: 写 audit-icon-fill-currentcolor.mjs

主流程：
```js
import { readFileSync, readdirSync } from 'fs'
const catalogDir = 'src/icons/catalog/generated'
const allowlist = JSON.parse(readFileSync('figma-sync/audit-allowlist/icon-multicolor.json', 'utf8'))
const findings = []
for (const file of readdirSync(catalogDir).filter(f => f.endsWith('.ts'))) {
  const content = readFileSync(`${catalogDir}/${file}`, 'utf8')
  // parse SVG entries: regex match `"icon-name": \`<svg>...</svg>\``
  // for each entry, extract path fills via /<path[^>]*fill="(#[0-9a-fA-F]{3,6})"/g
  // determine mono vs multi by unique fill count
  // if mono and not in allowlist → finding (severity: error)
  // if multi → finding (severity: warn)
}
// output JSON + markdown report
```

报告格式 `docs/internal/_reports/f25-audit-icon-fill-currentcolor-baseline-2026-05-09.md`：
```markdown
# F25 audit:icon-fill-currentcolor baseline 2026-05-09

## 总览
- mono-color hardcoded fills: N (error)
- multi-color hardcoded fills: M (warn)
- 已豁免 (allowlist): K

## findings
[列每个 file + icon-name + fill hex + suggest]
```

### 任务 2.A2-A4: 同款式写另外 3 个 audit

按 §0 phase A 描述实现。每个 audit 输出 markdown baseline + JSON。

### 任务 2.A 收口: package.json + 跑 baseline

`package.json` scripts 段加：
```json
"audit:icon-fill-currentcolor": "node figma-sync/audit-icon-fill-currentcolor.mjs",
"audit:component-no-inline-svg": "node figma-sync/audit-component-no-inline-svg.mjs",
"audit:no-hardcoded-design-tokens": "node figma-sync/audit-no-hardcoded-design-tokens.mjs",
"audit:docs-page-bg-contrast": "node figma-sync/audit-docs-page-bg-contrast.mjs"
```

跑 4 个 audit，确认 exit 0 + 报告文件存在。

### 任务 2.B: export-icons.mjs 改 currentColor

按 §0 phase B。改 export-icons.mjs 增加 path fill 分析逻辑。重生 catalog. 重跑 audit:icon-fill-currentcolor 验证 finding 大降。

### 任务 2.C: auto-tokenize-exact-match.mjs

按 §0 phase C。写 batch fix script。跑 vue-tsc 验证。重跑 audit 验证 finding 大降。

---

## §3 — 验收清单（每 phase 各自验收，不混）

### Phase A
- [ ] 4 个 audit script 文件存在 + 各跑通 (exit 0)
- [ ] 4 个 baseline 报告文件存在
- [ ] `package.json` 加了 4 个 npm script
- [ ] `figma-sync/audit-allowlist/` 下 2 个 json 存在
- [ ] vue-tsc 0 errors（应不变）
- [ ] **不动** src/ playground/docs/ 文件

### Phase B
- [ ] export-icons.mjs 改后 sync:icons + generate:icons-catalog 跑通
- [ ] catalog/generated/*.ts 重生，mark.ts 含 `currentColor`（mono-color icons）
- [ ] audit:icon-fill-currentcolor 重跑：finding 数下降 ≥ 50%
- [ ] vue-tsc 0 errors

### Phase C
- [ ] auto-tokenize-exact-match.mjs 文件存在
- [ ] 跑后 vue-tsc 0 errors
- [ ] audit:no-hardcoded-design-tokens 重跑：findings 下降 ≥ 30%
- [ ] 修改文件 ≤ 200（hard cap）
- [ ] 文件改的全是 docs page，不动 src/

---

## §4 — 完成报告（每 phase 各写一份）

### `docs/internal/_reports/f25-phase-a-baseline-{date}.md`
```
# F25 Phase A — Audit suite baseline

## 改动文件
[git status --short]

## 4 audit baseline finding 总览
- icon-fill-currentcolor: N findings (mono M / multi K)
- component-no-inline-svg: P findings
- no-hardcoded-design-tokens: Q findings (color X / spacing Y / radius Z)
- docs-page-bg-contrast: R findings

## 验收 self-check
[逐条 §3 phase A 勾选]

## 未解决项
- 无 / 或具体问题

STOP — Plan owner 校验后 commit + push。
```

类似格式 phase B / phase C 各一份。

---

## §5 — 严守约束总览

- ⚠️ **不 commit 不 push**——Plan owner role 做
- ⚠️ §0 改造文件清单不可超出
- ⚠️ phase 间独立交付：phase A done → 写报告 → STOP；phase B / C 同；不要积攒一次性 commit
- ⚠️ phase C auto-tokenize **只动 exact-match**，no-match 留 hex + TODO 注释；绝不"近似匹配"替换
- ⚠️ phase C 改完 vue-tsc fail → 立 rollback（git checkout 受影响文件）+ 报告
- ⚠️ 各 phase §4 报告**必写**——这是 Plan owner role gate 验收的输入
