# Tier 1-A Sprint 2 — prop-aliases.md → JSON + md split

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

---

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

```bash
git status --short
# 应只剩别 session dirty（.claude/settings.json）；其它干净
# 不应含 src/design-system/translation/ 或 docs/internal/

git log --oneline -3
# 顶部应是 40e8c777 feat(tier1a-sprint1): ...

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

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

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

---

## 1. 任务摘要

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

- **结构化 table entries → JSON**（spec §2.2 草案）
- **narrative rationale + 历史段 → md 瘦身保留**（D6 决议）

不是 sprint 1 的"整 md 归档"路径——这次 **md 文件路径不变**（仍在 `src/design-system/translation/prop-aliases.md`），但内容大幅瘦身。

**严格范围**：仅本文件 + 0 audit 脚本（实证 sprint 1 前 grep 0 引用）。其它 translation/ 文件不动（sprint 3-4 处理）。

---

## 2. 任务输入

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

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

### 2.1 11 个 table 清单（按 md 出现顺序）

| # | md 段标题 | 字段（横向） | scope 标签 | 预估 entries |
|---|---|---|---|---:|
| T1 | `## Known Entries` | Component / Code Prop / Figma Property / Status / Notes | `component-prop` | ~11 |
| T2 | `## Vue 生态增强（代码侧添加，Figma 无对应）` 第 1 张 | Component / Code Prop/Event/Slot / Figma / Status / Notes | `vue-ecosystem-addition` | ~6 |
| T3 | `## Vue 生态增强...` 第 2 张 | Component / Code Prop / Figma / Status / Notes | `runtime-addition` | ~4 |
| T4 | `## 组件级命名映射` | Code Component / Figma Component Set / 差异类型 / Status / Notes | `component-naming` | ~5 |
| T5 | `## 枚举值命名映射` | Component / Code Value / Figma Value / Status / Notes | `value-alias` | ~4 |
| T6 | `### 表 A — Axis 名 alias` | Figma Axis Name / Canonical/Derived Axis / Scope / Notes | `global-axis-alias` | ~2 |
| T7 | `### 表 B — Axis 值 alias` | Canonical/Derived Axis / Figma Value / Derived Value / Scope / Notes | `axis-value-alias` | ~2 |
| T8 | `### 表 C — 当前已识别影响范围` | Component / canonical prop name 状态 / 备注 | `identified-impact-scope` | ~6 |
| T9 | `## Boolean Property Aliases` | Component / Code Prop / Figma Boolean Property / Status / Notes | `boolean-property` | ~18 |
| T10 | `## Slot Property Aliases` | Component / Code Slot / Figma Slot Property / Status / Notes | `slot-property` | ~9 |
| T11 | `### 表 A — 标准 design-system 复用` (Sub-component Composition) | Figma data-name / Canonical / Props / Status / Notes | `composition-component` | ~7 |
| T12 | `### 表 B — Icon refs` (Sub-component Composition) | Figma data-name pattern / Canonical / Notes | `composition-icon` | ~13 |
| T13 | `### 表 C — Button refs` (Sub-component Composition) | Figma data-name / Canonical / Status / Notes | `composition-button-blocked` | ~4 |

**不入 JSON**：
- `## Template` 段示例（行 12-14）
- `### 表 D — Layout container names`（行 222-223）— md 已明示"不属 composition alignment scope"
- 所有 narrative 段 + 历史段 + "Figma axis 处理规则" 段

### 2.2 Status enum 全集（实证从 md 抽，executor 跑时遇到新值要列出）

- `approved alias` → kebab-case `approved-alias`
- `exact match` → `exact-match`
- `Vue ecosystem` → `vue-ecosystem`
- `runtime addition` → `runtime-addition`
- `axis alias` → `axis-alias`
- `inverted alias` → `inverted-alias`
- `match` → `match`
- `named slot` → `named-slot`
- `approved value alias` → `approved-value-alias`
- `n/a` → `n-a`

**Status 字段转 kebab-case**（spec §2.2）；空 → `null`。

### 2.3 多组件字段处理（T2 实证）

T2 第一列形如 `Input/InputNumber/CheckBox/Radio/Switch/Select` 用 `/` 列多组件。
- JSON 用 `components: string[]`（拆 `/`）
- 单组件用 `component: string`
- T2 entry 用 `components`，其它 table 单组件用 `component`

