# Tier 1-A Sprint 3 — divergences.md → decisions JSON + md split

> **触发方式**：用户对 executor 说 `请按 docs/internal/_prompts/tier1a-sprint3-divergences-split.prompt.md 执行`
> **角色**：executor
> **依赖**：
> - [`docs/internal/_plans/tier1a-translation-schema-spec.md`](../_plans/tier1a-translation-schema-spec.md) §2.3 + §4 Sprint 3
> - Sprint 1 ship（`40e8c777`）+ Sprint 2 ship（`76e99070`）— `divergences-decisions.json` 与 `axis-implementation-map.json` / `prop-aliases.json` 平级
> **完成后 STOP**，列改动 + 未解决项给 plan owner 复审

---

## 0. 起手 Pre-flight check（mandatory 顺序）

**Pre-flight 判断规则**（注意：只看本 sprint 范围，不看无关 dirty）：

只有当**以下任意一项**为真时才 STOP：

1. 本 sprint 输出路径已有 dirty / untracked（说明上次 fire 残留或别 session 在动同一文件）：
   - `src/design-system/translation/divergences.md` modified
   - `src/design-system/translation/divergences-decisions.json` exists
   - `src/design-system/translation/schemas/divergences-decisions.schema.json` exists

2. 已 ship sprint 的产物被改动（说明回归风险）：
   - `src/design-system/translation/axis-implementation-map.json` modified
   - `src/design-system/translation/schemas/axis-implementation-map.schema.json` modified
   - `src/design-system/translation/prop-aliases.json` modified
   - `src/design-system/translation/prop-aliases.md` modified
   - `src/design-system/translation/schemas/prop-aliases.schema.json` modified

3. 本 sprint 明示不动的目录被改动：
   - `figma-sync/` 任何 audit-*.mjs modified
   - `src/design-system/translation/icon-aliases.ts` modified
   - `src/design-system/translation/token-aliases.ts` modified

4. baseline 不绿（见下）

**其它 dirty / untracked**（如 `.claude/`、`docs/STATUS.md`、其它 `_prompts/`/`_plans/` 文件、untracked `node_modules/` 等）**与本 sprint 无关，不影响 pre-flight，正常继续**。按 plan owner instruction：parallel session dirty 不主动消化。

```bash
git status --short
# 用上面 4 条规则判断。若仅有无关 dirty（如 .claude/settings.json / docs/STATUS.md /
# 本 prompt 文件 untracked），通过；继续下一步。

git log --oneline -3
# 顶部应是 76e99070 feat(tier1a-sprint2): ...

pnpm test                       # 应 105 passed | 1 skipped
pnpm exec vue-tsc --noEmit      # 应 0 错

# Sprint 1 + 2 baseline 仍 green
node -e "
  const Ajv2020 = require('ajv/dist/2020.js').default;
  const ajv = new Ajv2020({ strict: true });
  const validate1 = ajv.compile(require('./src/design-system/translation/schemas/axis-implementation-map.schema.json'));
  const validate2 = ajv.compile(require('./src/design-system/translation/schemas/prop-aliases.schema.json'));
  const d1 = require('./src/design-system/translation/axis-implementation-map.json');
  const d2 = require('./src/design-system/translation/prop-aliases.json');
  if (!validate1(d1)) { console.error('axis fail', validate1.errors); process.exit(1); }
  if (!validate2(d2)) { console.error('prop fail', validate2.errors); process.exit(1); }
  console.log('Sprint 1+2 baseline OK:', d1.instances.length, 'instances /', d2.entries.length, 'entries');
"
# 预期：Sprint 1+2 baseline OK: 16 instances / 102 entries
```

任一不绿 → **STOP**，报告，不要硬上。

---

## 1. 任务摘要

把 [`src/design-system/translation/divergences.md`](../../../src/design-system/translation/divergences.md) **split**：

- **明确 status 的决议 entries → JSON**（spec §2.3 草案）
- **所有 narrative rationale → md 大量保留**（D6 决议 — divergences 价值在 "为什么"，比 prop-aliases 更不应该 over-extract）

**与 Sprint 2 的关键差异**：
- prop-aliases 是 **table-heavy**（90% 内容是结构化 entry，~10% narrative）
- divergences 是 **narrative-heavy**（70% 内容是叙述，~30% 结构化 status entry）
- 因此 md **不大幅瘦身**，只在每段末尾加 "对应 decisions.json#<id>" 引用

