# 从归档复盘提炼回来的结论集（ADR）

> **这是什么**：`docs/_archive/retrospection/` 下 34 份复盘（4,199 行）在 **2026-08-25** 被删除**之前**，
> 从它们身上提炼出来的 **66 条**结论（A–I 组 63 条 + J 组量化历史 3 条）。提炼与删除在**同一个 commit** 里，依据是本仓归档规则
> 「**提炼完原件才可删**」（ai-ds-lab spec §11.2）。
>
> **⛔ 本文件不在 onboarding 必读链路里，也不该进去。** 它是**按需查**的检索型资产 ——
> 起手必读链路的真源是 [`docs/STATUS.md`](../STATUS.md) §起手必读链路，那里刻意不含本文件。
> 理由：这 66 条是「怎么走到这里的」，不是「现在该怎么做」；把它塞进必读面会直接加重
> [[INFRA-F58]] 正在盯的那个分母（五份规则文档当前 8,131 行）。
>
> **怎么用**：遇到「这个坑以前踩过吗 / 这条规则当初为什么这么定」时 grep 本文件。
> 命中后若发现某条**该升成机械闸或该进规则文档**，那是一次独立的改动，走正常流程。
>
> **出处怎么读**：每条末尾的 `<文件名>:<行号>` 指向**已删除的归档原件**。
> ⛔ 刻意写成纯文本、不做链接 —— 本仓约定「链接是活指针，裸文本是历史提及」，而那些文件已经不在了。
> 要看原文：`git log --diff-filter=D --  'docs/_archive/retrospection/*'` 找到删除 commit，
> 再 `git show <删除commit>^:docs/_archive/retrospection/<文件名>`。
>
> **提炼的已知不足（是边界，不是 TODO）**：
> 1. **有损压缩。** 66 条来自约 4,165 行（删前实测 —— ⚠️ 处方写的 4,199 是 pin 处的旧读数）；原文的具体现场（哪个 commit / 哪个 node id / 哪次对话）不进本文件。
>    git history 仍可查，但**不会被检索到** —— 这是删除的真实代价，刻意记在这里。
> 2. **裁决是单裁判 AI 做的**（lab 的 S2，`extract-then-delete` 32 份 / `delete` 2 份），
>    未满足 lab spec §6.1 铁律 1（三票须来自不同厂商/型号）⇒ **「哪些该提炼」这个判断不具备统计有效性**。
>    机械复核器只验裁决自洽 + 证据逐字可定位（35 份 / 108 条证据全过），**不验对不对**。
> 3. **没有任何闸能验证本文件的语义正确性。** 2026-08-25 实测：删那 34 份后
>    `audit:stale-anchors` 与 `audit:plan-lifecycle` 都仍 exit 0 —— 因为那 34 份**按构造就是「外部入站 = 0」**，
>    而「0 入站」正是它们被选中删除的理由。任何「引用方向」的闸在这里逻辑上封闭。
>    ⇒ 若日后发现某条提炼错了 / 漏了，从 git history 补，别指望闸会响。
>
> **§2.4 那 11 条（plan owner 行为约束）不在本文件** —— 它们**自称「必记入册」而实测从未入册**，
> 所以直接落进了 [`AGENTS.md` §plan owner 角色行为约束](../../AGENTS.md)（该节 9 → 20 条）。
> 那 11 条是**规则**（约束当下行为），本文件这 66 条是**结论**（解释历史判断）。

---

## A · 判据与测量有效性