### 2.4 字段命名规则

JSON 字段统一 camelCase：
- `Code Prop` → `codeName`
- `Code Prop/Event/Slot` → `codeName`（含 event/slot 一律 codeName）
- `Code Value` / `Code Slot` → `codeName`
- `Code Component` → `codeName`
- `Figma Property` / `Figma Value` / `Figma Boolean Property` / `Figma Slot Property` → `figmaName`
- `Figma Axis Name` / `Figma data-name` / `Figma data-name pattern` → `figmaName`
- `Canonical/Derived Axis` → `canonicalAxis`
- `Derived Value` → `derivedValue`
- `Figma Component Set` → `figmaComponentSet`
- `差异类型` → `diffType`
- `canonical prop name 状态` → `canonicalPropState`
- `Props` (T11) → `props`
- `Canonical` (T11/12/13) → `canonical`
- `Status` → `status` (kebab-case enum)
- `Scope` (T6/T7) → `aliasScope`（避免与 entry-level `scope` 字段冲突）
- `Notes` / `备注` → `notes`

每条 entry 必加：
- `id`: `<scope>-<idx>` 形如 `component-prop-001`（每 scope 内独立编号 001 开始；executor 自定）
- `scope`: 上面 13 个枚举值之一

---

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

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

**路径**：`src/design-system/translation/prop-aliases.json`

**结构**：

```json
{
  "$schema": "./schemas/prop-aliases.schema.json",
  "version": 1,
  "entries": [
    {
      "id": "component-prop-001",
      "scope": "component-prop",
      "component": "PromptMessage",
      "codeName": "closable",
      "figmaName": "showCloseIcon",
      "status": "approved-alias",
      "notes": "Vue-ecosystem naming wins. This is documented and no longer treated as a conformance bug."
    },
    {
      "id": "vue-ecosystem-addition-001",
      "scope": "vue-ecosystem-addition",
      "components": ["Input", "InputNumber", "CheckBox", "Radio", "Switch", "Select"],
      "codeName": "modelValue + update:modelValue",
      "figmaName": null,
      "status": "vue-ecosystem",
      "notes": "Vue v-model 标准契约"
    },
    {
      "id": "global-axis-alias-001",
      "scope": "global-axis-alias",
      "figmaName": "dark theme",
      "canonicalAxis": "theme",
      "aliasScope": "GLOBAL",
      "notes": "figma 原始命名（含空格）"
    },
    {
      "id": "boolean-property-001",
      "scope": "boolean-property",
      "component": "CheckBox",
      "codeName": "disabled",
      "figmaName": "enable",
      "status": "inverted-alias",
      "notes": "canonical disabled = !figma.enable"
    },
    {
      "id": "composition-icon-001",
      "scope": "composition-icon",
      "figmaName": "icon/Arrow/Previous",
      "canonical": "<Icon name=\"previous\">",
      "notes": "uses canonical Icon"
    }
  ]
}
```

**fidelity 要求**：
- 13 table（T1-T13，T11/12/13 是 sub-component composition 三张表）entries 全部转，**1:1** 保 md 内容
- 字段无值时 用 `null`（不省略 key — schema 一致性优先）
- 个别 entry md 中字段缺失（如 T2 第 6 行 `Button/FormItem/CheckBox/Radio/Tooltip slot:default`）字段对齐用 `null` 填
- entry `codeName` / `figmaName` 含特殊符号（如 `<slot></slot>`、`<Icon name="...">`）保留原样，JSON 转义
- `composition-icon` (T12) 行如 `icon/Edit/Add 1` / `Close` / ... 多 name 合一行 — 拆为多条 entry，每名 1 条

### Deliverable 2 — 新 JSON Schema 文件

**路径**：`src/design-system/translation/schemas/prop-aliases.schema.json`