**严格范围**：仅 divergences.md + 0 audit 脚本（实证 sprint 1/2 grep 0 引用）。

---

## 2. 任务输入

源文件：[`src/design-system/translation/divergences.md`](../../../src/design-system/translation/divergences.md)

**起手 read 全文**（15.6KB）建立全貌。

### 2.1 9 个主段清单（按 md 出现顺序）

| # | md 段标题 | 子段数 | category（spec §2.3） | 预估 entries |
|---|---|---:|---|---:|
| S1 | `## Figma SVG export pipeline limitation — Icon Variable resolved-to-hex` | 1 | `figma-pipeline-limitation` | 1 |
| S2 | `## 组件级映射 (Component-level Translation)` | 9 | `component-level-translation` 🆕 | 9 |
| S3 | `## Code 端双源 (AI 工具消费指引)` | 1 | `code-side-dual-source` | 1（Badge） |
| S4 | `## 设计态属性批量不映射` | 8 | `accepted-divergence` | 8 |
| S5 | `## API 双形态映射` | 4 | `dual-form-mapping` 或 `api-split` 或 `migration-plan` | 4 |
| S6 | `## PromptMessage.interact` | 1 | `accepted-divergence` | 1 |
| S7 | `## Notification.success` | 1 | `resolved` | 1 |
| S8 | `## Notification.type` | 1 | `resolved` | 1 |

**总预估 entries：~26**

**category 细分**（S5 内 4 子段按 status 分）：
- `FormItem.label / Tooltip.content` → `dual-form-mapping`
- `Badge API 拆分` → `api-split`
- `Button 双 API 完成迁移决策` → `migration-plan`

**🆕 新 category 候选**：spec §2.3 列了 7 个 category，S2 (组件级映射) 在 spec 草案里**未列**，应加 `component-level-translation`（这是 sprint 2 加 2 status 同模式 — fidelity 1:1，新值列报告）。

### 2.2 Status enum 全集（实证从 md 抽）

按 md "Status" 字段值转 kebab-case：

| md 原值 | kebab-case |
|---|---|
| `✅ resolved` | `resolved` |
| `accepted documented divergence` | `accepted-documented-divergence` |
| `accepted documented divergence (with exceptions)` | `accepted-documented-divergence-with-exceptions` |
| `approved dual-form mapping` | `approved-dual-form-mapping` |
| `approved dual-form mapping（参考 Element Plus）` | 抹去括注 → `approved-dual-form-mapping` |
| `approved API split` | `approved-api-split` |
| `approved migration plan` | `approved-migration-plan` |

**S1 / S2 / S3 多数子段无明确 Status 字段** — 设 `status: null`（schema 允许）。

### 2.3 字段命名规则

每条 entry：

| JSON 字段 | 类型 | 必填 | 备注 |
|---|---|---|---|
| `id` | string | ✓ | kebab-case，pattern `^[a-z0-9-]+$` |
| `category` | enum | ✓ | 见 §2.1 |
| `component` | string \| null | — | 单组件 |
| `components` | string[] \| null | — | 多组件（如 S4-1 `Input/CheckBox/Radio/Switch/Select/Tooltip` 拆 array） |
| `subject` | string | ✓ | 子段标题简化（如 "Badge API 拆分" / "Figma dark theme property"） |
| `figmaSide` | string \| null | — | figma 端契约描述（叙述抽取 1-2 句） |
| `codeSide` | string \| null | — | code 端契约描述 |
| `status` | enum \| null | — | 见 §2.2 |
| `reason` | string \| null | — | "Reason: ..." 段提炼 |
| `resolvedAt` | string (YYYY-MM-DD) \| null | — | 仅 `resolved` 类填 |
| `resolutionRef` | string \| null | — | 仅 `resolved` 类填（如 "Phase 6.3"） |
| `phase` | string \| null | — | 仅 dual-form / api-split / migration-plan（如 "Phase 6.6"） |
| `verifyHint` | string \| null | — | 推荐：可机械验证的 grep（如 `grep -rE "['\"]success['\"]" src/components/Notification/ → 0 hits`） |
| `notes` | string \| null | — | 其它备注 / 历史 / 实证 |

### 2.4 叙述抽取 vs 保留 md 的边界

**关键判断**：每个段的"为什么"叙述 → 留 md；明确决议 enum → 进 JSON。

