# Retrospect — INFRA-F36 / form_item / select discovery：提取产物反推上游的连环误判

> 2026-06-03 session。主线：drift:summary 剩余 A 的 select/dropdown discovery + form_item + INFRA-F36。
> 技术结论已在 commits（`9ec6bf82` / `7b930683` / `8cec0721` / `778022c0`）+ STATUS + tracker ledger + backlog。
> 本复盘只记**通用工程教训 + 反模式**（协议：踩反模式 / 学到通用经验 → 必写）。

## 一句话
一个 session 内 **3 次**把「提取后/归一化产物」当成「上游真实结构」反推，被用户两次挑战才纠正。根因不是懒，是**没意识到 extract 是有损变换 + 可能自带 bug**，产物长什么样 ≠ Figma/真源长什么样。

## shipped（一句话各一）
- **select/dropdown discovery**：10 残余 A 全是 verifier/Figma-hygiene artifact，真 code drift = 0（Drop down 3 修 classify 正则归 B；select 7 是设计师 set 内 placeholder 散绑 raw grey → BRIDGE-DESIGN-REVIEW）。
- **INFRA-F36**：组件数 4729→685（修 extract collectComponents 重复收集 + orphan-purge 定向 dedup + 离线 surgical 清理）。
- **form_item**：reverse CANONICAL-019（error label 应保持灰，红在独立 message）+ manifest theme 大小写修；41→0。

## 反模式实证（3 连环误判）

| # | 我说的 | 真相 | 我读了什么 / 该读什么 |
|---|---|---|---|
| 1 | Select 是 610 散装组件、没 combine 成 set | Select 是 COMPONENT_SET（filled/line 各 144 变体）| 读了 raw `componentSetId:null` 文件 → 该查 live Figma `get_metadata` |
| 2 | 4044 是 stale + orphan-purge 50% 熔断器卡住 | collectComponents 每次 extract 重复收集（一直 valid，永不进 toPurge）| 读了 extractedAt 时间戳猜 stale → 该读 collectComponents 源码 |
| 3 | form_item label 该比对隐藏星号 `"* "` | 星号是 extract firstTextNode 取错节点，真 label 是可见 "Form Label" | INFRA-F39 已发现但 raw 没 re-extract → re-extract + live Figma 才显形 |

**共同根因**：`figma-data/raw|normalized/*` 是 **lossy 变换 + 可能含 extract bug** 的产物：
- 拍平 set→standalone（collectComponents bug，树节点缺 componentSetId）
- firstTextNode 只取一个节点（取了隐藏星号）
- strip child geometry（EXTRACT-007 缺口）

把它当 Figma 真源镜像读 = 把 extract 的"翻译腔/错别字"当成原文。

## 第二类教训：dry-run 验证的是你的假设，不是真实行为
commit `7b930683` 我修在 orphan-purge + 写了"熔断器卡住"根因，还跑了 dry-run "命中 4044" 自我确认。**dry-run 复现的是我的（错误）stale-in-toPurge 模型 → 假性通过**。直到 full sync 打出 `extracted 4729`（根本没清）才戳破 → 真因是 collectComponents。**机制 bug 的根因，必须看真实 pipeline 的 observable effect（count/render 真变了吗），不是看你自写校验脚本对你假设的复现**。

## 第三类教训：清理用 surgical 不用 sledgehammer
为清 4044 我跑了 `sync:figma-library --with-extract`（重武器）→ 顺带拉 155 fresh 内容 drift 和结构清理纠缠 + 第一次根本没清（fix 在错地方）。**纯结构 dedup 应离线 surgical**（删文件 + 按 key 过滤 index/manifest 数组，零内容 churn）→ 后来这么做才干净（8088 删除 + 3 数组过滤，drift 不变 84）。

## 做对的（保留）
- 每次误判都被实证纠正了（live Figma `get_variable_defs` + screenshot 是 deterministic 终审）—— FIGMA_AS_SOURCE_OF_TRUTH 第 0 步的价值。
- form_item / select 的真假分类全部 deterministic（live Figma + token 解析 + 全报告扫描），没靠启发式。
- 纠正后文档/commit 叙述都回填正确根因，没留错误叙述在仓库。

## 预防（已固化）
- **memory**（个人缓存）：`feedback_extract-output-not-figma-truth` —— 推断上游结构禁读提取产物，查 live Figma 或 extract 源码；机制 bug 看 observable effect；清理用 surgical。
- **本复盘**（团队 SoT）。
- 与既有 [[trigger-O]] / [[name-search-absent-fallacy]] / [[review-result-vs-rationale]] 同族（都是"derived/cached 信号不可全信"），但本条专抓"提取产物反推上游"这个 trigger-O 没精确覆盖的子面。