**策略**：用 **loose union schema** — 所有字段 optional（除 `id` / `scope` / `version` 必填）。**不**做 scope-specific discriminated validation（那是 Sprint 4 audit 的事，本 sprint 只保 schema 结构合规）。

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "prop-aliases.schema.json",
  "title": "Prop Aliases",
  "description": "翻译层 prop / event / slot / axis / value / composition 全部 alias 真源。13 类 scope 共享 loose union schema；scope-specific 字段验证延后到 audit:translation-completeness。",
  "type": "object",
  "required": ["version", "entries"],
  "additionalProperties": false,
  "properties": {
    "$schema": { "type": "string" },
    "version": { "const": 1 },
    "entries": {
      "type": "array",
      "items": {
        "type": "object",
        "required": ["id", "scope"],
        "additionalProperties": false,
        "properties": {
          "id": { "type": "string", "pattern": "^[a-z0-9-]+-[0-9]{3,}$" },
          "scope": {
            "enum": [
              "component-prop",
              "vue-ecosystem-addition",
              "runtime-addition",
              "component-naming",
              "value-alias",
              "global-axis-alias",
              "axis-value-alias",
              "identified-impact-scope",
              "boolean-property",
              "slot-property",
              "composition-component",
              "composition-icon",
              "composition-button-blocked"
            ]
          },
          "component": { "type": ["string", "null"] },
          "components": {
            "type": ["array", "null"],
            "items": { "type": "string" }
          },
          "codeName": { "type": ["string", "null"] },
          "figmaName": { "type": ["string", "null"] },
          "canonicalAxis": { "type": ["string", "null"] },
          "derivedValue": { "type": ["string", "null"] },
          "figmaComponentSet": { "type": ["string", "null"] },
          "diffType": { "type": ["string", "null"] },
          "canonicalPropState": { "type": ["string", "null"] },
          "canonical": { "type": ["string", "null"] },
          "props": { "type": ["string", "null"] },
          "aliasScope": { "type": ["string", "null"] },
          "status": {
            "type": ["string", "null"],
            "enum": [
              "approved-alias",
              "exact-match",
              "vue-ecosystem",
              "runtime-addition",
              "axis-alias",
              "inverted-alias",
              "match",
              "named-slot",
              "approved-value-alias",
              "n-a",
              null
            ]
          },
          "notes": { "type": ["string", "null"] }
        }
      }
    }
  }
}
```

### Deliverable 3 — 瘦身保留 prop-aliases.md

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

**保留段落**（D6 决议 — 全保留 narrative + 表头 stub）：

1. **文件头注释**（`Responsibilities` 段）— 全保
2. **新增**：顶部加 split note：

   ```markdown
   <!--
   Split 2026-05-14 — Tier 1-A Sprint 2 (commit <new-sha>)
   13 个 table entries 已迁到 prop-aliases.json (+ schema)；本 md 保 narrative + 表头 stub。
   活跃 SoT：
   - 结构化 entries → src/design-system/translation/prop-aliases.json
   - 规则 / rationale → 本 md
   -->
   ```
3. 每个 table（T1-T13）位置改为 **段头 + 链接 stub**：

   ```markdown
   ## Known Entries

   > entries 已迁到 [`prop-aliases.json`](./prop-aliases.json) `scope: component-prop`。
   > 详细字段定义见 [`schemas/prop-aliases.schema.json`](./schemas/prop-aliases.schema.json)。
   ```
4. **必须保留**段：
   - `## Figma axis 处理规则`（整段，含"规则 1: 单值 axis 跳过" + 实施位置 + 实证案例）
   - `## 项目级 GLOBAL axis alias` 段头 + 引言（line 71-72，但表 A/B/C 改 stub）
   - `### 历史`（T8 后段）
5. **删除**段：
   - `## Template` 段（行 12-14 — 示例无意义）
   - `### 表 D — Layout container names`（明示 out of scope）

**最终 md 体积**：从 14.6KB 瘦身到 ~3-4KB（按 D6 估算）。

### Deliverable 4 — `package.json` audit 一行（无 npm script，仅 verify）

**不**加 `audit:translation-completeness` script（那是 sprint 4 deliverable）。本 sprint 0 package.json 改动。

---

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

1. 起手 §0 pre-flight 全绿
2. Read `prop-aliases.md` 全文
3. 提 13 table entries 到 array（按 §2 字段命名规则）
4. 写 Deliverable 1 JSON
5. 写 Deliverable 2 schema
6. **AJV 2020 验证**（spec §3 注意段）：

   ```bash
   node -e "
     const Ajv2020 = require('ajv/dist/2020.js').default;
     const schema = require('./src/design-system/translation/schemas/prop-aliases.schema.json');
     const data = require('./src/design-system/translation/prop-aliases.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.entries.length, 'entries passed schema');
   "
   ```