**S1 Pipeline limitation** 例：
- JSON 提：`id` / `category=figma-pipeline-limitation` / `subject="Figma SVG export Variable resolved-to-hex"` / `figmaSide="image API resolves Variable to literal hex (#dbdbdb)"` / `codeSide="transformSvgCurrentColor in export-icons.mjs"` / `status=null` / `verifyHint`（audit:icon-fill-currentcolor 命令）
- md 保留：4 段完整叙述（问题 / 实证 / Code 端治本 / 消费方 fallback / Audit 保护 / Why 不视为漂移 / 未来 Variable 重绑）

**S7/S8 Notification.success/type** 例（resolved 类）:
- JSON 全字段填（subject / figmaSide / codeSide / status=resolved / resolvedAt=2026-04-28 / resolutionRef="Phase 6.3" / verifyHint）
- md 段保留原样 + 末尾加 "决议详情：[`divergences-decisions.json`](./divergences-decisions.json#L<approx>)" 链接（line 锚不强求精确）

---

## 3. 任务输出（3 个 deliverable）

### Deliverable 1 — 新 JSON 数据文件

**路径**：`src/design-system/translation/divergences-decisions.json`

**结构**：

```json
{
  "$schema": "./schemas/divergences-decisions.schema.json",
  "version": 1,
  "decisions": [
    {
      "id": "notification-success-deletion",
      "category": "resolved",
      "component": "Notification",
      "subject": "success status",
      "figmaSide": "no success status in published component set",
      "codeSide": "historical runtime-only status",
      "status": "resolved",
      "reason": "code invented a status outside the Figma family",
      "resolvedAt": "2026-04-28",
      "resolutionRef": "Phase 6.3",
      "verifyHint": "grep -rE \"['\\\"]success['\\\"]\" src/components/Notification/ → 0 hits"
    },
    {
      "id": "formitem-label-dual-form",
      "category": "dual-form-mapping",
      "component": "FormItem",
      "subject": "label prop ↔ Label SLOT",
      "figmaSide": "SLOT",
      "codeSide": "string prop OR default slot (slot 优先)",
      "status": "approved-dual-form-mapping",
      "phase": "Phase 6.6"
    },
    {
      "id": "input-dark-theme-axis-batch",
      "category": "accepted-divergence",
      "components": ["Input", "CheckBox", "Radio", "Switch", "Select", "Tooltip"],
      "subject": "Figma dark theme property",
      "reason": "设计态主题预览开关；运行时主题由全局 ThemeProvider / CSS 变量处理",
      "status": "accepted-documented-divergence",
      "notes": "例外：Notification.theme + PromptMessage.theme 单实例运行时切换，已映射为 code prop"
    }
  ]
}
```

**fidelity 要求**：
- ~26 entries 全转，1:1 保 md 关键内容
- 叙述长段不入 JSON（留 md）— JSON 字段值控制在 1-3 句
- 字段无值 → `null`（schema 一致性优先）
- entry ID 命名：`<component-lowercased>-<subject-shortened>` 或 `<category>-<seq>` 二选一

### Deliverable 2 — 新 JSON Schema 文件

**路径**：`src/design-system/translation/schemas/divergences-decisions.schema.json`