| # | 结论 | 出处（已删归档原件） |
|---|---|---|
| A1 | **口径纪律**：审计余量（A 数）是相对「当前覆盖的 manifest」的，不是绝对健康度。覆盖面 backfill 会重置分母 ⇒ 跨段数字不可续接，必须**重取 baseline 而非估值** | 2026-06-02-wave1a…:25 |
| A2 | **「量错元素」既虚高也掩盖真 drift**：错误测量点上两边巧合相等 ⇒ 假 PASS。retarget 到正确元素会同时清幻影 + 暴露真问题；**数字只在拓扑对了之后才双向可信** | 2026-06-03-infra-f39…:70 |
| A3 | **判据 / 报告 bug 的三层核对**：`normalized JSON → audit JSON → markdown report`。⛔ 不要只看报告 grep 结果 —— 「报告为空 / 轴消失」多半是渲染层或**验证命令自身**的问题（起止 pattern 相同让 awk 立即结束、`-A1` 只抓到空行），数据其实在 | 2026-04-29-meta-rules…:196 |
| A4 | **「文件存在」不能算验证通过**：任何 `✅ xxx-match-via-*` 都必须有真实 evidence（CSS 值 / prop 枚举 / 变量链），否则是假阳性 | 同上 :191 |
| A5 | 修判据时**论证单调性**：只可能把 fail 变 pass、不可能反向的修复是安全的，可免全量回归 | 2026-06-02-wave1a…:16 |
| A6 | **fixture drift 是 silent failure**：写死 runtime 渲染文本的断言，数据漂移时不编译错也不运行错，只在跑测时报错 | 2026-05-13-vitest…:36 |
| A7 | **source-grep 测试测错了层**：断言源码里有某字面字符串，在页面重构成运行时渲染后必然失效；rendered-text 检查应走 mount-based 测试 | 同上 :44 |
| A8 | **分诊标准动作**：怀疑某改动引入回归时，`git stash -u && 跑测 ; git stash pop` 数秒给出确凿答案，**先做它再诊断** | 同上 :48 |

> A1 / A2 与 lab 后来独立得出的 N19 / E3 / N10 是同一件事 —— 归档里躺着的，是别人后来自己重新推导了一遍的方法论。这本身就是「只进不出的归档池」的代价。

## B · 规则的执行力（rule-hit / discoverability）

| # | 结论 | 出处 |
|---|---|---|
| B1 | **L1 文本规则 = 提示，L3 hook = 触发。** 客观可测的关键流程必须升 L3，文本规则不可替代机械触发 | 2026-05-13-onboarding-gate…:76 |
| B2 | **文本提及 ≠ checklist 显式步骤。** 文档顶部提过某个 SoT，不等于它进了起手必读的**编号清单** —— 前者会漏，后者才会执行 | 同上 :80 |
| B3 | **写下一条规则的下一秒就违反了它。** 这不是认知问题而是 execution discipline 问题：规则不会自动 enforce 自己，「规则放进 conventions 文档」≠「规则会被执行」 | 2026-05-09-microapps…:149 / :92 / :155 |
| B4 | **规则不能假设「机制 = 行为」**：机制存在（如 import 复用）不等于行为自动发生；规则要约束**行为**。⛔ 也不能因为「看似不会发生」就省略镜像规则 | 2026-05-11-m21-r6…:109 |
| B5 | discoverability 的一手证据：某份复盘自陈「应 grep 历史复盘看教训」这件事**不在任何协议里** —— 结论写下了，但起手不会被读到 | 2026-05-13-canonical-011…:58 |

## C · 写规则的方法论

| # | 结论 | 出处 |
|---|---|---|
| C1 | **写规则当下就在当前任务上 self-test**：新规则的首要验收标准是它能指导手头这个决策。在自己任务里都用不上 = 规则错或用得不到位 | 2026-05-11-m21-r6…:108 |
| C2 | **scope 显式标注**：把适用时序差（greenfield vs incremental）写进规则正文，避免后续误判适用范围 | 同上 :110 |
| C3 | **规则之间必须 cross-reference** + 优先级表写明谁 override 谁；一次错误可同时踩多条规则的盲点，单条补强不够 | 2026-05-11-trifecta…:80 / :72 |
| C4 | **反增生**：同一类偏差用一张 generic 维度检查表覆盖，而不是为每个新 case 追加一条规则 | 2026-05-12-evolution-step-1:22 |
| C5 | 规则措辞不应隐含「逐个 override 默认值」—— 那违反举一反三，也让 instance 失去 library 同步价值；写「**必须评估**」而非「必须改」 | 同上 :21 |
| C6 | **合并规则时保留 sub-number**（M11.1 / .2 / .3）而非删号，让历史 cross-reference 仍可解析 | 2026-05-12-evolution-step-2:22 |
| C7 | 规则措辞 **path-neutral 化**（「生成 deliverable / 采用 source 组件」），使同一条规则跨 Figma 与 code 两面适用 | 2026-05-12-evolution-step-3:29 |

