Skip to content

Commit 129b819

Browse files
committed
docs(spec): 更正 pinnable 取值与字号越界读数
1 parent a53fb50 commit 129b819

3 files changed

Lines changed: 13 additions & 11 deletions

File tree

‎app/src/ui/primitives/textBaseline.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ export const RESIDUAL: readonly { file: string; kind: TextResidualKind; reason:
171171
* 相对 `app/src` 的正斜杠路径 → 该文件**允许残留的字号越界处数上限**(只许降,键不许新增)。
172172
* 交给**批 5/6** 的工作量底稿:映射规则 `9/10/10.5/11/11.5 → 12`(`11.5` 仅在 `font="mono"` 时合法
173173
* —— 六档字阶的 s6 就是 11.5,仅用于数字对齐);逐文件明细见 `tmp/t16a/slice.md`。
174-
* ⚠️ T16-B **未动本表**:迁移时越界值一律**原样留在行内**(R2:只登记,交批 5/6)⇒ 558/120 不变。
174+
* ⚠️ T16-B **未动本表**:迁移时越界值一律**原样留在行内**(R2:只登记,交批 5/6)⇒ 551/120 不变。
175175
*/
176176
export const FROZEN_FONT_OOB_BY_FILE: Readonly<Record<string, number>> = {
177177
"components/AiConversationDock.tsx": 7,

‎docs/standards/line-limit-exemptions.md‎

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -210,21 +210,21 @@
210210
> ⚠️ **来源标记:本节是人工维护的记录块,非机器生成** —— 数值写成 Markdown **引用行**(`> - ` 起首,形如 `> - 文件:**N**`),而 `parseTable()` 只认 4 列 `| path | N | … |` 表行(引用行一律忽略);且本块位于 `## 已拆分` 标题**之后**,`parseHistory()` 对该节**逐字保留** ⇒ `--write` 永远既不重算也不删除它,数值过期后**没有任何门禁会报警**(2026-09-11 已发现 Loading / StatusLine 共 6 个值过期,实测更正)。
211211
> **刷新规则:本节与 `docs/adr/ADR-033-l1-primitives-and-view-layer-contract.md`、`docs/superpowers/specs/2026-09-11-frontend-redesign-design.md` 三处副本不一致时,一律在 HEAD 按 `countLines()` 口径(含空行)重新实测,并以实测值同步全部副本。机器锚点:三处副本的每处数值行后紧跟一行 HTML 注释 `<!-- line-count-src: files=… caliber=… authority=… -->`,供门禁按 `files=` 逐个在 HEAD 重测、与相邻数值行对拍 —— 锚点内**刻意不写数值**,否则等于又造一份手抄副本。**
212212
>
213-
> **新建目录 `app/src/ui/primitives/` 下 42 个文件**(实测行数口径 = `scripts/line-limits.mjs` 的 `countLines()`,即含空行的全部行数;**最大 297**):
214-
> - `Text`:`Text.tsx` **89** · `Text.css` **46** · `Text.test.tsx` **130**
215-
> - `Surface`:`Surface.tsx` **97** · `Surface.css` **73** · `Surface.test.tsx` **168**
216-
> - `Button`:`Button.tsx` **132** · `Button.css` **92** · `Button.test.tsx` **286**
217-
> - `Modal`:`Modal.tsx` **188** · `Modal.css` **81** · `Modal.test.tsx` **296** · `Modal.exit.test.tsx` **91** · `useFocusTrap.ts` **122** · `useFocusTrap.test.tsx` **236** · `ime.ts` **18** · `ime.test.ts` **32**
218-
> - `ConfirmDialog`:`ConfirmDialog.tsx` **192** · `ConfirmDialog.css` **58** · `ConfirmDialog.test.tsx` **297**
219-
> - `Toast`:`Toast.tsx` **210** · `Toast.css` **65** · `Toast.test.tsx` **249** · `Toast.interrupt.test.tsx` **167** · `Toast.style.test.ts` **132**(⚠️ 这 4 个 `Toast.*` 在本次收尾期间由 **T9 补正实施者**并行修改,已落入 `6cb44424`;上面数值与该次提交逐格一致)
220-
> - `EmptyState`:`EmptyState.tsx` **127** · `EmptyState.css` **81** · `EmptyState.test.tsx` **276**
213+
> **新建目录 `app/src/ui/primitives/` 下 42 个文件**(实测行数口径 = `scripts/line-limits.mjs` 的 `countLines()`,即含空行的全部行数;**最大 299**):
214+
> - `Text`:`Text.tsx` **119** · `Text.css` **58** · `Text.test.tsx` **171**
215+
> - `Surface`:`Surface.tsx` **98** · `Surface.css` **85** · `Surface.test.tsx` **175**
216+
> - `Button`:`Button.tsx` **132** · `Button.css` **100** · `Button.test.tsx` **286**
217+
> - `Modal`:`Modal.tsx` **260** · `Modal.css` **81** · `Modal.test.tsx` **296** · `Modal.exit.test.tsx` **91** · `useFocusTrap.ts` **122** · `useFocusTrap.test.tsx` **236** · `ime.ts` **18** · `ime.test.ts` **32**
218+
> - `ConfirmDialog`:`ConfirmDialog.tsx` **202** · `ConfirmDialog.css` **58** · `ConfirmDialog.test.tsx` **297**
219+
> - `Toast`:`Toast.tsx` **257** · `Toast.css` **76** · `Toast.test.tsx` **249** · `Toast.interrupt.test.tsx` **167** · `Toast.style.test.ts` **134**(⚠️ 这 4 个 `Toast.*` 在本次收尾期间由 **T9 补正实施者**并行修改,已落入 `6cb44424`;上面数值已按批 6 T16 实测刷新,该次提交时的登记值为 **210 / 65 / 249 / 167 / 132**)
220+
> - `EmptyState`:`EmptyState.tsx` **170** · `EmptyState.css` **103** · `EmptyState.test.tsx` **276**
221221
> - `Loading`/`Skeleton`/`Probe`:`Loading.tsx` **105** · `Loading.css` **79** · `Loading.test.tsx` **238**
222222
> - `StatusLine`:`StatusLine.tsx` **94** · `StatusLine.css` **42** · `StatusLine.test.tsx` **267**
223223
> - `usePresence`:`usePresence.ts` **200** · `usePresence.test.tsx` **282** · `usePresence.node.test.ts` **71**
224-
> - 接缝 / 导出面 / 守卫:`motion.css` **74** · `index.ts` **45** · `style-seams.test.ts` **271** · `style-contract.test.ts` **214** · `motion-coverage.test.ts` **147**
224+
> - 接缝 / 导出面 / 守卫:`motion.css` **271** · `index.ts` **48** · `style-seams.test.ts` **299** · `style-contract.test.ts` **296** · `motion-coverage.test.ts` **186**
225225
> <!-- line-count-src: files=app/src/ui/primitives/motion.css,app/src/ui/primitives/index.ts,app/src/ui/primitives/style-seams.test.ts,app/src/ui/primitives/style-contract.test.ts,app/src/ui/primitives/motion-coverage.test.ts caliber=countLines@scripts/line-limits.mjs authority=HEAD-remeasurement -->
226226
>
227-
> **★ 一次真实的口径事件(记在此以免被当成"新文件登记豁免"的先例)**:收尾实施者最初把 Task 14 的全部守卫**追加**进 `style-seams.test.ts` ⇒ 该文件涨到 **340 行 > 300**,`--full` **exit 1**(`(c) 超过 300 行但未登记`),**会拦下全仓所有人的提交**。处置**照批 0-D 裁决**:**不用 `--write` 登记豁免**(登记表/棘轮是给**存量**文件的历史债机制),而是**按语义拆** —— 「原语 CSS **文本**反例」(零颜色字面量 · `--ed-stamp` 不作底色)留在 `style-seams.test.ts`;「**跨文件**契约」(CSS 接线 · 联合契约锚 · 退场时长三方对拍)落 `style-contract.test.ts`;「**reduced-motion 覆盖**」(基类名单 · **动画落点含伪元素**)另立 `motion-coverage.test.ts`(T11 评审 Critical 修好后追加的那条守卫再次逼近 300 行红线,遂二次按语义拆)。三个文件 **271 / 214 / 147** 行、职责写进各自 `@ai-context` 文件头,T3/T4/T12 已追加的 describe **逐条保留**(追加式演进)。
227+
> **★ 一次真实的口径事件(记在此以免被当成"新文件登记豁免"的先例)**:收尾实施者最初把 Task 14 的全部守卫**追加**进 `style-seams.test.ts` ⇒ 该文件涨到 **340 行 > 300**,`--full` **exit 1**(`(c) 超过 300 行但未登记`),**会拦下全仓所有人的提交**。处置**照批 0-D 裁决**:**不用 `--write` 登记豁免**(登记表/棘轮是给**存量**文件的历史债机制),而是**按语义拆** —— 「原语 CSS **文本**反例」(零颜色字面量 · `--ed-stamp` 不作底色)留在 `style-seams.test.ts`;「**跨文件**契约」(CSS 接线 · 联合契约锚 · 退场时长三方对拍)落 `style-contract.test.ts`;「**reduced-motion 覆盖**」(基类名单 · **动画落点含伪元素**)另立 `motion-coverage.test.ts`(T11 评审 Critical 修好后追加的那条守卫再次逼近 300 行红线,遂二次按语义拆)。三个文件 **299 / 296 / 186** 行、职责写进各自 `@ai-context` 文件头,T3/T4/T12 已追加的 describe **逐条保留**(追加式演进)。
228228
> <!-- line-count-src: files=app/src/ui/primitives/style-seams.test.ts,app/src/ui/primitives/style-contract.test.ts,app/src/ui/primitives/motion-coverage.test.ts caliber=countLines@scripts/line-limits.mjs authority=HEAD-remeasurement -->
229229
>
230230
> **本批配套改动(不涉行数登记,仅为溯源)**:① `--ed-shadow-1/2` 定值(亮档投影 / **暗档反相描边** `0 0 0 1px rgba(255,255,255,.06)`)落在生成器真源 `app/scripts/gen-tokens.mjs` 与产物 `app/src/ui/tokens.css`(`--ed-shadow-card` 被取代,实测 0 处代码引用 ⇒ 不留兼容别名);② **`ui/tokens.css` 入口接线** = `app/src/main.tsx:5` 的 `import "./ui/tokens.css";`(此前该文件从未被 import ⇒ 原语的 `var(--ed-*)` 运行时无值;该文件只有 `:root`/`[data-theme]` 自定义属性、无选择器 ⇒ 零视觉变化;防回归断言在 `tokens.drift.test.ts`);③ `--ed-due` 亮档第二次修正 `#A05F10 → #9F5E10`(剪报底 4.4950 → **4.5571**,纸 4.9309 / 面 5.1436);④ **守卫**(零颜色字面量 · `--ed-stamp` 不作底色 · reduced-motion **基类名单** · CSS 接线)+ 三条补充判据(联合契约锚 · 退场时长三方对拍 · **`animation` 落点含伪元素必须逐字进 reduced-motion 名单**)落在上述三个 `.test.ts`;⑤ `app/src/App.css`(123 行、非 UTF-8、**从未被 import** 的死样式)由 Task 13 删除 —— 它**本就不在** 301–600 档表内(`.css` 不在 `SOURCE_EXT` 管辖内),故删除对计数的贡献为 **0**。

‎docs/superpowers/specs/2026-09-11-frontend-redesign-design.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,7 @@
396396
> **2026-09-12 批 3 回写(原文一律保留,只加注)**
397397
> **① `ColumnSpec` 实际是 7 个字段(W21)**:上面那句列了 6 个 —— `{ key, default, min, max, autoFoldBelow, pinnable }`;**实现多一个 `page: PageKey`**(`app/src/shell/columnRegistry.ts`)。加它的**判据收益**有两条:① `columnsOf(page)` 能按页取列(顶栏/页面接线不必另立清单)② 守卫能判「**列不许挂在已删页上**」(`page ∈ 导航注册表键集`)。⇒ 这是**实现的加法**,不是规格的反悔;本行**原文保留**,字段清单以这 7 个为准。
398398
> **② `pinnable` 是计划取的默认、无消费方**:规格给了字段但**未给逐行值** ⇒ 批 3 全行写 `false`,**今天没有任何消费方**(登记给批 6,与列折叠动效一起定)。
399+
> **🔻 批 6 收口就地加注 · `pinnable` 的批 3 实际取值(R6.6;2026-09-13,**上面原文一字未改**)**:上面「批 3 全行写 `false`」**与代码不符** ⇒ **代码是权威**:`app/src/shell/columnRegistry.ts` 的 `notes-outline` 那一行逐字含 `pinnable: true`,且该文件的口径注释自称「除笔记大纲列…为 `true`」⇒ 批 3 的**实际取值 = 除 `notes-outline` 外全 `false`**(13 行逐行值:12 行 `false` / 1 行 `true`)。**本规格两处(本②与 §10「批 3 的收口」行)都写「批 3 全行 `false`」⇒ 两处原文均按本加注读**。消费方仍为 **0**(全 `app/src` 实测 15 处 `pinnable` 命中**全在同一注册表文件内**:1 处注释 + 1 处接口字段 + 13 行取值,**无任何读取点**)⇒ 本批(列折叠 Flip)**只登记消费方缺口,不接线**。
399400
> **③ 大纲列「接线拖拽+记忆**或**删钩子」的裁决(W22 / D6)**:走**接线**(不删钩子)。计划 Task 8 Step 4 逐字写「`onToggleOutline` **改为 `outlineCol.expand()`**」——**字面照做会把 ✕「收起大纲」也变成 `expand()`**,凭空制造一个新缺陷;实现取 `folded ? expand() : setManualFolded(true)`(窄条 → 展开、✕ → 手动折叠),**两个控件各自语义正确**。旧实现的死局(J1-3:窄窗自动折叠下 `folded ≡ true`,点窄条永不展开)由此解开。
400401
> **④ 笔记列表列的阈值(D3)**:本表写 `autoFoldBelow = 1024`,而**今日实测是 700**(且三值并存:`860×4 / 700×1 / 1100×1`)——批 3 已按 §1 决策 16 与「折叠后正文仍 ≥520px」的口径**改判为 `BREAKPOINTS.threeCol = 1024`**,三值并存消灭;本行原文保留。
401402
> **⑤ 本表 13 行的落地状态**:13 行**全部**进 `shell/columnRegistry.ts`(单一注册表);页面**不再自建宽/夹取/阈值**,但**执行器仍是 `useColumnLayout`**(A5 裁决:注册表持规格、hook 执行)。7 处旧调用点 + 4 处未接入点(`ChatSidebar` / `GoalsPage` / `SettingsPage` / `ClassroomRightPane`)全部改为从注册表取规格。
@@ -645,6 +646,7 @@
645646
| ↳ 批 2 的收口(批 2 完成时更新) | **口径注**:`manualChunks` **本身一个字节都不降首屏**(只把同一批字节切成多文件,入口仍静态依赖全部 chunk);它的价值是 ① 让批 6 的 GSAP 落进独立懒 chunk ② 给 `import()` 产生的懒 chunk 稳定的共享 vendor 边界。**首屏下降全部来自 `import()`**(Task 6 页级 + Task 7 窗口变体 + Task 8 对话面板,**三条缺一不可**)。**交付形态 = 8 页懒 + 课堂页静态**(懒课堂页会把「首屏即被抓取的 20.04 kB」记作 lazy,**低估首屏读数 20.04 kB**)。**终态 25 chunk = 首屏 3 + 懒 22**;**两窗变体首屏 97.29 / 94.19 kB**(计划原推理「入口 + 零 vendor」**为假**,实测 = 入口 + 4 个 vendor chunk;「变体 < 60 kB」**结构性不可达** —— `vendor-react` 单独即 60,367 B,且三窗共用同一份 `index.html`、静态闭包逐字节相同) | 收口六门禁(2026-09-12 实测):`line-limits --full` `0 / 123 / 123` · `docs-check` exit 0 · registry **312/312/0** · `tsc` 0 错 · vitest **125 文件 / 1233 用例** · `cargo test` **2300 / 0 / 6** · clippy **19(集合 identical)** · 首屏预算守卫 **exit 0 · 92.79 kB**。**包体瓶颈清单见** [批 2 计划 §收口回写](../plans/2026-09-11-frontend-redesign-batch2-bundle.md) |
646647
| **3 壳层落地** | A′ 顶栏 + ⌘K + 溢出策略 + 窗口尺寸 + 列注册表 + 断点 + `--nav-h` **✅ 已落(2026-09-12 收口,`85d51d83^..` 至收口提交,**22 个提交**)** | 9 页全走注册表 **✅**;1024 无溢出 **✅(限定词:常态;toast 已按 A3 移出导航行)**;7 处魔数归零 **✅(判据重述:**已吸收 8 · 有目标未吸收 1 · 无目标 2**,见下注 —— **不压回「7」**) |
647648
| ↳ 批 3 的收口(批 3 完成时更新) | **改动面 8 个文件族**:`shell/{navRegistry,columnRegistry,breakpoints,windowSize,TopBar,CommandPalette,ShellFallback,kbCommands,useKbPaletteSearch}` + `App.tsx` + 4 处页面/组件接线(`ChatSidebar` / `GoalsPage` / `SettingsPage` / `ClassroomRightPane` / `NoteReadingView` / `NotesReadingColumn`);**`--nav-h` 的落点是 token 生成器**(`app/scripts/gen-tokens.mjs` 单一真源 → `ui/tokens.css` 产物,**不是手改产物**);**列契约的执行器归属(A5 裁决)**:注册表**持有规格**、`useColumnLayout` **仍是执行器**(选项 (b)「注册表自实现」登记为**日后可能的合并方向,且不得声称能力对等**);**`pinnable` 字段是本计划取的默认**(规格 §6.2 给了字段但**未给逐行值**,批 3 全行 `false`,无消费方);**本批四个非目标**:① 不重做批 2 包体工作(守住)② 不迁 L1 原语(守住,三条 `primitives=false` 断言)③ 不建视图层(守住)④ 不装 GSAP / 不加动效(守住,CSS 静态属性断言) | 三条验收的机器判据与原始读数:批 3 计划 §收口回写 · `tmp/acceptance.md`(不入库) |
649+
> **🔻 批 6 收口就地加注 · `pinnable` 的批 3 实际取值(R6.6;2026-09-13,**上格原文一字未改**)**:上格「批 3 全行 `false`,无消费方」的**取值半句与代码不符** ⇒ **代码是权威**:`app/src/shell/columnRegistry.ts` 的 `notes-outline` 那一行逐字含 `pinnable: true`,且该文件的口径注释自称「除笔记大纲列…为 `true`」⇒ 批 3 的**实际取值 = 除 `notes-outline` 外全 `false`**(13 行逐行值:12 行 `false` / 1 行 `true`)。**本规格两处(本行与 §6.2 的批 3 回写②)都写「批 3 全行 `false`」⇒ 两处原文均按本加注读**;「无消费方」半句**成立**(全 `app/src` 实测 15 处 `pinnable` 命中全在同一注册表文件内,**无任何读取点**)⇒ 本批(列折叠 Flip)**只登记消费方缺口,不接线**。
648650
649651
> **🔻 收口评审 M-2 就地加注(2026-09-12,**上格原文保留**)——「8 个文件族 / 4 处接线」两个数字不可追溯,实测口径如下**:
650652
> - **改动面实测 = 31 个生产文件**(命令:`git diff --name-only 85d51d83^..42e88740 -- app/src app/src-tauri app/index.html app/scripts app/package.json`,再剔除 `*.test.*` / `test.mjs`):`app/src/**` **28**(`shell/*` 11 · `ui/*` 2 · `components/*` 5 · `pages/*` 9 · `App.tsx` 1)+ `app/index.html` + `app/scripts/gen-tokens.mjs` + `app/src-tauri/tauri.conf.json`。⇒ 上格「8 个文件族」**是计划期陈旧估算**(照抄批 3 计划 Task 3 Step 5 的「写清 8 个文件的改动面」),**既非实测、也与它自己列的 `shell/{…}` 清单(9 个名字)不符**。

0 commit comments

Comments
 (0)