# 2026-07-31 复盘 — 判据要量「墨」不是量「盒」· entry 的转述不可信 · 新闸落地的豁免表范式

> **触发**：WRAP-UP §Retrospection 判断表的「学到通用工程经验 / 发现新 pattern」。
> **本轮范围**：合并两条并行 session 的续跑清单 → 做完其中零-owner-输入的 5 项 → owner 拍板后按 Figma 真源修完两条新闸抓到的真缺陷。
> **commits**：`03fe0a6f` `1daa875d` `1d43c7d4` `2d5735bd` `1aac3ff8` `1a91a66f` `3815cbba` `94df3848`

---

## 1. 教训：backlog entry 里「自己对自己修法的转述」是二手源，本轮两次被实测推翻

硬规则 #10 说的是「判断仓库/远端当前状态前先读活源」。本轮暴露出一个更细的面：**entry 里那句「怎么修 / 修完会怎样」也是二手源**，它写的时候是**预测**，读的时候容易当成**已验证的结论**。

| entry 原话 | 实测 | 代价 |
|---|---|---|
| F67 (c-1)：「按 2026-07-29 数据，加谓词后 **14 条残余全部出桶** → 桶归零 → 可翻阻塞」 | 照它实现完，**3 条落进阻塞桶**（`label.form-item__label` ×2 + tabs 卡） | 差点把「判据误报」当成「存量债务」塞进豁免表 |
| F67 (c-3)：`.try-button` 的 border「badge 用 `--line-divider-light`、table 用 `--line-light`，同一个类两个 token」 | 两者**解析值逐字相同**（`variables.css` 里 `--line-divider-light: var(--line-light)`，两主题实测 dark #434343 / light #cccccc） | 我据此对 owner 报了「已经分叉、胜者由加载顺序定」，**是误报**；owner 因此被要求做一个并不存在的 token 语义裁定 |

⚠️ 第二条特别值得记：**那句误报是我自己写进 entry 和 commit message 的**，一轮之后又被我自己当依据引用。二手源不只来自别人，**也来自上一轮的自己**。

**可操作判据**：entry / commit message / handoff 里凡是「加了 X 之后会归零 / 这两处已经分叉 / 这条依赖那条」这类**含预测或含因果**的句子，动手前必须自己跑一次拿到基线数字，或去读 token/实现活源。措辞上也要自律：写「预计」而不是写成既成事实。

---

## 2. 新认知：判据要量「墨」不是量「盒」

F67 (c-1) 首版之所以出 3 条假阳，根因**不是**谓词选错，而是**测量对象错**：用 `getBoundingClientRect()` 递归取「内容右缘」，把**透明包裹层的空盒**也算成了内容。

- `label.form-item__label` 溢出 3.2px 进 `div.form-item__content`，而后者 `background-color: rgba(0,0,0,0)` —— **遮不住任何东西**，2026-07-29 的人工三倍放大也判过「字形完整可读」。
- tabs 卡按盒子量溢入 **29.9px**、按墨量只有 **13.9px** —— 两个数字都对，但只有后者对应「读者看不到的像素」。

**落地判据 = ink 右缘（文本 `Range.getClientRects()` + 自身真绘制的后代）+ 遮挡方 `paints()` 成立**（不透明背景 / 背景图 / 边框 / replaced element）。

**通用化**：凡是判「用户是不是真的看不到」，度量必须落在**会产生像素的东西**上——盒模型、`scrollWidth` 这类几何量只是线索。同源反例是同一条 entry 早就否掉的两个诱惑：按 Δ 设阈值（Δ 5–75px 与「是否真丢内容」零相关）、加 jitter 容差（16/16 实测 `jitter=0`）。

---

## 3. 验证有效的范式：新闸落地时用「具名 + shrink-only 豁免表」，并让闸自己宣布修完

本轮两条新闸**落地当天就各自抓到真缺陷**，而修法都触 `.css` → 撞 `.husky/pre-commit` 的视觉门（`VISUAL_COMMIT_APPROVED=1` 只有 owner 看过截图才能设）。三个选项里：

| 选项 | 后果 |
|---|---|
| 直接让桶阻塞 | 在 owner 过目前**封死所有人的提交** |
| 放宽判据让它绿 | 又变回一个不响的闸（本轮要治的正是这个） |
| **具名 + 带日期 + 带根因与修法方向的单条豁免，新缺陷照样红** | ✅ 采用 |

