Skip to content

Commit 091d1c3

Browse files
committed
docs(spec): close out primitives batch four
1 parent 199da54 commit 091d1c3

5 files changed

Lines changed: 438 additions & 0 deletions

‎docs/adr/ADR-033-l1-primitives-and-view-layer-contract.md‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,11 @@ ADR-032 交付了 token 层(色阶 / 字阶 / z-index 标尺 / 图标),但
8989
(首个落在 `Surface.css`,`Button.css` 是第二个)· `:disabled` 与 `[aria-disabled="true"]` 的统一视觉降级 ·
9090
`cursor: not-allowed` · `:disabled` 移出 Tab 序而 `busy` 保留焦点(`aria-disabled` + `aria-busy`)。
9191

92+
> ⚠️ **批 4 收口就地加注 · §4 的「行内 style 禁令」自何时起有真实输入(2026-09-12;**上面原文一字未改**)**:
93+
> - 本条禁令(「调用点不得用行内 `style` 覆盖类的底/圆角/边框」)在批 0-D 落笔时**对真实代码是空真的** —— 当时全仓 `<Surface>` **0 个**。批 4 的 `69489f9f`(`refactor(ui): migrate card borders to surface`)**第一次真正使用 `Surface`**:14 个 `<Surface>` 开标签,机器判据(`surfaceRatchet.test.ts` ⑦)实测**覆盖命中 0**;同一提交把 `FROZEN_SURFACE_TAG_TOTAL` 由 **0 → 14**(T17-A 冻结的「零」是**故意的空真登记**,一迁移就会红)。⇒ 本条禁令**自 `69489f9f` 起有真实输入**。
94+
> - **已知边界(诚实登记,不得读成「判据完备」)**:⑦ 的文本级启发式只认 `style={{ … }}` **字面对象** ⇒ `style={S}` / `style={pick()}` 这类**间接写法是假阴**(写在 `overridesSurface()` 的文档注释里)。批 4 迁移的 14 处**全是直接形态**,故对本批读数无影响 —— 但**下游若用变量间接给 `style`,棘轮会漏**。
95+
> - **同源的两条原语缺口(批 4 实测,登记为 follow-up 而非本批动作)**:① `SurfaceProps` 无 DOM 属性透传(`onClick`/`id`/`aria-*`/`data-*`/`dangerouslySetInnerHTML`/`ref`)⇒ 至少挡住 3 处已点名 + 未来 21 处;② `Surface` 基类**必出底色**、无「只出边框」档 ⇒ 挡住 **28 处**透明边框容器。两条都属「批 5 与视图层一并裁」(B22 第 3 条)。
96+
9297
### 5. 动效接缝契约:`[data-phase]` 三态 + `usePresence` + 时长变量名
9398

9499
- **相位协议**:`enter`(已挂载的起点态,等一帧让过渡起步)→ `entered`(终态)→ `exit`(退场中),
@@ -151,6 +156,14 @@ ADR-032 交付了 token 层(色阶 / 字阶 / z-index 标尺 / 图标),但
151156
**消费者不得自建第二套** —— `ConfirmDialog` 已按此改写(无 `createPortal` / 无 `zIndex` / 无文档级键盘监听,
152157
有源码与 CSS 扫描断言钉住),批 4 的 28 个手写弹层迁移后同样不得保留自己的遮罩与 `window` ESC 监听。
153158

159+
> ⚠️ **批 4 收口就地加注 · 本条契约的「适用对象」与三口径并列(2026-09-12;**上面这段原文一字未改**)**:
160+
> - **适用对象 = 对话框类(`role="dialog"` 那一类),不是「一切手写浮层」。** 上句「批 4 的 28 个手写弹层」是**本 ADR 落笔时(批 0-D / 批 4 开工前)的合计口径**;批 4 的实际执行按控制方 **B1/B2** 分成了「迁」与「不迁」两支:
161+
> - **迁(验收口径 = 20)**:`role="dialog"` 20/20 —— 20 个文件全部只经原语(barrel 含 `Modal` ∧ 无深导入 ∧ 无自建遮罩 ∧ 无 `keydown` ∧ 无裸 z-index),`role="dialog"` 的**源码命中**只出现在 `ui/primitives/Modal.tsx` 与已登记例外;构成 `A14 + B4 + E2` 钉在 `dialogMigration.e.test.ts` 的 `DIALOG_20`。
162+
> - **不迁(14)**:**11 个锚定菜单**(`BrowserChrome` · `GroupRowContextMenu` · `GroupSidebarRow` · `NoteHeaderActions` · `NoteListBatchMenu` · `NoteMoveToGroupMenu` · `NoteRowContextMenu` · `RouteInfoPopover` · `SessionRowContextMenu` · `chat/ChatLaunchMenu` · `note-selection/SelectionActionMenu`)**只落 `popover(200)`**;**3 个采集/预览覆盖层**(`CaptureOverlayPanel` · `ImagePreviewOverlay` · `ScreenSelectOverlay`)**保留裸值并逐条带理由**。这 14 个**仍须登记在案**(不许从账本里消失),且**不得 import 原语层**(两条硬守卫:`dialogMigration.e.test.ts` ② + `buttonMigration.test.ts` ④)。
163+
> - **三口径并列(互不替代)**:**20**(本 ADR 上文「20/20」的验收口径 = 对话框类)· **28**(本 ADR 这句的**同行口径**)· **34**(**跨行容忍口径**:把 `position:fixed` 与 `inset:0` 分写两行的形态也算进来)。**等式**:`34 − 20 = 14 = 11 锚定菜单 + 3 覆盖层`;`28 ⊆ 34 ∧ |28| = 28 ∧ 28 == 34 − 6`(机器判据在 `dialogMigration.e.test.ts`)。
164+
> - **本条的 ESC 残留纪律仍然有效且已结清登记**:上句「5 处属批 4 迁移时必须一并处理的残留」——批 4 的处置是**逐条登记、不修**(B1:改它们 = 改菜单退出语义,属批 5/8):`note-selection/SelectionActionMenu.tsx:78` 的 `window` **捕获相**监听 + 4 处元素级 `onKeyDown`(`GroupSidebarRow` / `LinkEntityPicker` / `SessionDetailHeader` / `SessionListRow`)。⇒ 本 ADR 的「必须一并处理」**应读作「必须一并登记并给出不修的理由」**,不是「批 4 必须改掉它们」。
165+
> - **§7 的 z-index 面**:批 4 已完成整段迁移 —— 裸数字 **58 处 / 43 文件 / 17 值 → 3 处 / 3 文件 / 3 值**(全部是上述 B2 例外);六档标尺 6 个值(`raised 10` / `panel 100` / `popover 200` / `modal 300` / `modalNested 400` / `toast 500`);**有意值收敛**(`50/51/60/999/1000/1100/1150 → modal(300)` · `30–61 → popover(200)` · `900 → panel(100)`)是**可见观感变化**,已在规格 §11-2 与 `docs/versions/v0.22.md` 批 4 节 durable 登记。
166+
154167
两条实现口径(踩过坑,勿再犯):
155168
- **ESC 的"最内层"判定必须用 React 树深度**(`ModalDepthContext`):实测**朴素入栈序**(React effect 自底向上)
156169
与 **DOM 序**(portal 插入序会反转)都会把外层当成栈顶;最内层 `stopPropagation()` 只能拦住 `document`/`window`

