# 2026-05-09 — F23 FormItemPage rewrite + 跨层 fix lineage

## TL;DR

- F23 backlog (INFRA-F23) 完成: FormItemPage 从手写 dual-theme dual-card 范式重写到 INFRA-F19 toggle-aware 范式
- F23 executor (Codex 在另一 session) 完成机械 rewrite 后 plan owner 视觉验收**两次不通过**，连续暴露 4 个跨层 bug，最终通过本次 plan-owner-led debug + 修复
- 落 4 commit: SelectBoxBase 1 line fix + BaseFormItem 治本 refactor + FormItem page 重写 + 本复盘
- 解锁: F19 范式最后一个未对齐 page 收尾，docs site 18 page 全部 toggle-aware

## Lineage

```
F22 case-insensitive (3376d4a0)
  └── 解锁 FormItem normalized data 顶层 theme field (dark=32 / light=32)
      └── F23 prompt 落仓库 (d261cb73)
          └── User spawn Codex executor → 机械 rewrite
              └── User dev verify → 不通过 ("Composition Usage 之外 figma 不对")
                  └── Plan owner 介入诊断 (本 session)
                      ├── Bug 1: 8 个 canonical child 组件 (InputBoxFilled /
                      │         SelectBoxFilled / Radio / CheckBox / Switch)
                      │         没传 :dark-theme prop, 锁 dark; toggle 切 light
                      │         child 组件不响应 → 视觉错位
                      ├── Bug 2: <FigmaMembersGrid :component="FormItem" />
                      │         渲染 64 variant 不传 slot, FormItem fallback
                      │         走 placeholder 路径 (literal v/x + fake static
                      │         controls), 不可交互
                      ├── Issue 2 (兼修): SelectBoxBase .select-wrap--filled
                      │         .select-trigger 用 var(--bg-layer4),
                      │         light theme 灰 (#dbdbdb), 跟 Input 白
                      │         (--input-filled-bg) 不一致
                      └── Issue 3 (二次回看): .member-card :deep(.form-item__main)
                                align-items: center, error 状态 content 高度
                                增至 52px 后 label 垂直居中飘到 content 中央,
                                跟 input top 错位; user 报 "Error 应在 Value
                                正下方, Label 跟 Value 同行"
                                  → align-items: flex-start fix
                                      → User 视觉验收通过
                                          → 4 commit 落 master
```

## 关键决策

### D1: F23 architectural mismatch (Bug 2 解决路径选择)

User pushed back when 我提出 3 路 (path A 删 matrix / path B 手写矩阵 / path C 改 BaseFormItem fallback)。User 选 path C 治本。但实操发现 path C 不能让 64 个静态 cell 真正可交互 (FigmaMembersGrid 不支持 per-cell slot child)。

最终 **path B + path C 一起做**:
- path C: BaseFormItem fallback 用真组件 (好处不限于 F23——其它消费者 figma-shell preview 视觉提升)
- path B: FormItemPage Member Matrix 实际上不再用 FigmaMembersGrid, 手写 5 type × 2 status = 10 卡可交互矩阵 (FormItem 的 slot-based 架构跟 FigmaMembersGrid 的 no-slot 渲染模型本质不兼容)

教训: prompt 设计阶段 (F23 prompt v1) 误以为 FigmaMembersGrid 通用; 实际 FormItem 的 slot-required 性质让 FigmaMembersGrid 不适配。**架构兼容性需要在 prompt 设计阶段 verify, 不能让 executor 跑完才发现**。

### D2: align-items: center → flex-start (Issue 3)

`.member-card :deep(.form-item__main)` 历史 `align-items: center` 是为 Normal 状态 (label/value 都 32px) 设计的视觉居中。Error 状态破坏假设——content 包 message 后高度增 52px, label 32px 垂直居中变 y=10-42, input 在 y=0-32, 视觉错位。

`align-items: flex-start` 让 label/value 顶对齐, error 在 value 下方。Normal 状态视觉跟 center 一致 (两个 32px 子项顶对齐 = 居中)。

**Plan owner 元教训**: 历史 CSS override (尤其是 `:deep` 选择器) 经常基于"Normal 假设" 写, error / loading / disabled 等扩展状态会暴露 layout 假设。下次定 :deep override 时**先列出所有可能 child layout state 再决定 align-items**。

### D3: Error message visual placement

User 反复点出 "Error 放在 Value 的正下方"。现 layout 满足: label/value 顶对齐, error 在 content column 内 input 下方, 整体跟 Input 各 100% width 视觉清晰。

剩余视觉细节 (例如 Switch toggle 40px 窄但 error message 文本宽于 toggle, 视觉上 error 比 switch 多向右伸) 当前可接受; user 验收通过。

## 实证沉淀 (建议入 meta-rules.md 附录)