7. 瘦身 md（Deliverable 3）
8. 跑 §5 验收命令
9. STOP + 报告

---

## 5. 验收命令

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

# AJV 2020 schema 验证
node -e "
  const Ajv2020 = require('ajv/dist/2020.js').default;
  const schema = require('./src/design-system/translation/schemas/prop-aliases.schema.json');
  const data = require('./src/design-system/translation/prop-aliases.json');
  const validate = new Ajv2020({ strict: true }).compile(schema);
  if (!validate(data)) { console.error(validate.errors); process.exit(1); }
  console.log('OK:', data.entries.length, 'entries passed schema');
"
# 预期：OK: ~80-100 entries passed schema（实际数量 executor 报告）

# Sprint 1 baseline 仍 green（确保未影响 axis-implementation-map）
node -e "
  const Ajv2020 = require('ajv/dist/2020.js').default;
  const schema = require('./src/design-system/translation/schemas/axis-implementation-map.schema.json');
  const data = require('./src/design-system/translation/axis-implementation-map.json');
  const validate = new Ajv2020({ strict: true }).compile(schema);
  if (!validate(data)) { console.error(validate.errors); process.exit(1); }
  console.log('Sprint 1 baseline still OK:', data.instances.length);
"

# Deliverable 3 — md 仍存在但瘦身
test -f src/design-system/translation/prop-aliases.md
wc -l src/design-system/translation/prop-aliases.md
# 预期：~80-150 行（原 ~225 行）

# scope 字段覆盖率（13 scope 全有 entries）
node -e "
  const data = require('./src/design-system/translation/prop-aliases.json');
  const scopes = [...new Set(data.entries.map(e => e.scope))];
  console.log('scopes used:', scopes.length, '/ 13 expected');
  console.log('list:', scopes.sort().join(', '));
"
# 预期：scopes used: 13 / 13 expected

# 全套现有 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 2 完成报告

### 改动文件清单
- [ ] 新建 src/design-system/translation/prop-aliases.json
- [ ] 新建 src/design-system/translation/schemas/prop-aliases.schema.json
- [ ] 瘦身 src/design-system/translation/prop-aliases.md (X 行 → Y 行)

### entries 统计
- 总 entries：Z
- 13 scope 覆盖：[全 13 / 缺哪个]
- Status enum 实际遇到值：[列表，对比 §2.2 给定 10 值]

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

### 实际耗时
[Xh，对比 spec §4 估 2-3 day]

### Sprint 3 calibrate 建议（divergences.md split）
[实跑 Sprint 2 后，对 Sprint 3 divergences.md 9 段叙述分类难度的估时调整]

### 未解决 / 待 plan owner 决策项
- [遇到的边界 case，如某 entry 字段格式异常 / md 中 entry 字段不完整 / status 值在 enum 外]
- [瘦身 md 时拿不准的段落归属（保留 / 删除 / 改 stub）]
```

---

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

- ❌ 改 audit 脚本（0 引用 prop-aliases.md，本 sprint 0 audit 改动）
- ❌ 触碰 axis-implementation-map.json/.schema.json（Sprint 1 已 ship，不动）
- ❌ 触碰 divergences.md / icon-aliases.ts / token-aliases.ts（sprint 3-4 处理）
- ❌ 修正 md 中 entry 内容（如改 Status 拼写）— **fidelity 1:1**；如发现 typo，列报告
- ❌ 自创新 entry / 删 entry — fidelity = 1:1
- ❌ 加 scope-specific validation 逻辑到 schema（Sprint 4 audit 做）
- ❌ 改 STATUS.md / tracker.md / CHANGELOG.md（Sprint 4 时做）
- ❌ commit — plan owner 审完后用户决定

如 md 中字段命名 / 格式与本 prompt §2 列的字段名 / scope 表不一致 → **STOP** 报告，不要"修一下顺手"。

---

## 8. 完成后 STOP

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

- 是否 commit sprint 2
- 是否进 sprint 3（divergences.md split）
- 是否 calibrate spec § 4-5 估时