## D · plan owner 行为约束 → **不在本文件**

那 11 条（D1–D11）已直接落进 [`AGENTS.md` §plan owner 角色行为约束](../../AGENTS.md)，该节 **9 → 20 条**。
它们与本文件其余各组的区别：**D 组是约束当下行为的规则，其余是解释历史判断的结论。**

## E · 完成声明与证据

> ⚠️ **E9 不在处方 §2 的表格里** —— 它是本轮执行时从 `2026-06-11-contrast-closure…:29`
> 现读出来的一条方法论结论，处方的分组漏了它。⇒ 处方 §2 的 106 条**不是穷尽的**，
> 提炼这件事本身也有 recall 缺口，⛔ 别把它当完备清单。

| # | 结论 | 出处 |
|---|---|---|
| E1 | **核磁盘实物，别信摘要**：subagent 摘要未提的越权改动，靠核 git log 才抓出 ⇒ 完成声明必须用磁盘 / git 实物复核 | 2026-06-30-dual-framework…:63 |
| E2 | **中间步骤成功 ≠ 链路成功。** 任何流程都要显式写出 final artifact 是什么，并有一步专门 verify 它 —— tag pushed / CI green / CLI exit 0 都只是 means | 2026-05-11-package-rename…:152 / :7 |
| E3 | **脚本返回无报错 ≠ 结果正确**：批量写操作先单例验证再批量，批量后立刻查计数核对实物（当次「运行成功」的脚本写错了页面，产生 44 个重复 frame） | 2026-06-01-source-type…:85 / :83 |
| E4 | **pickup / handoff 里写的「修法」若未被 gate 实证，一律当假设**：某次 pickup 的 `shadowRoot:false` 修法实测更糟（1 A → 134 A），spike 后才找到正解 | 2026-06-30-dual-framework…:106 |
| E5 | **review 的根因判断也要 probe 再信**：review 说「transition race」方向对但**位置**判错 ⇒ 凡另行定位读 computed style 的节点都要先 disable transition，不止 root。false-PASS 与 false-FAIL 同源于此 | 同上 :125 |
| E6 | **「我 grep 没找到」≠「不存在」**：下结论前必须覆盖全仓库（`tests/` + `scripts/` + `.husky/` + config，不止 markdown） | 2026-05-14-v040…:75 |
| E7 | 协议盲点是正常的，关键是暴露时**显式 patch 到机制层**，且**不 retrofit 历史叙事**掩盖错判 —— 错判要留作 baseline 实证 | 2026-05-11-package-rename… §5 |
| E8 | 错判会沿「上游文档这么写所以是真的」**链式信任**传播（曾跨 STATUS / 复盘 / pickup / CHANGELOG 四处放大，持续 1–2 周）⇒ **派生文档不能作为事实来源** | 同上 |
| E9 | **「等设计师 / 等 owner」类 entry 报给 owner 之前，先 live 复核它是不是 stale。** 实证：某批登记当天～次日就被 owner 自己修掉了，而 backlog 文字仍写「待设计师」—— owner 是并发编辑者，文档记载落后于实际产品态 | 2026-06-11-contrast-closure…:29 |

## F · 实验设计

| # | 结论 | 出处 |
|---|---|---|
| F1 | **baseline 接近天花板 ⇒ 实验没有区分度**，加难度不如换测量路径（某次白跑 2 轮才发现 A 路径自己就 8/8） | 2026-05-27-bridge-mockup-007…:128 |
| F2 | **双消费者的 SoT 必须两边都测**：「只跑一边等于只测一半」—— code 侧无增益不代表 mockup 侧无增益（实测差 44pp） | 同上 :131 |
| F3 | **扩量前先做小样对照**：不直接做 N× scope expansion，先花半小时跑 5–10 case 的 A/B，Δ 超阈值才扩量 | 2026-05-28-bridge-mockup-008…:93 |
| F4 | 当 AI 自由检索优于 SoT 时，根因通常是 SoT 的 **scope 洞**而非 schema 坏 —— 结论应是扩 scope | 2026-05-27…:134 |
| F5 | **baseline 实跑先于定路径**：backlog 的工作量估值必须标「估（假设）」vs「已验证」；真相与假设差 >2x 时 **STOP 重新 propose**，不要 fight 走完原路径 | 2026-05-11-bridge-mockup-004…:10 / :71 |
| F6 | 估时栏标「**实跑前不信**」，下一轮重估用上一轮实跑数据（本项目实测 4–8x 乐观偏差） | 2026-05-14-v030…:114 |