**策略**：loose union schema（同 Sprint 2 prop-aliases），category-specific 验证延后 Sprint 4。

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "divergences-decisions.schema.json",
  "title": "Divergences Decisions",
  "description": "翻译层显式不映射 / dual-form / API split / migration plan / accepted divergence / pipeline limitation 全部决议真源。category-specific 字段验证延后到 audit:translation-completeness。",
  "type": "object",
  "required": ["version", "decisions"],
  "additionalProperties": false,
  "properties": {
    "$schema": { "type": "string" },
    "version": { "const": 1 },
    "decisions": {
      "type": "array",
      "items": {
        "type": "object",
        "required": ["id", "category", "subject"],
        "additionalProperties": false,
        "properties": {
          "id": { "type": "string", "pattern": "^[a-z0-9-]+$" },
          "category": {
            "enum": [
              "resolved",
              "dual-form-mapping",
              "api-split",
              "migration-plan",
              "accepted-divergence",
              "figma-pipeline-limitation",
              "code-side-dual-source",
              "component-level-translation"
            ]
          },
          "component": { "type": ["string", "null"] },
          "components": {
            "type": ["array", "null"],
            "items": { "type": "string" }
          },
          "subject": { "type": "string", "minLength": 1 },
          "figmaSide": { "type": ["string", "null"] },
          "codeSide": { "type": ["string", "null"] },
          "status": {
            "type": ["string", "null"],
            "enum": [
              "resolved",
              "accepted-documented-divergence",
              "accepted-documented-divergence-with-exceptions",
              "approved-dual-form-mapping",
              "approved-api-split",
              "approved-migration-plan",
              null
            ]
          },
          "reason": { "type": ["string", "null"] },
          "resolvedAt": {
            "type": ["string", "null"],
            "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$"
          },
          "resolutionRef": { "type": ["string", "null"] },
          "phase": { "type": ["string", "null"] },
          "verifyHint": { "type": ["string", "null"] },
          "notes": { "type": ["string", "null"] }
        }
      }
    }
  }
}
```

### Deliverable 3 — 保留 divergences.md（轻度修改）

**路径**：`src/design-system/translation/divergences.md`（原路径不变）

**修改**：

1. **顶部加 split note**：

   ```markdown
   <!--
   Split 2026-05-14 — Tier 1-A Sprint 3 (commit <new-sha>)
   ~26 决议 entries 已迁到 divergences-decisions.json (+ schema)；本 md narrative 大幅保留。
   活跃 SoT：
   - 结构化决议 → src/design-system/translation/divergences-decisions.json
   - 完整 rationale / 实证 / 历史 → 本 md
   -->
   ```
2. **不删任何 narrative 段** — divergences 价值在 "为什么"
3. 每个 status enum 行 / 决议行后加 stub 链接：

   ```markdown
   - Status: ✅ resolved (2026-04-28, Phase 6.3)
   - Resolution: ...
   - **决议详情**: [`divergences-decisions.json`](./divergences-decisions.json) `id: notification-success-deletion`
   ```
4. **md 体积变化预估**：原 ~225 行，瘦身后 ~240-260 行（**反而略增**，因加了 ~26 个 stub link）。不像 Sprint 2 大幅瘦身。

---

## 4. 执行步骤（按顺序）

1. 起手 §0 pre-flight 全绿
2. Read `divergences.md` 全文
3. 按 §2 分类 9 段、提 ~26 决议 entries
4. 写 Deliverable 1 JSON
5. 写 Deliverable 2 schema
6. AJV 2020 验证：

   ```bash
   node -e "
     const Ajv2020 = require('ajv/dist/2020.js').default;
     const schema = require('./src/design-system/translation/schemas/divergences-decisions.schema.json');
     const data = require('./src/design-system/translation/divergences-decisions.json');
     const ajv = new Ajv2020({ strict: true });
     const validate = ajv.compile(schema);
     if (!validate(data)) { console.error(validate.errors); process.exit(1); }
     console.log('OK:', data.decisions.length, 'decisions passed schema');
   "
   ```
7. Light-edit md（Deliverable 3）— **不删 narrative**，只加 stub link
8. 跑 §5 验收命令
9. STOP + 报告

---

## 5. 验收命令

```bash
# Deliverable 1 + 2 — 文件存在
test -f src/design-system/translation/divergences-decisions.json
test -f src/design-system/translation/schemas/divergences-decisions.schema.json

# AJV 2020 验证
node -e "
  const Ajv2020 = require('ajv/dist/2020.js').default;
  const schema = require('./src/design-system/translation/schemas/divergences-decisions.schema.json');
  const data = require('./src/design-system/translation/divergences-decisions.json');
  const validate = new Ajv2020({ strict: true }).compile(schema);
  if (!validate(data)) { console.error(validate.errors); process.exit(1); }
  console.log('OK:', data.decisions.length, 'decisions passed schema');
"
# 预期：OK: ~26 decisions passed schema

# Sprint 1 + 2 baseline 仍 green
node -e "
  const Ajv2020 = require('ajv/dist/2020.js').default;
  const ajv = new Ajv2020({ strict: true });
  const v1 = ajv.compile(require('./src/design-system/translation/schemas/axis-implementation-map.schema.json'));
  const v2 = ajv.compile(require('./src/design-system/translation/schemas/prop-aliases.schema.json'));
  const d1 = require('./src/design-system/translation/axis-implementation-map.json');
  const d2 = require('./src/design-system/translation/prop-aliases.json');
  if (!v1(d1) || !v2(d2)) process.exit(1);
  console.log('Sprint 1+2 baseline still OK');