‎docs/adr/ADR-034-l2-shell-navigation-and-column-contract.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,11 @@
120120
- `scripts/**/*.mjs` 与 `app/vite.config.ts` 不在 `line-limits` 扫描域 · `check-bundle-budget.mjs` 未接 CI:**批 8**。
121121
- 「会话详情头改粘性」与「笔记工具栏三层合并为单行」(规格 §6.2「本次改动」列的两条):**批 3 未做**,登记给**批 4/批 5**。
122122
> ⚠️ **加注④(2026-09-12 批 4 前置对码 · 原 `:115`;原文一字未改)**:这两条在**批 4 计划的 19 个任务里无人承接**(T0 对码报告 §四 · S-4:登记 ≠ 承接,批 3 已因此丢过一次)。🔴 **控制方 2026-09-12 已裁:由 T18 收口承接、或按批次归属登记**(本 ADR 不代裁去向,只写明这条裁决)。在 T18 落定前,本行**保持「批 4/批 5」的登记不变**。
123+
> ⚠️ **加注⑦ · T18 的处置(2026-09-12 批 4 收口 · S-4 结清;上面两条加注的原文一字未改)**:🔴 控制方裁决给了两条走法 ⇒ **T18 选后者:按批次归属登记为「批 5(视图层样板)」的 follow-up,并明确它**不是**批 4 的交付。**
124+
> - **事实核对(两条都可复现,不是推断)**:批 4 的 **48 个提交**里**没有**任何一条做这两件事 —— ① `git diff 4905d4d8^..HEAD -- app/src | Select-String '^\+.*(sticky|粘性)'` ⇒ **空**(`components/session-detail/SessionDetailHeader.tsx` **确实在本批改动集里**,但那是 T15/T16-B 的 `StatusLine`/`Text` 迁移,**与粘性头无关**);② `git show HEAD:app/src/pages/NotesPage.tsx | Select-String 'Toolbar'` ⇒ **空**(三层工具栏**一处未合并**)。⇒ 上句「登记给批 4/批 5」里的**批 4 一支已空转**(T0 的 S-4 警告「登记 ≠ 承接」**第二次应验**)。
125+
> - **归属:批 5**(视图层样板 = `viewRegistry` / 会话 4 视图 / 笔记 3 视图 / 惰性挂载)—— 两条都是**页面/面板结构**改动,与批 5 的对象-视图矩阵同面;**若批 5 未做 ⇒ 回落批 8 治理收口**(与批 3 follow-up #15 的处置一致)。
126+
> - **代价(若一直不做)**:详情头不粘性 ⇒ 长转写滚动后失去上下文锚点;工具栏三行不合并 ⇒ 垂直空间被占(属**观感/可用性**债务,不是正确性债务)。
127+
> - **注册位置**:批 4 计划 §收口回写 §七 follow-ups(逐条具名归属)· `docs/versions/v0.22.md` 批 4 节「未做登记」。
123128
- 批 4 从本 ADR 接手的壳层残留:`shell/CommandPalette.tsx`(自建遮罩/Esc/焦点 → `Modal`)· `shell/ShellFallback.tsx`(→ `Loading`/`StatusLine`)· `App.tsx` 的 AI toast(→ `Toast`)· `App.tsx` 对话面板的裸 `zIndex: 900`(→ `panel`)——**逐条见批 4 计划的任务总表**。
124129

125130
## 加注⑤ · 本次新增的两条守卫 + T0 报告 §四 五条建议的登记(2026-09-12 批 4 前置单元)

0 commit comments

Comments
 (0)