## G · 上下文经济学 / portability

| # | 结论 | 出处 |
|---|---|---|
| G1 | **「变薄」的实现取舍**：不删规则正文，而是在顶部加必读链路入口表 —— 理由是删除会打断历史 AI 依赖这些文件的 onboarding 路径。⚠️ 这条也是「归档池只进不出」的同源病灶，与归档出口规则并读 | 2026-05-12-evolution-step-3:28 |
| G2 | **早期 cold-start 观测**：新 session 只读 `design-process.md` + `domain-tvu.md`（约 16 条规则）即可覆盖约 **80%** 决策路径 —— 可作 cold-start 维度的历史锚点 | 同上 :37 |
| G3 | **portability 表述**：多 AI 工具在同一项目协作不互相破坏，关键是把规则「硬」在仓库里，而不是「软」在某个 AI 的 prompt 历史里 | 2026-05-11-v0-1-publish-flow:216 |
| G4 | **portability 兜底**：hook 只在单一 harness 生效，跨工具靠 L1 文本 + 项目契约文档兜底 ⇒ 机械触发与中立表达要**同时**存在，不能二选一 | 2026-05-13-onboarding-gate…:77 |
| G5 | **角色化而非工具化**：规则用 plan owner / executor 等角色表述，切换工具不需改任何规则文件 —— 这是可移植性最早一次成文 | 2026-04-29-meta-rules… §5 |
| G6 | 把散落在各份复盘「待办」段的问题集中成一份项目级 backlog 真源 —— 散落待办跨 session 检索成本高、易忘、无统一入口 | 2026-05-06-t2-sample…:110 |

## H · 具体技术约束（动手前必知，丢了会返工）

| # | 结论 | 出处 |
|---|---|---|
| H1 | **`audit:tokenized-diff` 断言 raw 与去 token 后的 tokenized 结构恒等**，tokenize 只能新增 token 字段 ⇒ 任何「把某字段置 null」的修法不能落在 normalize 层，只能落在 verifier 层 | 2026-06-03-infra-f39…:24 |
| H2 | **共享组件不得 emit no-op inline style**：`color: currentColor` 语义等于 inherit，但作为 inline style 具最高 specificity，会屏蔽所有外部 class 的 color 规则 ⇒ prop 未显式设置时不要 emit | 2026-05-07-phase-a4…:145 |
| H3 | **Vue 3.5 在 light-DOM 自定义元素模式下明确拒绝注入编译后 styles（只 warn）** ⇒ `shadowRoot:false` 必须配手动把 styles 注入 `document.head`；样式在 base 组件时还需额外声明样式来源 | 2026-06-30-dual-framework…:104 |
| H4 | **loader-shard 模式**：拆大 JSON SoT 成目录时，唯一知道磁盘形状的地方是一个共享 loader，把目录重组回旧的合并形状使消费方零语义改动；写操作必须幂等（`write(load())` byte-identical）；**拆分键必须选全值字段**，否则产生孤儿桶 | 2026-06-01-affordance-sot-shard…:16 / :24 |
| H5 | **并行 session 认知纠正**：同机同目录的并行 session **共享同一个工作树**，不存在「留给那个 session」；但基于起手 Read 快照直接改 dirty 文件会 clobber 在途工作 | 同上 :46 |
| H6 | **Figma**：`node.characters = newChars` 后旧字符样式按位置残留，必须先对 (0, len) 强制 reset 再逐 range 套用 | 2026-05-13-layout-a…:23 |
| H7 | 删 CSS 前**逐个**实证每个 icon 的 SVG fill 实际值（hardcoded vs currentColor），不用「这类都是 X」的类别化假设 —— 当次误删导致视觉回归 | 2026-05-07-phase-a4…:137 |
| H8 | **构建工具的 alias 解析 ≠ 审计脚本的静态 text-grep**：同一个 alias 概念在两套系统里独立处理，审计脚本会因此**长期静默失效**（那条 regex 自写出来就 broken，因构建侧照常跑通所以无人发现） | 2026-05-08-phase-x4-2… §阶段 C |
| H9 | **本地发布前置链跑过 ≠ CI 一定过**：Node 版本差异会在 module load 期就 SyntaxError（try/catch 来不及兜底）⇒ 脚本只用稳定 stdlib，或 dynamic import + 兜底 | 2026-05-18-v050…:60 / :102 |
| H10 | 真源 migration 时，**所有引用该真源命名的代码点都要 grep 一遍修全**（token-aliases / divergences / prop-aliases），不能只修 extract 输出端 | 同上 :81 |