配套的关键一笔是 **S2「只许缩」判据**：豁免条目**不再命中时闸会 FAIL 并点名要求删行**。它带来两个实证收益：

1. 修完后**不是我手动宣布「修好了」**，而是闸报出「这些条目已经不碰撞了，请删行」——**完成由机制确认**，符合「完成声明必须有可复核证据」。
2. 修好的洞不会留成一个永久吸收下次同名回归的缺口。

范式来源 = `tests/visual-baseline-coverage.test.ts` 的 `KNOWN_MISSING_BASELINES`（F86② 那轮）。**本轮两条豁免表都在当天清空 = 正常终态，不是待办**。

---

## 4. 新认知：Figma 真源可以把「修法选项」直接砍到只剩一个

owner 对两处都只答了「以 Figma 真源为依据修改」。原以为这需要 owner 再选一次形态（换行？横滚？给宽度？），实测**真源本身就排除了另外两个**：

`figma-data/raw/components/tab_list__4452_7148.json` 变体 `Type=Line` node `4605:7196` —— root `w: 325` / `gap: 24` / `layoutMode: HORIZONTAL` / `layoutSizingHorizontal: FILL` / **无 `layoutWrap` 字段**；三个 Tab/Item 固定 93 + 92 + 92 = 277，加 2×24 = **325，与实测所需宽度逐字相符**。

- 设计里**没有换行** → 「让 tab 行换行」= 造 Figma 没有的形态；
- 设计里**没有横滚** → 「套 `overflow-x:auto`」同上（`docs.css` 那段注释早就写着 never wrap a live component in a scroll box）；
- gap 24 本身就是真源 → **不回退**。

**通用化**：遇到「A 还是 B」型修法分叉，先去真源里找**否定证据**（有没有这个字段 / 这个形态），往往不需要拍板就只剩一条路。同理，token「哪个名字对」不靠投票也不靠多数派，去 `token-aliases.ts` 的双向映射看**哪个名字有 Figma 名**（`--line-light` 有、`--line-divider-light` 没有）。

---

## 5. 踩坑（工具面）：并行仓库里不要用裸 `git stash pop` 当探测手段

想确认一条 tsc 报错是否既存，用了 `git stash push -- <path>` + `git stash pop`。两处出错叠加成事故：

1. 前一条命令里的 `cd react-pilot` **cwd 残留**，使 pathspec 变成 `react-pilot/react-pilot/...` → `stash push` **什么都没 stash**（报 pathspec 不匹配）；
2. 紧随的 `git stash pop` 于是弹出了**并行 session 留下的 `stash@{0}`**，在 `docs/internal/design-process.md` 造成 `UU` 冲突。

已复原：`git checkout HEAD -- <path>` + 核 `git diff --quiet HEAD` 逐字节一致，两个 stash 条目均未丢（pop 失败时条目会被保留）。

**纪律**：① 读旧版本用 `git show HEAD:<path>`，不要动 stash；② 复合命令里的 `cd` 会残留到后续 Bash 调用，凡跨目录操作一律用绝对路径；③ 这条与既有 memory `git-index-shared-across-sessions` 同源 —— 并行仓库里**任何隐式操作全局状态的 git 命令**（index / stash / HEAD）都要先确认目标明确。

---

## 6. 一处流程订正：「暂缓」与「前提已不存在」必须分开写

两份并行 session 的续跑 prompt 都写着「Task 1 + Task 10 = 两次 tag push，owner 定不着急发版 = 暂缓非取消」。实测 Task 1（用 `1.1.2` 作纯文档最小载荷先验发布链）的**两条前提都已不存在**：`changeset:status` 算不出 patch（待发条目里有 minor），且 Task 6–9 的 code 早已在 master —— 按它发 = **用 patch 标签把一批 minor 内容发出去**，比不发更糟。

**通用化**：卡在 owner 手里的条目，收尾时要区分「**等一句话**」与「**这条路已经不通**」。前者原样留着，后者必须当场标作废 + 写判据，否则下一个 session 会把一条死路当活路捡起来（本轮前一天就已实测出这一点，但只记在归档里、没落到计划本体，于是被两份 prompt 同时继承）。