"

# category 分布
node -e "
  const data = require('./src/design-system/translation/divergences-decisions.json');
  const cats = {};
  data.decisions.forEach(d => { cats[d.category] = (cats[d.category] || 0) + 1; });
  console.log('category distribution:', JSON.stringify(cats, null, 2));
"
# 预期：8 个 category 全列出（resolved / dual-form-mapping / api-split / migration-plan /
#       accepted-divergence / figma-pipeline-limitation / code-side-dual-source /
#       component-level-translation）

# 全套现有 audit 0 回归
pnpm test                                       # 105 passed | 1 skipped
pnpm exec vue-tsc --noEmit                      # 0 错
pnpm audit:design-system                        # 全 pass
pnpm audit:figma-conformance                    # 全 pass
pnpm audit:docs-site                            # 全 pass
pnpm audit:published-vs-code                    # 38 matched / 0 figma-only / 0 code-only
pnpm audit:no-hardcoded-design-tokens           # baseline
pnpm audit:icon-fill-currentcolor               # 0 finding
pnpm audit:component-no-inline-svg              # baseline
pnpm audit:component-tokens                     # 全 pass
pnpm audit:tokenized-diff                       # baseline
```

**任一验收 fail → STOP，不要硬上**，报告给 plan owner。

---

## 6. 报告格式（STOP 后必交）

```markdown
## Sprint 3 完成报告

### 改动文件清单
- [ ] 新建 src/design-system/translation/divergences-decisions.json
- [ ] 新建 src/design-system/translation/schemas/divergences-decisions.schema.json
- [ ] light-edit src/design-system/translation/divergences.md (X 行 → Y 行)

### decisions 统计
- 总 decisions: Z
- category 分布：[列表]
- Status 实际值（对比 §2.2 给定 7 值）：[列表 + 新发现值]
- 新 category 值（对比 spec §2.3 给定 7 值 + 本 prompt 加的 component-level-translation 共 8 值）：[确认 8 个全用到 / 缺哪个 / 多哪个]

### 验收结果
- AJV schema 验证：[OK / FAIL]
- Sprint 1+2 baseline：[OK / fail]
- pnpm test: [105 passed | 1 skipped / fail]
- vue-tsc: [0 错 / 报错]
- 全 audit 套：[全 pass / 哪个回归]

### 实际耗时
[Xh，对比 spec §4 估 2-3 day。Sprint 1 / 2 各 1h]

### Sprint 4 calibrate 建议（audit:translation-completeness 实现）
[Sprint 4 是最重 — 5 维 audit 跨 3 JSON + 2 TS + figma-data。预估 2-3 day。
Sprint 1/2/3 实际 1h，Sprint 4 因含 audit 实现 + 10th strict gate + allowlist 决策可能 真要 2-3 day]

### 未解决 / 待 plan owner 决策项
- [遇到的边界 case，如某段叙述无明显 status / Alert ❓ 段如何处理 / Code 端双源 Badge 段长 narrative 怎么切]
```

---

## 7. 严格不做的事（executor 边界）

- ❌ 改 audit 脚本（0 引用 divergences.md，本 sprint 0 audit 改动）
- ❌ 触碰 axis-implementation-map.json / prop-aliases.json + 它们 schema（Sprint 1+2 已 ship）
- ❌ 触碰 icon-aliases.ts / token-aliases.ts（spec D 段：不动 TS）
- ❌ 修正 md 内容（如修 typo / 改 status 拼写）— fidelity 1:1
- ❌ 删 md narrative — divergences 价值在 narrative
- ❌ 自创新决议 / 删既有决议
- ❌ 加 category-specific 验证逻辑到 schema（Sprint 4 audit 做）
- ❌ 改 STATUS.md / tracker.md / CHANGELOG.md（Sprint 4 时做）
- ❌ commit — plan owner 审完后用户决定

如某段叙述实在抽不出 entry（如 §S3 "其它 16 组件不算双源" — 这是说明性段落，**不入 JSON**，仅 md 保留）→ 报告给 plan owner，不要勉强造 entry。

---

## 8. 完成后 STOP

把报告交给 plan owner（Claude Code），由 plan owner 复审 + 用户决定：

- 是否 commit sprint 3
- 是否进 sprint 4（audit:translation-completeness 实现 + 10th strict gate）
- 是否 calibrate spec §4-5 估时