## I · 流程机制

| # | 结论 | 出处 |
|---|---|---|
| I1 | **audit gate 的 `warn-only` 有两种语义**：「基线 FAIL 等修复」与「**预期长期状态、由某 tracker 维持**」。后者必须在 gate 表备注「由谁维持 + 升级触发条件」，否则读数无法解释 | 2026-05-11-bridge-mockup-004…:102 |
| I2 | **audit gate 分层**（strict / warn-only）：strict 走发布前置链任一 fail 即阻断，warn 走独立步骤 continue-on-error；升级只需一处改动 | 2026-05-11-v0-1-publish-flow §工程技巧 5 |
| I3 | **pre-flight gate 写否定式判断**：列「哪几类 dirty 触发 STOP」，而不是要求「全工作树 clean」—— 后者必被无关 dirty 打破 | 2026-05-14-v030…:130 |
| I4 | **SoT drift 的链式传染**：resolved 只更新一处、下游复制时没 cross-check、再下游沿用 stale —— 每步都合理，链路上没人 cross-check ⇒ **派生段不是真源，必须有机械 cross-check gate 而非文本规则** | 同上 :134 |
| I5 | **destructive 操作判断框架**：按「实物影响 + 历史可追 + 可重做 + 替代成本」四维判断，而不是「看上去 destructive 就绕」 | 2026-05-13-v020…:84 |
| I6 | **scope creep 的可接受边界**：同 commit + 同 pattern + 同 user pain → 顺手扩 OK；换 pattern 或产生新 deliverable → 不扩 | 同上 :105 |
| I7 | **「真源 + 持续 drift 检测」模式**：SoT 一次 author 完后不再依赖人工对照，上游任何改名 / 增删由 sync pipeline 的 drift gate 自动报警 | 2026-05-28-bridge-mockup-008…:97 |
| I8 | **memory / 决策的实证完成即 closure 触发器**：不应永久保留「待某端改名」这类 open-ended action | 同上 :101 |
| I9 | **cascade 边界原则** + canonical 新组件的 **export wiring 完整清单（8 项）**，历史最易漏 `src/canonical/index.ts`（它是 `audit:published-vs-code` 的真源依赖） | 2026-05-13-canonical-011…:51 |
| I10 | **tracker entry 范式**：单一 task entry 工作量爆炸（>2x 估值）且可自然拆分时，改为 tracker + child entries，写明 Resolved 条件与关联 gate 升级动作 | 2026-05-11-bridge-mockup-004… §工程技巧 1 |
| I11 | **写 `:deep` CSS override 前先枚举 child 的所有 layout state**（Normal / Error / Loading / Disabled）再决定 align-items；默认 flex-start 比 center 鲁棒 | 2026-05-09-f23…:59 |
| I12 | **gate scope 诚实界定**：canvas 内像素无法经 `getComputedStyle` 自省 ⇒ 该 gate 只覆盖容器 / 主题 token，**必须写明**而不是让读者以为全覆盖 | 2026-06-30-dual-framework… |

## J · 量化历史（重建成本高，刻意留数）

⚠️ 下面三条是**当时的实测值**，不是当前状态。引用前先自己重测。

1. **v0.2–v0.5 估时偏差 3–8x**；**release CI 一次过率约 60%（3/5）** ⇒「本地全绿」不能替代 release CI 这道门
   （2026-05-18-v050…:102 · 2026-05-14-v040…:97）