| 实例 | 反模式 / 触发器 | 正解 |
|---|---|---|
| F23 prompt v1 误用 FigmaMembersGrid 渲染 FormItem 64 variant, 忽略 FormItem slot-required 性质 | 反模式 #4 (设计完没问下游怎么消费) | prompt 设计阶段需 verify "目标组件的 slot 模型 ↔ generic grid 渲染模型" 兼容性. 命名上 "X 通用 grid for figma 真源" 跟 "X 必须 slot 真组件" 是冲突约束 |
| `.member-card :deep(.form-item__main) align-items: center` 历史 override 基于 Normal 状态假设, error 状态下 label 垂直居中错位 | 反模式 #5 (没问扩展时改哪里) | 写 :deep CSS override 时先列出 child 所有 layout state (Normal / Error / Loading / Disabled), 再决定 align-items / justify-content; 默认 flex-start (顶对齐) 比 center 更鲁棒 |
| FormItemPage 8 个 child slot 实例 executor 没加 :dark-theme prop, plan owner 在 prompt v1 没列出"child 组件 darkTheme prop 跟随 docsTheme"清单 | 反模式 #4 + 触发器 G (踢任务边界) | prompt 设计阶段需检查每个 child 组件的 theme-related prop 清单, 写到 prompt §2.X 任务步骤里, 不能假设 executor "自然识别" |

## 改动文件 4 commit

| commit | 文件 | 范围 |
|---|---|---|
| `b6b5cc38` fix(SelectBoxBase) | `src/canonical/SelectBoxBase.vue` | filled trigger bg `var(--bg-layer4)` → `var(--input-filled-bg)`, 1 line |
| `b442edf3` refactor(FormItem) | `src/components/FormItem/FormItem.vue` | import Icon/Switch/Radio/Checkbox + baseTheme computed + slot fallback 用真组件 + 删 fake control CSS, +28/-79 |
| `5bbc1149` feat(F23) | `playground/docs/pages/FormItemPage.vue` | inject docsTheme + formItemTheme + childDarkTheme + 8 child :dark-theme + Member Matrix 手写 5×2 矩阵 + align-items 修复, +101/-66 |
| (本复盘) | `docs/internal/retrospection/2026-05-09-f23-formitem-page-rewrite.md` | 本文件 |

## Audit baseline (post-F23)

- vue-tsc: 0 errors
- audit:icon-fill-currentcolor: 0 finding
- audit:component-no-inline-svg: 0 finding
- audit:no-hardcoded-design-tokens: 37 finding (color 3 / spacing 27 / radius 7) - src/ 范围
- audit:figma-conformance: overallPass=true
- audit:docs-site: 仅 6 历史 in-review warn
- audit-page-t2-sample: exit 0 (18 page 全过)

## 待办 / 后续

> **⚠️ Next session 起手第一件事 (2026-05-10 更新决策)**：先做 **META-F27 系统性 review**, 再起 F20。**不要直接跑 F20**。
>
> 理由：F20 baseline = 锁定当前状态。如果 review 发现 dead code / 假数据 / 历史遗漏 / 双源混乱（如已知 src/legacy/, 2 个 CheckBox dir 大小写不一致, src/icons/registry.ts vs src/icons/catalog/ 双 registry, figma-data/normalized/ 多个 skeleton-promotion-plan-*.json 是否仍消费等），F20 baseline 会把这些一起锁进基线，后面再清理要重录 36 张 baseline。Review 应该 inform F20 scope, 不是反过来。
>
> 详见 backlog **META-F27** entry。

### 优先级顺序 (next session 拍板按这个走)

1. **META-F27** 系统性 review (新): 识别 dead code / 假数据 / 历史遗漏 / 组织混乱; 输出 cleanup 候选清单 + F20 prompt 边界建议
2. (review 完后) Plan owner 决定哪些 cleanup 现在做; 落 cleanup commits
3. **INFRA-F20** visual snapshot framework setup (review-informed scope)
4. **INFRA-F21** pre-commit hook (依赖 F20)
5. **INFRA-F24** docs page theme injection 范式统一 (CheckboxPage / RadioPage / SwitchPage 仍用 props.isDark 旧轨; 优先级 Medium, 不阻塞 F20)
6. F25 cleanup 仍有 16 noMatch + 21 exact-match in src/ 待 plan owner 单独 review (review 阶段一并处理可能更经济)

### 副效 / 监控点

- BaseFormItem path C refactor 让 src/legacy/index.ts / playground/App.vue 等消费 BaseFormItem 的地方默认 fallback 视觉提升 (未跑视觉验证, 假设无回归; review 阶段需 spot-check, 否则 F20 baseline 兜底捕获)
- SelectBoxBase filled bg 改 --input-filled-bg 影响所有 SelectBoxFilled 消费者 (TopBar / etc.); review 阶段 spot-check, 或 F20 兜底

## Backlog 状态更新

- ✅ **INFRA-F23 done** — 移到 Resolved 段 (本复盘 + 3 commit 即记录)
- 🟢 INFRA-F19 由 F22+F23 链路彻底收尾 — docs site 18 page 全 toggle-aware

## 工作区状态

- HEAD: `5bbc1149` feat(F23): FormItemPage toggle-aware + Type And Status Matrix interactive
- branch: master
- pushed to origin: 待本复盘 commit 后一并 push
- dirty files: 仅 3 个 pre-existing untracked F19/F20-deferred 脚本 (`.f19-cell-labels.mjs` / `.f19-visual-audit.mjs` / `.light-theme-audit.mjs`)