2. 一次三轮 A/B 对照实验的完整读数：**v1 0pp / v2 0pp / v3 +44pp**（阈值 30pp），含 8 题逐题评分
   （2026-05-27-bridge-mockup-007…）
3. 「tracker 估时往后可以 ÷ 4 作 baseline」（2026-05-14-v040…:101）

---

## 附：删除批次与同批约束（2026-08-25 执行记录）

删除按归档内互引边分批，括注「同批」的必须同批删否则留死链：

| 批 | 内容 | 份 | 约束 |
|---|---|---:|---|
| B1 | `2026-05-12-evolution-step-4` + `step-5` | 2 | 唯一两份 `delete`（产物全在 repo 外）；先删这批校准闸的信号 |
| B2 | `evolution-step-1/2/3` + `2026-05-09-microapps-mockup-retrospect` | 4 | 同批（step-2→1、step-3→2，且 step-2/3 → microapps）；B1 须在 B2 之前或同时 |
| B3 | `2026-05-11-package-rename-scope-alignment` + `2026-05-11-v0-1-publish-flow` | 2 | 同批（前者把后者当 baseline 实证引用）。⚠️ 后者含**已被推翻的假断言**，提炼时已注明 |
| B4 | `2026-05-08-phase-x4-2` + `2026-05-07-phase-a4-deep-debug` + `2026-05-06-t2-sample-extension` | 3 | 同批（x4-2→a4→t2-sample）；含 D1–D9 那批未入册约束，已先提炼进 AGENTS |
| B5 | `2026-05-27-bridge-mockup-007` + `008` + `2026-05-11-bridge-mockup-004` | 3 | 同批（008→007） |
| B6 | `2026-05-13-v020-release-and-infra-f30` + `2026-05-13-canonical-011-prompt-gap` | 2 | 同批（v020→canonical-011） |
| B7 | `2026-05-11-mockup-conventions-trifecta-rule-update` | 1 | ⚠️ **必须同时改** `2026-05-11-saas-dashboard-2-option-pm-review.md:3`（live-source，保留）里指向它的 markdown 链接 |
| B8 | 其余单件（`m23-18` / `contrast-closure` / `layout-a` / `tier1a-translation` / `wave1a` / `affordance-sot-shard` / `vitest-fixture-drift` / `infra-f39` / `onboarding-gate` / `m21-r6` / `source-type-mockup-batch` / `v050-release` / `f23-formitem` / `dual-framework` / `v040-release` / `v030-release` / `2026-04-29-meta-rules`） | 17 | 无同批约束 |

**合计 34 份 / 4,199 行删除。** 保留 19 份 / 3,325 行 = 18 份 live-source（有外部入站引用）+
process-gap-report-2026-06-11（判 `hold-for-human`：内含 4 条 owner-gated 未决项，⛔ 归档池不该装未闭合决策）。**⇒ 2026-08-25 后续**：那 4 条（B3 / B5 / C2 / C3）已全部由 owner 拍完 —— **裁定留痕各归其位，⛔ 不在 STATUS**（那条已按「只留未完成项」移除）：**B5** = [`design-process.md`](./design-process.md) §跳步规则 US-3 行下 · **C3** = [`meta-rules.md`](../meta-rules.md) §触发器 N 触发条件段末 · **B3** = M23.0 卡表 `Acceptance` 必填行（已落地，无需改动）· **C2** = `audit:variables-freshness` 的 L4+L5 挂载已覆盖该场景（补 `WRAP-UP.md` 的 L1 checklist 属降档）。**该报告随即删档**（删前逐行核过 §五 Action List：11 行里恰好只有这 4 行没有 ✅/❌ 结论标记 ⇒ 无其它未闭合决策）。本行的文件名刻意写成**裸文本**，因为它已不存在。

**执行前的机械核对（2026-08-25 在落地 HEAD 上重跑 lab 的 `ds-doc-graph`，⛔ 不用 pin 处的旧读数）**：
`_archive/retrospection` 53 份中外部入站 = 0 的恰好 **35 份 / 4,665 行**（34 待删 + 1 hold）；
现行层（排归档、排 worktrees）对这 34 份的引用**实测零命中**；归档内部会成死链的**只有 B7 那 1 处**，已同批修。
