Skip to content

Latest commit

 

History

History
1278 lines (1018 loc) · 302 KB

File metadata and controls

1278 lines (1018 loc) · 302 KB

v0.22:前端重设计系列(组件体系 / 布局 / 动效 · L0–L6 全层)

状态:实施中 —— 批 0-A(设计系统基座)与批 0-B(图标集)已交付并通过评审;批 0 的其余部分(ADR-033~035 · 豁免表纠偏 · 拆 4 个 >600 行文件 · 原语三层)待立计划 2026-09-12 追加(批 2 收口,原文保留不改):批 1(删除批) 与**批 2(包体治理)**已交付,交付记录见下「交付记录」节(批 1 = 「删除批」节 · 批 2 = 「批 2 · 包体治理」节)。上面那句「批 0 其余部分待立计划」写于 2026-09-11,批 2 收口时未复核其是否仍成立 —— 批 0-C1(行数治理)/ 0-C2(拆超限文件)/ 0-D(L1 原语层,ADR-033)的落地状态请以规格 §14 的表格与本文件各节记录为准。 权威规格:2026-09-11-frontend-redesign-design.md(513 行,本系列的唯一定义源;本文档只做批次归属与交付记录) 关联:UX 市场惯例审计(本设计的直接输入)· 长期优化清单 · 需求池 · ADR-010(本系列修订为退役)

版本归属说明(为何是 v0.22 而非 v0.21)

v0.21 已由「执行型智能体(目标执行层)」预留,且预留写得很实 —— 2026-09-05-goal-execution-agent-design.md 内有 v0.21.0(P0 执行数据层)/ v0.21.1(P1 AI 增强层)/ v0.21.2(P2 闭环增强)三档明确映射,并记录「裁决点:执行层走 v0.21 系列顺延,建议顺延不插队」;v0.20.md 的 D6 亦载明「v0.21 系列留给执行型智能体」。

本系列为不同主题(前端重设计 ≠ 目标执行层),故取 v0.22:不插队、不改动既有预留、不要求任何已记录决策回退。若将来执行型智能体顺延,其 v0.21 归属不受本系列影响。

一句话

把「一份内容只有一种样子」的产品,改造成「一份内容有多种样子 + 会呼吸、会生长、会显影的纸」—— 在此之前先补上它从未有过的地基:token 层、原语层、视图层。

批次与 REQ 映射

REQ 预留:REQ-318 起(现池止于 REQ-317)。具体条目于每批开工轮的「需求池登记」步骤落位,本文档不预写未排期条目,避免出现指向不存在条目的引用。

批 内容 主题归属 REQ
v0.22.0 · 批 0 基座:ADR-032~035 + 修订 ADR-010 · 豁免表纠偏 · 拆 4 个超限文件 · token 变量层 · z-index 六档标尺 · 图标集 + 单测 · 原语三层 治理 + 基建 REQ-318 起
v0.22.1 · 批 1 删除批(纯减法):21 条命令 + 补缝三连及其连带模块 + 清理死文案 API 面收敛 —
v0.22.2 · 批 2 包体基线治理:manualChunks + 按页动态 import + 量首屏 gzip(现状 651.25 kB gzip / 预算 200 kB) ✅ 已落(2026-09-12) 性能 —

2026-09-12 批 2 收口更正:上表 v0.22.2 行的「现状 651.25 kB」是过期快照 —— 实测开工基线是 654.72 kB;交付终态 92.79 kB(−85.83%)⇒ ✅ 达标。逐条读数、瓶颈清单与 follow-ups 见「批 2 · 包体治理」节。 2026-09-12 批 3 收口追加:上表 v0.22.3 行已标 ✅。批 3 的开工点 = 上表 v0.22.2 交付终态 92.79 kB;批 3 终态首屏 97.16 kB(Δ+4.37 kB)⇒ 仍远低于 200 kB 判据。逐条读数、三条验收、计划错误与 follow-ups 见「批 3 · 壳层落地」节。 | v0.22.3 · 批 3 | 壳层落地:A′ 顶部 Tab + ⌘K + 溢出两级策略 + 窗口尺寸 + 列注册表 + 断点 + --nav-h ✅ 已落(2026-09-12) | 布局 | REQ-318 起 | | v0.22.4 · 批 4 | 原语迁移进各域:20 弹层 / 44 空态 / 85 加载态 / 196 错误行 / 4 toast / 2 confirm / Button·Surface·Text | 组件体系 | — | | v0.22.5 · 批 5 | 视图层样板:viewRegistry + ViewSwitcher + 会话 4 视图 + 笔记 3 视图 + 惰性挂载 + flushSave 守卫 | 展示形式 | REQ-318 起 | | v0.22.6 · 批 6 | 动效系统:GSAP 接入 + token + 四层纲领 + 三档强度 + 相变两态 + 6 个签名动效 + usePresence ✅ 已落(2026-09-13) | 动效 | REQ-318 起 | | v0.22.7 · 批 7 | 未接线落地:12 条补 UI(含 kb_search → ⌘K)· 标签线 · 档位通道 · B 桶 3 条撤下 IPC | 能力补齐 | REQ-318 起 | | v0.22.8 · 批 8 | 治理收口:豁免表终态 · 回写 ui-ux-system.md / theme.md · 新增动效规范章节 · 需求池同步 | 治理 | — |

2026-09-13 批 6 收口追加(R6.7 的批次归属就地消歧;上表原文一字未改):上表 v0.22.6 行已标 ✅(批 6 = 动效系统,终态见「批 6 · 动效系统」节)。⚠️ 上表 v0.22.8 行的「新增动效规范章节」与规格 §14(:836)两说 —— 实际落点:动效规范章节(docs/standards/motion.md)已在批 6 落地(T1,bffed928;并已进 docs/standards/README.md 索引),批 8 留下的是 docs/product/ui-ux-system.md / theme.md 的四层动效 / 三档强度回写(规格 §14 逐字仍留批 8;progress.md §一 的「🟡 待裁」仍在)⇒ v0.22.8 行按本加注读。

实施粒度约定:不建议一次性生成全部 9 批的实施计划。每批各自一份实施计划,且后一批的计划在前一批验收通过后再写 —— 批 3 之后的细节依赖批 0–2 的实测结果(尤其包体瓶颈清单与拆件后的真实文件结构)。

决策记录(摘要,36 项全文见规格 §1)

层 关键裁决
L0 视觉基座 基座路线 C 全部从代码(回写规格为目标态)· 视觉方向 C 活页(纸 + 中文衬线正文 + 印章 + 到期刻度)· 材质语言 D 显影(四档墨度 = 确定度)· 来源标记 剪报底纹默认开 · 图标语言 A 自绘线性图标集
L1 原语层 收敛 10 类原语 · 删除哲学 甲 两档分级(低危可逆 → 撤销 toast 10s;高危 → 确认框并列明级联;级联不给撤销)· 软删回收站不做(独立技术债)· 拆件顺序 NotesPage → NoteListView → SessionDetailPanel → ClassroomPage(行为等价)
L2 容器与壳 导航 A′ 顶部 Tab(8 项 + ⌘K + 设置下沉齿轮)· 域数纪律:新增能力进域内页签 · 顶栏溢出两级 · 相变两态(采集/复习)· 列契约三列上限 + 单一注册表 · 窗口 1280×800 / 最小 1024×640
L3 视图层 四部件 ViewSpec / viewRegistry / ViewSwitcher / 依赖方向 · 本批会话 4 + 笔记 3 视图(新增 5 个组件)· 原文永远保留 · 非默认视图惰性挂载 · 编辑态切视图先 flushSave(失败则阻断)
L4 动效 引擎 GSAP(core + Flip + ScrollTo + CustomEase)· 纲领 「活的纸」四层(响应/环境/编排/生长)· 基调 丙 双基调(有「读数」用仪器,有「文字」用纸墨)· 强度三档,系统 prefers-reduced-motion 优先
L5 未接线 A/B 桶能接入 UI 的尽量接入 · C 桶除视频档案四连外删去 · 视频档案四连删 3 留 2 · 档位通道做完整 · 标签线补完 · AI 补缝三连全删并修订 ADR-010

红线与两处经批准的例外

红线:本地优先不破 · 不引入路由库 · 不砍任何已接线功能 · 每批 tsc/vitest/cargo test 全绿 · 行数红线(不往 4 个超限文件里加代码)· 后端数据模型零改动,除下列两处。

# 例外 原因 回滚
E1 MemoryEntry 增加 tier 字段 档案记忆库根本没有 tier 轴 → 「画面档位选完不生效、也不跨会话记住」 旧 JSON 无该字段时按 None 读取(向后兼容读,无需迁移)
E2 tag_colors 补种子/迁移写入 表建了但永远没有数据 → 前端色板第三档恒不生效 迁移可空跑;标签色本身是可逆 UI 状态

新增例外须再次裁决;不得由这两处推而广之为先例。

验收门槛(11 条,全文见规格 §11)

  1. 15 个 >600 行文件 → 0(实测值:前端 5 + Rust 10;规格原文的「4 个」只扫了前端且漏掉 SessionListPanel.tsx);>300 行 100% 在豁免表内且数值与实测一致。

    2026-09-11 用户裁决:范围取实测 15 个;口径取「全部行数」,以 [System.IO.File]::ReadAllLines(path, UTF8).Count 为准(即 scripts/line-limits.mjs),禁用 Get-Content(少算可达 56 行)· Measure-Object -Line(只数非空行)· 字节 0x0A 计数(末尾无换行时少算 1)。 执行机制:node scripts/line-limits.mjs(本地提交门禁 + CI --full 守数值),>600 用棘轮只减不增 —— 拆分由 0-C2(前端 5)/ 0-C3(Rust 10)推进,每拆完一个从 FROZEN_OVER_LIMIT 删一行。 债务未关:15 个文件当前仍全部 >600,棘轮只保证「不再增加」,→ 0 由 0-C2 / 0-C3 兑现。该缺口的完整实测与豁免表治理债登记为 TD-2026-09-11-H(清单与证据在 docs/tech-debt/review-2026-09-11.md —— ⚠️ 该文件目前未入 git,故此处不写成 Markdown 链接,否则新克隆会断链)。🔻 2026-09-13 加注(T26 归档后补记):该目录已于批 8 归档到 docs/archive/2026-09-13/(快照 review-2026-09-11.md,内容零改动);本行理由在当时成立,原文保留。

  2. 手写弹层 20 → 全走 Modal;z-index 不同值 17 → ≤6 档;role="dialog" + 焦点陷阱 20/20
  3. 空态 / 加载 / 错误行 / 弱化文本 / 卡片边框 五类重复 → 各自 1 个原语
  4. CSS 变量 0 → 覆盖全部语义色/字阶/间距/圆角/时长/缓动;hex 88 → ≤ token 数
  5. prefers-reduced-motion 覆盖率 100%,系统优先于强度档位
  6. 会话与笔记各 ≥2 种展示形式可用,原文形态不丢
  7. 47 条未接线命令逐个有结论,无「不知道」
  8. 标签能写进去且标签过滤面板有内容;画面档位选完真的生效且跨会话记住
  9. JS 包首屏 gzip 达标或给出瓶颈清单;GSAP 只在独立 chunk 懒加载

    进度(批 2 收口,2026-09-12):✅ 达标 —— 首屏 JS gzip 654.72 → 92.79 kB(预算 < 200 kB),守卫 scripts/check-bundle-budget.mjs exit 0、余量 107.21 kB。GSAP 未安装(批 2 硬非目标),但 vendor-gsap 独立 chunk 槽位已预留并被单测钉住,批 6 必须用 import()。⚠️ 达标不来自 manualChunks(它一字节不降首屏),全部来自 import():8 页懒 + 课堂页静态 + 两窗变体 + 对话面板。

  10. 6 个签名动效各自可中断、可反向,reduced-motion 下正确降级
  11. npx tsc --noEmit 0 错 · npx vitest run 全绿 · cargo test 全绿(每批)

    进度(批 3 收口,2026-09-12):八门禁全绿 —— line-limits --full >600 0 · 301–600 档 123 · 登记条目 123(exit 0)· docs-check exit 0 · registry 312/312/0 · tsc --noEmit 0 错 · vitest 143 文件 / 1370 用例 / 0 失败(既有 1233 条逐文件一模一样、一条未少;+18 个新文件 / +137 用例)· cargo test --test app_lib_tests 2300 passed / 0 failed / 6 ignored(逐字持平,本批零 Rust 改动)· 首屏预算守卫 exit 0 · 97.16 kB · 余量 102.85 kB(CSS 与字体不计入该判据,只报告)· clippy 唯一位置集合 20 = 基线(SET-IDENTICAL)。 ⚠️ 一条既有 flake 的处置:app/src/components/KnowledgeGraphView.test.tsx > 单击节点 → 1~2 度邻居展开、范围外淡出 在批 3 开工基线树 a7bd1899 上复现过(全量 1232 passed / 1 failed,隔离复跑 11 passed / exit 0);批 3 终态这次全量未复现(1370/1370)。⇒ 既有负载敏感 flake,非本批引入;两种读数都记在「批 3 · 壳层落地」节。

交付记录

逐批追加。

批 0-A · 设计系统基座(2026-09-11,4e3bfa1a..7148533e,12 个提交)

2026-09-12 追加(收口评审 M-3 结清)—— 提交数的口径声明:本行的「12 个提交」= 含左端点(实测 git rev-list --count 4e3bfa1a^..7148533e = 12)。同一记号按 git 原生语义 A..B 不含左端点,读数为 11。⇒ 本文档批次行一律采用「含左端点」口径(A^..B);批 2 行是全文唯一例外,已在彼处就地注明。

交付:ADR-032(前端设计系统与 token 层落地)· token 单一真源 app/scripts/gen-tokens.mjs + 生成产物 app/src/ui/{tokens.ts,tokens.gen.ts,tokens.css} · 对比度纯函数 contrast.ts(WCAG 相对亮度 / 对比度 / AA 判定)· z-index 六档标尺 zIndex.ts(17 个散值收敛为 6 档)· 漂移守卫 tokens.drift.test.ts(行尾归一,防新检出假阳性)· 对比度守卫(绑定底色而非硬编码常量)。

验收:tsc 0 错 · vitest 全绿 · 终局全分支评审 + 修复波 + 受限复审通过。 规格修正:§4.1 色阶 16 token 的对比度按实测回写 —— --due 亮档 #B26A12(4.06:1) → #A05F10(4.86 / 5.07),作废值 3.1:1 → 3.22:1。

过程中纠正的计划错误(6 处,均由实施者或评审者实测抓出):ADR 相对链接层级写错 · 生成器「有第二份 WCAG 公式」的不实描述 · 漂移测试逐字节比对在新检出会假阳性 · 对比度守卫测硬编码常量而非底色 · 两处 normalizeEol 已分叉 · 断言计数不符。

批 0-B · 图标集(2026-09-11,25bd5d99..2fbf81d4,21 个提交)

2026-09-12 追加(收口评审 M-3 结清)—— 口径同上(含左端点):实测 git rev-list --count 25bd5d99^..2fbf81d4 = 21;不含左端点 25bd5d99..2fbf81d4 = 20。

交付:app/src/ui/icons/ —— types.ts(几何契约,三种元素白名单 path/circle/rect、无颜色字段)· paths.domain.ts(域 9)+ paths.action.ts(对象与动作 15)= 24 个自绘图标 · paths.ts(合并注册表 + 启动期重名检测 + 零列名字面量联合 IconName)· Icon.tsx(唯一渲染入口:currentColor / 默认 aria-hidden / 有 label 时角色转为 img)· index.ts(导出面 10 项)· 三个测试文件共 21 例 · 内联 <svg> 棘轮守卫 no-inline-svg.test.ts · app/src/node-builtins.d.ts 扩写(无 @types/node 前提下的最小环境声明,不用 any)。

验收:tsc --noEmit 0 错 · vitest 103 files / 809 tests 全绿(图标层 21/21)· cargo test exit 0(2337 passed / 0 failed / 6 ignored;本批零 Rust 改动,属回归确认)· docs-check ✅ · 零新增依赖 · 界面外观零变化(本批只定义不消费:未改任何组件、未替换任何 emoji,消费在批 4)。

终局全分支评审(2026-09-11):READY_WITH_FOLLOWUPS —— 0 Critical / 0 Important。批次验收 4 条经评审者逐条独立判定,4/4 满足;三个历史静默缺陷(网格测试空转、IconName 塌回 string、棘轮同前缀漏判)均已闭合并由评审者独立复现。未发现新的 Critical/Important 级静默失败模式。 评审提出的 follow-up 已全部写进计划「交接给批 3 / 批 4 的遗留项」节,无需本批返工。

评审新发现的代码缺陷(1 处,已修 ecbaf364):paths.ts 的重名检测 if (merged[name]) 走原型链 —— 名为 constructor 的图标(命名规范恰好放行)即使毫无重名也会抛「图标重名」,属误导性的启动期崩溃。修为 Object.prototype.hasOwnProperty.call(...)(不用 Object.hasOwn:它是 ES2022,而本仓 target/lib 为 ES2020)。已用真实模块探针自证:插入 constructor 图标后模块正常导入(旧代码则导入期抛错、全灭)。

两项关键实测结果:

  1. 24 组几何数据零转录漂移 —— 与计划数据逐字比对(域 9/9、动作 15/15,键序一致),并用变异探针证明该比对非空转。
  2. 棘轮基线为空 —— src/**/*.ts(x) 共 327 个文件,src/ui/icons/ 之外没有任何内联 <svg> ⇒ 棘轮语义实际为「一个都不许新增」(比「不许增加」更强,且无需特赦任何存量文件)。守卫已用探针证明会真实失败。 ⚠️ 其第 2 个断言(基线过期项检查)在空基线下休眠,不计入当前防护力。

过程中纠正的计划错误(10 处,逐条见批台账):index.ts 的真实 TS2459 · IconName 偏差裁定撤回并改为立即修 · ACTION_ICON_PATHS 用了计划自己明令禁止的宽注解 · DOMAIN_ICON_PATHS 缺 satisfies · 「as const satisfies 会 TS1360」不成立(实测不报错)· 圆越界举例方向写反 · 类型断言片段缺 void(noUnusedLocals 下 TS6133)· Task 3 的守卫探针位置无效(写在被设计性排除的目录内)· Task 3 守卫代码在本仓编译不过(缺声明,tsc exit 2)· 棘轮守卫用裸字符串前缀排除图标目录 ⇒ 同前缀兄弟目录(ui/icons-legacy/)被静默豁免(计划原文如此,由终局任务评审用双针实测抓出,见提交 c22d2bda)。

另有 2 处「控制方在交接单里给出的结论」被终局评审推翻并已更正(记录在案,勿重犯):① 「mergeGroups 重名不可测 ⇒ 接受现状」——错,评审者用 vi.doMock + vi.resetModules 在不动数据文件下即复现该抛错(本仓已有 46 个测试文件用 vi.mock),结论改为可测、应补;② 「Icon.tsx 的 <rect> 兜底会静默渲染坐标全 undefined」——错,向联合加入第 4 种元素必然 5×TS2339 编译失败,故 switch + assertNever 只是可读性收益、批 3/4 不必排期。两处已改写进计划交接单。

批 1 · 删除批(2026-09-11 立案 / 2026-09-12 落地,10fcd58e..aa3a2bcf,11 个实施单元 + 1 次计划同步提交)

交付:IPC 注册面 334 → 312(−22 条「有定义、有注册、前端生产代码零调用」的命令)· 补缝式 AI 在代码层清空(三命令 + ai_judge 判定器模块 + AiMockAdapter::enhance + ai_protocol.rs 的 AiEnhance* 半边)· 产物模板子系统整族退役(commands_artifacts.rs + artifact_templates{,_visual,_voice,_tests}.rs + narrative_detect{,_tests}.rs)· ADR-010 转「已废弃」(文件保留 + 退役节 + 索引 / 2 处交叉引用 / 需求池同步)· structuredBlocks.ts 的 "AI 增强待 V1.0" 死文案及其函数与断言清除 · 豁免表 app_commands.rs 行人工理由列按实测更正(334 → 312 条)。

验收(收口单元 2026-09-12 串行实测,全部 exit 0):check-command-registry = 定义 312 / 注册 312 / 重复 0 · cargo test --test app_lib_tests = 2300 passed / 0 failed / 6 ignored · cargo build = 0 条 dead_code(仅既有 lib.rs 多 target 提示 + build-script DLL 占用噪声)· cargo clippy --all-targets = 19 条,集合与开工基线 identical · line-limits --full = >600 0 · 301–600 档 123 · 登记条目 123 · docs-check exit 0 · tsc --noEmit 0 错 · vitest 124 文件 / 1124 用例。

账(与计划的差额逐条归因):Rust 用例 2359 → 2300(−59),而计划原预测只删 16 条 —— 2359 → 2334(T3,−25:控制方把删除面扩大为整族 7 文件)→ 2308(T4+T5 合并单元,−26 = 9+7+10)→ 2304(T6,−4)→ 2300(T7,−4)。前端 1125 → 1124(−1,T9)。删文件 10 个(git diff --name-status --diff-filter=D e96ab63d HEAD)· 301–600 档 125 → 123。每一笔计划外删除都由控制方在「STOP → 实测绿色解 → 授权 → 落地 → 门禁回绿」的闭环里逐条裁决,不是实施者自行扩大范围。

规格漂移纠正:§9 汇总 21 → 22(open_capture_float 由「待核实」改判为「删」,B 桶唯一无把握项结清)· §10 批 1 行打进度标记 + 归属注 · §11 验收 7 补进度注 · §13「删命令删到活代码」缓解栏升级为三向复核 + 同名三域归属 + 子串陷阱清单 · §14 豁免表与交付记录落点行更新 · 需求池 REQ-055 / REQ-056 / REQ-135 / REQ-193 / REQ-201 改真(REQ-050/052/053 属功能级改写,登记待办)。

过程中纠正的计划错误(本批最有价值的交付,逐条可复现):

  1. 「不删」清单被证伪五次:artifact_templates 族(T3)· ai_protocol.rs 的 AiEnhance* 半边(T4)· 「5 处调用点」实为 4 调用 + 3 定义(T2)· vad_threshold_slot 三符号(T6)· spec_from_kind(T7)。根因统一:用「看起来还有人用」代替「删除后可达性」,而 build_artifact 的「25 处命中」多为同一子系统内部自引用。替代方法已写进批 1 计划「收口回写」节收口一。
  2. 计划与自身 Global Constraints 不自洽(T4 / T6 / T7 各一次):保留某符号必然新增 dead_code ⇒ 收口门禁不可达绿。裁决一律以 Global Constraints 为准(先例是规格对 vad_threshold_diag 的「不留半成品」判词),并要求先给出实测绿色解再授权。
  3. 删除粒度可升可降:T3 首次 STOP 时把「符号级警告」误读成「模块级矛盾」,正解是降一个粒度(按警告逐符号外科删除);T4/T6/T7 则是升一个粒度(整族删除才自洽)。⇒ 门禁红了不是让你放宽门禁,而是提示删除粒度不对。
  4. 一条「覆盖损失」被评审证伪:T7 报告称夹具改写损失了 lookup_form 的 kind 回退分支覆盖,实测该分支删除前就从未被任何测试执行(先存缺口,非回归)⇒ 补测动作仍批准,理由改写为「补先存缺口」。
  5. Copy-Item 保留 mtime ⇒ cargo 回放陈旧警告:还原源文件后必须先 touch 再复验(曾读出 build 20 / clippy 35 的假读数,与哈希证据矛盾)。
  6. PowerShell 辅助函数命名撞内置别名:删除脚本把函数命名为 Rd,而 rd 是 Remove-Item 的别名 ⇒ 「读失败但写/删照常执行」(7 文件被删、lib.rs 被写成 1 行;已从 HEAD 全量恢复重做)。⇒ 辅助函数禁用 rd/rm/mv/cp/ls/cd 等别名名。
  7. cmd /c "git show X^:path" 会吃掉 ^(静默变成看当前提交)⇒ 读历史文件一律在 PowerShell 里读完整文件,绝不读 diff hunk 推断全文。

本批新增/确认的读数陷阱(通用,建议后续批次当清单用):

  • \b 正则在全角 )(U+FF09)前永不匹配 ⇒ 残留面扫描一律 git grep -nF 逐名字面量(本批因此漏过 1 处悬挂注释)。
  • git archive 在未跟踪的子目录里执行 ⇒ 10240 字节空归档 + exit 0 ⇒ 基于它的「0 命中」全是假绿。一律在仓库根 + 绝对 -o,并以「完整树约 14.6 MB」自检。
  • 在 git archive 解包树里跑 git grep ⇒ 静默 0 命中(该目录无 .git)——仪器坏,不是树干净。
  • 裸 includes() / 子串 grep 判「命令是否还有人调用」⇒ 本批实测 6 例假活(refine_session ⊂ "auto_refine_session" · finish_session ⊂ "finish_photo_session" · video_profile_memory ⊂ "video_profile_memory.json" · recognize_image ⊂ recognize_image_timeout · remember_video_profile ⊂ remember_video_profile_form/_domain)。
  • 全树扫描必须排除 .superpowers/:评审者在 tmp/ 解包的归档副本会被当成命中源(本批一次假 313 命中)。
  • core.autocrlf=true 且工作树存在 LF-only 异类文件 ⇒ git hash-object 相等与空的 git diff 都可能掩盖 EOL 差异;git status 干净是唯一可靠判据。
  • 任何「0 命中」结论必须点名仪器,并先证明它能命中一个已知存在的串、且对无意义串报 0 —— 本批 6 次假绿/假阴性全部由这一条抓住或本该抓住。

未做(登记,逐条带归属):structuredBlocks.ts 整模块存废 → 批 7(接线或删除二选一,含 .ed-low-confidence)· 25 条「补 UI / 登记不排期 / 撤下 IPC / 有意保留」→ 批 7(有意保留 3 条无期)· 旧凭据槽 "default" 的应用内撤销路径 → 处理 AI 凭据的批次(产品裁决)· VAD 写端 publish 当前 0 测试覆盖 → 批 7 或 VAD 诊断批次(可选)· artifact 行已无任何新建路径(refine 链的正当性只对历史产物行成立)→ 登记,与批 7 的产物判定同批· ASR_REQUEST_TIMEOUT 的删除事实 / 取回方式 / 重引入触发条件 → 登记(无期)· commands_video.rs:279 的 @param form 注释与实现不符 → 登记(无期,纯注释)· REQ-050 / REQ-052 / REQ-053 的功能级陈旧表述 → 产品文档 pass · 真机 IPC 冒烟整批跳过(2026-09-11 用户裁决;等价性依据是静态证据链 + 编译期路径解析,批 3 起如需真机结论必须重新派发,不要沿用「已跳过」)。

批 2 · 包体治理(2026-09-12,实施 e46e0e82..9921767c(11 个提交)+ 收口回写 3f9c64ce)

2026-09-12 追加(收口评审 M-3 结清)—— 本行是全文唯一采用「不含左端点」口径的批次行,现已声明:e46e0e82..9921767c 按 git 原生语义不含左端点 ⇒ 11 个提交(含左端点 e46e0e82^..9921767c = 12)。相邻批次行用的是「含左端点」口径(见批 0-A / 0-B 行的注),两种数法都成立、但不可混用。 另:批 2 的收口回写提交不在该区间内 —— 3f9c64ce(计划/规格回写)· af57dab8(本节落盘)· 49f953f4(超长 subject 登记)· f5c35990(回写定位改锚)共 4 个都在 9921767c 之后 ⇒ 批 2 的提交应按「11(实施,不含左端点)+ 4(收口回写)」表述(若用含左端点口径则是 12 + 4)。

交付:app/vite.config.ts 接线 manualChunks(7 个 vendor 族:editor/katex/canvas/md/react/tauri + 为批 6 预留的 gsap 槽)· 纯函数 app/src/build/manualChunks.ts + 单测 manualChunks.test.ts(本批唯一新增的测试文件)· 首屏预算守卫 scripts/check-bundle-budget.mjs(含 14 条 --self-test,口径 = 入口 + 只沿静态 ESM import 可达的 .js,gzip zlib level 6,十进制 kB)· 首屏静态可达性探针 scripts/bundle-eager-graph.mjs · app/src/App.tsx 的模块加载边界重写(8 个页面按页 import() + 首访挂载保活、两个窗口变体面板按变体懒加载、AiConversationDock 首开挂载)· .gitignore 取反 app/src/build/。三个非目标全部守住:不装 GSAP · 不动 app/src/ui/primitives/** · 不碰任何 Rust。

验收(收口单元 2026-09-12 串行实测,全部 exit 0):check-command-registry 312/312/0 · line-limits --full >600 0 · 301–600 档 123 · 登记条目 123 · docs-check exit 0(扫描 273 / 检查 173)· tsc --noEmit 0 错 · vitest 125 文件 / 1233 用例 · cargo test --test app_lib_tests 2300 passed / 0 failed / 6 ignored · cargo clippy --all-targets 19 条,集合 identical(集合比对,禁止比 sha256)· check-bundle-budget.mjs(含真实构建)exit 0 · 首屏 92.79 kB · 余量 107.21 kB。

账(首屏 gzip 前后对比 + chunk 拓扑):首屏 JS gzip 654,722 → 92,789 B = 654.72 → 92.79 kB(−561,933 B = −85.83%),预算利用率 46.39%;首屏 chunk 1 → 3(index 27.87 + vendor-react 60.37 + vendor-tauri 4.55 kB);懒 chunk 0 → 22 个 / 574.84 kB;全部 JS chunk 1 → 25;首屏可达应用源文件 251 → 47、首屏 npm 包 15 → 4(react / react-dom / @tauri-apps/api / plugin-dialog);构建模块数 746 不变。两窗变体首屏 ?float=1 97.29 kB · ?overlay=1 94.19 kB(均达标)。

诚实代价(不许省略):全部 JS gzip +12,908 B = +12.91 kB(+1.97%)(25 chunk 的样板与跨 chunk import 开销,总量守恒不成立)· index.html +166 B(两条 modulepreload)· CSS gzip +36 B · >500 kB 警告仍在(vendor-editor 608,384 B raw / 208.59 kB gzip,整块落在懒 chunk 内)· dist 总量只降 4,415 B(−0.14%),59 个 KaTeX 字体 1,072,948 B 一字节未动 ⇒ 磁盘与安装包不因此变小(首屏省下的 561.93 kB 是挪进懒 chunk,不是消失)。

规格漂移纠正:§2 包体行 651.25 → 654.72 kB(过期快照;「超标 3.26 倍」→ 3.27×)+ 批 2 终态与诚实代价注 · §10 批 2 行打进度标记并加口径注(manualChunks 自身一个字节都不降首屏;下降全部来自 import(),Task 6/7/8 三条缺一不可)+ 收口行 + 瓶颈清单相对链接 · §11 验收 9 加进度注(✅ 达标;GSAP 未装但槽位已预留并被单测钉住)· §13「包体继续膨胀」缓解栏补批 2 已落项与守卫两个待修缺口 · §14 豁免表行(App.tsx 439→519,登记值已同步)与交付记录落点行更新。

过程中纠正的计划错误(本批最有价值的交付,逐条可复现;全文见批 2 计划就地加注):

  1. 计划 L1317「窗口变体首屏 = 入口 + 零 vendor」为假 —— 三个窗口共用同一份 index.html(WebviewUrl::App("index.html?float=1"))⇒ 入口静态闭包逐字节相同,早返回只能切断动态边。实测 = 入口 + 4 个 vendor chunk ⇒ 变体 97.29 / 94.19 kB。连带「变体 < 60 kB」结构性不可达(vendor-react 单独即 60,367 B > 60 kB)。
  2. 计划 Task 6 的「9 页 lazy / 0 静态页面 import」经控制方裁决改判为「8 懒 + 课堂页静态」:课堂是默认页,懒它会让「首屏即被抓取的 20.04 kB」被记作 lazy ⇒ 首屏读数被低估 20.04 kB。计划 Step 2 预期、Step 3 标题与代码、提交 subject、V1/V2 全部随之过期(实测 V1=8 / V2=1)。
  3. 计划 Task 6/8 的 Files 清单漏了必须的 docs/standards/line-limit-exemptions.md 刷新(App.tsx 439 → 519 行)。收口时 node scripts/line-limits.mjs --write 无 diff(前序任务已刷新)⇒ 收口提交不含该文件(按计划 Step 6 的规则)。
  4. 计划 Task 10 V4 期望 vitest 124/1124 不可能成立:本批净增恰好一个测试文件 ⇒ 终态 125 文件 / 1233 用例。判据改为「用例数只增不减 ∧ 0 处断言修改 / 0 处新增 await / 0 处改 mock」(Task 6/7/8 各自前后逐字相同)。
  5. 计划 Task 9 说「四个候选」实为五个(katex 双版本 · structuredBlocks 孤儿 · @codemirror/lang-markdown 传递链 · basicSetup 附带件 · 59 个 KaTeX 字体),交付是五行结论表,无一条同时过「size-only ∧ behavior-neutral」双闸。
  6. 单位漂移(会造出假 Δ):计划 §表 1 的「字体 1,047.80 kB」「dist 3,157.49 kB」与 Task 9 候选 5 的 1,047.80 / 797.64 都是 KiB,十进制是 1,072.95 / 3,233.27 与 1,072.95 / 816.78 kB。候选 3/4 的 59.07 / 24.11 kB 是分裂前的探针值(探针总量比真实构建膨胀 +6.3%),落地 A/B 实测为 −84.04 / −45.10 kB,且 100% 落在懒 chunk 内。
  7. 计划 Task 7 Step 5 给的 commit subject 53 字符,超 ≤50 限 —— 交付改用 42 字符的 perf(app): lazy-load window variant panels。
  8. 计划 V3 判据「首屏 gzip 变化 ≤3 kB」被实测 −4.39 kB 突破 ⇒ 控制方改判为「只许变小 ∧ modules 不变」(原判据建立在「分块不会改变总量」这一错误假设上)。
  9. 计划自带的「子串碰撞」反例恒假红(@xyflow/react 的 id 里没有连续子串 node_modules/react)· @types/katex 覆盖闸必然红(dependencies 实为 14 个,计划写 12;已加 1 行惰性登记,根因 F4 登记批 8)。
  10. .gitignore 的 build/ 未被锚定 ⇒ 静默吞掉 app/src/build/(Task 3 的两个文件靠 git add -f 才入库)。本批只做点状取反 !app/src/build/**,未动锚定语义(登记批 8)。
  11. Task 1 冻结的 clippy 基线 sha256 不可复现(基线文件 BOM+CRLF 1724 B vs 抽取器无 BOM+LF 1702 B)⇒ 判据一律改集合比对(本批实测集合 19/19 相同、sha256 不同)。
  12. 「文件不存在」被假报两次(Task 5 报 task-3-fix-report.md 不存在但实际 247 行;Task 9 同类)⇒ 断言「不存在」与断言「0 命中」同等对待:说明仪器并自检。

本批新增/确认的读数陷阱(累计 13 类,逐条见批 2 计划 Global Constraints 的仪器纪律注):含中文的搜索模式经 PowerShell 字符串层被 GBK 误解码(给出 0 命中的假阴性)· 无 BOM 的 UTF-8 中文 .ps1 被 -File 按 GBK 解码(连脚本内 cmd 行一起毁)· 整树 ripgrep 遵守 .gitignore ⇒ 对被忽略目录整体失明(同一仪器实测 0 vs 19 命中)· PS 5.1 > 重定向写 UTF-16LE · Tauri 命令名不是唯一 chunk 标记 · chunk 依赖边是「模块图」的性质、不是「归属表」的性质(环的根因:只挪模块不挪它自己的依赖闭包)· git archive 在未跟踪子目录出 10240 B 空归档 + exit 0 · 解包树里 git grep 静默 0 命中 · Copy-Item 保留 mtime ⇒ cargo 回放陈旧诊断(还原后先 touch)· A/B Δ 恰为 0 先当仪器故障、自证仪器能测出已知差异再下结论。

未做(登记,逐条带归属):路线 A 叶级懒加载(被 B′ 在首屏上完全包含 · 测试面更险)→ 批 5 · 页级错误边界 / 懒 chunk 加载失败重试(PageSlot 的 <Suspense fallback={null}> 之上只有全局 AppErrorBoundary ⇒ 一次失败卸载整个 MainShell、已访问页状态一起丢,这是本批新增的失败模式)→ 批 3/4 · 两个窗口变体分支没有错误边界(chunk 加载失败 = 空白窗)→ 批 3/4 · 首访加载态 fallback={null} → L1 Loading 原语 → 批 3/4 · 变体首屏正式度量口径(本批只给实测值 + 证明 < 60 kB 不可达)→ 批 3 · structuredBlocks.ts 整模块存废 + katex 版本偏斜(含 @types/katex)→ 批 7 · @codemirror/lang-markdown 传递链(懒 chunk −84.04 kB)+ basicSetup 附带件(−45.10 kB)两条耦合,须一起裁决 → 批 4/5 · 59 个 KaTeX 字体 1,072.95 kB(仅 .woff2 可省 816.78 kB)→ 批 8 · 批 6 装 GSAP 必须 import() 且核对 vendor-gsap 不在首屏(槽位已预留并被单测钉住)→ 批 6 · check-bundle-budget.mjs 接线 .husky/pre-commit / CI(本批有意不接:它要跑真实构建并写 app/dist/)→ 批 8 · 守卫的嵌套输出路径盲区(assets/vendor/*.js 既不计首屏也不计懒,仍打印 ✅ 达标 + exit 0;已用真实构建复现)→ 批 8 · 守卫把「非首屏」一律说成「仅动态可达」的假文案(从未验证动态可达性)→ 批 8 · 没有任何门禁看构建日志里的 Circular chunk(环本批已断:1 → 0 条,但「依赖升级可能让死边复活」⇒ 建议纳入某处判据)→ 批 8 · 两个贴限文件:scripts/check-bundle-budget.mjs 299/300、app/src/build/manualChunks.test.ts 292/300 ⇒ 任何新增必须按语义拆分(守卫拆「口径 / CLI」,测试拆「分组规则 / 反例」)→ 批 8 · 下次改动者当次拆 · .gitignore 的 build/ 锚定语义未动(本批只点状取反)→ 批 8 · scripts/**/*.mjs 不在 line-limits 扫描域(SOURCE_EXT 不吃 .mjs、SCAN_DIRS 只有 app/src + app/src-tauri/src)⇒ 本批两个新脚本无门禁保护 → 批 8 · app/vite.config.ts 同时不在 line-limits 扫描域与 tsc --noEmit 的 program(--listFilesOnly 879 文件 0 命中,正样本 main.tsx = 1)→ 批 8 · F4 把 @types/* 挪 devDependencies(依赖卫生)→ 批 8。本批未复核「批 0 其余部分」的落地状态(本文档「批 0 其余部分(未落地)」节写于 2026-09-11)→ 批 8 复核 · AGENTS.md §5 的「subject ≤50」是一条无机器门禁的约定 —— commitlint.config.js 沿用 config-conventional 的 header-max-length = 100,未覆盖为 50,故本批有 2 条 51 字符提交(e46e0e82 / f0592654)照抄计划落地并顺利入库;建议加 'header-max-length': [2, 'always', 50] → 批 8。

瓶颈清单指针:本批的瓶颈清单(14 行,每行含实测 gzip / 为什么降不下去 / 具名归属批次 / 复现命令)在批 2 计划 2026-09-11-frontend-redesign-batch2-bundle.md 的 §收口回写节,另有 Task 12 收口终态节(终态六门禁表 + 回写落点表 + 追加 follow-ups 15–18)。规格 §10 明写「后一批的细节依赖批 0–2 的实测结果(尤其是包体治理量出的瓶颈清单)」⇒ 批 3 的计划者请先读该清单。

批 3 · 壳层落地(2026-09-12,85d51d83^.. 至收口提交,22 个提交)

提交数口径(本文档既定规矩):本文档批次行一律采用「含左端点」口径(A^..B,见批 0-A 行的声明)。本行同款:85d51d83^.. 至收口提交 = 22(git rev-list --count 实测)。其中截至本行落盘时 85d51d83^..d9d0dfc0 = 21(1 计划 + 19 实施与修复 + 1 修复单元),加本节所在的收口提交 = 22。批 2 行是全文唯一例外(不含左端点,已就地注明),本行不与它混用。

交付

  • 单一导航注册表 app/src/shell/navRegistry.ts(111 行):PAGE_COMPONENTS(9 页组件,保留各自精确 props 类型)+ NAV_ENTRIES(8 项,顺序 = 今日 NAV_ITEMS 顺序)+ SETTINGS_ENTRY(设置下沉齿轮)+ ALL_ENTRIES / PRIMARY_KEYS / navComponent / navEntry / isPageKey / PageKey(由组件表键集派生)。App.tsx 不再直接 import 任何页面模块。
  • 单一列注册表 app/src/shell/columnRegistry.ts(77 行):规格 §6.2 的 13 行 + columnSpec(未注册即抛)+ columnsOf(page) + COLUMN_KEYS;7 个字段(规格的 6 个 + page)。执行器仍是 useColumnLayout(A5 裁决:注册表持规格、hook 执行,hook 零改动)。
  • 断点单一真源 app/src/shell/breakpoints.ts(52 行):threeCol 1024 / twoCol 1100 / navFull 1180 / navActionsFull 1400 / outlineCol 1280;6 处散落阈值改判,页面 0 残留。
  • --nav-h 进 token 生成器:app/scripts/gen-tokens.mjs(单一真源)→ ui/tokens.css 产物;10 处 / 9 文件的 56 全部改为消费变量(App.tsx 高度 + AiConversationDock top + 8 个页面的 calc(100vh - 56px))。
  • 窗口尺寸 app/src-tauri/tauri.conf.json:960×720 → 1280×800 + 最小 1024×640;app/index.html 加全局 reset(html, body, #root { margin:0; height:100% })+ 6px 滚动条。
  • A′ 顶栏 app/src/shell/TopBar.{tsx,css}:品牌 + 8 个域 Tab(自绘线性图标 + 纯文字,emoji 出局)+ ⌘K + right 插槽 + ⚙ 齿轮;溢出两级(≥1180 文字 / 1024–1179 仅图标 + title)+ 右簇第二级(<1400 仅图标 + title);AI toast 移出导航行进 fixed 覆盖层。
  • ⌘K 命令面板 app/src/shell/CommandPalette.{tsx,css} + 数据源 kbCommands.ts(纯函数、零 React)+ useKbPaletteSearch.ts(180ms 防抖 + seq + 降级标记)+ utils/kbHits.ts;Ctrl+K 接在 window,与既有 Ctrl+Shift+A 先判更具体组合。
  • 页级错误边界 + 首访加载态 app/src/shell/ShellFallback.tsx(60 行):PageSlot(边界在 Suspense 之外、children 之内)· ?overlay=1 · ?float=1(CaptureStatusProvider 仍在边界外层)· dock —— 四处接线,「叶级」性质由测试证明(出错只卸载那一页、壳层 state 保活、兄弟槽位仍在)。
  • 19 个新守卫测试文件(app/src/shell/* 与 3 个组件/页面测试),既有 1233 条一条未改。

    🔻 收口评审 M-5 就地加注(2026-09-12,上句原文保留)——「19」是误计,实测 = 18 个新测试文件:git diff --name-only --diff-filter=A 85d51d83^..42e88740 -- app/src 实测新增 18 个测试文件(app/src/shell/* 14 + components|pages 4)。两个口径:① 新文件数 = 18(本行 + §11-11 批 3 进度注 + 批 3 计划 §收口回写 §二 门禁表第 5 行的 +18 新文件 / +137 用例,三处一致);② 上句里的「3 个组件/页面测试」也偏小 —— 实测是 4 个(ChatSidebar.test.tsx · ClassroomRightPane.test.tsx · notes/NotesReadingColumn.outline.test.tsx · pages/GoalsPage.test.tsx)。⇒ 本行按 18 / 14+4 读(「19」无出处:它把 KnowledgePage.test.tsx 这个被修改的既有文件也算了进去)。

验收(三条 + 八门禁;原始读数见批 3 计划 §收口回写 · tmp/acceptance.md)

验收 判据 读数
① 9 页全走注册表 navRegistry.test.ts 12 用例全绿(① 键集/孤儿页/import 路径 ② App.tsx 的 page === "key" + navComponent + 不直连页面 ③ 图标 ④ 取值口正/负样本 ⑤ 顺序与 label 冻结 + 保活)+反向证据(非同源第二仪器:注册表源码抽 9 键 ↔ App.tsx 的 page === 字面量集合双向相等)+阴性样本 "not-a-page" → MISS ✅ 三条全过(探针 exit 0)
② 1024 无溢出(限定词:常态;toast 已不在导航行) 合成页探针(真 TopBar 组件 + CDP 精确视口):3 档 × 3 个 toast 态(ok/err/errlong) × 2 徽标 × before/after = 48 行,判据 natural > clientWidth ⇒ OVERFLOW;改前 21 行溢出 / 改后 0 行;加跑 1440 档覆盖 navActionsFull=1400 的第二级 ⇒ 64 行 0 溢出。真实产物探针(加载真 app/dist):1024 / 1180 / 1280 三档判据②③全过 ✅ 1024 +317.89(最坏徽标 +245.89)· 1180 +137.06(最坏 +65.06)· 1280 +237.06(最坏 +165.06)· 1440 +237.2(最坏 +165.2)· 真实产物 1024 +410.47 / 1180 +229.64 / 1280 +329.64
③ 「7 处魔数归零」 不迁就数字:判据 = 「能否被单一真源吸收」(A1)。逐处 before/after + 剥注释口径 + 阳性对照取自不可变旧版本 a7bd1899 + 阴性对照 ✅ 已吸收 8(M1–M7 七处全部归零 + 大纲列 180)· 有目标未吸收 1(KnowledgeDetailPanel 的 34)· 无目标 2(ColumnBar 的 26 · ColumnResizer 的 5)⇒ 不压回「7」

八门禁终态(2026-09-12,干净树,HEAD=d9d0dfc0,app/dist mtime 2026-09-12 14:06:11 且由本次真实构建产出)

line-limits --full >600 0 · 301–600 档 123 · 登记条目 123(exit 0,--write 复跑零 diff)· docs-check exit 0 · registry 312/312/0 · tsc --noEmit 0 错 · vitest 143 文件 / 1370 用例 / 0 失败 · cargo test --test app_lib_tests 2300 / 0 / 6(9.26s,逐字持平)· check-bundle-budget.mjs exit 0 · 首屏 97.16 kB · 余量 102.85 kB(766 modules;懒 21 个 574.71 kB 不计入;CSS 52.27 kB 原始 / 12.58 kB gzip 不计入判据,只报告)· cargo clippy --all-targets 唯一位置集合 20 = 基线,SET-IDENTICAL(汇总行口径:lib 15 / lib test 19(15 重复)/ app_lib_tests 19(19 重复))。

首屏账:92,789 → 97,155 B = 92.79 → 97.16 kB(+4,366 B = +4.37 kB,+4.7%);入口 chunk index-*.js 87,573 → 99,860 B(+12,287 B 原始);index.html 655 → 1,558 B(+903 B,reset + 两条 modulepreload);懒 chunk 22 → 21 个(CaptureFloatPanel 改名重组)。

首屏静态可达图(三件套,永不使用裸绝对数):① 工具口径(把 import type 也算边)47 → 67 文件 / 4 → 4 包;② 真实边口径(TS 编译器 API 剔纯类型边)36 → 56 文件;③ Δ 两口径一致 = +20,新增 20 个文件全部是批 3 的壳层/ui 模块(shell/* 10 个 + ui/icons/* 6 个 + ui/tokens{,.gen} + ui/zIndex + utils/kbHits),pages/** 新增 0 · npm 包新增 0 ⇒ 没有任何页面被静态拉回首屏。

规格漂移纠正(逐处,原文保留 + 就地加注)

漂移 落点
D1 §2「9 个顶部 Tab」遗漏对话面板钮 + 采集徽标 + AI toast 规格 §2 回写块
D2 §2「useColumnLayout 只被 4/9 页采用」→ 页数一致、处数是 7 不是 4 规格 §2 回写块
D3 §6.2 笔记列表列写 1024、今日 700(三值并存 860/700/1100) 规格 §6.2 回写块
D4 审计 J1-8「56px 硬编码三处」实测 10 处 / 9 文件 规格 §2 回写块(审计文档本身归批 8)
D5 审计落点 NotesPage:395 / App:225 因批 0-C2 拆件已过期 规格 §2 回写块(只登记)
D6 §6.2 大纲列「接线或删钩子」→ 走接线;onToggleOutline 走 setManualFolded 不含 expand()(J1-3 死局坐实) 规格 §6.2 回写块
D7 §6.1「9 个 focus* 参数跳转」实测 10 个(多 focusChatId) 规格 §6.1 回写块
§6.1 两个估数 「约 1070px」的前提是右侧簇不带文字(实测满档 1281.8 → R2 后 1027.94);「约 720px」准确(改前 717.11,Δ2.89) 规格 §6.1 回写块
§6.2 ColumnSpec 字段 规格写 6 个、实现 7 个(多 page) 规格 §6.2 回写块
§10 批 3 行 验收词与进度标记 规格 §10 表(本行 + ↳ 批 3 的收口 行)
§12「3 套 markdown 渲染器 · 可并入批 4」 → 批 4 裁决 B8 不并入,去向 批 5/7 规格 §12 该行就地加注
§14 ADR-034 未写(实盘最高仍是 ADR-033,已列目录复核)⇒ 建议批 4 前补写或并入批 8 规格 §14 该行 + §10 ADR 归属行
§11-2 / §5.2 的弹层 20 / 28 与 z-index 17:批 3 未涉及,只登记(本批未迁任何弹层) 规格 §11-2 就地加注

过程中纠正的计划错误(本批最有价值的交付,逐条可复现;全文见批 3 计划就地加注)

  1. Task 3 的验收正则含被转义的 \|(第 1 处判据缺陷):3 种形态只匹配 1 种 —— 「10 处里只有 App.tsx 的 height:56 在射程内,其余 9 处(top:56 + 8 处 calc)未迁移时恒给 0 ⇒ 判绿」(全未迁移时会红,1 命中)。结论在正确仪器下仍成立(10 处消费 / 9 文件、旧写法残留 0)。
  2. Task 6 的 V4 把 import type 算成静态边(第 2 处):47 与 57 两个口径并存;评审用 TS 编译器 API 剔掉纯类型边后,判据重定为「Δ + 机理」三件套(永不使用裸绝对数 —— 同一个「真实静态可达」曾被三方测出 38 / 39 / 49)。
  3. Task 7 Step 5 的预期值被实测推翻(第 3 处):计划写 a-tabs@1280 ≈ 909.99(余量 ≈370),实测 1281.8(−16.8)⇒ 在默认窗宽上的可见回归,而「1024 无溢出」这条验收反而判绿 —— 判据没覆盖的地方,绿灯不是证据。A7 裁决 R2 返工后三档全绿。
  4. Task 8 的 onToggleOutline 字面指令有歧义(第 4 处):逐字「改为 outlineCol.expand()」会把 ✕「收起大纲」也变成 expand(),凭空制造新缺陷 ⇒ 实现为 folded ? expand() : setManualFolded(true)(两个控件各自语义正确)。
  5. 计划自相矛盾(第 5 例,W28):## Global Constraints 逐字「本批不许改 ChatPage.tsx」vs Task 9 的 Files/Step 2 逐字要求改它。裁定走 Task 9 侧(与既有 6 处调用点形态一致);代价:ChatPage.tsx 变 599/600(余 1 行),下一个动它的任务必须先拆。
  6. 计划自相矛盾(第 6 例,W30):Task 11 的 Interfaces 要 onPick: (cmd: Command) => void,Step 4 逐字要 onPick { kind:"page",key }/{kind:"dock"} ⇒ T11 取可执行的 Step 4,Command 仍按计划导出。
  7. Task 14 Step 2 的探针路径走不通(第 7 处判据缺陷,本节新增,收口时实测):计划逐字让探针打开 file:///…/app/dist/index.html —— vite 产物用绝对路径 /assets/index-*.js + crossorigin(Tauri 从应用协议根提供,绝对路径是对的)⇒ file:// 下解析成 file:///assets/…(不存在),实测 #root 子节点 = 0。正解 = 用本地只读静态服务器提供 app/dist(探针 --mode http,绑 127.0.0.1、结束即关)。--mode file 的失败读数保留在 tmp/acceptance.md 用于复现,不得用作结论。
  8. 验收计数与口径的三处过时数字(均已重定):① vitest 基线「≥1256」是 T6 之后的读数,真基线是 125 文件 / 1233 用例 ⇒ 判据改为「既有 1233 条逐文件一条不许少 ∧ 新增只增不减」(实测:125 个既有文件用例数一模一样、0 消失、0 减少);② V6 期望「12–15 个原子提交」,实数 22(构成见提交清单,不为落进区间而合并提交);③ 计划 Step 8 写「A1–A5 五处裁决」实为 A1–A7(A6 = 删 legacyLabel 的授权;A7 = 顶栏 ≥1180 回归与 R2 返工)。
  9. 计划 V 表里的 PowerShell 单行命令在 PS 5.1 下 SyntaxError(第 4 处判据缺陷,W29):T9 的 V3 逐字命令跑不起来 ⇒ 改用等价 Node 脚本;判据一律改成可粘贴的脚本文件。
  10. Task 4 缺「行为中立性」核对程序(W7):只给了结论没给程序 ⇒ 本节按 T4 实际做法补写该程序(见计划 Task 4 就地加注)。
  11. 计划两处计数错(W9):表 2 的 M1 写「8 个页面」实测 7 页(8 处,ReviewPage 占 2);表 1 写 useColumnLayout「5 页」实测 4 页。
  12. Task 1 节无可粘贴 argv / 无代码围栏(W24)· 宽度探针全部读数出自离线复刻页、且 A_TABS 顺序与已提交注册表已分叉(W23/I-3:…复习,体系,目标,AI对话 vs …复习,AI对话,体系,目标)。⇒ T14 的探针按注册表真实顺序渲染(复用真 TopBar 组件,顺序由注册表 map 决定)。
  13. Task 7 Step 3 第②层「只测 title」口径不足(W11/A6):删 legacyLabel 后,注册表 label 成为规范态文字的唯一真源 ⇒ 补「可见文字 textContent 逐字 === e.label」+ A2 的 emoji 负判据(DOM/注册表双口径),配 4 个变异体。
  14. 「7 处魔数」的「7」从未被定义(W1/A1):规格全仓仅 1 命中、从不展开 ⇒ 判据取「能否被单一真源吸收」,不迁就数字(终态 8 / 1 / 2)。
  15. --nav-h = 56 是计划者取值(W4):规格只给名字不给值 ⇒ 只把 56 搬进 token 生成器,值暂保持 56(不在本批发明数字)。

未做(登记,逐条带归属批次)

真机 1024×640 / WebView2 冒烟 → 批 8(用户已裁决本批跳过;不得出现「已在真机确认」类表述)· 命令面板迁移到 Modal 原语 → 批 4 · ShellFallback → Loading / StatusLine → 批 4 · focus* 状态机收敛(本批只收敛入口,10 个字段一个未删)→ 批 5 · 列折叠的连续运动(Flip)→ 批 6 · 相变两态(§6.3)→ 批 6 · pinnable 无消费方 → 批 6 · 列状态对象对齐(A5 选项 (b):删 useColumnLayout、注册表自实现)作为日后可能的合并方向,不得声称能力对等 → 无期 · 快捷键集中注册表(⌘K 与 Ctrl+Shift+A 都注册在 window)→ 批 4/8 · index.html 的细滚动条在弹层/虚拟列表中的核对 → 批 4 · ADR-034(壳层)未写 → 批 4 开工前或批 8(需控制方裁决)· §6.2「本次改动」列里的 🗂 会话·详情头改粘性 与 📝 笔记·工具栏三层合并为单行 → 未做(不属壳层/列契约;去向需裁决)· 34px 窄条吸收 → 批 4(与统一列头/ColumnBar 收敛一起做)· 26 / 5 两处无规格目标 → 登记不碰 · 3 套 markdown 渲染器归一 → 批 5/7(批 4 裁决 B8 不并入)· scripts/**/*.mjs 与 app/vite.config.ts 不在 line-limits 扫描域 → 批 8 · check-bundle-budget.mjs 未接 pre-commit/CI → 批 8 · bundle-eager-graph.mjs 把 import type 计成静态边 → 批 4 或独立小单元(改它会改历史读数 ⇒ 必须新旧口径并列)· W27 pre-commit 跑全树、--write 按工作树刷新 ⇒ 并行提交必生窗口(批 3 实证 3 次)→ 批 8 加 --staged 模式。

诚实代价(不许省略)

  • 首屏 gzip +4.37 kB(92.79 → 97.16 kB,+4.7%),入口 chunk 原始 +12.29 kB —— 涨的是必要成本(导航注册表 + 列注册表 + 断点 + 窗口常量 + 顶栏 + 命令面板 + 三个守卫 + 四个新测试面)。仍远低于 200 kB(余量 102.85 kB)。
  • index.html 变大(655 → 1,558 B,+138%):全局 reset + 两条 modulepreload。
  • 这是本系列第一次「界面真的变了」:顶栏 emoji 被自绘线性图标替换、AI toast 换了位置(从导航行 → 右上 fixed 覆盖层)、右簇在 <1400px 只剩图标、设置从 Tab 下沉为齿轮、「课堂助手」改名为「课堂」(用户可见改名,非纯样式 —— 建议产品口径确认,见 follow-ups)。规格 §10 末句明写「骨架在批 3」,与批 0–2 的「界面几乎不变」不同。
  • 三个贴边文件:ChatPage.tsx 599/600(余 1 行) · NotesPage.tsx 300/300(余 0) · App.tsx 574/600(余 26)(批 2 收口时 519)⇒ 下一个动它们的任务必须先拆。

    🔻 收口评审 M-8 就地加注(2026-09-12,上句原文保留)—— 按「任务预算贴边」口径还须加第四个:app/src/shell/CommandPalette.tsx 219/220(余 1 行)(= scripts/line-limits.mjs 的 countLines() 口径;硬限 ≤300 不贴边、无需豁免登记,但 T11 预算 ≤220 已贴边:T11 交付 179 → T12 追加「取数 / 降级 / skipped」三条渲染 +40)。批 4 的 Modal 迁移必动它 ⇒ 提前登记(同列:先拆 CommandList 子组件,或由批 4 计划把预算提升到 ≤260)。四者性质分两档:ChatPage / NotesPage / CommandPalette 是预算贴边(动它们前必须先拆/提预算),App.tsx 是余量登记(余 26 行)。

  • 4 个文件超计划预算(均 ≤300 硬限、无需豁免登记、--write 零变化;控制方裁定接受并回写计划预算,理由:计划预算只是估算,绑定约束是 ≤300 且不登记;拆文件解决不了,压回预算只能删减既有判据覆盖面 —— 那正是 A1 明禁的「为凑数字牺牲实质」):TopBar.css 142(≤120)· columnConsumption.test.ts 126(≤120)· ShellFallback.test.tsx 163(≤120)· ClassroomRightPane.test.tsx 138(≤120)。
  • 首屏静态可达 +20 文件(shell/* + ui/icons/* + ui/tokens* + ui/zIndex + utils/kbHits)—— 这是必要的(新壳层就是要在首屏),但它是批 2 挣来的余量第一次被实质消耗;pages/** 与 npm 包均 0 新增(机理核查)。
  • 一条既有 flake 未消除:KnowledgeGraphView.test.tsx 的负载敏感用例(批 3 开工前就存在,已在基线树复现)。
  • 真机未验证:tauri.conf.json 的四个数字在真实 Tauri 窗口里的表现一次未跑;顶栏像素证据来自 headless Edge,不是 WebView2。
  • 1 条提交超 ≤50 约定:ecc36a8d = 53 字符(commitlint 沿用 config-conventional 的 100,未拦住)⇒ 与批 2 同类,建议加 header-max-length: [2,'always',50](归批 8)。

    🔻 收口评审 M-7 加注(2026-09-12):同一条 ecc36a8d 还有第二个性质须登记 —— 它是卫生修复(视口复原),无可红判据(见上方提交清单第 12 行注)。⇒ 本行不得被读成「它是一条有判据的修复(只是 subject 超长)」。

app/src-tauri/tauri.conf.json 的 §10 额外审查记录(W25 —— 之前只留在 gitignored 的报告里,此处 durable)

AGENTS.md §10 把 tauri.conf.json 列为「变更需额外审查的文件」。批 3 确实改了它(Task 4),审查结论如下(出处:.superpowers/sdd/2026-09-11-frontend-redesign-batch3-shell/task-4-report.md §3,评审 M-f 已独立核对):

  • 改动面 = app.windows[0] 的五个键:width: 960 → 1280 · height: 720 → 800 · 新增 minWidth: 1024 · 新增 minHeight: 640 · 新增 resizable: true。title 未动(原值已是「熵减 · 本地知识提取」)。
  • security(CSP + assetProtocol)与 bundle(resources / icon / targets)逐字节未动 —— diff 之外没有第二个 hunk。
  • 无夹带:未动 Rust(commands_window.rs 的采集浮窗 inner_size(360,240) + resizable(false) 保持原样);未新增/删除任何权限、capability 或 CSP 指令。
  • 可验证性:JSON 的四个数字由 app/src/shell/windowSize.test.ts(4 用例)与 TS 常量逐字对齐;EOL 保持纯 CRLF(crlf=43 / bare_lf=0),未引入 EOL 噪声。
  • 未验证:真实 Tauri 窗口是否真按 1280×800 打开、最小尺寸是否真的夹住拖拽 —— 一次未跑(需要桌面会话),归批 8 真机验收。

提交清单(22 个,85d51d83^.. 至本收口提交;逐条 subject ≤50 除 ecc36a8d 53 字符)

# sha subject 归属
1 85d51d83 docs(plan): 批 3 壳层落地实施计划(14 任务) 计划
2 71ca8600 feat(ui): add nav height design token T2
3 02032cfe refactor(shell): consume nav height token T3
4 d01a623f feat(shell): set window size and reset html T4
5 c7d20954 feat(shell): add single source of breakpoints T5
6 4c89c687 fix(shell): make scrollbar 6px take effect T4 修正
7 742b892d feat(shell): add navigation registry for 9 pages T6
8 92ea5d6b feat(shell): add column spec registry T8
9 fd83abb4 feat(shell): rebuild top bar, float ai toast T7
10 4f8f3d3c feat(shell): wire three pages to column specs T9
11 882a61ef test(shell): pin column tier mapping T8 补强
12 ecc36a8d test(notes): restore viewport in knowledge page tests 微单元(M-c)· 卫生修复(无仓内可红判据)
13 6b81f414 fix(classroom): unify right pane width wrapper T10
14 477bf604 feat(shell): add command palette and Ctrl+K T11
15 a8854292 fix(chat): wire sidebar resize handle T9 评审 I-1
16 767a8b32 test(shell): pin key identity and 0/0 guard T8 评审 I-1/M-1
17 2989c8c3 test(shell): 补常驻状态件装配判据 T7 评审 I-1/I-2
18 b567f0e6 feat(shell): wire kb search into palette T12
19 9bcb4720 feat(shell): add slot error boundary and loading T13
20 2b426236 fix(shell): 修 T12 评审 I-1/I-2 与 M-1/M-2/M-4/M-5 T12 修复单元
21 d9d0dfc0 fix(shell): 加固 T10/T13 五条评审 Minor 判据 T10/T13 修复单元
22 (本次收口提交) docs(spec): close out shell batch three T14

注:第 22 行的 sha 无法写进它自己的提交内容里(自引用);批 2 的先例同样把「收口回写提交」单列在区间之外。本行的「22」= 85d51d83^..<收口提交> 含左端点。

🔻 收口评审 M-7 加注(2026-09-12)—— 第 12 行 ecc36a8d 的性质是「卫生修复」,不得列进「有判据的修复」:它是环境卫生修复(KnowledgePage.test.tsx 的 afterEach 补视口复原),没有任何仓内可红判据 —— 收口评审的变异体 ecc-no-restore(去掉复原)实测 exit 0 · 6/6 全绿(导出副本,未用 --reporter=basic、未用 eval),即该风险在本仓(vitest 默认每文件独立环境 + 该文件 beforeEach 每例重设视口)不可证伪。修复有效性由探针实测:用「后续 describe 的 beforeAll」读环境值 ⇒ 修复态 1024 / 泄漏态 1280(修复确实生效)。⇒ 判据归属:防泄漏的机器判据(例如全仓 afterEach 环境还原守卫)归批 8 的测试治理单元,本批不声称它有判据。

🔻 提交树自洽性更正(收口评审 I-1,2026-09-12)—— durable 载体上「实证 3 次」记错,实测 5 个提交:本节先前的台账/计划口径是「批 3 提交树不自洽实证 3 次(92ea5d6b / 4f8f3d3c / fd83abb4 之前同类)」。收口评审把批 3 的全部 22 棵提交树逐一导出(git -c core.autocrlf=false archive -o t.tar <sha> → tar -xf → 在树内跑它自带的 node scripts/line-limits.mjs --full)实测:5 个 exit 1 · 17 个 exit 0。

  • 92ea5d6b(T8):(e) 行数不一致:app/src/App.tsx 声明 **509** / 实测 **503**;
  • 4f8f3d3c(T9)· 882a61ef(T8 补强)· ecc36a8d(微单元 M-c)· 6b81f414(T10):四处逐字同形 —— 声明 548 / 实测 509,全落在 fd83abb4(T7) 与 477bf604(T11) 之间的同一并行窗口;
  • fd83abb4 其实自洽(先前把它算进「不自洽」是错的);其余 17 个(含收口提交 42e88740)全部 exit 0。
  • 口径更正:批 3 实证 = 5 个提交(不是 3 次),点名 5 个 sha;docs/superpowers/plans/2026-09-11-frontend-redesign-batch3-shell.md 的 §一 W27 注与 follow-up #1 已就地加注(原文保留)。
  • ecc36a8d 的门禁读数取自工作树(见上条 M-7 注):该单元的「提交后门禁 exit 0」只在工作树口径成立,它自己的提交树带一处并行窗口不自洽 —— 这是本批「工作树绿 ≠ 提交树绿」的第 5 个实例。
  • 机理结论不变(--write 按工作树刷新登记表):⇒ follow-up #1(批 8 给门禁加 --staged 模式)的依据比原先记的更强(5 个,不是 3 个)。HEAD 本身不受影响(42e88740 自洽)。

批 4 · 原语迁移(2026-09-12,4905d4d8^.. 至收口提交,49 个提交)

提交数口径(本文档既定规矩):本文档批次行一律采用「含左端点」口径(A^..B,A = 该批第一个提交,见批 0-A 行的声明)。本行同款:4905d4d8^.. 至收口提交 = 49(git rev-list --count 实测 = 48 个实施/评审/修复提交 + 本节所在的收口提交 1 个)。同口径校验:批 3 的 85d51d83^..42e88740 实测 22,与批 3 行的「22 个提交」逐字相符 ⇒ 口径无误。另报两个字面读数以免歧义:git rev-list --count 42e88740..HEAD = 48(不含左端点)· git rev-list --count 42e88740^..HEAD = 49(它把批 3 的收口提交 42e88740 也算进来了)⇒ 批 4 自己的提交数按 4905d4d8^.. 那一行读。批 2 行是全文唯一例外(不含左端点,已就地注明),本行不与它混用。

交付

  • 原语层补齐(批 4 的三处能力扩展,全部走 B6 的「≥3 共用 ⇒ 改原语」或「结构上无法表达」例外通道):① Modal 的 body 滚动锁(20 个弹层共用 ⇒ 改原语;引用计数 + 原值快照、门控 presence.mounted 而不是 open);② Text 的两个属性级受控槽 testId / title(B16:各 ≥3 处,不加 role/onClick/aria-*/任意 DOM 透传);③ Surface 的第 5 档圆角 radius="pill"(B17:切片内 999 实测 3 处 ⇒ 加档,落 2360c3d9)。
  • 五条棘轮 + 切片清单(B11 的「切片 + 棘轮」中间态):emptyStateRatchet(切片 28 文件 + 例外 8 + 余量 5)· loadingRatchet(冻结 8,表 18 键逐格钉死)· statusLineRatchet(迁移面 49 文件 + 三红 114 处 / 67 文件)· textRatchet(弱化灰 249 → 63;字号越界 558 / 120 只冻结)· surfaceRatchet(边框 240 → 226 · 越界圆角 270 → 261 · 阴影 24(值 11 → 6) · FROZEN_SURFACE_TAG_TOTAL 0 → 14)。每条都带防真空阳性对照、逐文件牙齿(或显著登记的下界)、防僵尸豁免。

↳ 收口后更正(2026-09-12 · 收口评审 I-6 + 修复单元 ed07d491;上行原文一字未改):本行 textRatchet 的(弱化灰 249 → 63)终态是 64 —— FROZEN_MUTED_GRAY_TOTAL = **64**、逐文件格 components/NoteRowContextMenu.tsx 1 → 2(条目数/文件数仍 44/44)。249 = 186 + 63 是旧剥注释仪器口径下的恒等式;物理真值 = 250 = 迁移 186 + 例外 64。逐类真源(我自测 tmp/docfix/d2-kind.mjs):条目数 14 / 8 / 9 / 7 / 4 / 1 / 1(Σ44)· 处数 19 / 11 / 11 / 14 / 7 / 1 / 1(Σ64);旧分解「interactive* 35 · ternary-no-equivalent 10 · nontext 6 · b1-non-migrated 9 · tag 1 · colorMap 2 · C 类 2」自列之和 = 65 且 colorMap 与「C 类」重复计数,不得再引用。

  • 20 个手写弹层全部迁入 Modal(A14 + B4 + E2 = 20,清单钉死在 dialogMigration.e.test.ts 的 DIALOG_20);z-index 六档整段迁移(裸值 58 处 / 43 文件 / 17 值 → 3 处 / 3 文件 / 3 值,那 3 条是 B2 的例外且逐条带理由)。
  • 四套 toast → 3 套收敛 + 1 套机器可判例外(App.tsx AI toast 走新的 placement="belowNav" 槽 · SessionsPage 改 useTransientToast · hook 换渲染并归 toast(500) 档 · 面板级内联 banner 带 4 条理由不迁)。
  • 8 处 window.confirm → ConfirmDialog(6 个文件;文案按分隔符逐字拆解,疑问句进 title,不新造一句;取消路径逐处渲染级取证,含 NotePreviewView 的 setStatus 副作用)。
  • 按钮收敛:*Btn* 常量族 → <Button>,原生 <button> 493 → 394 处 / 121 → 114 文件(Δ −99,逐文件 Δ 之和 == 形状表总数 99);const *Btn* 79 → 56 行 / 55 → 44 文件;棘轮 510 → 394。

↳ 收口后更正(2026-09-12 · 收口评审 M-11 + 修复单元 531eb93f;上行原文一字未改):上行「394 处 / 114 文件」(与棘轮 510 → 394)是 f6dd012f 时点的读数,不是 HEAD。收口修复单元把 nativeButtonBaseline 收紧到实测 ⇒ 终态 = 394 → 393 处 / 121 → 115 文件、FROZEN_NATIVE_BUTTON_TOTAL = **393**(文件数 +1 来自 T13-b 拆件把 components/chat/ChatLaunchMenu.tsx 计入,SPLIT_MOVES 已登记守恒、守卫未失效)。独立复算(node …/tmp/docfix/measure.mjs <tree>/app/src,剥注释后整段 /<button[\s>]/g):f6dd012f 导出树 394 处 / 114 文件 · HEAD 393 处 / 115 文件。

  • 五类切片迁移:空态(切片 28 文件全走 EmptyState;ChatPage 先拆件 599 → 578 + 新件 ChatLaunchMenu.tsx 77)· 加载(10 文件,6 处骨架)· 错误行(49 文件走 StatusLine)· 弱化文本(186 处走 Text tone="ink-3";testId/title 两槽实用 12 处)· 卡片边框/圆角/阴影(<Surface> 14 处 · 6→8 9 处 · 阴影 token 20 处)。
  • 23 个新测试文件 / 227 用例(逐条见批 4 计划 §收口回写 §二);新增 6 条独立守卫族(原生按钮棘轮 · z-index 棘轮 · 四条切片棘轮 · 两条 shell 守卫 · 两个弹层形态判据族)。

🔻 收口评审后的更正与溯源(2026-09-12 · 收口评审 + 收口修复单元;以上「交付」原文一字未改)

更正块 A · 修复单元带来的 3 处数字变化(那 4 条提交不计入下面的 49):

# 项 旧 新 机理 提交
1 Text 弱化灰例外总量 63 64 sliceScan.stripComments 不再把 JSX 闭合标签 </x> 的 / 当正则起点 ⇒ 受害行 components/NoteRowContextMenu.tsx:175 由「被抹掉」变「被数到」 ed07d491
2 同上 · 逐文件格 components/NoteRowContextMenu.tsx 1 2 同一文件内 +1;条目数与文件数仍是 44 ed07d491
3 原生 <button> 总量 / components/WindowSelectCard.tsx 格 394 / 4 393 / 3 T12 后 271a281c 把 1 处换原语但基线未同步(收口评审 M-3 的 slack)⇒ 收紧到实测;FROZEN_NATIVE_BUTTON_TOTAL = **393** 531eb93f

独立复算(本单元自跑,非照抄):弱化灰三口径并列(HEAD 工作树,域 = app/src/** 减 *.test.ts(x) 减 ui/primitives/**)—— OLD 仪器(091d1c3d 的 sliceScan)63 行 / 44 文件 · NEW 仪器(HEAD)64 行 / 44 文件 · NAIVE(朴素剥注释)64 行 / 44 文件,三口径唯一差异文件 = components/NoteRowContextMenu.tsx(1 / 2 / 2);原生 <button> HEAD 393 处 / 115 文件 · f6dd012f 394 处 / 114 文件(命令:node .superpowers/sdd/2026-09-12-frontend-redesign-batch4-primitives/tmp/docfix/measure.mjs <tree>/app/src)。

另登记两条:① dialogMigration.e.test.ts 不受该修正影响 —— 它不 import sliceScan(只 import node:fs / node:path / vitest,自带 stripComments)⇒ 未改一行;② 贴边表变化 —— ui/primitives/loadingRatchet.test.ts 拆出 ui/primitives/loadingScan.ts(101 行)后自身降到 181 行(不再是贴边文件);ui/primitives/textBaseline.ts 仍 299/300(贴边);ui/primitives/dialogMigration.e.test.ts 仍 300/300(余量 0)。

更正块 B · 收口评审 I-5 / I-6 / I-7 与 13 条 Minor 的落点(原文保留 + 只追加):

  • I-5(弹层测试覆盖写反):下文「两条未验证的诚实边界」里的「20 个弹层里只有 5 个有同名测试 / 无覆盖的 15 个」实测不成立 ⇒ 真值 = 10 个有同名测试文件且该文件真的 render(<X) / 10 个无(该处已就地加注,含逐个列名与复现命令;批 4 计划 §六 第 3 条同款更正)。
  • I-6(弱化灰「7 类」分解):见更正块 A 的独立复算;真源逐类 = 条目 14/8/9/7/4/1/1(Σ44)· 处数 19/11/11/14/7/1/1(Σ64)。
  • I-7(规格 §11-2 例外表 3 个成员错):BrowserChrome / GroupSidebarRow / NoteHeaderActions 不在 NON_MIGRATED_14,缺 NoteEditView / NoteLinkToSystem / RichEditorView ⇒ 规格 §11-2 与 ADR-033:162 均已追加「🔻 更正表」(逐行成员资格 + 复现命令)。
  • M-1 计划 ADDED 分组「ui/primitives/ 16 个(158 用例)」与其自列清单之和 175 不符(175 + 30 + 22 = 227 = 同句总数)⇒ 更正为 175(本单元复算:70 + 9 + 6 + 6 + 7 + 6 + 8 + 3 + 8 + 7 + 4 + 16 + 25 = 175,见批 4 计划 §二 门禁 5)。
  • M-2 dialogMigration.e.test.ts:218 的 onkeydown= 是死分支(TSX 里 React 只写 onKeyDown;git grep 'onkeydown=' -- app/src 的 4 处命中全在该族测试文件自己的注释/断言串里,生产源码 0;onKeyDown= 实测 19 处)⇒ 只登记不修(该文件 300/300 余量 0)。
  • M-3 已由 531eb93f 关闭 ⇒ 编码数字同更正块 A 第 3 行。
  • M-4 pages/ChatPage.tsx 行数:579 权威(cbc15837 拆件 → 578 · T16-B 的 be925809 → 579;控制方 20:4x 已就地更正台账、豁免表 :24 亦为 579)⇒ 本行下方贴边表的 578 已就地加注。
  • M-5 app/src/ui/zIndex.guard.test.ts:221 的失败文案「对已知存在的 5 处应命中 5」陈旧 ⇒ 已改为「3 处应命中 3」(只改这句文案、零断言改动;该文件 262 行 < 300,line-limits --full 仍 exit 0 且零新增登记)。
  • M-6 计划「296 是手抄噪声」这个机理不成立:296 是朴素剥注释口径的真值(42e88740 导出树:OLD sliceScan 295 / NEW 296 / NAIVE 296,差额 = components/NoteRowContextMenu.tsx:175)⇒ 那是口径差、不是手抄;解释读数差异必须点明两种口径。
  • M-7 五条新仪器陷阱已入册(见下文「陷阱 4 · 批 4 收口新增的仪器陷阱」)。
  • M-8 「精确写法」终态 = 157(42e88740 180 → T17-A 0bc09a41 171 → HEAD 157)⇒ 计划 §八 4 的「终态 171 精确」实为 T17-A 冻结值(本单元复算:border:\s*"1px solid #e5e7eb" 口径 = 180 / 171 / 157;含复合口径 = 259 / 240 / 226)。
  • M-9 fontSize 全量终态 = 1088(42e88740 1274 → 8f5bd9f1 1172 → T16-A/T17-A 3ed9cfe9 / 0bc09a41 1123 → HEAD 1088)⇒ 计划 §八 4 的「终态 1123」实为 T16-A 时点(本单元复算逐字一致)。
  • M-10 「弱化灰 249 行 / 100 文件」是 T16-A(3ed9cfe9)时点的值,不是终态;同一时点的修正仪器读数是 250 / 100,终态 = 64 / 44 ⇒ 计划 §八 4 需带时点。
  • M-11 原生按钮「394 处 / 114 文件」是 f6dd012f 时点的值,不是终态(HEAD = 393 / 115)⇒ 本节「按钮收敛」那行已就地加注。
  • M-12 b1-non-migrated 的「9 处」是回退动作数(tmp/t16b/revert-b1.mjs 的 SITES = 9 条 / 7 文件);该类冻结处数是 14(收口修复前 13)⇒ 两个数必须分开写。
  • M-13 规格 :614 的「CommandPalette 两处 zIndex("modal")」在 HEAD 为 0(bde807dc 已把层级交给 Modal;git grep -n 'zIndex(' -- app/src/shell/CommandPalette.tsx 实测空、bde807dc^ 上为 2)⇒ 规格该处已补时点更正。

🔻 溯源与提交数(收口后):批 4 的 closed range = 4905d4d8^..091d1c3d = 49 提交(含左端点口径,不变;git rev-list --count 4905d4d8^..091d1c3d 实测 49,与本节开头逐字相符)。收口评审后的修复提交 = 4 条(不计入那 49,在此作为「收口后修复」登记):

sha subject 关闭的评审条目
ed07d491 test(ui): fix slice scanner closing tag bug I-1(sliceScan 的 </x> 误判 + 弱化灰重冻)
8a2dd5e1 test(ui): harden loading ratchet teeth I-2(aria-label 穿透)+ I-3(迁移面只许增锚)
531eb93f test(ui): tighten native button baseline M-3(原生按钮棘轮 slack 收紧)
cd85e4c3 test(ui): stabilise graph focus assertions I-4(flake 最小稳定性修改)

另:7d541254(docs(plan): 批 5 视图层实施计划)是并发单元的产物,不属批 4(既不计入 49,也不计入上面 4 条)。

🔻 I-4 的 flake 处置(控制方已裁):components/KnowledgeGraphView.test.tsx 的「局部聚焦」是既有负载敏感 flake(批 3 已在 a7bd1899 上复现过;批 4 未改该测试文件,git diff --name-only 42e88740..091d1c3d -- …/KnowledgeGraphView.test.tsx = 0)。修复单元做了最小稳定性修改(18 处 waitFor 超时 5000 → 15000,与 vitest.config.ts 的 testTimeout: 15000 对齐;未放宽任何断言、未加睡眠、未改配置、未加 retry),但本机两种负载各 8 次 + 无负载 6 次均未复现 ⇒ 状态记为「已加固、未复现」(不声称已修好)。纪律:① 变异体实验不得与全量测试并发;② 今后若在顺序执行下再红 ⇒ 按新 flake 重新定位。

验收(两条 + 八门禁终态;原始读数与命令见批 4 计划 §收口回写 §一/§二)

验收(规格 §10 批 4 行逐字) 判据 读数
① z-index ≤6 count-bare-zindex.mjs(exit 0)+ zIndex.guard.test.ts(7 用例 exit 0) 裸值 58 处 / 43 文件 / 17 值 → 3 处 / 3 文件 / 3 值(10·999·1000,全部是 B2 例外、逐条 why >20 字);冻结名单 58 → 3;六档逐字 = raised 10 · panel 100 · popover 200 · modal 300 · modalNested 400 · toast 500 ✅
② role="dialog" 20/20 dialogMigration.{a1,a2,b,e}.test.ts + zIndex.guard.test.ts(5 文件 / 77 用例,exit 0) 20/20 只经原语(barrel ∧ 无深导入 ∧ 无自建遮罩 ∧ 无 keydown ∧ 无裸 z-index);role="dialog" 的源码命中只出现在 ui/primitives/Modal.tsx(恰 1);三口径并列 = 20(验收)/ 28(ADR-033 同行)/ 34(跨行容忍),等式 34 − 20 = 14 = 11 锚定菜单 + 3 覆盖层 ✅
R2 的中间态(必读) 五条棘轮 验收第 3 条「五类重复 → 各自 1 个原语」在批 4 结束时并不成立:批 4 = 切片内清零 + 切片外余量冻结(去向批 5/7)。规格 §11-3 已就地加注(含「若选 (A) 全量的余量清单在此」与判据限度)。

八门禁终态(HEAD = 199da54b · 静止干净树 · 真实构建产出 app/dist mtime 2026-09-12 19:54:33 · 采集 19:52–19:56)

line-limits --full >600 0 · 301–600 档 122 · 登记条目 122(exit 0;--write 复跑零 diff ⇒ 豁免表不在本次提交路径)· docs-check exit 0(扫描 276 / 检查 176,五项全 ✅)· registry 312/312/0 · tsc --noEmit 0 错 · vitest 166 文件 / 1608 用例 / 0 失败(逐文件对拍批 4 开工基线 143/1370 ⇒ LOST=0 · SHRUNK=0;GROWN 6 · ADDED 23)· check-bundle-budget.mjs(真实构建,取 tmp/build.lock)exit 0 · 首屏 100.30 kB gzip(原始 317,778 B;余量 99.70 kB;CSS 62.63 kB 原始 / 14.42 kB gzip 不计入判据,只报告;入口 index-4qKuUwYr.js 108,099 B)· bundle-eager-graph 89 文件(源 76 + CSS 13)/ npm 包 4,TS-API 真实边口径 65 / 4,Δ = 0 · Rust 未复跑(本批零 Rust 改动:git log 42e88740..HEAD -- app/src-tauri 为空)—— 判据仍是批 3 的 2300 / 0 / 6,不得读成「已跑」。

首屏账(Δ + 机理;未做逐提交二分定位):计划表 1 基线 97.16 kB(= 97,155 B gzip / 309,524 B 原始) → 终态 100.30 kB(100,297 B / 317,778 B) ⇒ Δ = +3,142 B gzip = +3.14 kB。机理逐项(有独立 A/B 证据):T9 的 barrel + 原语层进首屏 = +2,348 B(ShellFallback 半程 +2,159 · palette 半程 +189;真实边 52 → 65 = ui/primitives/** 全层;pages/** +0;npm 包 4 → 4)· T10 = +373 B · T16-B 的 Text 迁移 = −112 B · T17-B 的 Surface 首次进首屏 = +101 B(产物里 ed-surface--bordered 迁前 0 命中 ⇒ 组件曾被 tree-shake)· T16-A 两槽 = +17 B · T17-A 结构性 0 · 剩余 ≈ +357 B 属 T11–T15 的调用点接入(未逐提交二分)。⚠️ 纪律:< ~2 kB 的 Δ 必须用同源真构建对比(同源两树曾被实测差 9 B,其中 index.html 18 B 纯 CRLF、CSS 排序后逐段相同 ⇒ 差异来自 rollup 的 CSS 拼接顺序,非确定性)。B5 的诚实代价实测 = +2.35 kB,低于 B5 给出的上界 +3.41 kB。

首屏静态可达图(三件套,永不使用裸绝对数):工具口径 67 → 89 文件(= 源 63 → 76 + CSS 4 → 13)· 真实边口径(TS 编译器 API 剔 import type)52 → 65 · npm 包 4 → 4 ⇒ +13 全部是 ui/primitives/** 全层(barrel + 12 个原语模块),没有任何页面被静态拉回首屏。

规格漂移纠正(逐处,原文保留 + 就地加注)

漂移 落点
§4.2「四档圆角」→ 批 4 新增第 5 档 pill(实测 3 处;token 真源仍 4 档、走 var() 兜底;SURFACE_CLASSES 是自计数式守卫) 规格 §4.2 加注(原文逐字保留)
§4.3 条件③(审校模式 ≥4.5:1)在仓内无实现 ⇒ 批 4 的 Text 一律 ink-3、ink-4 0 使用 规格 §4.3 加注
§5.1 收敛账本 10 行 → 逐行「批 4 实测口径」(Button 107/63 不可考 ⇒ 三口径并列 510/121 · 80/55 · 103/37;Surface 180 ⇒ 真面 172、实迁 14;Text 251 ⇒ 249 = 186 + 63;Loading 85 ⇒ 棘轮口径 18/18 → 8;StatusLine 196 ⇒ 迁移面 49 + 三红 114/67;Toast 4 → 3 + 1 例外;ConfirmDialog 21 ⇒ 实测 confirm( 24 = 8 window.confirm + 16 非 window) 规格 §5.1 加注(表下整块)
§10 批 4 行 → 加 ↳ 批 4 的收口 行(✅ + 两条验收读数 + R2 的中间态 + 八门禁 + 观测口径) 规格 §10 表
§11-2 → 20 的构成(A14+B4+E2)+ 例外表(11 菜单 / 3 覆盖层,逐条理由)+ 28/34 并列 + 有意值收敛 规格 §11-2 加注
§11-3「五类重复 → 各自 1 个原语」→ 加注中间态(B11 的附带硬要求;含终态表与「(A) 全量的余量清单在此」) 规格 §11-3 加注
§11-11 八门禁 → 加批 4 进度注(含「cargo 未复跑」的显式声明与 flake 登记) 规格 §11-11 加注
§14 ADR-034 行 → ✅ 批 4 已补写(4905d4d8 + 两轮加注 + 已进 docs/adr/README.md);ADR-035 仍顺延批 6;S-4 两条本批未做 ⇒ 归批 5 规格 §14 加注 + ADR-034 §登记 加注⑦
§12「3 套 markdown 渲染器」(B8) 已在批 3 收口提交 42e88740 就地加注(「不并入批 4 ⇒ 批 5 或批 7」)⇒ 本批不重复加注(避免第二处真源)
ADR-033 §7「28 个手写弹层」的适用对象 → 明确为「对话框类」(B1 的落点)+ 三口径并列 + ESC 残留 5 处的「必须一并处理」改读为「必须一并登记」 ADR-033 §7 加注
ADR-033 §4 的行内 style 禁令 → 自 69489f9f 起有真实输入(14 个 <Surface> 开标签、覆盖命中 0)+ style={S} 间接写法是假阴 + 两条 Surface 缺口 ADR-033 §4 加注

过程中纠正的计划错误(全表 ①–⑲;⑧–⑰ 是台账 §四 点名的那一段,⑱⑲ 为本次补登)

① Task 5 的「6 个测试文件需改」实测 0 处需改(全仓对那 9 个锚点零引用)· ② Task 5 的 V5 把 zIndex.guard 记成 4 用例(实为 7)· ③ Task 6 的 M5 是空变异(锚已无引用)· ④ Task 0 Step 2 的两处口径(六档值判据的真身是 ui/zIndex.test.ts:16-25;删规格行红在模块加载期)· ⑤ 计划 :13 的 gitignored 链接(导出树 docs-check 必红)—— ✅ 已修 0228a013 · ⑥ T1:Step 5 的 M4 期望写反 · ⑦ T1:计划者探针在 Windows 下域过滤失效(includes("/ui/primitives/") 对反斜杠恒假)· ⑧ SessionListPanel.tsx 误记为第 4 套 toast(只是消费者 ⇒ 零 diff)· ⑨ Task 5 的「6 个测试文件需改」(同 ①,T5 侧登记)· ⑩ Task 6 的 M5 空变异(同 ③)· ⑪ Task 9 Step 2 的 autofocus 前提错(Modal 首个可聚焦元素是关闭钮)· ⑫ 任务总表把 T11 标为可与 T12 并行、漏了 AiProviderSettings.tsx 双点名 · ⑬ B4 的 37 文件清单未扣除 B1/B2 的 14 条 · ⑭ Task 11 的「16 处 confirm(」与「impacts{ ≥ 8」两个数都不成立(实测 confirm( 24 = 8 + 16;impacts={ 6)· ⑮ Task 13 的 Step 3 + V2 与铁律①自相矛盾 · ⑯ 施工图 §13.1/§13.2 与守卫 ② 的文本口径互斥 · ⑰ 施工图未核对「文件是否本就 >300」(23 个里 8 个已 >300)· ⑱ Task 14 的 V2/V3 三个数不可复现(真值 18/18;「门控 9/5」用任何可辩护口径都复现不出)· ⑲ Task 8 的 V3「四个测试文件共 92 条」实为 70(6+31+18+15)。

另有三种「非计划错、但必须记住」的口径事故(逐条见批 4 计划 §收口回写 §八):仪器没跑到断言被读成「判据无牙」(--cache.dir 在 vitest 4 已废弃 ⇒ exit 1 且 0 用例;纪律:变异体 harness 必须把「跑到了断言(用例数 >0)」与「跑红了」分开判)· 同一棵导出树上「改→跑→还原」给假红(copyFileSync 保留 mtime + vitest 缓存写在借来的 node_modules 里;正解 = 每个变异新解一棵树)· 把上一单元的门禁读数抄成自己的(7457c7f1 的 163/1557 实为 164/1561 ⇒ 纪律:门禁读数必须在本次提交的树上重跑)。

未做(登记,逐条带归属批次)

真机 / WebView2 验收 → 批 8(用户已裁决本批跳过;不得出现「已在真机确认」类表述)· 像素/排版探针(6→8 9 处 · 边框暖色 · 20 处阴影 · Text 行高 · 20 弹层宽度 Δ · StatusLine 间距 · belowNav 落点 · right 16→18 的 2px · Modal 退场手感)→ 批 8 · 五类棘轮余量(空态例外 8 + 余量 5 · 加载 8 · 三红 114/67 · 弱化灰 63/44 · 边框 226+261+24)→ 批 5/7 · 11 锚定菜单的退出语义(含 4 处元素级 onKeyDown 与 SelectionActionMenu 的捕获相 ESC)→ 批 5 或批 8 · Text 的 558 处字号越界(映射规则已在 tmp/t16a/slice.md)→ 批 5/6 · ink-4 与 §4.3 条件③ → 批 5/6 · b1-non-migrated 9 处 + NON_MIGRATED_14(批 5/7 要迁它们的排版,必须先裁决 B1/B2 的守卫范围)→ 批 5/7(前置裁决) · token 真源补 pill 档四处(gen-tokens.mjs / tokens.gen.ts / tokens.css / tokens.drift.test.ts:52)→ 批 5/6 · Surface 的 DOM 属性透传(解锁 3 处)与透明容器是否接受多一层底(+28 处)→ 批 5 · 错误行的位置问题 → 批 5 · SURFACE_CLASSES 是否升级为真判据 · MIN_CALLS 与 T15 探针表逐格对拍 · bundle-eager-graph.mjs 把 import type 计成静态边(批 3 #2)· Toast 的 belowNav 堆叠失效 · --ed-nav-h 兜底 56px 无绑定判据 · Modal 滚动位置不恢复 · docs/tech-debt/review-2026-09-11.md(191 KB,mtime 2026-09-11,未入库)→ 待用户裁决 · 规格 §6.2 的「会话详情头改粘性 / 笔记工具栏三层合并」(批 3 #15 = ADR-034 S-4;本批实测未做)→ 批 5(回落批 8) · 3 套 markdown 归一(批 3 #16)→ 批 5/7 · ADR-035(L4 动效)→ 批 6 · 门禁 --staged 模式(批 3 #1)→ 批 8。

↳ 收口后更正(2026-09-12;上行原文一字未改):本行三处读数已过期 —— ① 五类棘轮余量里的弱化灰 63/44 → 64/44(FROZEN_MUTED_GRAY_TOTAL = 64;见上文「更正块 A」)· ② b1-non-migrated 的「9 处」是回退动作数,该类冻结处数 = 14(收口修复前 13)· ③ 既有 flake 的处置已定为「已加固、未复现」(cd85e4c3;见上文「I-4 的 flake 处置」)。

↳ 批 7 T10 更正(2026-09-13;上面原文一字未改):① 上行逐字写的 FROZEN_MUTED_GRAY_TOTAL = 64 已过期 —— 真值 63(textBaseline.ts 的常数 == 逐文件表之和 == 实测,三者一致;「63/44」亦应作 63/43):64 是 ed07d491 的旧值,已在 f193808d 随一次真实迁移收紧回 63/43。② 上行逐字写的「边框 226+261+24」亦已过期 —— 批 7 T7 迁完 <Surface> 后重冻为 201 + 254 + 24(边框 201/99 · 越界圆角 254/107 · 阴影 24/24;三者「常数 == Σ表 == 独立复算」已复测)。⚠️ rulings.md §C10.6 清单原写「223/260/24」= T7 落地前的读数,已被 T7 的重冻取代 ⇒ 以本行实测值为准。

诚实代价(不许省略)

  • 首屏 gzip 97.16 → 100.30 kB(+3.14 kB,+3.2%),入口 chunk 原始 +8,239 B。涨的是必要成本(原语层 barrel + 12 个模块 + 10 份原语 CSS 首次进首屏),低于 B5 给出的上界 +3.41 kB,远低于 200 kB(余量 99.70 kB)。CSS 62.63 kB 原始 / 14.42 kB gzip 不计入判据,只报告。
  • B9 的逐字中间态:「只有接缝、没有纲领」—— 三档强度 / 双基调 / GSAP 在批 6。 批 4 把 [data-phase] 三态、--ed-dur-* 与 reduced-motion 块接到了真实调用点上 ⇒ 界面第一次真的会动,但手感未设计、未调参;验收不得把接缝当最终手感,也不得声称动效系统已交付。
  • 这是本系列「观感变化」最大的一批,而且大部分变化是「不便逐条列举的观感」:叠放值收敛(50/51/60/999/1000/1100/1150 → modal(300) · 30–61 → popover(200) · 900 → panel(100) —— 规格 §10 逐字「观感从批 4 开始变」在这里的形态就是它)· 20 个弹层的档位宽度 Δ(10 个变宽:560/680/460/340/360/640 → 720/720/520/380/380/720 等,最大 +160;RefineWorkbench 1200/90vw → 720 = −480)· RefineWorkbench 并排 → 单栏可读(面板 −36.7% · 两栏 −40.7% · 每行 46 → 28 字;顺带修掉 720 下 32px 水平溢出)· 卡片 6→8 9 处 · 边框冷灰 → 暖纸(14 处)+ 近白底冷灰 → 暖纸(8 处) · 20 处阴影换 token(含 1 处有损) · 遮罩统一 rgba(26,26,26,.34) · 11 处 / 13 串标题装饰 emoji 去掉(🗑 等语义字符保留)· 关闭钮统一 · 加载态由「居中块」变一行 + 6 处骨架首上线 · 错误行改 StatusLine(flex + gap 8px) · 弱化文本 186 处墨度 2.54:1 → 5.13:1、行高由字阶类接管。这些全部只有类级/属性级/源码级证据(jsdom 不排版;真机已裁决跳过)⇒ 批 8 的像素探针才是判据。
  • 两处「规模缩小」是本批最大的计划-实际偏差,逐条带分区:① 6→8 计划 254 处 → 实改 9 处(254 的完整分区:控件 161 · NM14 25 · 交互 13 · 透明 13 · 间接 1 · 有底色 41;其余 245 处维持现状,控制方 B22 裁决「不机械拉齐」);② 卡片边框计划 172 处 → 实迁 14(172 = 控件 96 + NM14 14 + 锚定菜单 4 + 交互 4 + 条件底色 4 + 透明 28 + 有底色 22;57 分隔线 + 11 条件色结构上表达不了)。
  • T15 的守卫回退代价(明确选中):为守住 B1/B2,6 个文件逐字回退 ⇒ 错误行迁移面 55 → 49、三红回升 +6 行、空态例外 5 → 8 条(B21:代价不对称)。
  • 9 个贴边文件(动它必须先拆):ui/primitives/dialogMigration.e.test.ts 300/300(余量 0 ⇒ 禁止再碰) · ui/primitives/textBaseline.ts 299 · ui/primitives/loadingRatchet.test.ts 299 · ui/primitives/emptyStateRatchet.test.ts 296 · pages/NotesPage.tsx 300/300 · ui/primitives/surfaceRatchet.test.ts 287 · ui/primitives/textRatchet.test.ts 266 · pages/ChatPage.tsx 578/600 · shell/CommandPalette.tsx 203/220。

↳ 收口后更正(2026-09-12 · 收口评审 M-4 + 修复单元;上行原文一字未改):① pages/ChatPage.tsx 的 578 是 7457c7f1 时点的值 ⇒ 579 权威(cbc15837 拆件 → 578 · T16-B 的 be925809 → 579;豁免表 :24 声明 579,控制方 [System.IO.File]::ReadAllLines(...) 亲测 579、LF 579、末尾有换行、29,151 B)。② 贴边表本身也变了:ui/primitives/loadingRatchet.test.ts 299 → 181(8a2dd5e1 拆出 ui/primitives/loadingScan.ts 101 行)⇒ 不再是贴边文件;ui/primitives/textBaseline.ts 仍 299/300(贴边);ui/primitives/dialogMigration.e.test.ts 仍 300/300(余量 0 ⇒ 禁止再碰)。

↳ 批 7 T10 实测更正(2026-09-13;上面原文一字未改):贴边表里那 5 个「已变 / 待复核」的行数,按 countLines()(scripts/line-limits.mjs,含空行的全部行数)在当前提交树逐个重测 —— ui/primitives/surfaceRatchet.test.ts 287 → 261 · ui/primitives/textRatchet.test.ts 266 → 270 · pages/NotesPage.tsx 300/300 → 295 · shell/CommandPalette.tsx 203/220 → 207;ui/primitives/textBaseline.ts 复测仍为 299/300(§C10.6 清单原写「299 → 297」是已过期的预期值,299 才是实测 ⇒ 该处不动)。⚠️ §C10.6 另外四个目标值(261 · 270 · 295 · 207)与本次实测逐字一致。

  • 13 个判据文件超计划预算(dialogMigration.a2 268/220 · .e 286/240 · confirmMigration 297/220 · buttonMigration 268/220 · zIndex.guard 284/200 等)—— 全部 ≤300 硬限、零新增豁免登记;口径:预算是估算,不为落进预算删判据(批 3 已有 4 例先例)。
  • 两条未验证的诚实边界:20 个弹层里只有 5 个有同名测试(无覆盖的 15 个已在批 4 计划 §六 逐条列名;PracticeQuestionsOverlays/SopRunOverlay 从未被任何测试渲染过)· App.tsx 无渲染级测试面(仓内没有 App.test.tsx)⇒ 顶栏/命令面板的真实装配只有 T10 的一条渲染级断言 + 真机证据(未跑)。

↳ 收口评审 I-5 就地更正(2026-09-12;上行原文一字未改):上行「20 个弹层里只有 5 个有同名测试(无覆盖的 15 个)」实测不成立。两种口径各测一次(复现命令:node .superpowers/sdd/2026-09-12-frontend-redesign-batch4-primitives/tmp/docfix/d1-coverage.mjs —— DIALOG_20 从 app/src/ui/primitives/dialogMigration.e.test.ts 解析、不手抄):① 有同名测试文件 X.test.tsx 的 = 10 / 无 = 10;② 其中真的 render(<X) 的 = 10 / 不是 = 10 —— 两口径完全重合,差额为空(没有「有同名文件却不渲染该组件」的项)。

  • 有测试面的 10 个:ChatSaveNoteDialog · GoalPlanApprovalDialog · GraduateDialog · InterviewDialog · KnowledgeDecisionForm · KnowledgeSystemWizard · ModelCardCreateDialog · RefineLaunchDialog · RefineWorkbench · TaskLaunchDialog。
  • 无同名测试文件的 10 个:GroupCreateDialog · GroupDeleteConfirm · KnowledgeConceptDialog · KnowledgeModelDialog · ModelCardFromNoteDialog · NoteAiDialog · PracticeQuestionsOverlays · ProofreadPanel · SecondPassPanel · SopRunOverlay。 差额逐个列名(口径① 有 · 口径② 无)= 空。原文点名的 5 个(ChatSaveNoteDialog / InterviewDialog / RefineWorkbench / KnowledgeSystemWizard / TaskLaunchDialog)是这 10 个的真子集。「原写法 5/15 的来源不可考」:批 4 只改过其中 1 个测试文件(RefineWorkbench.test.tsx),其余 9 个 git diff --name-only 42e88740..091d1c3d = 0 ⇒ 差异也不是「批 4 触碰过」这个口径。同条其余两句仍成立:PracticeQuestionsOverlays / SopRunOverlay 在全仓测试文本里零引用 ✅、.e 只钉源码形态 ✅。
  • 一处历史不实(不重写):8f5bd9f1 是 T13 误 --amend 的产物(内容无缺失、历史线性未重写);54b9b938 携带了 T2 的 ADR-033 加注(索引串味)⇒ 两条都只登记。

提交清单(49 个,4905d4d8^.. 至本收口提交;逐条 sha / subject / 归属 / 文件数见批 4 计划 §收口回写 §三)

归属 提交数 sha(按时间序)
计划(+ ADR-034 补写) 1 4905d4d8
批 3 收口评审修复(非批 4 交付,落在区间内) 1 e4901247
T1 基线 + 按钮棘轮 1 357ab117
前置守卫单元(T0 的 G3/G5) 2 783a62ae · 6effbda5
T2 / T3 2 a9c63c0a · 54b9b938
T4 z-index 六档 1 8d84ecfe
前置守卫评审 follow-up 2 f3b2b6ce · a25ed2c6
T5(含授权前置 0228a013) 2 0228a013 · 57a78c7d
T6 / T7 2 09c49941 · cc6cdadd
回填 + 修复单元(emoji / decorateRefined) 3 4c52cdd8 · 854c0af9 · 45ce9292
T8(20 清单收口) 1 0148b5ed
T9(两半) / T10 3 b5c464af · 4a804a58 · bde807dc
T11 / T12(三提交) 4 0e17e666 · 5d485ff8 · 1a7762bd · f6dd012f
T7–T12 评审修复单元 2 ebac9d73 · 9c2a00a4
T13(拆件 / 空态切片 / 棘轮收紧) 3 cbc15837 · 37c068aa · c635c0bb
T14(两提交,第二提交被 amend) 2 271a281c · 8f5bd9f1
T15 接管收口(57 路径) 1 7457c7f1
T16-A(地基) 2 3ed9cfe9 · 93763ae7
T17-A(地基 + pill 档) 2 2360c3d9 · 0bc09a41
T13–T15 评审收口修单元(F1–F4) 4 f2a91eb6 · 5825fae3 · 451db3fb · 0b27540c
T16-B(迁移,三提交) 3 9532b189 · be925809 · a9c7e300
T17-B(迁移,四提交) 4 1ac129ae · 69489f9f · 18d56cbc · 199da54b
T18 收口(本节所在提交) 1 (自引用,无法写入本节)
合计 49 ——

注:本收口提交的 sha 无法写进它自己的内容里(自引用);批 2/批 3 的先例同样把「收口回写提交」单列在区间之外或标注自引用。本行的「49」= 4905d4d8^..<收口提交> 含左端点;git rev-list --count 42e88740^..199da54b 的 49 与 42e88740..199da54b 的 48 一并报出(前者含批 3 的收口提交 42e88740,不是批 4 的提交数)。

批 5 · 视图层样板(2026-09-12,2559a3fd.. 至收口提交,31 个提交)

提交数口径(本文档既定规矩):本文档批次行一律采用「含左端点」口径(A^..B,A = 该批第一个提交,见批 0-A 行的声明)。本行同款:批 5 的第一个提交 = ad9d80d2(test(sessions): pin detail panel before split)⇒ ad9d80d2^.. 至收口提交 = 31(30 个 T0–T17 的实施/守卫提交 + 本节所在的收口提交 1 个)。另报字面读数以免歧义:git rev-list --count 2559a3fd..b4edf8e4 = 30(= 批 5 本批 T0–T17 的全部提交,不含收口提交;b4edf8e4 = T18-A/B 的开工 HEAD)· git rev-list --count 4905d4d8^..b4edf8e4 = 88(含左端点,从批 4 计划提交起算)· git rev-list --count 091d1c3d..2559a3fd = 9(批 4 收口后追加的那 9 条)。

⚠️ 边界端点更正(记控制方账上):派发书写「批 4 收口后追加的提交(修复 4 + 文档 4 + 批 5 计划 1 = 9 条,区间 091d1c3d..7d541254)」—— 总数 9 正确,端点错:实测 091d1c3d..7d541254 = 5 条,因为其中 4 条文档提交是批 5 计划提交的「子」提交(顺序:7d541254 计划 → 6038bb42 → 11018f40 → 2901511f → 2559a3fd)。正确端点 = 091d1c3d..2559a3fd(9 条),且 2559a3fd 正是 T0 冻结基准的 HEAD(compare-perfile.mjs 的 FROZEN_HEAD,逐字吻合)⇒ 用它当批 5 起点与全批台账一致。另:那 9 条按 Conventional Commits 类型分实为 test ×5 + docs ×4(派发书的「修复 4 + 文档 4」与实测「test 5 + docs 4」总数一致、内部分类不一致 —— 2901511f test(ui): fix stale zindex guard comment 被计入「文档」而非「修复」)。如实登记,不擅自改派发书数字。

交付

  • 视图层从 0 到 1:新建 app/src/views/ 子域(session/ + note/ 两个子目录),views/** 实测 17 个文件(9 个生产 + 8 个测试),全部 ≤300 行(最大 NoteCardFlowView.test.tsx 273)。生产件逐个:views/registry.ts 109(ViewSpec + load + viewsFor + FROZEN_VIEW_KEYS)· views/useViewMemory.ts 70(顶格)· views/session/SessionTriTrackView.tsx 207 · views/session/SessionProofView.tsx 168 · views/session/SessionCardFlowView.tsx 104 · views/session/SessionNotePreview.tsx 38(T6b 的会话槽适配器)· views/note/noteCardModel.ts 106(结构派生器,文件头显式命名「批 7 归一」)· views/note/NoteCardFlowView.tsx 38。
  • ⚠️ 数字更正(Minor-1 / Minor-2;上面那一行原文一字未改,只在此追加 —— 守「删除行 0」纪律):上一行括号里的生产/测试数写反(写作 9+8)⇒ 实为 8 个生产 + 9 个测试(与上一行随后「生产件逐个」列出的 8 件一致 ⇒ 原句的句内自相矛盾由此解除);「最大 NoteCardFlowView.test.tsx 273」报小 ⇒ 最大 = views/note/noteViews.test.tsx 295(余量 5),273 是次大(views/session/SessionCardFlowView.test.tsx)。total 17 与「全部 ≤300 行」两条原本就成立。复现:node tmp/fix18/verify-facts.mjs ⇒ {total:17, prod:8, test:9, over300:[], max:{noteViews.test.tsx,295}, second:{SessionCardFlowView.test.tsx,273}};同款更正见批 5 计划 §八 #27 与本文档「过程中纠正的计划错误」段紧后的补登(2/2)。
  • ViewSpec 按 C1 升级为可执行加载器:字段 { key, label, icon, appliesTo, load? },load?: () => Promise<{ default: ComponentType<P> }>(取代规格 §7.1 的静态 Component 与 lazy 布尔),宿主用 React.lazy + Suspense(复用既有 ShellFallback)。默认视图无 load(session[0].hasLoad = false · note[0].hasLoad = false),非默认 5/5 全有,每个 load 体内恰 1 个 import(,注册表顶部 0 个视图组件静态 import(4 条 import 逐字全是 import type)。
  • 一个新原语 ViewSwitcher(ui/primitives/ViewSwitcher.tsx 135 + .css 63 + ViewSwitcher.test.tsx 225 / 14 passed):分段控件,进 ui/primitives/index.ts barrel(45 → 48)并在 style-contract.test.ts 的枚举里(233 → 296 行,用例 6 → 10,只增不删);零行内 style;落 --ed-dur-micro(120 ms)响应层接缝。类名走 R-2:容器 .ed-btn-group + 段 .ed-btn--segment(复用 ed-btn 基座命名空间 ⇒ 既有断言改动数保持 0)。
  • 视图矩阵终态 = 会话 5 个 · 笔记 2 个:会话 ["raw","tritrack","proof","cardflow","preview"](raw = 原文常驻默认;tritrack = 三轨对齐,三轨 = 转写 / 画面 / OCR 文字;proof = 印样;cardflow = 卡片流;preview = 既有的笔记预览,按 §7.3② 一并进注册表并由页 chunk 转为惰性);笔记 ["raw","cardflow"] —— 第三种「带证据三轨」是 C2 的条件项,只读探针判不存在逐段级「笔记 ↔ 证据」读取路径 ⇒ 按 C2 逐字「交付 2 视图 + 就地加注规格 §7.2/§11-6 + 登记批 7」,T13 = 零代码登记提交,不建空壳视图。
  • 两个视图宿主:components/session-detail/SessionViewHost.tsx 136(会话侧:注册表接线 + 视图记忆 + 默认视图常驻 + 惰性挂载 + web 早退 + C11 槽位)· components/notes/NotesReadingColumn.tsx 290(笔记侧:变视图宿主 + flushSave 阻断 + 就近 StatusLine + C11 槽位)。
  • 三条硬约束全部落到机器判据(规格 §7.3,本批的验收主轴):① 原文永远保留(registry[0].key === "raw" ∧ 默认无 load ∧ H1 11/11 ∧ F5 11/11)· ② 非默认视图模块级惰性(每个 load 恰 1 个 import( ∧ H2/H3 11/11 ∧ F6 11/11 ∧ 懒 chunk 22 → 31)· ③ 编辑态切视图先 flushSave、失败则阻断(F1–F4 11/11 ∧ F9;catch ⇒ 不切视图 + 保持编辑态 + 就近 StatusLine kind="error",不用 toast)。
  • 拆件(C9,每个拆件独立原子提交、先补安全网再拆):components/SessionDetailPanel.tsx 297 → 148(T2 四步抽件;随后被 T10 的接线下沉到 182)· 新件 SessionRawView.tsx 157 · SessionViewHost.tsx 136 · SessionAuxBlocks.tsx 127(三件 + 安全网 164 行)· session-detail/SessionScreenCard.tsx(T3 抽单卡)· pages/NotesPage.tsx 300 → 288(T4 拆到 285 → T16 的 focus* + T14 的 2 行接线 ⇒ 288;未新增登记)。
  • 会话详情头粘性(C13):session-detail/SessionDetailHeader.tsx 161 → 176,形态 position: sticky + top: var(--ed-space-4)(4 px)+ zIndex("raised")(10);配套行为级判据 SessionDetailHeader.test.tsx 9 passed(改前 5 passed / 4 failed)。
  • C6 的最小收敛:5 个粘滞字段(focusSessionId / focusNoteId / focusNoteSearch / focusSystemId / focusGroupId)补 onFocus*Consumed 复位回调(声明形态与类型零改动 ⇒ CommandPalette.kb.test.tsx 既有断言一字未改且 9 passed);useNotesDeepLink.ts:18 的注释与实现不符处已改正(+ onConsumed);App.tsx 584 → 590/600。{value,key} 全量统一登记批 7/8(durable;若届时要动,须先请裁改写那条既有断言)。
  • C18 的棘轮向下重同步(T2 独占):迁移吃掉豁免 ⇒ 逐族下调并保持 FROZEN == Σentries + 锚同步 —— 弱化灰 64 → 63 / 文件 44 → 43 · 字号越界 558 → 551(键 8 → 1)· 边框 226 → 223 + 锚 108 → 107 · 越界圆角 261 → 260 + 锚 109 → 108 · 三红 114 → 113;每条判据各带变异体(M1–M4 全红)+ 反例守卫 M5 绿。
  • 测试面:新增 18 个测试文件 / 138 用例(逐条见 tmp/t18/measurements.md §3.1 的 ADDED=18 清单)+ 4 个既有文件 GROWN(navHeight.consumption.test.ts 3 → 6 · Modal.scroll-lock.test.tsx 6 → 9 · style-contract.test.ts 6 → 10 · colorPalette.test.ts 40 → 43);既有用例一条不少(逐文件对拍批 5 开工基线 LOST=0 · SHRUNK=0)。
  • ⚠️ 数字更正(Minor-3;上面那一行原文一字未改,只在此追加):上一行的「138 用例」标错 ⇒ 实为 149 用例(= 上一行自己引用的「ADDED=18 清单」18 件用例数之和 8+4+2+17+2+12+10+13+11+9+6+11+5+14+6+5+5+9);同段的 GROWN 增量 = 13(不是 24:6−3 · 9−6 · 10−6 · 43−40)。总数不变:13 + 149 = 162 = 24 + 138 ⇒ 1608 + 162 = 1770 ✅。复现:node tmp/fix18/verify-facts.mjs;同款更正见批 5 计划 §八 #28。
  • C16 的两条工具侧事实(入账):scripts/check-bundle-budget.mjs 没有任何锁机制 ⇒ 批 5 的真实构建一律走显式取锁协议(flag: "wx" 原子创建 + 退避 30 s × ≤6 + finally 释放 + 锁体含 createdAt/pid/purpose/owner/attempt),且工具不打印 dist mtime ⇒ provenance 由执行单元自采。

验收(三条硬约束 + 八门禁终态;原始读数与命令见批 5 计划 §收口回写 §一/§二)

验收(规格 §10 批 5 行逐字「各 ≥2 种形式可用;原文不丢」) 判据 读数
① 原文视图永远保留 registry.ts:109 的 [0].key === "raw"(自写结构探针 exit 0)+ views/registry.test.ts(12 用例)+ SessionViewHost.test.tsx(H1)+ NotesReadingColumn.views.test.tsx(F5) session[0].key = "raw" ✅ · note[0].key = "raw" ✅ · 默认无 load ✅ · H1 11/11 · F5 11/11;反向对照 T10-M1(6 红含 H1)· T14-M5(唯一红 F5)
② 非默认视图模块级惰性 A1/A2/G7(图级 + 结构)+ H2/H3 + F6 + 懒 chunk 台账(R-1) 每个 load 恰 1 个 import((5/5)· 顶部运行时 import 0 · H2/H3/F6 各 11/11 · 懒 chunk 22 → 31;反向对照 T10-M2c(仅 H2 红)· T10-M3(含 H3)· T14-M6(唯一红 F6)
③ 编辑态切视图先 flushSave、失败则阻断 NotesReadingColumn.views.test.tsx 的 F1–F4 + F9(既有断言原样绿) F1–F4 各 11/11 passed;F4 断言「阻断全过程 0 个 toast 节点」并证选择器有牙;反向对照 T14-M1(把 catch 改成继续)⇒ 唯一红 = F1;F9 = 文件头注释(无 it、无变异体,设计如此)
验收「各 ≥2 种可用」 两个 FROZEN_VIEW_KEYS 清单 会话 5 ≥ 2 ✅ · 笔记 2 ≥ 2 ✅(「笔记 3 视图」是条件项、未兑现,见规格 §7.2/§11-6 加注)

八门禁终态(HEAD = b4edf8e4 · 采集窗口 22:57:07 – 22:58:51 +08:00 · 真实构建产出 app/dist mtime 2026-09-12T14:58:51.595Z = 22:58:51 +08:00)

line-limits --full >600 0 · 301–600 档 122 · 登记条目 122(exit 0;--write 复跑逐字节零 diff、sha256 相同 ⇒ 豁免表不在本次收口提交路径里)· docs-check exit 0(扫描 277 / 检查 177,五项全 ✅)· registry 312/312/0 · tsc --noEmit 0 错 · vitest 184 文件 / 1770 用例 / 0 失败 / 0 skip(逐文件对拍批 5 开工基线 2559a3fd 的 166 文件 / 1608 用例 ⇒ LOST=0 · SHRUNK=0;GROWN 4 · ADDED 18;testResults.length 是权威文件数口径 —— vitest 4.1.11 的 JSON 顶层没有 numTotalTestFiles 字段,而 numTotalTestSuites = 647 是 describe 块数、与文件数差 463)· check-bundle-budget.mjs(真实构建,取 tmp/build.lock,attempt=1、finally 释放、事后锁不存在)exit 0 · 首屏 100.49 kB gzip(原始 318,299 B;余量 99.52 kB;CSS 3 个 63,229 B = 63.23 kB 原始 / 14.51 kB gzip 不计入判据,只报告;入口 index-Bn5oI23G.js 108,620 B)· bundle-eager-graph 91 文件(源 77 + CSS 14)/ npm 包 4,TS-API 真实边口径 66(结论口径),--keep-type-only = 77 自证(「91 − 66 = 25」确由 14 CSS + 11 条纯类型边构成)· Rust 未复跑(本批零 Rust 改动:git log 091d1c3d..HEAD -- app/src-tauri 与 git log 4905d4d8..HEAD -- app/src-tauri 两条均为空)—— 判据仍是批 3 的 2300 / 0 / 6,不得读成「已跑」。

三条硬约束的判据与变异体出处:逐条见批 5 计划 §收口回写 §一(含 ran 闸与 CONTROL)。⚠️ 引用变异体必须带任务号:T10 的 M1(默认视图条件渲染)≠ T14 的 M1(catch 分支继续切换)—— 两者同名不同物。

首屏账(Δ + 机理;基线 = 091d1c3d 冻结值):首屏原始 317,778 → 318,299 B(+521 B / +0.16%),全部落在入口 chunk(108,099 → 108,620 B);gzip 100,297 → 100,485 B(+188 B / +0.19%);首屏 chunk 个数 3 → 3(Δ = 0,构造性成立);vendor-react / vendor-tauri 逐字节不变;CSS 62.63 → 63.23 kB(+599 B)。懒 chunk 22 → 31 个、原始 1,790,753 → 1,805,017 B(+14,264 B)、gzip 575.16 → 583.98 kB(+8.82 kB)。eager 三件套:工具 89 → 91 文件(= 源 76 → 77 + CSS 13 → 14)· TS-API 真实边 65 → 66 · npm 包 4 → 4 ⇒ +2 全部是 ViewSwitcher.tsx + ViewSwitcher.css(唯一新增的 barrel 导出),没有任何页面被静态拉回首屏。

规格漂移纠正(逐处,原文保留 + 就地加注)

漂移 落点
§7.1 ViewSpec 的 Component / lazy → load(C1:把布尔升级为可执行加载器;默认视图无 load) 规格 §7.1 加注(原文一字未改)
§7.2 会话 4 视图 → 5 个(preview 按 §7.3② 一并进注册表并转惰性) 规格 §7.2 加注(会话侧读数块)
§7.2 笔记 3 视图 → 2 视图(C2 条件项判否;不许空壳视图;R8 防「条件项被当成已交付」) 规格 §7.2 加注(表格后整块,T13 备好文本逐字落位)
§7.3 三条硬约束 → 机器判据落点 + 9 条判据 + 变异体出处(含「F9 无 it 无变异体、设计如此」与 A5①/A5② 的守卫自证缺口) 规格 §7.3 加注
§8.6 签名动效 1 的第三轨 = OCR(C2 连带硬要求;「笔记轨」未交付的原因与去向) 规格 §8.6 表后加注
§10 批 5 行 → 加 ↳ 批 5 的收口 行(✅ + 两处数字更正 + 三条硬约束 + 八门禁 + B9 观测口径) 规格 §10 表
§11-6 → 会话 5 种 / 笔记 2 种(含「本条验收不因此变红:2 ≥ 2」) 规格 §11-6 加注(T13 备好文本逐字落位)
§11-9 → 批 5 首屏进度注(100.49 kB / 余量 99.52 · CSS +599 B · 懒 31 · GSAP 仍未装) 规格 §11-9 加注
§11-11 八门禁 → 加批 5 进度注(含「cargo 未复跑」的显式声明 + numTotalTestFiles 不存在的仪器口径) 规格 §11-11 加注
§5.1 → 「错误行的位置」处置(批 5 只预留槽位、不重排既有 StatusLine 调用点;像素判定转批 8) 规格 §5.1 加注(C11)
§6.2「本次改动」列最后两条(🗂 会话 · 详情头改粘性 ✅ 批 5 已做 + 真实粘性不可验;📝 笔记 · 工具栏三层合并 → 批 8) 规格 §6.2 加注(A5 = C13)
§12「3 套 markdown 渲染器」(C8:批 5 不做归一、转批 7;本批只保证不新增站点;口径更正为「4 套活 + 1 套死」) 规格 §12 加注
§13 风险表三条(视图层内存膨胀 / 编辑丢稿 / 包体继续膨胀的兑现度与未验证面) 规格 §13 表后加注
§14 两行(v0.22 的批 5 节已落;批 5 未新增任何 ADR、docs/adr/README.md 索引零改动、ADR-035 仍顺延批 6) 规格 §14 表
ADR-033 §1(导出面新增第 10 个原语 ViewSwitcher:barrel / 枚举 / --dur-micro / 零行内 style;上表行数 45 → 48、233 → 296) ADR-033 §1 加注
ADR-033 §4(R-2 类名空间语义折中的诚实代价 + 产物级前后对照锚 ed-btn--segment 由 NOT-FOUND 变命中;两条 Surface 缺口 → 批 7) ADR-033 §4 加注(D12)
ADR-033 §登记(视图层契约在批 5 的载体 + flushSave 行为 + 两条未做项 + 行数代价 + ADR-035 仍批 6) ADR-033 §登记 加注(C3 = C4)
ADR-034 §登记(:115 两条的最终结果:粘性 ✅ 已做 / 工具栏三层合并 → 批 8;F-3 的文件名更正) ADR-034 §登记 加注⑧(C4 = C13)

过程中纠正的计划错误(①–⑳;逐条带读数与出处)

① C14① 被实测否证 —— 计划写「ViewSwitcher 进 barrel ⇒ 首屏 Δ 不是 0,机理 = barrel 已在首屏」,实测 JS Δ = 0(rollup 把它 tree-shake 进懒 chunk registry-C-RvXIfE.js)+ CSS +604 B ⇒ 结论改成「barrel 里有导出 ≠ 产物里有模块」· ② W4 与 Step 1/Step 3 互斥(Step 1「不设状态类」+ Step 3「枚举恰 2 项」与 W4 第一条子句「选中段与未选中段的 className 不同」不可同时成立)⇒ 控制方裁决 1:接受 T5 实施 + 强化 W4(每段 className 逐字等于 ed-btn ed-btn--segment;aria-pressed 是状态的唯一权威)· ③ V3 与 Step 1③ 互斥 ⇒ 口径改为「新增 ≫ 删除 ∧ token 保序包含」· ④ A2③ 的 components/** 前提不成立 —— 计划原以为 views/** 零 components/**,实测有 4 条真实边(NoteMarkdown ×2 · SessionScreenCard · NotePreviewView)⇒ 判据收窄为「只禁 pages/** / shell/**」(今日独立复测 = 0 条边,且带仪器双侧自证)· ⑤ P2 与 H1 互斥(计划判词与源码不符;P2 从「同步」改「异步」、从「存在性」改「可见性」)· ⑥ SPLIT_MOVES 条目删除(T10 删了 T2 登记的那条 —— 迁移不是搬运:两个原生 <button> 随切换器迁进 L1 原语(原语层在扫描域外)⇒ 计数真的由 1 降到 0;删除它 = 撤掉豁免、恢复逐文件棘轮的牙齿,FROZEN 是上界故判据仍绿)· ⑦ useViewMemory 住面板(C19 GO-3 的三项 STOP 之一:SessionDetailPanel 仍持 viewMode state,记忆 hook 的调用点落在面板层)· ⑧ 三处预算超支(navHeight.consumption.test.ts 165 vs 预算 110 · Modal.scroll-lock.test.tsx 269 vs 追加预算 +60 · NotesReadingColumn.tsx 290 vs ≤260)—— 口径:预算是估算,绑定约束是 ≤300 + 零新增豁免登记 · ⑨ 两处「拆件时点目标」被接线增量推翻(SessionDetailPanel 182 > 150:T2 拆到 148 后被 T10 的接线下沉;NotesPage 288 > 285:T4 拆件时点目标,T14 的 2 行接线 + T16 的 focus* 推到 288;C19 四条条件③逐字要求登记这条偏差)· ⑩ 测试文件从「共用 sessionViews.test.tsx」改为各自测试文件(C17④:计划 Task 7/8/9 的 Files 与「T7∥T8∥T9 可并行」互斥 —— 三单元写同一文件必然丢更新;实测 SessionTriTrackView.test.tsx / SessionCardFlowView.test.tsx / SessionProofView.test.tsx 各自存在,sessionViews.test.tsx 盘上不存在)· ⑪ 「13 个新文件」台账按实测改写(计划 §规模与预算 §1 写「13 个基础 + 1 个条件项」;实盘 views/** = 17 文件(9 生产 + 8 测试),且拆件产物确实是 3 个:SessionRawView + SessionViewHost + SessionAuxBlocks)· ⑫ 计划「预计提交 17(+1 条件项)= 18」→ 实测 30(机理:多数任务按「安全网 / 实现 / 收口」拆成 2–4 个原子提交 —— T5 单独 4 条、T2/T3/T4/T14 各 2–3 条)· ⑬ 懒 chunk 期望「27 或 28」→ 实测 31(逐块归属 10/10 全部闭合;见「诚实代价」的措辞改写)· ⑭ 计划 Task 13 的 V1 归属判据不可用(原写「提交统计不含 app/src/**」在多单元并行下不成立)⇒ 改为「零提交 + 暂存区空 + git status 无我产生的路径」(tmp/t13/zero-change-selfcert.md 的 V1a–V1i)· ⑮ 计划 Task 15 的 A3 判据形态错(整目录裸子串 includes("@tauri-apps") 会让 6 个文件里 5 个假红)⇒ 权威口径 = 剥注释 + 排除 *.test.* + 只匹配 import/export 声明 + 保留阳性对照 + 两个读数并列 · ⑯ 计划 C14① 的「首屏 Δ 不是 0」(同 ①,F 类事实更正)· ⑰ 计划写「CommandPalette.kb.test.tsx 17 用例」是笔误(实测 9 个 it;另一文件 12)· ⑱ 计划点名的 H1 锚点漂移(计划 :966 写 getByTestId("session-raw-view"),全仓 0 命中;落地用 data-testid="resident-probe",SessionViewHost.test.tsx 5 处 —— 双侧自证:前者 0 命中、后者 5 命中,同仪器同次 grep)· ⑲ 贴边表 13 格中 2 格与实测不同(textBaseline.ts 声明 299 → 实测 297,机理未判定(需批 4 中间树,本批禁 checkout)· loadingRatchet.test.ts 声明 299 → 实测 181,已归因:批 4 收口把扫描器搬进新文件 loadingScan.ts(101 行))· ⑳ 控制方前提错误的 6 例(① pwsh 不存在(本机只有 PS 5.1)② numTotalTestFiles 字段不存在 ③ 批 4 后追加 9 条的区间端点写错(..7d541254 只有 5 条)④ 工作树洁净度前提(?? docs/tech-debt/ 始终在场)⑤ 批 4 计划的 1964 行是被 T18 追加 §收口回写之前的时点值(引用一律按节名 + 逐字引文,不要用行数)⑥ scripts/check-bundle-budget.mjs 没有任何锁机制(C16 事实更正 1/2))。

另有两条「非计划错、但必须记住」的口径事故:① 计划 Task 7/8/9 的 Files 与并行互斥(同 ⑩;C17④)· ② 活树 app/dist 可能滞后一整个批次(T16 实测:它构建前的活树 dist 只有 25 个 .js / 懒 22 个、无任何批 5 视图 chunk ⇒ 拿它当 before 会误记 +9 懒 chunk;批 5 的 R-1 台账因此改用 tmp/t1/lazy-chunks.md(@2559a3fd)作 BEFORE,并在导出树里独立跑了一次真实构建复核,逐字节相等)。纪律:任何「before/after」必须用同源两棵树各跑一次真实构建(= 批 4 「< ~2 kB Δ 必须同源真构建」的强化)。

↳ 收口评审补登(1/2)· surfaceRatchet 判据语义修正 = 新增调用点登记制(T15a cc49b09c,5 文件 +388/−83)—— 计划写「标签数 == FROZEN_SURFACE_TAG_TOTAL 常数」⇒ 任何新视图用 <Surface> 必然红(T9 实测被迫改用 token 变量绕开)⇒ 判据改为「FROZEN == Σ登记值 == Σ实测」+ 逐文件 ≤ / ==(legacy 行 实测 ≤ 登记值、新登记行 实测 == 登记值)+ 表自洽 / 锚({entries:9, TaskConversationView, 3} 三查)/ legacy 和锁(14) + 未登记 = 0 + 防僵尸;唯一新通道 = 新文件同一次提交里登记 {file, count 恰等于实测, reason} + 抬高 FROZEN_SURFACE_TAG_TOTAL + 同步锚(四条堵漏:① legacy 和锁 禁「降值腾位」② 总数是既有 9 文件的紧上界 ③ 新条目恰等于实测 ④ 未登记 = 0 + 防僵尸)。本批新登记 0 条(通道已开,M5 合法登记变异 30/30 全绿证明可用);因 300 行硬限被迫从 3 路径扩到 5 文件:surfaceRatchet.test.ts 287 → 261 · surfaceBaseline.ts 261 · surfaceResidual.ts 81 → 184 · 析出 新 surfaceScan.ts(80) + 新 surfaceTagRegistry.test.ts(145)(加完新牙实测 391 > 300,line-limits 当场红);未动任何 ui/primitives/** 生产代码。逐条见批 5 计划 §八 #23(台账 §二十二 ④ 用词「必须」)。

↳ 收口评审补登(2/2)· 数字更正(Minor-1;上面 ⑪ 原文一字未改,只在此追加 —— 守「删除行 0」纪律):⑪ 括号里的生产/测试数写反(写作 9+8)⇒ 实为 8 生产 + 9 测试(total 17 与「全部 ≤300」两条不变);最大行数见本文档「交付」段第一条紧后的「⚠️ 数字更正」行(295,非 273)。复现:node tmp/fix18/verify-facts.mjs;同款更正见批 5 计划 §八 #27。

诚实代价(不许省略)

  • 首屏 gzip 100.30 → 100.49 kB(+188 B / +0.19%),入口 chunk 原始 +521 B;远低于 200 kB(余量 99.52 kB)。CSS 62.63 → 63.23 kB(+599 B,不计入判据,只报告)。首屏 chunk 个数 Δ = 0(构造性),但入口 chunk 内容变了。
  • ViewSwitcher 进 barrel 的首屏 Δ = JS 0 B + CSS +604 B —— 计划 C14① 的「首屏 Δ 不是 0」被实测否证:ed-btn-group / ed-btn--segment 在 dist 的 25 个 JS 里 0 命中、只在首屏 CSS 里命中 ⇒ rollup 把它的 JS tree-shake 进了懒 chunk(registry-C-RvXIfE.js)。⇒ barrel 里有导出 ≠ 产物里有模块。
  • 懒 chunk 22 → 31(+9)· 583.98 kB gzip(原始 1,805,017 B,不计入预算)。措辞必须照此读(E7 改写):「真新增 9 块 + 1 次共享块再分组(1 拆 2)」 —— 不要写成「ADDED 10 / REMOVED 1」(那会读成新增了 10 块、删掉了 1 块代码)。逐块具名(10 条全部有归属):SessionTriTrackView 2,155 · SessionProofView 2,058 · SessionCardFlowView 1,351 · NoteCardFlowView 1,489 · SessionNotePreview 11,472 · registry 4,943 · NoteMarkdown 6,564 · SessionScreenCard 332 · fmt 634 · RefineLaunchDialog 19,250。再分组的精确归属(导出树实测闭合):BEFORE 那块 21,149 B 的 useTransientToast-XJI3diKc.js 是一块共享懒块、同时装着 RefineLaunchDialog 与 useTransientToast(rollup 按其中一个模块命名 ⇒ 名字极具误导性);批 5 让 views/registry.ts + ViewSwitcher 进入同一分组后该块重新分组为两块 ⇒ 21,149 = 19,250(RefineLaunchDialog 独立)+ 1,899(useTransientToast 迁入新共享块) ✅ 无字节丢失;两个源文件在批 5 区间零提交(git log 已证)。恒等式闭合:50,248(ADDED 10)− 21,149(REMOVED 1)− 14,835(保留 21 个的字节变化)= +14,264 B = 实测净 Δ(1,805,017 − 1,790,753)逐字节相等。⚠️ 纪律(陷阱 #110):chunk 名不是稳定标识 ⇒ 判 chunk 增删必须用模块级字面量归属,或至少逐块做字节闭合核算;只比名字会同时产生假 ADDED + 假 REMOVED。
  • 「页 chunk 变小、总懒基本持平」:SessionsPage 页 chunk 73,703 → 63,415(−10,288 B) · NotesPage 页 chunk 161,732 → 156,917(−4,815 B) —— 视图代码搬出页面 chunk、改由懒 chunk 承载(另有 colorPalette +229 B(T4 把笔记派生搬进 utils/colorPalette.ts,124 → 175 行)· KnowledgePage +39 B)。
  • R-2 的类名空间折中(语义代价):容器 .ed-btn-group + 段 .ed-btn--segment 借用了按钮基座命名空间 —— 读到它的人会先以为是 Button 的一个档位。收益:Button 的 variant 枚举与 Button.css 零改动,且既有动效/接缝计数(motion-coverage / style-seams)零改动 ⇒ 本批对既有断言的改动数 = 0(这是本批最值得记的一笔)。
  • 三处「拆件顺带迁移」的可见/观感变化(登记,不是「写法变了、观感不变」):① 字阶 11 → 11.5 与 13 → 12(拆件时落到字阶档位)· ② 弱化灰 #9ca3af → ink-3(批 4 的 5.13:1 口径延续)· ③ 圆角 6 → 5(落 --ed-radius-control 档;起因是 T2 一度把圆角改成 4「躲开冻结集合」被打回,最终落到真档位)—— 这些全部只有类级/属性级/源码级证据(jsdom 不排版;真机已裁决跳过)⇒ 批 8 的像素探针才是判据。
  • 行数代价(逐条带口径):SessionDetailPanel.tsx 182 > C9 的 ≤150(T2 拆到 148 后被 T10 接线下沉)· NotesReadingColumn.tsx 290 > 260(超 30,已登记)· useViewMemory.ts 70 = 顶格(余量 0) · 三处预算超支(navHeight.consumption.test.ts 165/110 · Modal.scroll-lock.test.tsx 269/+60 · NotesReadingColumn 290/260)· component/NoteMarkdown.tsx 244 → 266。全部 ≤300 硬限、零新增豁免登记(301–600 档 122 → 122、FROZEN_OVER_LIMIT 仍为空数组)。
  • B9 的逐字中间态:「只有接缝、没有纲领」—— 三档强度 / 双基调 / GSAP 在批 6。 批 5 交付的是内容与结构(视图层骨架 + 多视图可用 + --ed-dur-micro 120 ms 的响应层接缝),手感未设计、未调参;验收不得把接缝当最终手感,也不得声称动效系统已交付。
  • 三处「本批没能验证」的诚实边界(详见下节):真实粘性(jsdom 无布局引擎)· 真实滚动恢复(jsdom scrollingElement 不滚动)· 惰性挂载的运行时内存效果(字节面可测、内存面不可测)。

未做(登记,逐条带归属批次)

真机 / WebView2 验收 → 批 8(用户已裁决本批跳过;不得出现「已在真机确认」类表述)· 像素/观感探针(字阶 11 → 11.5 / 13 → 12 · #9ca3af → ink-3 · 圆角 6 → 5 · 视图密度观感 · 切视图卡顿 · 槽位像素位置与可达性)→ 批 8 · 「笔记工具栏三层合并」→ 批 8(C13;要动 NotesPage 288/300 + NoteListView 241 + NoteListToolbar 95 三个无测试面文件)· 错误行的位置重排 → 批 8(C11:批 5 只预留槽位)· flushSave 返回类型升级(NoteEditHandle)→ 批 8 接口卫生 · RichEditorView 内的 Ctrl+E / 完成按钮仍不阻断 → 批 8(C4②,非本批引入的回归)· {value,key} 全量统一 → 批 7/8(C6;要动须先请裁改写 CommandPalette.kb.test.tsx 的既有断言)· 3 套 markdown 渲染器归一 → 批 7(C8;口径「4 套活 + 1 套死」)· Surface 两条(DOM 属性透传 +3 / 透明容器 +28)→ 批 7(D12;接受 ② 会要求抬高 surfaceRatchet 冻结值 ⇒ 须一次显式裁决)· 笔记「带证据三轨」→ 批 7(必须先写规格)(C17①:E2 降级为 ms 最近邻 · E1/E3 改为「带锚点段落数」· 覆盖 OcrDirect/Web/手动笔记/anchor_timestamps=false 四类无锚点情形)· b1-non-migrated 与 B1/B2 守卫范围 → 批 5/7(前置裁决)(本批的编辑态提示落宿主层、不碰 NON_MIGRATED_14)· 卡片插槽 API 若 T9 后续需要 ⇒ 在 T9 消费时设计(本批未预扩) · token 真源补 pill 档四处(gen-tokens.mjs / tokens.gen.ts / tokens.css / tokens.drift.test.ts:52)→ 批 6 · ink-4 与 §4.3 条件③ → 批 6 · Text 的 558 处字号越界 → 批 5/6(映射规则已在 tmp/t16a/slice.md;本批已顺带迁 7 处 ⇒ 实测 551,C18 重同步时由 558 → 551) · 五类棘轮余量(弱化灰 63/43 · 字号越界 551 · 边框 223 + 越界圆角 260 + 阴影 24)→ 批 5/7 · FROZEN_NUMERIC_ZINDEX 等批 4 遗留项 → 批 5/7 · 视图的真实数据分布 · evidence 视图(C17① 的缺数据前置)· markdown 归一 · Ctrl+E/完成按钮仍不阻断 四项的成熟度判断 → 批 7/8 · 守卫自证缺口四条(G-1 A5① · G-2 A5② · G-3 A2③ · G-4 F9)→ 批 6/7(只登记、不在收口提交里补测:收口禁改代码;四条的性质分别由 G2 / F5+H1 / A2③ 判据本身 / T0 的 --frozen 对拍守着 ⇒ 不是覆盖漏洞,只是这几条判据自己没有专属变异体) · bundle-eager-graph.mjs 把 import type 计成静态边(工具本身)→ 批 8(C10 修正②:批 5 留批 5 但只作为判据口径,双口径并列,不修工具) · docs/tech-debt/(未入库)→ 待用户裁决 · ADR-035(L4 动效)→ 批 6。

提交清单(31 个,ad9d80d2^.. 至本收口提交;逐条 sha / subject / 归属见批 5 计划 §收口回写 §三)

归属 提交数 sha(按时间序)
T2 拆件 A(安全网 / 拆件 / 棘轮重同步 / 圆角落档) 4 ad9d80d2 · 0bf849d2 · f193808d · d48fca57
T4 拆件 C(NotesPage 派生搬 colorPalette) 2 e579df63 · 343b38f0
T3 拆件 B(屏卡安全网 / 抽单卡) 2 4bee9d7a · 06116283
T5 地基 A(ViewSwitcher,4 提交) 4 afd35439 · ca19275a · 3c739c74 · 927aedf8
T6a / T6b(记忆 + 槽契约 / 注册表 + 适配器) 2 b2d5d477 · 556515b8
T7 / T8 / T9(三轨 · 印样 · 卡片流) 5 f191ab9b · 02dd20ba · d4794227 · e73b3616 · a41e9438(T7 · T7 判据复核 · T8 · T8 判据修正 · T9)
T11(粘性头) 1 a36145c5
T12(笔记卡片流) 1 6d49bb21
T15a(surfaceRatchet 登记通道) 1 cc49b09c
T17(--ed-nav-h 绑定 / Modal 滚动恢复) 2 7deeb274 · c927d547
T14(笔记接线:宿主 + 注入) 2 dadd2515 · a9f8fe97
T10(会话接线,重落地) 1 5f39cefe
T16(focus* 收敛 + 注释更正) 1 c652f67f
T15(架构守卫,2 文件) 2 1d4023e4 · b4edf8e4
T13(零提交 —— 条件项判否、零代码登记) 0 (progress.md 逐字「零提交(开工 6d49bb21 → 收工 c927d547)」)
T18(A 只产读数零提交 · B 本节所在收口提交) 1 (自引用,无法写入本节)
合计 31 ——

注:T13 = 0 提交是 C2/C17① 的正确形态(探针判否 ⇒ 交付「为什么不做」的登记而不是空壳);T18-A 也零提交(只产 tmp/t18/** 读数包)。上表逐条与 tmp/t18/measurements.md §4.2 的 30 条逐任务表对得上(该表按 oldest-first 列 30 条,上表按归属归组)。本行的「31」= ad9d80d2^..<收口提交> 含左端点;git rev-list --count 2559a3fd..<收口提交> 的 31 与 git rev-list --count 2559a3fd..b4edf8e4 的 30 一并报出(后者不含收口提交)。

批 6 · 动效系统(2026-09-13,ac504b06^..975b3285,77 个提交)

提交数口径(本文档既定规矩:一律「含左端点」A^..B):批 6 的第一个提交 = ac504b06(docs(plan): 批 6 动效系统实施计划(36 任务))⇒ git rev-list --count ac504b06^..975b3285 = 77(= 计划 1 + T1–T34 里已提交的 34 个任务的提交 + 微单元;T15 与 T34 各零提交:前者是证据型任务、后者只产读数)。 冻结提交 = 975b3285(test(motion): 拆开探针字面量并收紧显影判据 = 波 C 最后一个提交);真实构建产出 app/dist mtime 2026-09-13T05:10:24.838+08:00、入口 index-CBZzLV5U.js 117,002 B。 🔴 读数正本 = .superpowers/sdd/2026-09-12-frontend-redesign-batch6-motion/task-34-report.md(T34,326 行):本节所有数字一律引用它、未重新实跑(唯一例外 = 「台账行数」一节由 T35 按提交树 countLines() 亲测,见 line-limit-exemptions.md 的二次刷新)。

交付

  • 纲领与决策载体:新建 docs/standards/motion.md(T1,bffed928;先于任何动效代码落地)· 新建 ADR-035(T2,97295d64;含**「后端契约例外」节**)+ docs/adr/README.md 索引 +1 行。规格 §14(:836)的「docs/standards/ 新增动效规范章节」由此兑现(批次归属消歧见本节「规格漂移纠正」)。
  • 引擎:app/src/motion/engine.ts(唯一入口,顶层 gsap.registerPlugin(useGSAP, Flip, ScrollToPlugin, CustomEase),恰 4 个、顺序逐字)+ engine.test.ts + engine.guard.test.ts(闭包交集判据 + 产物三件套,真实构建后复跑 11/11 passed / exit 0);app/package.json dependencies 15 → 17(gsap@^3.15.0 · @gsap/react@^2.1.2)—— R2.1 的唯一一次「零新增依赖」破例。
  • token 真源:10 个时长/缓动变量迁入 app/scripts/gen-tokens.mjs(motion.css 的 --ed-* 定义恒 0,回归封条落在 style-seams.test.ts)+ pill 档(radiusScale 第 5 档 = 999,取自既有兜底字面量)+ 新 token --ed-nav-h-live: 58px + 两个基调缓动 token。
  • 三档 / 双基调 / 位移:app/src/motion/intensity.ts(data-motion 三档 + motion:intensity 持久化 + 跟随系统 + 源序守卫)· components/MotionIntensityControl.tsx + SettingsPage 接线(复用 ViewSwitcher)· app/src/motion/tone.ts(data-tone + CustomEase 具名 ease)· app/src/motion/shift.ts(位移 8px 唯一出口 + 扩域守卫)。
  • 底座与出口:app/src/test/motionHarness.ts(确定性推进底座 + matchMedia 桩 + 纪律入册)· app/src/motion/controls.ts(可中断 / 可反向的唯一出口,interrupt() 真 kill 且 killTweensOf 先、timeline.kill() 后)。
  • 响应层 / 环境层:motion.css 的元素级全局回执(七类动作,零调用点改动)+ 原语层四类回执 + app/src/motion/responseCoverage.test.ts / responseSeams.test.ts / responseScan.ts;环境层四件 + @keyframes 桶边界(app/src/motion/env.ts = 幅度真源)。
  • 守卫改判与补测:G1 / G2 / G3 / G6 改判(每条给旧断言原文 / 新断言 / 专属变异体 / 为什么更强)+ G-1..G-4 补测(T15 = 证据型、零提交)+ T16 的三处文档就地更正(textBaseline.ts 头注 · 规格 pinnable 两处 · 豁免表人工块 19 条漂移)。
  • 相变两态与承载面(波 B):shell/shellPhase.ts + shell/phaseSource.ts(单一写入方)+ shell/PhaseChrome.tsx + App.tsx 接线(599/600)· components/Waveform.tsx(div 条阵列,禁 SVG)+ shell/LiveBar.tsx(采集态 58px LIVE 仪表)· 复习态零 chrome(motion.css 相位块 + TopBar.css 两态,不 animate height)· components/review/DueScale.tsx(到期刻度视觉)· views/session/TimeRail.tsx + TimeRail.css + ThumbStrip.tsx(时间轨 / 播放头 / 掠过条)+ 音频降级提示 · SessionViewSlot 注入槽 + useSessionAudio.ts(音频引用的唯一过桥点)。
  • 后端三条例外(R0.1 第 1 条):E3 Flashcard.intervalDays(Rust 4 文件 / 5 处,含 types_contract_tests.rs 的追加行)· E4 session_audio_path 只读命令(312 → 313)· E5 WAV 轴 ≡ 会话轴(audio_align.rs + audio_align_tests.rs + 写块补静音 + sidecar {id}.wav.meta.json + aligned 自证量 + MAX_GAP_MS = 10 min)+ ADR-013 就地加注(「WAV 轴与会话轴的对齐」节)。
  • 6 个签名动效(波 C):useTriTrackAlign(#1 对齐)· useRevealChoreography(#2 显影编排,字符率近似)· usePhaseFreeze(#3 相变凝固)· useScaleGrowth(#4 刻度生长,回缩用精确 intervalDays)· usePlayheadJump + screensFor.ts(#5 时间码回跳 / 掠过缩略)· useRevealMemory(#6 记忆浮现,字距用 x 而非 letterSpacing)· useColumnFlip(列折叠 Flip,授权路径 B)。
  • 产品兑现点:[[ts:ms]] 回链接上毫秒 + 修掉死链(T26:NoteMarkdown / NoteReadingView / NotesReadingColumn / NotesPage / App.tsx 五处接线;芯片此前整条不可达 = 一个真实缺陷)· [[ts:ms]] 的 URL 消毒只放行内部锚点(T26 判据)。

验收(R0.1 第 2 条的验收面逐条 + 八门禁终态)

口径:生产调用点 = app/src/** 的 .ts/.tsx 减 *.test.*(域内 336 个生产文件)里的实际调用 / 挂载行(注释与 import 行不计)。原始清单 = T34 的 tmp/t34/callsites.txt。T36 出最终兑现度表;本节是 T34 的中间读数。

# 验收项 生产调用点 落点(逐字) 兑现度
1 #1 对齐 useTriTrackAlign 1 views/session/SessionTriTrackView.tsx:251 ✅ 可判
2 #2 显影编排 useRevealChoreography 1 components/session-detail/SessionRawView.tsx:96 🟡 部分:⚠️ 反向 / 重播 replay() 无生产入口(= 0)
3 #3 相变凝固 usePhaseFreeze 1 shell/LiveBar.tsx:90 ✅ 可判
4 #4 刻度生长 useScaleGrowth 1 components/review/ReviewSessionPanel.tsx:98 ✅ 可判
5 #5 时间码回跳 usePlayheadJump 1 views/session/TimeRail.tsx:140 🟡 部分:落位 + ≤8px 掠过已交付,长距离连续滑动未交付
6 #6 记忆浮现 useRevealMemory 1 components/review/ReviewSessionPanel.tsx:102 ✅ 可判
7 相变两态(data-shell-phase) 1 写入方 + 1 载体 shell/phaseSource.ts:84(全仓唯一 useShellPhase,shellPhase.guard.test.ts 名册守)· <PhaseChrome phase={phase}> = App.tsx:394 ✅ 可判
8 承载面① 采集态 58px LIVE 仪表 + 波形 链路闭合 1/1/1 App.tsx:394 → shell/PhaseChrome.tsx:102 <LiveBar …> → shell/LiveBar.tsx:135 <Waveform …> ✅ 可判
9 承载面② 到期刻度视觉 1 pages/ReviewPage.tsx:178 <DueScale due={scopeDue} testId="review-due-scale" /> ✅ 可判
10 承载面③ 时间轨 / 播放头 1(+1 内部) views/session/SessionTriTrackView.tsx:275 <TimeRail …/>;其内 TimeRail.tsx:220 <ThumbStrip …/> ✅ 可判
+ (附)列折叠 Flip useColumnFlip 2 / 8 处 components/ChatSidebar.tsx:80 · pages/GoalsPage.tsx:42 🟡 路径 B;其余 6 处未接线
+ (附)环境层第 3 件「未确认段落墨度」lowConfidenceClass 1(R12.4 要求 ≥2,差 1) components/session-detail/SessionRawView.tsx:137 🔴 未达标(只登记、不补)
+ (附)[[ts:ms]] 端到端 只通一半 笔记侧已接 ms;会话页那一跳未交付 ⇒ 批 7 首要候选 🟡
+ (附)E4 的后端契约面 session_audio_path 已注册 registry 313 / 313 / 0 ✅

🔻 T36 收口回写(2026-09-13,上表原文一字未改) —— 最终兑现度表(10 行)的落点 = .superpowers/sdd/2026-09-12-frontend-redesign-batch6-motion/task-36-report.md(gitignored;本节不复制,避免第二份会漂的手抄副本)。

  • 🔴 验收面 = 10 个(R64 #4 的更正:R0.1 正文写「9 个」而列举是 6 + 1 + 3 ⇒ 按 10 读;别处若仍写「9 项」按此加注读)。
  • 🔴 上表是 T34 在冻结提交 975b3285 上的中间读数;波 D 的 T35b / T35c / T35d 三个 comment-only 微单元改了 app/** 的注释行 ⇒ 四个行号在终态(7d6d677b)漂移 1–2 行,按终态读:#1 对齐 views/session/SessionTriTrackView.tsx:251 → :253 · #2 显影编排 components/session-detail/SessionRawView.tsx:96 → :97 · 承载面③ 时间轨/播放头 SessionTriTrackView.tsx:275 → :277 · 环境层第 3 件 SessionRawView.tsx:137 → :138。其余行号由 T36 逐条复测不变(LiveBar.tsx:90 · LiveBar.tsx:135 · PhaseChrome.tsx:102 · App.tsx:394 · phaseSource.ts:84 · TimeRail.tsx:140 · TimeRail.tsx:220 · ReviewPage.tsx:178 · ReviewSessionPanel.tsx:98 / :102 · ChatSidebar.tsx:80 · GoalsPage.tsx:42)。
  • 🔴 两处口径须并读(T36 点名的分叉):规格 §10 的批 6 收口行把 6 个签名动效写成「6/6 各有 ≥1 生产调用点、唯一缺口 = #2 的反向/重播入口 = 0」—— 该句只点 #2;#5 时间码回跳同样是部分交付(落位 + ≤8px 掠过已交付,长距离连续滑动补间未交付 ⇒ 见上表第 5 行与 task-31-report.md:137)。⇒ 两处并读:#2 的缺口是「入口 = 0」,#5 的缺口是「补间形态只交付一半」。均以 T36 的最终表为准(T35 §7-6 已声明「若分叉以 T36 为准」)。
  • 🔴 终态补记两条:① --ed-dur-page 今天 0 生产消费者(T35b 实测:全仓只有 ui/tokens.css:89 的定义与 ui/tokens.gen.ts:114 的生成物条目,零消费方;控制方引述错误第 7 例)⇒ 去向批 7/8 或删除(不发明消费者)。② docs/tech-debt/ 造成的 docs-check 差值已由 T36 直接测实:docs/** 磁盘 280 个 .md / 入库 279 ⇒ 唯一未入库件 = docs/tech-debt/review-2026-09-11.md(191,980 B / 1555 行,未入库且未被 ignore)—— 这闭合了 T35c/T35d 记为「强推断」的那条归因。
  • 🔴 环境层 4 件的终态口径(R11.3「落 seam 不算已交付」):① 探针摆动 1(ui/primitives/Loading.tsx:64)· ② 采集脉冲 1(shell/LiveBar.tsx:105)· ③ 未确认段落墨度 1 / 要求 ≥2 ⇒ 未达成(components/session-detail/SessionRawView.tsx:138;不得用 T13 的 seam 充数)· ④ 到期刻度微光 1(components/review/DueScale.tsx:120)。⚠️ 另:rich 档的「幅度提高」未机械兑现(只兑现频率)⇒ 不得写成「三档全兑现」。

三条硬约束(R0.1 第 1 条)的判据与读数:① 规格 §3 就地加注 = 本批提交(E3/E4/E5 三行 + 四列齐备 + 回滚逐字)· ② ADR-035 单列「后端契约例外」节 = T2 建、T35 定稿回填(五项读数:313/313/0 · sidecar 键名 · aligned 语义 · MAX_GAP_MS = 10 min · cargo test 逐字)· ③ 🔴 cargo test --test app_lib_tests 本批真跑(不是「沿用基线读数」):running 2335 tests → test result: ok. 2329 passed; 0 failed; 6 ignored,exit 0。

八门禁终态(HEAD = 975b3285 · 真实构建产出 app/dist mtime 2026-09-13T05:10:24.838+08:00)

line-limits --full >600 0 · 301–600 档 122 · 登记条目 122(exit 0;零新增登记,对拍批 5 收口 Δ 0)· docs-check exit 0(扫描 280 / 检查 180,五项全 ✅)· registry 313/313/0 · tsc --noEmit 0 错 · vitest 221 文件 / 2132 用例 / 0 失败 / 0 skip(一次通过、零 flake;testResults.length 221;对拍批 5 的 184 / 1770 ⇒ +37 文件 / +362 用例;⚠️ 全量 vitest 在无并发单元时跑 —— 本批有 6 个负载敏感 flake,见「诚实代价」)· check-bundle-budget.mjs(真实构建,取 tmp/t34/build.lock,attempt=1、finally 释放、事后锁不存在)exit 0 · 首屏 103.60 kB gzip(原始 326,681 B;余量 96.40 kB;CSS 4 个 68,778 B / 15.62 kB gzip 不计入判据、只报告)· bundle-eager-graph 103 文件(源 89 + CSS 14)/ npm 包 7(结论口径 = TS-API 真实边:75 源 / 4 包)· 🔴 cargo test --test app_lib_tests 真跑 2329 / 0 / 6(exit 0) · cargo clippy --all-targets:error 0 · lib warnings 15 = 基线。

首屏账 / CSS 账 / eager 账(Δ + 机理;基线 = 批 5 收口 b4edf8e4 的真实构建)

  • 首屏三件套:gzip 100,485 → 103,603 B = 100.49 → 103.60 kB(+3,118 B / +3.10%);原始 318,299 → 326,681 B(+8,382 B / +2.63%),其中 +8,382 B 全部落在入口 chunk(index-Bn5oI23G.js 108,620 → index-CBZzLV5U.js 117,002 B);首屏 chunk 数 3 → 3(Δ 0,构造性成立);vendor-react / vendor-tauri 逐字节不变(192,536 / 17,143 B);预算余量 99.52 → 96.40 kB(−3.12 kB)。⚠️ 仪器陷阱(本次新踩,登记):check-bundle-budget 的 JSON 里 firstScreen.totalBytes 装的是 gzip 合计、不是原始字节 ⇒ 原始字节必须自己从 chunks[].bytes 求和。
  • eager 账(结论口径唯一,R63.3 钉死):TS-API 真实边 66 → 75 源文件(+9)· npm 包 4 → 4(Δ 0);工具口径 91 → 103 文件 / 4 → 7 包只作旁证(2 个纯类型边 gsap / @gsap/react + 1 个注释字面量假命中 views)。新进首屏 = 9 个(逐条):components/Waveform.tsx · motion/intensity.ts · motion/tone.ts · shell/LiveBar.tsx · shell/PhaseChrome.tsx · shell/phaseSource.ts · shell/shellPhase.ts · shell/usePhaseFreeze.ts · utils/fmt.ts;REMOVED = 0 ⇒ 没有一个页面或视图被静态拉回首屏(pages/** 新增 0 个)。
  • vendor-gsap 的 V4 成立(真实产物上真跑):app/dist/assets/vendor-gsap-BQLVn3Z6.js 存在(105,584 B) 且 firstScreen.chunks = [index-CBZzLV5U.js, vendor-react-lr0dg1MX.js, vendor-tauri-UIF4jgRy.js] 不含它;engine.guard.test.ts 在本次构建后的 dist 上复跑 11/11 passed(exit 0)。
  • CSS 账(不计入预算,只报告):文件 3 → 4 个、原始 63,229 → 68,778 B(+5,549)、gzip 14,508 → 15,623 B。归因必须含 T12 / T13 / T19 / T29(不止 T5/T6),逐源文件:ui/primitives/motion.css 74 → 335(T5 token 迁移 + T6 档位块 + T12 响应层 +113 + T13 环境层 + T19 相位块 + T29 相变凝固)· ui/primitives/Text.css 46 → 66 · ui/primitives/Button.css 92 → 100 · shell/TopBar.css 142 → 149 · ui/tokens.css(生成物)100 → 119 · 新增 2 个懒 CSS:views/session/TimeRail.css 78 · views/session/TriTrackAlign.css 20(合起来即懒 CSS SessionTriTrackView-LATzHimF.css 772 B)。首屏 CSS 的 +4,777 B 可完整归因到前五个文件(motion.css 经 ui/primitives/index.ts barrel 进首屏);bundle-eager-graph 的 CSS 计数 Δ = 0(14 → 14)。
  • 懒侧账(不计入预算,只报告):chunk 31 → 36(+5)、原始 +354,344 B、gzip 583.98 → 698.86 kB(+114.88 kB);94.1% / 92.0% 来自两块 —— vendor-katex +227,858 B(内容哈希变 DhXGx0Ak → CLrGOHeO)+ 新块 vendor-gsap +105,584 B;其余具名:SessionTriTrackView +7,811 · ReviewPage +6,878 · SessionsPage +3,369 · registry −658 · 新小块 ≈ +9,800;余 ≈ 3,400 B 未逐块闭合(诚实登记:chunk 名不是稳定标识)。

规格漂移纠正(逐处,原文保留 + 就地加注)

漂移 落点
§3 红线 6 → 新增第三处例外 E3 / E4 / E5(「两处」按加注读作「三处」;四列齐备 + 回滚逐字 + cargo test 真跑读数) 规格 §3 表后整块加注
§4.3 条件③(审校模式)仍未实现 + ink-4 保持 0 生产调用点 + 环境层第 ③ 件的落点是 lowConfidenceClass(不是 ink-4)且只有 1 处(要求 ≥2) 规格 §4.3 表后加注
§5 的 42 文件表已完成「三副本同步」(规格 §5 / ADR-033 §1 / 豁免表人工块;逐值 HEAD 实测 + 19 项漂移逐条 + 登记「line-count-src 锚点全仓 0 个读者」) 规格 §5 加注 + ADR-033 §1 加注 + line-limit-exemptions.md
§6.2「采集态整列隐藏」vs §6.3「源列保留(采集配置面)」的内部矛盾(R40.1:两处原文保留 + 就地加注消歧;本批未实现列隐藏,两个口径按加注并存) 规格 §6.2 + §6.3 两处加注
§6.2 pinnable 的消费方仍为 0(本批 Flip 走路径 B、未接线消费) 规格 §6.2 加注
§6.3 实现面回填:三态通道 + 58px token + LIVE 仪表链路(1/1/1)+ 复习态零 chrome 走相位 CSS + 相位块块序 191 < 210 < 260 + navHeight.consumption.test.ts 零改动仍绿 规格 §6.3 加注
§8.1–§8.7 实现面回填(引擎与双实例陷阱 · token 真源 · 三档 + 源序机理更正 · 6 个签名动效逐条兑现度表 · maxDiff ≈ 0.409 @ x=0.40 · Flip 的 layout 属性冲突 · [[ts:ms]] 只通一半) 规格 §8 表后整块加注
§10 批 6 行 → 新增「↳ 批 6 的收口」行(✅ + 验收面逐条实际结果 + 八门禁终态 + 「60fps 未测」) 规格 §10 表
§11-5 / §11-9 / §11-10 / §11-11 四条进度注(机器判据落点 + 首屏与懒侧账 + 四行判据 + 八门禁终态 + 6 个 flake 名单 + 「并行窗口偶发红是一类现象」) 规格 §11 四处加注
§12「登记不排期」四项的被做数 = 0 的自证 + 本批 10 条新增登记项(aligned 残余 D3–D6 · 导入会话音频 · 跨窗口同步 · 孤儿 sidecar · Flip 与 R8.4 冲突 · ADR-019 缺号 · docs/tech-debt/ · 懒侧无门禁 + KaTeX 二份副本 · [[ts:ms]] 会话页那一跳 · hook 无 unmount 清理) 规格 §12 加注
§14 :836「docs/standards/ 新增动效规范章节」的批次归属(本批已做;v0.22:35 的「批 8」按加注读)+ ADR-035 已写 + ADR-019 缺号不补 规格 §14 加注 + v0.22.md:35 就地加注
ADR-035 定稿:例外节五项读数回填 · 决策 2 快照注释(白名单)与决策 3(闭包交集)两种口径 · 决策 5 的源序机理更正(!important 是承重机理、源序 = 防御性钦定)+ 块序硬事实 · 合规性验证 18 行终态 + 末行「挂账 → 定稿」的语义翻转 · 登记节补批 6 新增项 + 波 D 标签清扫清单 ADR-035 就地加注(T2 已冻结正文只加注、不重写)
motion.md 收口:↔ ADR-035 反向引用(R14.3,此前单向)· rich 档兑现口径(频率兑现 / 幅度上限不动,理由改写)· controls.ts 的适用面(R41.3 经 R61 重述)· getChildren() 的递归口径(默认 = 2)· 「不可用判据」九项的本批读数表 docs/standards/motion.md 就地加注
docs/adr/README.md 状态列措辞(「波 A 落地」→「波 A 进行中」+ 收口口径)· 例外节位置体例只加注不移动(R14.7 #4) docs/adr/README.md 加注
ADR-013 复核 + 最终读数补进(WAV 对齐节的 TODO 结清 · MAX_GAP_MS = 10 min · sidecar 键冻结 · cargo test 真跑 · 「不得声称播放已可用 / seek 已验证」) ADR-013 新增「批 6 收口复核」节
计划两处口径更正(:584 表的 V2 与 Task 11 Step 2 ① 的 getChildren().length === 1 ⇒ 默认递归正确值 = 2)· T8 诚实边界的「微小曲线差」量化加注(maxDiff ≈ 0.409 @ x=0.40,接受 ≠ 可两路横跳)· T15 变异设计表的两处更正(G-1 代守名单 · G-3 目标路径) 批 6 计划 :586 / :884 / :1009 / :1220 四处加注

过程中纠正的计划错误(逐条带读数与出处)

① T3:计划在 .ts 文件里写 JSX ⇒ 不可编译(9 条 tsc 错误 TS1005/TS1161)⇒ 改用 createElement(仓内既有 7 处 .ts React 测试范式)· ② T6:计划 V5 的「jsdom 下」与 Files 表的「node 环境」矛盾 ⇒ 采纳 Files 表(intensity.test.ts 不写 jsdom 头),连带硬要求 T7 补 jsdom 判据 · ③ T8:计划表 5 遗漏 style-seams:188 的同族断言(T8 STOP 请裁 ⇒ 追认;T8 的做法是「先 STOP 不擅改未授权断言」的正面实例)· ④ T12:计划 eco { transform: none } 与 Files/V2 矛盾(档位块不得新增私有 --ed-* 且不得反转无障碍优先级)· ⑤ T12:Files 表 vs V2 的门禁口径矛盾 · ⑥ T13 / T16 的预期值过期(T16 计划预期 style-seams 288 / motion-coverage 147,实测 299 / 186)—— 同族三条:T19 的预算过期(计划给相位块 ≤+40 行,实测 +42 ⇒ motion.css 275 → 317,越过 R11.8 的 ≤300 自律线;.css 不在门禁视野故不阻塞)· T23 的读数更正(R5.5-b 写 audio_store.rs「213 行」实测 212;recon-a A2 的「全仓 58px 0 命中」在本计划者仪器下是 2 命中 —— 两处都是 SelectionActionMenu.test.tsx 的 258px 子串 ⇒ 生产代码仍 0 处裸 58px)· T16 的关口读数(人工块二次刷新的范围由「1 条」更正为「2 条」,见 R63.2)· ⑦ T20:计划 V2 在单测里调 review_card 不可执行(tauri 2.11.5 的 State<'r,T> 字段私有、无 From<&T>、未开 test feature ⇒ 全仓 tauri::test 0 命中)⇒ 按仓内 inner 约定搬进 review_card_inner · ⑧ T20:控制方的「零新增文件」与计划自身的兜底互斥(R17.2 的派发错误)· ⑨ T4:V1 的「两半互证」不成立 + ③ 无法单独成立 · ⑩ T14:计划 G1 的新断言原文有假红洞****(/\d+\s*ms|…s/ 会把 var(--ed-dur-micro, 120ms) 判成裸值)—— 改用 withoutTokenVars 先剥,双向变异证明 · ⑪ T18:计划的 aria-pressed 不可满足 / Step 5 不可交付 / M2 预测为假(App.tsx 596/600 + ClassroomCapturePanel.tsx 298/300 ⇒ 无生产调用点;LiveBar 的挂载并入 T19)· ⑫ T21:计划 Step 3 自相矛盾(点名 scopeDue 而文案取 totalDue ⇒ 选组过滤时分叉;T21 未擅改既有文案 = 正确)· ⑬ T22:计划的跨任务互证不成立 · ⑭ T23:V1 冗余项 + timestamp_ms 是块末**(不是块首)** · ⑮ T24:计划的注册表类型落点不可行 + V3 的顺序探针 · ⑯ T26:V1 不可满足 · ⑰ T27:计划的 Files 表未列 TriTrackAlign.css · ⑱ T28:V5 与 V7 自相矛盾、且 V7 对 inline 元素无效(段正文是 <span> ⇒ transform 无效 ⇒ 「显影必须挂段落行」;这是本批最有价值的实测之一:一个在 jsdom 里全绿、在浏览器里完全看不见的判据形态)· ⑲ T29:计划 V3 的源序改判(相位块必须在档位块之前)· ⑳ T30 V6 / T31 M7 是等价变异体(诊断后换体才红)· ㉑ T32:无计划错误(唯一一条)· ㉒ T33:计划 Files 表写 useColumnFlip.test.ts,而该文件必须渲染组件 ⇒ .ts 装不下 JSX(同 ① 一类)· ㉓ R55.5 的两条计划缺陷(V1 空真 · V9 的「1770 用例」已过期)· ㉔ R58.3:useColumnFlip.test.ts 同类缺陷(= ㉒) · ㉕ 波 A 的 G-1 变异预测为假(批 5 D 表 :1772 与批 6 计划 :1214;代守名单更正为 A4① + A4② + G1①③ / G2① / G4)· ㉖ G-3 的变异目标路径不存在(计划点名 views/session/SessionRawView.tsx,T15 代以 SessionProofView)· ㉗ T15/T16 的守卫自证缺口(4 条) 与 T15 的「F9 无测试级牙」(只由命令级零 diff 代守)· ㉘ T11 的 V1 M1 期望在 paused 下不成立 + V2 的 M2 归因不成立(paused 上绝对 seek 与方向无关 ⇒ 拆成 V2a/V2b/V2c)· ㉙ 🔴 控制方的 3 处引述错误:(a) motion.md 的 === 1(motion.md 全 4 版扫 === 1 命中 0,该字面只在计划 :580/:1009)· (b) 追加 C 的前提为假(motion.md 从无「微小曲线差」措辞,且 :85 是规格 §8.3 的逐字表行、不许改)· (c) R29.2 的「12/12」实测为 6/6(以实测为准)· ㉚ 🔴 控制方的 2 处派发错误:(a) R17.2 的「零新增文件」过紧约束(与计划兜底互斥)· (b) R33.2 的 T16 派发早于依赖落定(motion.css / Text.css / motion-coverage.test.ts 当时仍在飞 ⇒ T16 登记的是工作树口径;二次刷新并入 T35)· 另控制方 1 处裁决错误:R12.1 判「取 ed-text--low-confidence ⇒ 零既有断言改动」漏了 structuredBlocks.test.ts:84(它是改类的必要连带)⇒ 追认为 G19 授权 · ㉛ 🔴 T13 面:M8b 的假读数归因更正(R42.2 ②) —— M8b 的真拦截者是「期望比对」,ran 下降只是旁证(原归因把旁证当主证)⇒ 计入判据纪律:ran 闸只证「跑起来了」、不证「拦下来了」(同族先例:批 4 #30 的 --cache.dir · T20 的过滤器拼错 · T89 的 git archive 取不到未跟踪文件 ⇒ 三次「被 ran 闸拦下」都是流程证据,不是判据证据)。

诚实代价(不许省略)

  • 🔴 真实 60fps 未测(jsdom 无合成器;rAF ≈ 39fps)⇒ 代理判据 = 未动 layout 属性;不得出现「60fps 已达成」类表述。
  • 🔴 Flip 的几何位移 jsdom 零可观测(bounds 全 0、位移增量恒 translate3d(0px,0px,0px))· 真实媒体播放 / seek 不可验证(不得声称「播放已可用 / seek 已验证」)· window 级滚动不可用(判据收敛到元素级)· 真机 / WebView2 观感未测(用户已裁决跳过)· 像素面全部未测(真的直线 / 真的 0.72 / 真的 220ms 淡入 / 真的 58px 零 chrome)。
  • 🔴 相变两态 = 「文字面 + 结构面已交付、像素面未测」(不得笼统声称「相变两态已交付」)。
  • 🔴 「对齐」的「错位语义」是控制方 R5.1 的定义(规格只给一句、代码无对应物)⇒ 用户可否决(R5.1 逐字)。
  • 🔴 六个负载敏感 flake 名单(本批登记;判据 = 单跑复绿 + 提交树全量绿):components/KnowledgeGraphView.test.tsx · components/notes/NotesReadingColumn.views.test.tsx · components/ChatSaveNoteDialog.test.tsx · views/registryResolution.test.ts · components/KnowledgeSampleView.test.tsx(第 6 个候选) · ffmpeg::tests::run_captured_handles_large_output;⚠️ 「并行窗口内的全量偶发红」是一类现象、不是固定名单(另有 3 个不在名单内的瞬时红)⇒ 全量 vitest 必须在无并发单元时跑。
  • 🔴 [[ts:ms]] 的芯片在修之前是死的(回链整条不可达)—— T26 修掉了这个真实缺陷(NoteMarkdown 一半);NotePreviewView + utils/html.ts:32 的另一半未修(批 7 候选)· 定位精度残余 = 块粒度 ±200 ms(写块周期 200 ms)。
  • 🔴 katex@0.18.4 的第二份副本进产物(T28 让 structuredBlocks.ts 首次进图)⇒ +227,858 B 原始 / +64,497 gzip,而懒侧今天没有任何预算门禁 ⇒ 登记两条批 7/8 候选:「把 lowConfidenceClass 析出轻模块」+「懒侧字节纳入门禁」。
  • 行数 / 结构代价:App.tsx 599 / 600(余 1) ⇒ 任何后续任务不许动它(硬边)· motion.css 335 行(6 次追加,越过 R11.8 的 ≤300 自律线;.css 不在门禁 SOURCE_EXT 视野内)· style-seams.test.ts 299 · views/session/SessionTriTrackView.tsx 295 · shell/TopBar.test.tsx 298(余 ≤5 的共 22 个文件,T34 §9 列全)。
    • 🔻 T36 回写(2026-09-13,上面这句原文一字未改):views/session/SessionTriTrackView.tsx 的 295 是 T34 的冻结读数;T35d(7d6d677b)为把「长列表的滚动/密度手感见批 6」这句悬空承诺改成如实未交付而净 +2 ⇒ 终态 = 297 / 300(余 3)(同提交 motion/engine.ts 75 → 80)。T36 在终态(7d6d677b)逐条复测:App.tsx 599 ✅ · motion.css 335 ✅ · style-seams.test.ts 299 ✅ · shell/TopBar.test.tsx 298 ✅(口径 = countLines());余 ≤5 的成员集不变 = 上列 22 个(app/src 572 个文件中 295–300 行者 23 个,去掉 T34 口径排除的 ui/primitives/dialogMigration.e.test.ts 300 后仍是 22)。
  • 流程代价:每次真实构建都要人工取锁(check-bundle-budget.mjs 无锁机制;取锁协议是人工约定)· docs/tech-debt/(191,980 B)全程占着 git status(唯一脏项,待用户裁决)· 1 条新 IPC 与 3 项后端只读改动(live_session*.rs 触发 AGENTS.md §10 额外审查记录)。

未做(登记,逐条带归属批次)

docs/product/ui-ux-system.md / theme.md 的四层动效 / 三档强度回写 → 批 8(§14 逐字仍留批 8;本节「规格漂移纠正」只做消歧)· ink-4 接线 / 「审校模式」 → 批 7/8 · Text 字号越界 551 处 / 120 文件 → 批 8(本批只保证新代码不新增)· 暗档 data-theme 接线 → 批 7/8 · 跨窗口档位 / 相位同步 → 批 7/8 · 导入会话的音频承载面 → 产品裁决 · 删会话不删音频 + 孤儿 sidecar → 产品裁决 · aligned 残余 D3–D6 → 批 7/8 · [[ts:ms]] 的会话页那一跳 → 批 7 首要候选(T26 的逐行成本与 patch 落点保留在 task-26-report.md)· lowConfidenceClass 析出轻模块 + 懒侧字节门禁 → 批 7/8 · 波 D 的一次性「标签清扫」(comment-only;涉及 app/** 源码注释 ⇒ 属生产代码面,本批只登记:已过期 4 处 + kbCommands.ts:15 的 312/312 + tokens.gen.ts:83-85 的「0 生产消费者」+ tone.test.ts:23 的「data-tone 0 命中」· 前向引用 4 处 · engine.guard.test.ts ① 的假 console.warn · controls.ts 的过宽措辞)→ 下一个动效 / 治理单元 · 五类棘轮余量 + FROZEN_NUMERIC_ZINDEX + bundle-eager-graph 的 import type 口径 → 批 5/7/8(照原表)· ADR-019 缺号 → 只登记、不补 · docs/tech-debt/ → 用户裁决 · Flip 的 width/height 与属性集合判据的冲突 → 批 7/8 与判据纪律 · hook 无 unmount 清理(时间线在卸载后仍存活)→ 批 7/8 · 真机 / WebView2 验收 → 批 8(不得出现「已真机确认」类表述)。

🔻 T36 回写(2026-09-13,上面这一整段原文一字未改) —— 两处已在本批内关闭,不再是「未做」:

  • 🔴 「波 D 的一次性标签清扫」已执行:T35b 9c1f615c(6 文件 / +36 −22)+ T35c 04dc9de2(8 文件 / +38 −18)+ T35d 7d6d677b(2 文件 / +10 −3)= 16 个 app/** 文件 / 合计 +84 −43(实测 git diff --shortstat 975b3285..HEAD -- app/),上面逐条点名的源码注释项全部封闭(含 kbCommands.ts:15 的 312/312 → 313/313/0 · tokens.gen.ts:83-85 的「0 生产消费者」→ card 6 / reveal 7 · tone.test.ts:23 → 4 处 data-tone · engine.guard.test.ts 的假 warn(用例名 + console.warn 两段)· controls.ts 的过宽措辞)。🔴 唯一未改 = R66.3 #3 判为「不算说谎」的两处测试名(components/session-detail/useRevealChoreography.test.tsx:283 · views/session/useTriTrackAlign.test.tsx:279)⇒ 只登记。⇒ 本条去向随之收敛为「下一个动效 / 治理单元」仅指那两处测试名。
  • 🔴 --ed-dur-page = 0 生产消费者(T35b 实测)⇒ 去向批 7/8 或删除(控制方引述错误第 7 例;T36 独立复现同读数)。

提交清单(77 个,ac504b06^..975b3285;归组依据 = 逐提交 git show --name-only 的改动面 + subject,探针 tmp/t35/commits.mjs)

归属 提交数 sha(按时间序)
批计划(docs(plan)) 1 ac504b06
T1 动效规范(+1 微单元:评审三条 Important) 2 bffed928 · b508c5e5
T2 ADR-035 + 索引 1 97295d64
T3 装 GSAP + 唯一入口(+4 微单元:引擎头注/转出口径三条) 5 864f4881 · ae868f71 · d2eacd2d · 5ecfe1f7 · a9cf152a
T4 懒加载三件套守卫 1 34fb857b
T5 token 真源迁移 + pill(+1 微单元) 3 2ebac5ed · 0042ecfa · 92d83623
T6 三档强度通道 + 源序守卫(+1 微单元) 2 eb55386e · c9f89692
T7 动效强度控件 1 3978e2b9
T8 双基调(+1 微单元:量化曲线差) 2 fef4a8d8 · b0ab516b
T9 位移上限唯一出口(+3 微单元) 4 4d60663b · dd48d933 · 1935dd2c · 17a8b8c3
T10 确定性底座(+1 微单元) 2 869b9f08 · 9508c5dd
T11 可中断出口(+1 微单元) 2 a53fb506 · 6d10a2db
T12 响应层七类回执(+4 微单元) 6 2071ec7a · e531a0cb · 488cb534 · 8f6031bc · 9e94d941 · 32effc92
T13 环境层四件(+T13b 的 5 处小修) 2 d5b7b646 · 5467a91c
T14 G1/G2/G3/G6 改判(+T14b/T14c 微单元) 7 4c422e05 · 00fafb7c · e3719d03 · a50a3449 · 348f8a81 · 4dc32808 · 19a2a953
T15 G-1..G-4 补测(证据型、零提交) 0 (全在 gitignored 报告与 tmp/t15/**)
T16 文档就地更正(三处) 1 129b819c
T17 相变态通道 + 58px token 2 0840fe44 · b1534d3d
T18 LIVE 仪表(+1 微单元) 3 b2afd6d8 · 25a4a2e5 · 1a50d2ba
T19 复习态零 chrome(+1 微单元) 2 0772d1a7 · 1cc35346
T20 intervalDays(+T20b 拆行映射域) 2 89972482 · 6268f34d
T21 到期刻度视觉 1 56303c61
T22 session_audio_path(312 → 313) 1 5b881dec
T23 WAV 轴 ≡ 会话轴 2 375e5058 · 911b6190
T24 注入槽 + 取数钩子 2 7c1899ee · 99ac683e
T25 时间轨 + 播放头(+1 微单元 + 台账刷新) 3 103703e6 · 9d3dfa5c · 0ea19a78
T26 [[ts:ms]] 接 ms(+1 微单元) 2 4cd9d23d · 3f99d52f
T27 #1 对齐 2 c0ce9933 · 0bdad6dc
T28 #2 显影编排 3 c518238a · 160d5936 · 975b3285
T29 #3 相变凝固(+台账刷新) 3 d90b89d2 · 17e96fe1 · 7d63a1bf
T30 #4 刻度生长 1 66f0e4a9
T31 #5 时间码回跳 1 48e453e4
T32 #6 记忆浮现 1 51f60191
T33 列折叠 Flip(路径 B) 4 dfcbd496 · c003d739 · 0ee1d0e0 · 3277ebad
T34 终态测量(零提交,只产读数包与报告) 0 (tmp/t34/** + task-34-report.md)
合计 77 ——

注:⚠️ 微单元的归属按「改动面」判定(例如 17e96fe1 chore(line-limits) 删的是 usePhaseFreeze.test.tsx 的登记行 ⇒ 归 T29;5467a91c 改的是 responseSeams.test.ts 的缓动名与 !important 口径 ⇒ 归 T13b 的 5 处小修)。🔴 权威的逐任务提交轨迹由 T36 的收口评审给出(批 6 计划 §收口回写 §3);本表不含 T35 本节所在的提交与 T36 的后续提交(自引用)。

🔻 T36 的归组对拍(2026-09-13,独立复核;上表原文一字未改) —— T35 §7-5 把「77 条提交的任务归组」列为未能验证,R64.2 #3 判「权威轨迹留 T36」;T36 用 git log --pretty=format:%h%x09%s 逐条对拍,结论 = 上表成立:

  • 🔴 区间与计数:上表 77 的区间是 ac504b06^..975b3285(只到冻结提交);批 6 的终态提交数 = 84(实测 git rev-list --count ac504b06^..HEAD = 84)= 上表 77 + T35 的 4 个(b3f2181f · 323acb58 · c7ef9ca4 · e719894f)+ T35b / T35c / T35d 各 1 个(9c1f615c · 04dc9de2 · 7d6d677b)。T36 本节自身的提交不计入(自引用)。
  • ✅ 0 个幻影 sha:上表 77 个 sha 逐条存在于 git log(git log --pretty=format:%h 6cbe964e..HEAD 的 84 条里 77 命中、0 缺失)· 36 行的「提交数」格与并列 sha 数逐行相等(mismatches = 0) · 微单元归属抽查 8 条(17e96fe1 → T29 · 5467a91c → T13b · 160d5936 → T28 · 1cc35346 → T19 · 92d83623 → T5 · 32effc92 → T12 · 0ea19a78 → T25 · 7d63a1bf → T29)逐条与 --numstat 的改动面一致。
  • ⚠️ 唯一一类差异(不是归属错误):9 个父任务报告从不引用自己的微单元提交(T1 b508c5e5 · T3 5ecfe1f7/a9cf152a · T6 c9f89692 · T8 b0ab516b · T9 dd48d933/1935dd2c/17a8b8c3 · T10 9508c5dd · T11 6d10a2db · T12 32effc92 · T14 a50a3449/4dc32808/19a2a953 · T20 6268f34d)—— 它们的旧/新原文记录在兄弟报告里(task-1-fix / task-6b / task-8b / task-9b / task-13b / task-14b / task-14c / task-20b)。⇒ 归组本身无需更正;读者须知「任务 = 报告集合」而不是「任务 = 单个报告」(T36 逐条差异表见 task-36-report.md §3.3)。

批 7 · 未接线落地(2026-09-13,681e73c6^.. 至全批收口提交,T21 落库时实测 59 个提交)

提交数口径(本文档既定规矩:一律「含左端点」A^..B):批 7 的开工 HEAD = 681e73c6(批 6 已收口并推送)⇒ T21 落库时 git rev-list --count 681e73c6..f0f2998c = 59(= 计划勘误 4 + 7a 的 11 个任务 + 7b 的 T13–T20 + T21 的规格回写 1)。 🔴 这不是全批终态:T22(全批收口) 的提交、以及本节所在的提交均不计入(自引用)。全批终态读数与最终提交清单由 T22 出。 🔴 读数正本 = .superpowers/sdd/2026-09-12-frontend-redesign-batch7-unwired/(台账 rulings.md §C0–§C54 · progress.md · 各 task-N-report.md),全部 gitignored。本节数字一律标明来源:凡未由 T21 亲测者,逐字写「引自 §Cxx / Txx 报告,未独立复核」。

交付

  • 三条验收(规格 §10 行 :722 时点锚 ⇒ 现 775):标签能写进去(T18)· 档位选完真生效(T19)· structuredBlocks 已作出接线或删除的明确裁决(T3 删除 + T2 析出 + T20 加宽)。
  • §1 L5 的四条规格义务:行 31 B 桶 3 条撤下 IPC 但保留内部函数(T4:create_session / add_session_segment / add_session_ocr_block;摘属性 + 删注册条目,函数体逐字节保留、无 *_inner 改名)· 行 34 档位通道 A 做完整(T19:start_live_session 第 5 参 tier + resolve_start_tier + 预置 profile_override 槽 + 启动失败回滚 · TierMemoryEntry + tier_entries(serde 缺省零迁移)· 新增 remember_video_profile_tier(定义 + 注册成对) · 读端 video_profile_for_spec 为真源)· 行 35 标签线 A 补完(T18:NoteTagsEditor + 写端三条命令各 ≥1 生产调用点 + 设色/清色成对 + tag_colors 幂等回填)· 行 30 A 桶补 UI。
  • structuredBlocks 的逐导出裁决(§C4.1 的明文授权,§C4.2 的硬条件):escapeHtml 只摘 :11 import + :13 再导出(真源 utils/html.ts:11 一个字不动)· renderLatex / renderMarkdownTable 删(唯一消费者是它们自己的测试)· lowConfidenceClass 留并析出到 utils/lowConfidence.ts(32 行)+ 加宽到 ≥2 生产调用点(T20 兑现:SessionRawView.tsx + SessionTriTrackView.tsx;批 6 R12.4 环境层第 ③ 件的「≥2」欠账就此补齐)。
    • 🔴 用例净 −7 的说明(非 LOST):全量 vitest 用例数 2132 → 2125(T3 的提交树上复算),逐条归因 = 删 structuredBlocks.test.ts 的 8 个 it(renderLatex 3 + renderMarkdownTable 4 + lowConfidenceClass 1)减 T3 自建的 utils/lowConfidence.test.ts 原样迁入 1 个 it(内含 4 条 expect) ⇒ 8 − 1 = 7。「LOST = 0 / SHRUNK = 0」的对拍纪律未被破坏(该 1 个 it 是搬家不是删除;T3 的授权出处 = §C9.19 + 表 6b 的 E-27)。此后 T7/T16/T17/T18/T19/T20 又各自新增用例(T21 未逐文件复算,以 T22 的逐文件对拍为准)。
  • markdown 归一(§12 的「3 套渲染器归一」,§C10.1 取代 §C9.15 的形态):新建 utils/markdownLine.ts(100 行:refineDiff.ts 的 mdLineHtml + NotePreviewView.tsx 的 renderMarkdown 合成一支,两模式具名常量逐字保留原样式)· ChatMessageMarkdown 并入 NoteMarkdown 后删除(react-markdown 站点 2 → 1 · 插件站点 8 → 4)· 终态 = 2 套活(NoteMarkdown + markdownLine)。🔴 禁止把两支手写链换成 react-markdown(它们是给 dangerouslySetInnerHTML 的串生成器,换 = 改 DOM 形态/样式/安全面)。
  • [[ts:ms]] 深链闭合(批 6 的「只通一半」):T15 给串渲染链的芯片补 data-ts-ms / data-ts-chip(utils/html.ts 40 → 48)· T17 迁入 markdownLine 并接容器侧事件委托 + 给 React 链(noteMarkdownComponents.tsx)补同名 marker + 修 App.tsx 深链 ms 载体 + focusSeekMs 四件齐(解构 / 转交 / 消费 / 复位)+ 深链到达后临时切三轨视图(禁止写视图记忆)。
  • 采集期逐段显影(批 6 登记转批 7):T6 先拆 LiveActivityPanel 513 → 242(新件 LiveTranscriptStream 297 / LiveOcrPreview 94,纯搬迁),T20 再拆 TranscriptRow.tsx(167 → 挂动效后 201)并挂 useRevealChoreography。
  • 懒侧字节门禁(批 6 的「懒侧无门禁」欠账):T9 新建(scripts/check-bundle-budget.mjs 首屏 + 懒侧两个独立读数 · scripts/lazyBudget.json 冻结基线 · 逐族上限 + 清单等式 + 总量硬棘轮 + 64 B 容差),口径写死「--no-build 的读数不可用于懒侧判据」。
  • 规格两章(只交规格、不写实现):§7.4「笔记带证据三轨」(E1/E2/E3 改写 + 两个分母 + 无锚点四类 fixture + 精修前后两态契约)· §4.3 的「审校模式」定义(入口 / 作用域 / 退出 / data-* 形态)。两章正文均逐字含「本批只交规格,实现未做」。
  • 补 UI 实做 10 条(§C9.1 逐字名单):reset_tag_color(#19) · update_note_tags(#25) · video_profile_for_spec(#28) · analyze_session_command(#34) · delete_session_images_all(#37) · finish_session(#39) · get_decision(#40) · refine_session(#42) · set_tag_color(#45) · update_knowledge_system(#47) —— 其中 4 条由 T18/T19 交付、6 条由 T20 交付(落点:SessionAnalysisPanel / GalleryBulkDelete / StaleSessionRecoveryBar / DecisionDetailPanel / SessionRefineSection / KnowledgeSystemEditPanel,判据件 batch7UiWiring.test.tsx 216 行)。

    🔻 收口更正(2026-09-13 · T21 追加轮;上一行原文一字未改)—— 实做面收口为 11 条:§C9.1 的「10 条」是计数口径,而逐个列名是 11 个名字 —— 计划 :2304 已自陈「数一数是 11 个名字」、:2305 裁决「按名字列全 11 个(不删任何一个)……不自行删减」。🔴 实测支撑(§C56.2 / §C57.4④):T20 交 6(其自记口径「6 + T18/T19 的 4 = 10」恰好吞掉了被删减的那一个名字)+ T23 补 1 + T18/T19 的 4 ⇒ 11 / 11 现已齐。

    • 11 条逐名:reset_tag_color(#19) · update_note_tags(#25) · video_profile_for_spec(#28) · analyze_session_command(#34) · delete_session_images_all(#37) · finish_session(#39) · get_decision(#40) · refine_session(#42) · set_tag_color(#45) · update_knowledge_system(#47) · update_fragment_group(#46)(最后一条由 T23 交付:125eec85 新件 app/src/components/FragmentGroupAction.tsx + 5f662811 + 5d59e332 的 feed 地形返工;T21 独立复测 PROD 0 → 1)。
    • 🔴 规格 §10 的「12」仍不改(那是规格原文、加注处理)⇒ 差额 = kb_search(#14),它在批 3 Task 12 已交付(b567f0e6)。
    • ⚠️ 上行的 batch7UiWiring.test.tsx 216 行是 T21 首轮的读数;T23 两条提交后 T21 实测 = 218 行(该判据件的 describe 标题也随之从「六条命令」改为七条命令,T23 自查后落 5f662811)。

验收(三条验收的兑现度 + T21 落库时的八闸读数)

验收(规格 §10 行) 判据 兑现度 证据
标签能写进去 写端三条命令各 ≥1 生产调用点 + 关库重开端到端 ✅ 成立 T18 的 PROD 各 1(NoteTagsEditor.tsx)· R-10 三路独立仪器(含自建 harness 逐字搬入 db_colors.rs 复现「加标签 → 关库重开 → tags 仍在 → 设色 purple → 清色 None」)· T21 独立复测 PROD 各 1
档位选完真生效 remember_video_profile_tier 写入 ⇒ 重新 load 仍是同档(机器代替品)+ start_live_session 五参兼容 ✅ 成立(代理判据) T19 的 tier_survives_reload_same_title + 负控 None · R-11 四段逐段实读(含消费端 live_profile_runtime.rs 与启动失败回滚)· T21 独立复测 video_profile_for_spec PROD 4 处
structuredBlocks 已作出明确裁决 逐导出裁决落地 + 规格 §10 行内授权逐字 ✅ 成立 T2/T3/T20 + T21 的规格 §10 加注(逐导出授权逐字)
+ §11-8「跨会话记住」是否全路径成立 —— ✅ 全路径成立 🔴 原不成立:source_window == None 路径(未选窗口 / 全屏)用净化去重后的会话标题当记忆键,而前端此时传常量 "实时课堂" ⇒ 该路径必读不回(§C51.4 的 Important I1);已由 T19 的 17d33095 修复(新纯函数 memory_key_for_start:窗口标题优先、未选窗口取去重之前的标题;判据 none_window_path_tier_roundtrip_across_reload + 负控)

三条验收的口径(必须并读,否则会误读成「已全部真机验证」):① 真机 / WebView2 冒烟由用户裁决跳过(§C6.4)⇒ 三条验收的「端到端」全部止于 jsdom / Rust 单测层;② 验收三的「明确裁决」是规格前置(§C9.10 逐字:写规格 + 裁决落库本身就是交付物形态);③ 「档位选完真生效」的「真生效」= 生效态(可经 live_session_status 读回),不是「采样参数真被采集链路消费」的像素级证据。

🔻 §11-8「段① 的『落库』」口径逐字(§C44.2 / §C45.1;T21/T22 照抄):段① 的「落库」= 会话生效态 + 记忆体,非 sessions 表落列。 依据:规格 §1 L5 行 34 的四段是「加 tier 参数 / 记忆加字段 / 新命令 / 读端接线」,没有一段要求 sessions 加列;验收「档位选完真生效」的实质 = 生效态(profile_override → worker → applied_tier,可经 live_session_status 读回);「跨会话记住」由记忆体满足(tier_survives_reload_same_title + 负控);改 schema 撞 AGENTS.md §10 且本批无此义务 ⇒ 属范围蔓延。

🔻 读端角色变更逐字(§C11.4;T21 已同批回写规格 §9 #30 行):KIND_TO_FORM / KIND_TO_TIER 的角色从「并行真源」变成「离线降级路径」(兜底) —— 它仍然存在、也仍有生产调用点(AGENTS.md §3.4 要求本地兜底路径必须留),不是被删除 ⇒ 当年删除 video_profile_spec_by_kind 的理由在"真源"这一层不再成立,在"兜底"这一层仍成立。

八闸(T21 落库时在工作树上串行实测;🔴 不是全批终态,终态由 T22 出)

line-limits --full exit 0「>600 硬限 0(棘轮内)· 301–600 档 121 · 登记条目 121」· docs-check exit 0(扫描 281 / 检查 181,五项全 ✅)· registry exit 0「定义 311 / 注册 311 / 重复 0」· 其余五闸本节不重跑(tsc / vitest / bundle-budget / bundle-eager-graph / cargo)—— T21 的写集只有 docs/**,对它们零影响;引用 T12/T20 的读数时必须标明来源与树(§C42.3 M-2/M-3 的纪律)。🔴 本批八闸的终态读数一律以 T22 为准。

🔻 批 7 终态回写(2026-09-13 · T21;上段三个读数原样保留为「T21 落库时」的时点读数) —— 全批收口件(gitignored)= closing-review.md · task-22-report.md(T21 本轮实测 109,327 B / 693 行 与 41,469 B / 323 行;控制方 §C59.1 报的 94,256 B / 28,796 B 是更早的落盘时点值 ⇒ 🔴 两处读数都带时点)。

① 第 ⑤ 闸(懒侧真构建**)的三个时点 —— 🔴 本批最有价值的一条读数**

时点 第 ⑤ 闸 读数
0a503cc8(T12 的 7a 段收口重冻)当时 ✅ 绿 limit 636,243
c0bff722(全批收口树)当时 🔴 红(exit 1) 懒侧 637,501 B > 636,243 + 64 ⇒ 超 1,194 B;具名 3 条 = 未归族 lowConfidence-CbMOBOyG.js · KnowledgePage- 28,466 > 27,620 · NotesPage- 48,627 > 48,087
55f502fa(T22 重冻)之后 ✅ 绿 limit 637,501 · unlisted = [] · fails = [] · 逐族红 0 · 首屏 105.95 kB pass=true
  • 🔴 T21 本轮逐字复核了两份日志:tmp/t22/logs/g5-bundle-budget-realbuild.txt(totalBytes 637501 / totalMaxBytes 636243 / unlisted 1 条 / fails 4 条 / ❌ 懒侧 gzip 预算超标(退出码 1))与 tmp/t22/logs/refreeze/g5-realbuild-post-refreeze.txt(totalBytes = totalMaxBytes = 637501、unlisted: [] / fails: []、各族 pass: true)。
  • 🔴 加注台账 §C47.4 的那句「7a 正式收口:八闸全绿」:🔴 该句在批 7 终态已不成立(c0bff722 树上第 ⑤ 闸真构建红)⇒ 原文保留、本注为准;这是 T22 的诚实纠错(§C59.10 第 2 条,控制方采信),不是笔误。⇒ 引用一律写「7a 段收口当时绿;全批收口树曾红;重冻后绿」,不得只引「八闸全绿」。
  • ⚠️ §C47.4 的原文在 gitignored 的 rulings.md(不在 docs/**) ⇒ T21 无法就地加注(写集硬边界 = 只改 docs/**)⇒ 本表即该句的 durable 更正(已在报告里点名)。

② 懒侧基线的精确性质(T21 本轮读 scripts/lazyBudget.json 逐值复核)

  • lazyTotalGzipBytesMax 636,243 → 637,501(+1,258 B / +0.20%)· lazyChunkCountMax 37 → 37(不变) · 族数 37 → 38(新增 lowConfidence- = 100 B)· generatedFrom 的真值:950afd5a(T12 重冻树) —— 谱系 = cd800d63(T9 批次中段) → 950afd5a(T12) → c0bff722(T22)(原写 90bb5f6a 与提交顺序不符,已由 T22 修正)。
  • 🔴 闭合性质(T21 复核):各族实测之和 = 637,501 = lazy.totalBytes = totalMaxBytes(逐字节相等 —— 重冻后日志里 totalBytes 与 totalMaxBytes 同为 637501);而 Σ gzipBytesMax = 638,029(比总量高 528 B)= shift- 族的 212 B 死预算(该族 chunkCount = 0、实测 0、上限 212)+ 其它族保留的 316 B 正 slack。
  • 🔴 结论逐字:除 64 B 容差外零余量 ⇒ 不得读成「还有空间」;🔴 shift- 的 212 B 死预算登记为批 8 清理项。
  • vendor-* 五族上限一字未动(canvas 58,784 · editor 208,585 · gsap 41,161 · katex 79,915 · md 50,622;T21 逐值复核一致),实测 +2 / 0 / +1 / 0 / +1(全部落在 64 B 容差内)⇒ 非回潮(§C46.4 条件⑤ 的 STOP 未触发)。
  • 🔴 逐族上限的陈旧度披露(2026-09-13 · T21 补轮;独立全批复核提出、控制方独立复现、T21 逐族逐字节复算):重冻后的真构建读数(tmp/t22/logs/refreeze/g5-realbuild-post-refreeze.json 的 lazyBudget.families)显示 —— 🔴 有 18 个族的实测已超各自上限,合计 +203 B: ActionPage- +25 · AiConversationDock- +39 · CaptureFloatPanel- +2 · CaptureOverlayPanel- +2 · ChatPage- +39 · RefineLaunchDialog- +2 · RefineStrategyPicker- +16 · SessionCardFlowView- +5 · SessionProofView- +2 · SessionScreenCard- +3 · SessionTriTrackView- +35 · SettingsPage- +3 · ViewSwitcher- +3 · colorPalette- +2 · registry- +21 · vendor-canvas- +2 · vendor-gsap- +1 · vendor-md- +1。 · 🔴 性质:均在 64 B/族容差内 ⇒ 未判红(闸的判定是对的、终态仍是绿)—— 本条披露的是逐族上限对这 18 个族已经陈旧,🔴 不是「闸有问题」。 · 🔴 登记为批 8 的逐族重冻输入(按 §C32.3 的「同提交可登记重冻」;🔴 总量上限不得抬高)。⚠️ 其中含 3 个 vendor-* 族(canvas +2 / gsap +1 / md +1)⇒ 上一行的「五族上限一字未动」(非回潮)与本条的「实测已在其上限之上 1–2 B(容差内)」是两件事,两句都要读。

③ 三条诚实纠错(逐条落账;🔴 全部归到计划卡 / 台账,不是实施者)

  1. 卡 V3 的「LOST = 0」与「以开工基线为锚」不自洽(§C59.4):T3 的合法删除就在锚区间内,逐文件对拍必然计入 LOST ⇒ 🔴 正确表述 = LOST = 1(components/structuredBlocks.test.ts,T3 5cda5bdb 经计划预授权的合法删除)· SHRUNK = 0 · 「LOST = 0」应读作「无未归因的丢失」。用例对账:开工基线 681e73c6 221 文件 / 2132(passed 2129 / pending 3,与 §C6.2 逐字吻合)→ 终态 229 / 2225;净 +93 = 新增 9 文件 Σ81 + 增长 7 文件 Σ20。
  2. 台账 cargo 2348 passed vs 实测 2354 passed(差 +6)(§C59.10 第 3 条)⇒ 🔴 逐字保留「成因未判定」,不许猜。第 ⑧ 闸实测:2360 run / 2354 passed / 0 failed / 6 ignored(exit 0)。
  3. 🔴 §C49.4 的「统一放宽 W1/W2/P1 的 1 s 等待上限」⇒ 作废(N = 0)(§C59.5):T22 实测一个都没放宽 ⇒ 🔴 批 7 不声称放宽过任何等待上限;该项从批 7 待办移除,登记为批 8 输入(若批 8 仍要动,必须先补 T17 之前的对照证据)。

④ 其余终态读数(T21 未独立复跑者逐条标明来源;§C42.3 M-2/M-3 的纪律)

  • 第 ①②③ 闸在本轮由 T21 自己的提交前实测复核:line-limits --full 0(121/121) · docs-check 0(281/181) · registry 0(311/311/0) ⇒ 逐字一致。
  • 第 ④ 闸 bundle-eager-graph 0(111 文件 / 7 包) · 第 ⑥ 闸 tsc --noEmit 0 · 第 ⑦ 闸 vitest 冷 1 / 热 1 / 第 3 次 0(229 文件 / 2225 用例,红集 = W1)· 第 ⑧ 闸 cargo 0(2360 / 2354 / 0 / 6) —— 引自 §C59.2 / task-22-report.md,T21 未独立复跑(需真构建与全量跑)。
  • 漂移红集(§C59.7):JS 5 成员(SessionDetailPanel W1/W2 · NoteReadingColumn.views F2 · SessionViewHost H4b · registryResolution A1 · KnowledgeGraphView)+ Rust ffmpeg::…large_output(10 s 墙钟签名);🔴 只有 W1 三件齐(冷红 / 热红 / 第 3 次绿;红时该用例 1146 ms ≳ 1 s 上限、绿时 401–415 ms)⇒ 判负载敏感红;其余 5 个一律「未判定」;成员会漂移。⇒ 本节「诚实代价」里的红点集合段据此不变。
  • ✅ 90bb5f6a(T19 的 U2 提交)补评:通过(§C59.8):「生效档 ≠ 本地映射档」构造成功(talking-head → 本地 low vs 后端记忆 rich):CONTROL 8/8 绿 ⇒ 自造变异体 7/8 / exit 1 / 红在具名断言;DOM 逐字节复核 = 两处且仅两处声明差异成立 ⇒ T18–T23 无第三次漂移。

规格漂移纠正(逐处,原文保留 + 就地加注)

漂移 落点
§10 批 7 行:structuredBlocks 的「接线或删除二选一」由控制方按逐导出裁决(第三条路)执行 ⇒ 明文授权入规格 + 「12 条补 UI 实做 10 条」+ registry 净值 311 + 撤下 3 条的形态 规格 §10 批 7 行后整块加注
§11-7:registry 313 → 311 · 前端零引用 24 → 11(口径 + 仪器 + 正控 68 / 负控 0)· 差价分解 −10 / −3 · 新命令不计入 · 残留 update_fragment_group 规格 §11-7 批 1 进度注后加注
§12「3 套 markdown 渲染器归一」的去向终态:已完成归一(markdownLine + ChatMessageMarkdown 并入)· 终态 2 套活 · 🔴 逐字「归一 = 逻辑归一;观感统一未做,归批 8」· 🔴 补登规格加注漏点(第 4 套活渲染器 NotePreviewView.tsx:40 renderMarkdown) 规格 §12 批 5 加注后加注
§9 表内三处状态更正:#14 kb_search(批 3 已交付)· #30 video_profile_spec_by_kind(角色变更登记)· #46 update_fragment_group(记录同步批 1 已做;T21 实测「接线」那一半未做) 规格 §9 表末(#47 行之后;块引用会截断表格 ⇒ 只能整表之后就地在注,注文逐条点名行号)
§9「删除的通用影响面:仅 lib.rs 的 generate_handler!」:注册清单已搬到 app/src-tauri/src/app_commands.rs(批 0-C3),lib.rs 已无 generate_handler! 规格 §9 该句后就地更正
贴边件清单(本批 10 条,见「诚实代价」)· 门禁盲区(末尾换行 / countLines 不可见)· pr-check.yml 的 paths-filter 缺口 + 懒侧守卫的执行者缺口 · 豁免表的「连带落库」机制记录 line-limit-exemptions.md + performance.md(各自就地加注)
规格 §4.3 的「审校模式」定义 + §7.4「带证据三轨」规格章 规格 §4.3 / §7.4(T20 的 fb73e313)

🔻 上表三条的收口更正(2026-09-13 · T21 追加轮;上表原文一字未改):

  • §10 批 7 行:上表写的「实做 10 条」⇒ 🔴 收口为 11 条(口径见本节「交付」段的收口更正:§C9.1 的 10 是计数口径,逐个列名 11 个;T23 补完第 11 个)。规格原文的「12」仍不改(差额 = kb_search,批 3 已交付)。
  • §11-7 行:前端零引用 24 → 11 ⇒ 🔴 收口为 24 → 10(口径不变:§9 那 47 条中仍在 registry 者 22 条里的前端生产零引用数;update_fragment_group 由 T23 接线后离开该集合)⇒ 有引用数 11 → 12;🔴 残留 1 条 → 残留 0 条。
  • §9 #46 行:上表写的「T21 实测「接线」那一半未做」⇒ ✅ 已在批 7 内由 T23 补做并交付(125eec85 + 5f662811 + 5d59e332)。🔴 原读数保留为 T21 首轮的过程记录 —— 它促成了这次补做;处置由「批 8 输入」改为「已交付」(rulings.md §C56.2:这是批 7 的交付缺口,不是有意的延期)。落点形态与判据见规格 §9 表末该行的收口更正。

过程中纠正的计划错误(第 1–12 例,逐条带出处与落位)

口径:这是控制方对计划编制单元的错误计数(与「控制方自己的第 N 例」是两条序列,勿混)。第 7–11 例由 T12 落账(§C46.6),第 1–6 与第 12 例由 T21 落账(本节 + 规格加注)。计划自身的勘误表 = 计划文件 ### 表 6b 的 E-1–E-30。

① 行号锚系统性错误 + 一处不实归属(§C12;计划方第 1 例):### 表 6 的 X2/X3 行号锚错,且 X2 把自己的读数冒充成「与控制方实测一致」(不实归属)。根因 = 编制期仪器 tmp/plan-writer/sites.mjs 的 stripComments 整段删除块注释 ⇒ 打印的是「剥注释后行号」(T2 定位)⇒ 全计划判错锚 24 条(E-1–E-22 行号类 + E-25/E-26)。落位:E1 的全量重推(367559ff 等 4 个提交)· 表 6b E-1–E-30 · 该「不实归属」句已删。② 表 5 的 Y2 行判错(§C13.3;E-24):把 toastMigration.test.tsx:146 判为「不改」,而 durationMs={3500} 在 AiToast 定义体内 ⇒ 搬迁后必红。落位:表 6b E-24 + 计划改为勘误(保留原文 + 写真值)。③ T3 卡依赖不存在的产物(表 6b E-27;计划方第 3 例):卡要求「lowConfidenceClass 用例已由 T2 搬到 utils/lowConfidence.test.ts」,而 T2 卡没有该文件、T2 也(正确地)没建它 ⇒ 控制方授权 T3 自建。④ 把「改文件」与「补豁免表行数」拆给不同单元(§C14.1;E-28;计划方第 4 例):line-limits --full 的 (e) 是逐文件判据、husky 扫工作树 ⇒ 每个中间提交都必然撞钩子(T2 与 T8 各自独立撞上)⇒ 裁决:行数列改由「改文件的单元」同批更新 + --no-verify 条件式授权。⑤ T4 卡预测 3 条 allow(dead_code)(§C15.1;E-29;计划方第 5 例):实测 4 条(第 4 条是传递受害的私有 helper normalize_source)⇒ 只加 3 处会留 1 条新告警 ⇒ clippy 集合差异非空。⑥ 计划的提交纪律与 §C18.2 矛盾(progress.md:124;E-30;计划方第 6 例):原 :188 强制 git commit --only -- <paths>(正是 fa45caf1 连带落库事故的机理),且把 --no-verify 列进「禁止」清单、与同段的 §C14 条件式授权自相矛盾 ⇒ E1 返工 4292dee2。⑦ T6 的台账实为四处,卡里只点名三处(§C22.5;计划方第 7 例)⇒ 已令 T6 逐张棘轮表搬家。⑧ T13 新件预算写 ≤170、实测 273(§C33.4 I-1;计划方第 8 例)⇒ 低估 103。⑨ 计划 V2 的 <Surface data-foo="1"/> 在 TS 下不报错(§C35.4;计划方第 9 例):带连字符的属性被豁免 ⇒ 该变异体无牙,改用 bar / onClick(R-8 独立复现)。⑩ 表 5 的 Y8 前提不成立(§C38.3;计划方第 10 例):假定 utils/html.test.ts 的 5 条 renderTimestampAnchors 用例「必须改写」,T15 逐条实跑证明一条都不红 ⇒ 实际处置是纯加宽(比机械改写更好)。⑪ 计划给的「预授权文本」本身编译不过(§C39.3;计划方第 11 例):**393**/114 里的 **/ 含 */ ⇒ 在 TS 块注释里提前闭合注释(25:72: Expected ";" but found ";";T10 实际被 vitest 挡下一次)⇒ 立为陷阱 P22/P23。⑫ H7 的指针错(§C54.3;计划方第 12 例):计划把 H7 指向 docs/tech-debt/…,而该文件里 H7 字面 0 命中(对照非 0);原文在 docs/Foresight/ux-market-convention-audit.md:109 ⇒ T20 只做属于 get_decision 详情面的那一片,其余 5 项逐字登记批 8;未触发 STOP(按「锚不符」条款处置)。出处:rulings.md §C12 / §C13.3 / §C35.4 / §C15.1 / progress.md:124 / §C22.5 / §C33.4 / §C38.3 / §C39.3 / §C54.3。

🔻 补登计划方第 13 例(2026-09-13 · T21 追加轮;上段的第 1–12 例原文一字未改) —— ⑬ 计划写的 IPC 载荷键名与 Rust 真身不符(§C56.3;计划方第 13 例):计划 :2299 与 :532 写的是 invoke("update_fragment_group", { **id**, groupId }),而 Rust 真身(app/src-tauri/src/commands_fragments.rs:141-145)是 update_fragment_group(state, **fragment_id**: i64, **group_id**: Option<i64>) ⇒ Tauri 2 是 camelCase ⇒ 🔴 JS 侧必须是 { fragmentId, groupId }。先例:app/src/components/FeedFragmentList.tsx 里既有的 delete_fragment 调用(同族形态)。⇒ 实际落库形态:FragmentGroupAction.tsx:92 逐字 invoke("update_fragment_group", { fragmentId, groupId: target })(T21 追加轮实测)。

  • 🔴 教训(§C56.3 逐字):计划里凡出现 IPC 载荷的键名,都必须在计划期用「既有同族调用点」对拍一次 —— 本批第 11 例(**393**/114 编译不过)与第 13 例同属「计划文本自身没被编译 / 执行过」这一类。
  • ⇒ 口径更新:本段标题的「第 1–12 例」按本注读作 13 例(规格 §11-7 与本节其余处若仍写「12」,按本加注读)。

🔻 另登记一条「控制方序列」的教训(勿混入上段的计划方序列) —— 控制方派单缺陷(§C57.2;控制方引述/派单类错误在本批的第 14 例):

  • 事实:控制方的派单措辞要求「复用同文件既有形态」,把 FeedFragmentList.tsx:109 的同文件注释(「目标=笔记容器组(feed 地形是碎片容器——不是笔记去向)」)当作先例,指定候选组取 containerGroups(container 地形)。🔴 那句是 promote_fragment_to_note(升为笔记)的去向语义,与 update_fragment_group(碎片归组)不是同一件事。
  • 由 T23 质疑并成立(它按派发书实现后自己提出:「capture_fragment 真实自动归入的是 feed 主题组(resolve_feed_topic_group)⇒ 是否改判 feed?」)⇒ 控制方取证后改判(Rust 侧决定性证据:commands_groups.rs:36 的 terrain 文档注释 + :44 的 container/feed 白名单 ⇒ feed 是一等公民地形;commands_fragments.rs:344-366 的 resolve_feed_topic_group 显式写 terrain: "feed")⇒ T23 以 5d59e332 返工。
  • 🔴 纪律(§C57.2 逐字):「复用同文件既有形态」这个派单措辞,必须附带「该形态服务于哪个流程」的说明 —— 同一文件里的两个流程可以有不同的语义前提;不附说明的「照它做」会把一个正确先例误用成错误先例。
  • ⚠️ 「§C57.2 属控制方序列、不属计划方序列」这一点必须写明(上段的①②…⑬是计划编制单元的错误计数;本条是控制方派单的错误)⇒ 引用时不得把它写成「计划方第 14 例」。

诚实代价(不许省略)

  • 🔴 真机 / WebView2 冒烟由用户裁决跳过(§C6.4)⇒ 像素 / 观感 / 手感类一律未测(归批 8)。不得出现「已真机确认」类表述。

  • 🔴 [[ts:ms]] 的残余以实测为准:串渲染链(NotePreviewView / RefineWorkbench)与 React 链(noteMarkdownComponents.tsx)两侧芯片均已可点(T17 落 data-ts-ms + 容器侧委托)⇒ §C10.2 期望的「RefineWorkbench 侧不再算残余」成立;🔴 但两处页内 seek 未接(AiRefineCard / NoteAiDialog)—— 那是另一条线(工作台/对话框内部跳转),无任何批次登记 ⇒ §C49.3 判为范围蔓延,登记批 8。不得声称「[[ts:ms]] 全链已通」。

  • 🔴 structuredBlocks 裁决的形态代价:删除三个死导出必然改 SessionRawView.test.tsx / env.test.ts 的既有断言 —— 授权出处 = §C4.3 的追认 + §C10.1 的预授权(清单外),每条都给了逐字 before/after 与「是删除导致的必需改动」的论证;未顺手放宽。用例净 −7 = 8 删 − 1 迁(非 LOST)。

  • 🔴 归一的代价(§C11.1 逐字):归一 = 逻辑归一;观感统一未做,归批 8。 两条链的可见输出零变化(两模式逐字保留原样式;91/91 行级夹具 + 14/14 夹具逐字节对拍)—— 换来的代价是两套模式常量长期并存,不是「观感已统一」。

  • 🔴 D 的六条展示面是「设计决定」而非裁决(§C54.6 逐字):T20 补齐的 analyze_session_command / delete_session_images_all / finish_session / get_decision / refine_session / update_knowledge_system 六条命令的展示面形态(面板位置 / 布局 / 文案 / 交互)全部是实施者定的,规格只给了「重新分析」「批量删」「结束会话」这类意图 ⇒ T21/T22 不得把它写成"按规格实现";充分性由控制方判。

  • 🔴 get_decision 的审计 H7 = 只做了详情面那一片(§C11.7 / §C54.3):授权只读 docs/tech-debt/review-2026-09-11.md 取 H7 原文(只读,不是处置 —— 该文件是用户所有,§C7.3 的「不处置」不变);在那里 H7 字面 0 命中 ⇒ 真原文在 docs/Foresight/ux-market-convention-audit.md:109;T20 只做属于 get_decision 详情面的那一项(「日志只读 ellipsis 无展开」),其余 5 项逐字登记为批 8 输入(只写「H7」+ 必要片段,未整段搬运审计原文入库)。

  • 🔴 C7「重启后卡录制」的覆盖面(§C54.5⑤):本批未覆盖该命令的完整触发面 —— 其触发口径有偏离(该命令无心跳字段)⇒ 登记批 8,不得读成「C7 已完整接线」。

  • 🔴 音频两条 = 待产品裁决(§C7.3,v0.22:689 逐字「产品裁决」):AudioStoragePanel 的死 UI(AudioStoreConfig 构造点全仓 10 处、无 JSON/env 通道 ⇒ status.enabled 恒 true)· 删会话不删音频(commands_session.rs 与 commands_session_delete.rs 零 audio 引用)⇒ 不在批 7 实施,登记为「待产品裁决」,不留成无主事项。

  • 🔴 docs/tech-debt/ 的归因(§C7.3 逐字):docs/tech-debt/(唯一成员 review-2026-09-11.md,191,980 B)是用户所有的决定(git status --porcelain = ?? docs/tech-debt/;git check-ignore -v exit 1 = 未被忽略)⇒ 批 7 不处置它、也不因此不开工;归档 / 删除 / 留着三条都改变用户的资料形态,不是控制方可以单方面处置的。⚠️ docs-check 的 1 个差 = 它:工作树 281/181 ↔ 提交树/导出树 280/180(差额必须逐字归因到本文件,不得当成本批的缺陷)。本节不得声称「本文档由本批创建」。

  • 🔴 懒侧门禁的余量很薄(§C47.3 逐字,必须进 T22):重冻后总量上限 == 实测值,只靠 +64 B 容差(本机两次独立真构建实测 0 B 漂移)⇒ 不得读成「还有 1.9 kB 空间」;且 🔴 本重冻是 §C46.4 明文授权的收口动作,不是守卫放宽(证据 = vendor-* 五族逐族零增长:canvas 58,784 · editor 208,585 · gsap 41,161 · katex 79,915 · md 50,622,逐字节不变)。

  • 🔴 本批 10 个贴边件(余量 ≤5)—— 任何后续编辑必须先拆件(T21 于落库时逐条 countLines() 实测,10/10 与台账一致;§C26.5 + §C46.5② + §C49.5① + §C54.5①):

    文件 行数 / 上限 余量
    app/src/ui/primitives/dialogMigration.e.test.ts 300 / 300 0
    scripts/check-bundle-budget.mjs 300 / 300 0
    app/src/hooks/useLiveCaptureControl.tsx 300 / 300 0
    app/src/components/notes/NotesReadingColumn.tsx 300 / 300 0
    app/src/views/session/SessionTriTrackView.tsx 300 / 300 0
    app/src/components/KnowledgeDetailPanel.tsx 300 / 300 0
    app/src/ui/primitives/textBaseline.ts 299 / 300 1
    app/src/ui/primitives/style-seams.test.ts 299 / 300 1
    app/src/ui/primitives/style-contract.test.ts 298 / 300 2
    app/src/ui/primitives/emptyStateRatchet.test.ts 296 / 300 4

    🔴 并且:app/src/views/note/NotesReadingColumn.tsx 不是真实路径 —— 实测路径 = app/src/components/notes/NotesReadingColumn.tsx(views/note/ 下无该文件)。rulings.md §C49.5① 与派发语均写错路径 ⇒ T21 于落库时就地更正,后续引用一律用 components/notes/。 🔴 「恰 300(余 0)」的 6 个文件里,dialogMigration.e.test.ts 与 check-bundle-budget.mjs 是本批之前/本批新建的判据件:加一行就红,且 dialogMigration.e.test.ts 的 CROSS_LINE_34 判据改不动(§C48.5② 的「潜在陷阱」)。 🔴 范围声明(2026-09-13 · T21 追加轮;§C55.3 的裁决)—— 上面那张表是「本批触碰过的件」,不是全树:它的取值范围 = 本批(T6/T7/T9/T16/T17/T18/T19/T20/T23)实际改过、且在改动当时余量 ≤5 的件 ∪ 两个判据件。🔴 它一律不得作为判据输入。

    • 🔴 全树机器扫描(唯一来源;口径 countLines(),域 app/src/**/*.{ts,tsx}):T21 于追加轮重跑(T23 的三条提交已改动行数,故不抄上游读数)⇒ 共 579 个文件 · ≥300 = 35 条 · 295–299 = 21 条 · 合计 56 条。 ⚠️ 对拍上游(§C55.3 的 578 文件 / ≥300 = 35 / 295–299 = 20 / 合计 55):差 1 个文件 + 1 条 295–299,逐条归因 = T23 的两处改动 —— ① 新件 app/src/components/FragmentGroupAction.tsx(155 行)⇒ 文件数 578 → 579;② app/src/components/FeedFragmentList.test.tsx 由 297 长到 299(T23 的 125eec85 + 再返工 5d59e332)⇒ 295–299 档 20 → 21。≥300 档不变(35)。
    • 🔴 逐字纪律(§C55.3):「手列清单一律不得作为判据输入;以全树脚本扫描为唯一来源」。上游那份手列清单已两次失真(前几轮转述为「10 条」),它漏掉的 45 条里有两个恰 300/300(余 0):app/src/components/notes/NotesReadingColumn.views.test.tsx = 300(同时是漂移红集成员 F2)· app/src/components/KnowledgeDetailPanel.tsx = 300;另有 T20 本批新建的 app/src/components/session-detail/useRevealChoreography.test.tsx = 298。⇒ 🔴 T22 必须给完整两张表(≥300 / 295–299,逐条 路径 + 实测行数 + 是否本批新增或被改过),并逐字写「任何后续编辑必须先拆件」。
    • 🔴 同一口径已同步进 line-limit-exemptions.md(行数治理的真源表)⇒ 本条与那张表必须并读。
    • 🔻 更正(2026-09-13 · T21 追加轮二次;上两行的「有两个」是控制方引述错误**,经 T21 实测异议 + 控制方独立复跑确认 ⇒ 本行更正,上两行原文保留)**: · 🔴 「有两个恰 300/300」→「有一个恰 300/300」。逐字证据:本节「诚实代价」段那份 10 条手列清单 已含 6 条恰 300 中的 5 条 —— 含上一行点名的 KnowledgeDetailPanel.tsx(它在该表第 6 行逐字 = | \app/src/components/KnowledgeDetailPanel.tsx` | 300 / 300 | 0 |)⇒ 🔴 **唯一漏项 = app/src/components/notes/NotesReadingColumn.views.test.tsx**(**同时是漂移红集成员 F2**)。**恰 300 的完整 6 条**见 line-limit-exemptions.md 文末的逐条名单。 · 🔴 **归到「控制方序列」(不得写成计划方错误)**:该句出自 **§C55.3(控制方实测纠错第 13 例)的细节**;T21 于追加轮**实测异议**、控制方**独立复跑确认**并更正 ⇒ 属引述/派单类错误在本批的**控制方序列**。🔴 **并且必须留痕一条事实**:**该错文已由 T21 首轮的落账逐字抄进入库文档**(即本块上面那一行)—— 「**控制方引述错误在入库文档里被传染**」这件事本身登记在案;**line-limit-exemptions.md文末那一处未受传染**(T21 首轮已按实测写成「真正漏掉的域内 300/300 是 **1 条**」)⇒ **入库文档里被传染处 = 唯一这一处,本行即其更正**。 · **「数字带时点」的历史链(两个数都留、各带时点,不得只留一个)**:**上游 §C55.3 时点 = 578 文件 / ≥300 = 35 / 295–299 = 20 / 合计 55** → **T21 追加轮实测(当前树)= 579 / 35 / 21 / 56 · 恰 300 = 6 条**;**差 1 文件 + 1 条**的归因**保留在上一行**(新件FragmentGroupAction.tsx 155 行 ⇒ 文件 +1;FeedFragmentList.test.tsx 297 → 299 ⇒ 该档 +1;🔴 **≥300 档不变 = 35**)。 · 🔴 **张力裁决落账(K,常设)**:本批**文档回写的唯一合法形态 = 「原文 + 就地加注」** ⇒ 派单里凡出现「**删掉 / 移除 / 改成**」这类**字面删改**措辞,**一律按「加注作废 / 加注更正」执行**,并在报告里指出该措辞与 **V2(− 列必须为 0)**的冲突;🔴 **不要为迁就措辞去破 V2**。控制方已自陈该要求**自相矛盾**并登记为**控制方错误**(其派单原文自称「第 16 例」);🔴 **T21 按加注执行的处置被登记为正例**。该通则已写进 [docs/standards/documentation.md`](../standards/documentation.md)(第四部分之后新增小节)。
  • 🔴 负载敏感红的「集合」是一组会漂移的成员,不是固定名单(§C43.3 / §C48.4 / §C50.4 / §C51.5;T22 的诚实边界不得简化成「只有 W1/A4」): JS 侧 SessionDetailPanel(W1 / W2)· components/notes/NotesReadingColumn.views(F2)· SessionViewHost(H4b)· views/registryResolution.test.ts(A1)· 以及 T15 冷跑见过的 KnowledgeGraphView; Rust 侧 ffmpeg::tests::run_captured_handles_large_output(签名 = 10 s 墙钟超时 + Io("cmd.exe 执行超时(10s)已终止"),裸跑 1.9–42.7 s)。 🔴 成员会随运行漂移(同一棵树上红点成员会换);未取得「≥3 次重复 + 与某可观测量相关 + 该文件不在写集内」三条者,一律登记为「未判定」,不得称为 flake。

  • 🔴 node_modules 环境级事故(§C23.5 逐字要求进 T22):本批发生过一次 app/node_modules 被清空事故(fs.rmSync 穿透导出树里的 junction)——是环境级事故、不是代码缺陷 ⇒ 不计入任何实施单元;已 npm ci 恢复(316 包)并复验 tsc 与 vitest;期间若干单元的复跑被阻断,其读数按「环境阻断」或恢复后重跑登记。

  • 🔴 fa45caf1 / f7ac5d0f 两棵树在 line-limits --full 的 (e) 判据上不自洽(§C16.2):机理 = git commit --only -- <paths> 只按路径取工作树内容、不看暂存区 ⇒ 跨单元连带落库;最终树自洽。🔴 不得声称「7a 段每个中间提交都过 (e) 判据」。

  • 🔴 两处代价数字:① 首屏 gzip 103.60 → 104.12 kB(T12 逐块归因到逐字节闭合:T6 拆件的模块边界成本 +557 原始字节 + 级联 −2 ⇒ Σ = +555 = chunk 原始差;残差 26 B 如实写「未能逐块归因」);② katex 字节账用一次真实构建结清:vendor-katex-* 1 chunk / 266,732 原始 / 79,915 gzip、marker 1/3/7,对拍批 6 的 2/6/14 + 494,590 B ⇒ −227,858 原始 / −64,497 gzip,全 39 chunk 扫描 0.18.4 = 0 / 0.16.47 = 1 ⇒ 顶层那份已从产物消失(manualChunks.ts:56 的解释成立)。「删 structuredBlocks 确实省掉整整一份 katex 副本」= 实测事实。

  • 行数 / 结构代价:App.tsx 549(599 → 537 → 549,余 51)· NotePreviewView.tsx 364(开工 346)· RefineWorkbench.tsx 497 · SessionsPage.tsx 355 · SessionDetailPanel.tsx 222 · LiveActivityPanel.tsx 513 → 242 · NoteMarkdown.tsx 104 → 203 · noteMarkdownComponents.tsx 277 · NotesReadingColumn.tsx 294 → 300 · 新件 PageSlot.tsx 31 / aiToast.tsx 41 / focusRouting.ts 32 / lowConfidence.ts 32 / markdownLine.ts 100 / noteMarkdownComponents.tsx 273 / TranscriptRow.tsx 201 / NoteCardFlowWithSeek.tsx 46 / NoteTagsEditor.tsx 165 / 六条展示面 68–115。豁免表 121 条(T6 整行移除 1 条、T19 4 行数值 + 散文 311)。

  • 流程代价:本批共发生 4 次「往被跟踪目录写临时产物」(P21,每次都有实际损害 —— 其中一次直接挡住了 T13 的带钩提交)· 1 次「连带回退」事故(bed72919 用陈旧私有索引整段回退 T18 的 5 个文件,已用带旧值守卫的 update-ref 原子重写为 81d62964)· 1 次「连带落库」事故(T20 的 4e074ed0 带走 T19 未完成的 I1 修复,已授权重写为 3d493429)。三次事故均已逐字披露 + 强制自证 + 核验别人内容俱在,并就地立为纪律(「提交后强制自证」/「提交前看 git status --porcelain 首列」/「历史重写的唯一例外」/「私有索引提交后必须重新对齐真实索引」)。

未做(登记,逐条带归属批次)

  • 🔴 归一 = 逻辑归一;观感统一未做 → 批 8(§C11.1)。
  • 🔴 规格两章的实现:「带证据三轨」实现(含它的两条红线裁决:段级身份 / 新 command)→ 批 8 · 「审校模式」实现(ink-4 保持 0 生产调用点;§4.3 条件 ③ 的前置定义本批已交)→ 批 8。
  • 🔴 R4.1 的「5 个粘滞字段形态」 → 批 8(批 6 登记的 follow-up,本批未承接)。
  • 🔴 两处页内 seek(AiRefineCard / NoteAiDialog)→ 批 8(§C49.3)。
  • 🔴 update_fragment_group(#46) 的「接线」那一半(T21 实测前端命中 0)→ 批 8。

    🔻 收口更正(2026-09-13 · T21 追加轮;上一行原文一字未改)—— 本行从「未做」清单撤回,移入「交付」:update_fragment_group(#46) 已在批 7 内由 T23 补做(125eec85 feat(components): 片段行补上移动到组入口 + 5f662811 + 5d59e332 fix(components): 碎片归组候选改用 feed 地形组;T21 独立复测 PROD 0 → 1,落点 app/src/components/FragmentGroupAction.tsx:92)⇒ 🔴 「→ 批 8」的处置作废(依据 rulings.md §C56.2:规格处置栏逐字「补 UI(本批)」,计划 :532/:2299/:2309 三处指派一致 ⇒ 这是批 7 的交付缺口,不是有意的延期)。

    • 🔴 逐字登记本条的完整来历(供 T22 的二分清单收录):① 计划侧正确且预警过 —— :2304 自陈「数一数是 11 个名字」、:2305 裁决「按名字列全 11 个,不删任何一个」;② 漏做 —— T20 的计数口径「6 + T18/T19 的 4 = 10」恰好吞掉了被删减的那一个名字;③ 发现 —— 由 T21 的仪器在收口回写时发现(前端 app/src/** 含测试 0 命中,而它仍在 registry);④ 裁决 —— 控制方 §C56.2 判定为批 7 的交付缺口并派 T23 补做;⑤ 补做 —— T23 三条提交(含一次由 T23 自己质疑、控制方取证后改判的 feed 地形返工);⑥ 更正 —— T21 于追加轮更正规格 §9 与本节。⇒ 缺口成因 = 实做方的计数口径,不是计划缺陷。
  • 🔴 C7「重启后卡录制」的完整覆盖面(触发口径偏离:该命令无心跳字段)→ 批 8(§C54.5⑤)。
  • 🔴 get_decision 详情面之外的审计 H7 其余 5 项 → 批 8(§C11.7 / §C54.3)。
  • 🔴 SURFACE_TAG_REGISTRY 对 legacy 文件没有「新增 <Surface> 调用点」的合法路径(机制缺陷,不是本批失误)→ 批 8 修(§C35.2):legacy 行的 count 只许降、file 键唯一、legacy 和锁又禁止腾挪 ⇒ 任何 legacy 文件内的容器都无法再迁入 <Surface>。本批的处置 = 接受 19/21,余 2 处(LiveImageStrip:109 / VersionPanel:135)按新类别 legacy-registry-frozen 留档、转批 8(不授权抬高 legacy 面)。
  • 🔴 技术债(逐条带出处;本批一律不改): · pr-check.yml 的 paths-filter 缺口 + 懒侧守卫的执行者缺口(§C14.5 / §C25.5②):pr-check.yml 的 paths-filter 根本没有 scripts/** glob(T8 实测缺 scripts/lib/**,T11 实测缺口形态未变、逃逸文件集合 +1)⇒ 只改 scripts/** 的 PR 不被任何被过滤的 job 看见;且 scripts/check-bundle-budget.mjs(首屏 + 懒侧的唯一守卫)在 pr-check.yml / .husky/pre-commit / scripts/validate-all.mjs 三处都没有执行者 ⇒ 这道门禁的牙只在有人手工跑时才存在。裁决:本批不改 .github/workflows/(AGENTS.md §10 + 发布自动化连带面 + 非本批登记项)⇒ 落账位置 = docs/standards/performance.md 的懒侧门禁节。修复形态 = 补 glob + 给守卫接一个执行者。 · scripts/check-exemption-prose.mjs 登记为「批 8 的候选闸」(§C11.8 ③):T11 新建的散文对拍探针(112 行)必须入库(否则批 8 无法复用)但 不纳入八闸 / CI / husky(理由:八闸的集合是批 8 治理收口的对账基线,本批扩闸会让逐字对账漂移;散文数字天然易漂 ⇒ 硬门禁会频繁假红)。T11 已自跑三条自动面(validate-all.mjs / husky / pr-check.yml)⇒ 三者都不捡它,无需换名或排除。该文件同时进入 paths-filter 缺口名单(§C41.4 U2)。 · @types/katex 是否仍为未使用的 devDependency(§C20.3):待查项 = 「rehype-katex 是否仍需要它」。🔴 本批任何单元都不许动 package.json(依赖与构建配置变更 = 超范围 + 撞 AGENTS.md §10 类边界)⇒ 不在批 7 删 → 批 8。 · Rust 回填 trim() 与前端 parseTags / allTags 不 trim 的不一致(§C48.5①):带空白的标签会有色行但 UI 查不到(现网无影响 —— 唯一写端已 trim)⇒ 潜在不一致,本批不改(改前端解析会动读端语义)→ 批 8 技术债。 · 新件头注含 position:"fixed" 字面量 = 潜在陷阱(§C48.5②):该新件若日后加上 inset:0 ⇒ 会新进 CROSS_LINE_34 ⇒ 而 dialogMigration.e.test.ts 恰 300 行、改不动 ⇒ 直接红且无合法处置路径(现无守卫受影响,dialogMigration.e 15/15 绿)。批 8 注意。 · 「commands_video.rs 末尾换行被吞而 countLines 不变」= 门禁盲区(§C51.7①):末尾换行的增删不改变 countLines() ⇒ 门禁看不见。这是「门禁盲区」的又一例(与 line-limit-exemptions.md 的口径节同源)⇒ 落账位置 = 该表。 · 「subject ≤50」当前没有机器判据(§C42.3 M-1):commitlint 的 header-max-length = 100 ⇒ 钩子对此无牙(T14 的 subject 实测 54 字符未被拦下)。是否收紧属批 8 治理(本批不改 commitlint 配置)。 · 音频两条(AudioStoragePanel 死 UI · 删会话不删音频)→ 产品裁决(§C7.3)。 · docs/tech-debt/ → 用户裁决(§C7.3;本批不处置、不阻塞)。
  • 本批不重跑的五闸(tsc / vitest / bundle-budget / bundle-eager-graph / cargo)→ T22(八闸终态)· 90bb5f6a(T19 的 U2 提交)尚未被独立评审 ⇒ 并入 T22 的全批收口评审(§C51.6)。

提交清单(59 个,681e73c6..f0f2998c;归组依据 = 逐提交 git show --name-only 的改动面 + subject)

归属 提交数 sha(按时间序)
计划勘误与裁决落位(docs(plan),E1) 4 367559ff · c0818e23 · dab62eab · 4292dee2
T1 App.tsx 拆件 + 深链 ms 载体(+真空真修正) 4 fa45caf1 · f7ac5d0f · 58a1cdb6 · d334ebd3
T2 析出 lowConfidenceClass 1 2ed5c836
T3 删 structuredBlocks 死导出(+自建判据件) 1 5cda5bdb
T4 撤下三条低级写原语命令 1 39f74e4f
T5 登记核对(证据型、零提交) 0 (全在 gitignored 报告)
T6 拆 LiveActivityPanel 1 1bce07d1
T7 Surface 受控槽 + 落点迁入 4 9755d475 · 8fc87190 · 6f1311cb · 473f11b9
T8 拆 bundleMeasure 度量模块 1 c29a1b86
T9 懒侧字节门禁(+口径/容差/顶层 pass 三轮) 4 80b1eabc · cd800d63 · e4ceffbf · d138760f
T10 注释/散文清扫(11 位点,6 提交) 6 709b41da · 04fce5f7 · bc41861c · e3cefbc0 · 8af217fa · 950afd5a
T11 豁免表探针入库 1 81d62964
T12 7a 段收口 + 懒侧重冻 2 a38585d8 · 0a503cc8
T13 拆 NoteMarkdown 1 2c3aa607
T14 聊天 markdown 并入 + 站点断言 2 9dcd49bd · cb924c06
T15 两支手写链归一 + 芯片毫秒 2 08862061 · 4fb441af
T16 NotePreviewView 表征测试 1 6509e04c
T17 深链毫秒链 / 三链芯片 / 死芯片 / 页内 seek 8 beca954f · edb6009c · 02c32baa · 42708604 · 47e73dbd · 08717e84 · 4f84831c · 279fb76a
T18 标签线(验收一) 4 58a34009 · 8cd96e25 · 78bf8aec · ac202c9c
T19 档位通道(验收二)+ I1 修复 4 c6a4cb7c · 5d4bd4a7 · 90bb5f6a · 17d33095
T20 最后一块内容(低置信 ≥2 / 逐段显影 / 规格两章 / 补 UI 6 条) 5 3d493429 · 747cd8c6 · 5d54f1ab · fb73e313 · b72d4709
并行单元尾随(T10 的 §C54.5④ 路由闭合) 1 36475641
T21 本节回写(规格面) 1 f0f2998c
合计 59 ——

注:⚠️ T21 的 v0.22 / docs(standards) 两个提交不在上表内(自引用,见本节开头的口径)⇒ 全批终态提交数与最终清单由 T22 出。🔴 「59」只在 T21 的规格提交上成立;此后任何单元落库都会改变它。


批 8 · 治理收口与三条主线(2026-09-13,5852cdc4^..396b5e5c,T21 落库时实测 63 个提交)

提交数口径(本文档既定规矩:一律「含左端点」A^..B):批 8 的开工 HEAD = 711ad639(批 7 已收口并推送)⇒ T21 于 2026-09-13T17:32+08:00 实测 git rev-parse --short 5852cdc4^ = 711ad639、git rev-list --count 711ad639..HEAD = git rev-list --count 5852cdc4^..396b5e5c = 63。 🔴 这不是全批终态:T22(全批收口) 与 T23(独立复核) 的提交、以及本节所在的提交均不计入(自引用)。全批终态读数与最终提交清单由 T22 出。 🔴 读数正本 = .superpowers/sdd/2026-09-13-frontend-redesign-batch8/(台账 controller-rulings.md §0–§40 · user-decisions.md · 各 task-N-report.md),全部 gitignored。本节数字一律标明来源:凡未由 T21 亲测者,逐字写「引自 §xx / Txx 报告,未独立复核」。T21 亲测的每一条都带命令 + 口径 + 时点(时点 = 2026-09-13 17:32–17:41 +08:00;开工 git status --porcelain 为空)。

交付

  • 段 8a · 地基与治理(T1–T5 + E8/E8b,零生产代码):scripts/line-limits.mjs 拆成 CLI + scripts/lib/lineScan.mjs(T1 547ffa1f,模块导出面 7 名逐字不变;countLines 的 re-export 全仓 0 importer = 潜在契约非现存契约)· 🔴 末尾换行判据 (f) 并进 --full(T2 aa93655c,执行者天然存在 —— .husky/pre-commit 与 CI 的无条件 job 都在跑它)+ 10 个源文件末尾换行归一(f1742399;正确判据 = git diff -w --numstat 为空 + countLines() 前后相等 + 逐文件字节证明,不是「− 列为 0」)· 批 7 残留 5 处入库文档更正(T3:c5b5a8ec · 50fde7bf · 4966d9ee · 0c299fc7)· E8 的机器期望系统扫描(ea2d0762 / 02ca571f / 7c1fcc41 / 72b07a91 / 527c11ef:167 条机器期望逐条分流 = 已跑 95 / 当场真跑 69 / 改「待测」3,不得由推理替代)· 8a 段八闸自证(T5,零提交 / 0 生产代码)。
  • 段 8b · 主线一:两条「规格已交、实现未做」的能力(T6–T11) —— 🔴 两条都走零新 IPC / 零 schema / 零 Rust(控制方 §2 A1/A2;get_session_detail 的 segments + ocr_blocks 本来就在既有命令里)。带证据三轨:模型层纯函数(T6 de1f43aa,views/note/noteEvidenceModel.ts 202 + noteEvidenceModel.test.ts 237 + noteEvidence.fixtures.ts 168,T21 实测行数)+ 规格 §7.4 §D 就地加注(T6 433c614a,三轨口径 = 笔记段落轨 + 转写段轨 session_segments.id + OCR 块轨 session_ocr_blocks.id)+ 视图片(T8 8cc627de,views/note/NoteEvidenceTrackView.tsx 178 + .test.tsx 202)+ 注册表第三项(T8 08b1afda:views/registry.ts:141 的 FROZEN_VIEW_KEYS.note 由 2 键变 3 键 ["raw","cardflow","evidence"])+ 容器取数(T10 e493eac8,hooks/useNoteEvidence.ts 157 + components/notes/NotesReadingColumn.evidence.test.tsx 178)。审校模式:模式位通道(T9 f673bef7,shell/proofreadMode.ts 63 + proofreadMode.test.ts 216 + proofreadMode.dom.test.tsx 85)+ 纯 CSS 覆盖(T9 3abe4cfc,新建 ui/proofread.css 12 行;属性名逐字 data-proofread-mode,不得用 data-proofread —— 后者已被 LLM 文本校对占用)+ 入口(T11 0916d126 顶栏按钮;b077d530 回写 ui-ux-system.md / theme.md 的审校模式并加注落点与命名;ffb7e28a 更正入口落地状态)。贴边件拆件三件(T7 521a8487 / 6dfbfa72 / e0335072)。
  • 段 8c · 主线二:观感/像素面「收编,不立项」(T12–T16):批 3 的仪器搬出 gitignored tmp/ 入库并参数化(T12 e430ad9b,scripts/viewport-probe.mjs 298 行,一字节未改仪器内核)+ 盲区随仪器登记(T12 c19418e7):验的是 WebView2 引擎不是 IPC/窗口层 · headless 默认 prefers-reduced-motion: reduce(可覆写)· headless 滚动条占位 0 · 必须用 Emulation.setDeviceMetricsOverride · --dump-dom 抓不到 · 🔴 profile 必须落 $env:TEMP,绝不许落仓内。读数任务 T13 / T14 / T15 全部零提交、零生产代码;T14 落地三条登记(4041eab5:--dist 假绿 · 18 族逐族上限陈旧度 · shift- 的 212 B 死预算);T16 落地三件(b7c34351 · bbd41795 · cc08c95f)。按需入口(段 8f 的 U4):app/package.json:11 新增 "check:visual": "node ../scripts/viewport-probe.mjs --width 1024 --height 640"(T24 ff181f99)+ 触发条件写死(T24 cb4686d1);🔴 不接 husky、不进 CI(用户未选 U4-b/c)。
  • 段 8d · 主线三:治理余项(T17–T20):CI 挂载(G2)—— 脚本域门禁挂进 pr-check.yml 的无条件 job(T17 01913605;:197 Line limits · :202 Command registry consistency),包体闸移入已构建的前端 job(T17 5b692792;:71 首屏,--no-build,懒侧不判);🔴 不补 scripts/** glob(控制方 G2 逐字)⇒ 该缺口仍在、列为技术债。散文探针转正(G6)—— check-exemption-prose.mjs 只作 CI 单列 step(:211 Exemption table prose check),🔴 不进八闸集合(保持批 7 定的对账基线)。化石处置(G3)—— scripts/validate-all.mjs 删除 + 改路由(T18 81304d52,git rm 形态 +3/−65;T21 实测 Test-Path scripts/validate-all.mjs = False)+ 两条后继更正(T18 110d980d · 0ffb46fd)。登记制(G4)—— SURFACE_TAG_REGISTRY 的键由 file 改成 (file, tier)(T19 0eae531f + 判据分档 aa93ceea + 纯注释更正 58829aec);不变量改前/改后逐字段差异 0(<Surface> 47 · 命中文件 29 · 登记行 29 · Σ 47 · legacy 9 行和 14)。提交信息牙 —— commitlint.config.js:16 装上 'subject-max-length': [2, 'always', 50](T20 2da0b14d)。
  • 段 8f · 用户裁决项落地(T24–T28 + T29):U1 = a 都修 ⇒ audio_store_config.rs 212(新,照同域先例 audio_preproc_config.rs 的「JSON 原子写 + 损坏降级 + env 覆盖」形态)· AudioStoragePanel 的假开关变真通道 · session_audio_config_set +1 条 IPC ⇒ 🔴 本批第一次抬高命令注册表:311 → 312(依据 = §29.6 用户裁决 A,授权恰 1 条;312 = 新基线,后续不得再抬高)· 删会话两级联清音频(T28 b0508d91 + 边界测试 47e2b56e,新件 session_audio_purge.rs 117 + session_audio_purge_tests.rs 248)。U2 = c 删除(仅代码路径):移除 "default" 作为合法凭据槽的读写路径(T25 a054ec73 + 具名红点收紧 ae3bba3e)。U3 = a 归档:docs/tech-debt/ 归档到 docs/archive/2026-09-13/(T26 335a6155 + 路径引用更正 630d2bfa)⇒ 批 7 全程占着 git status 的摩擦源正式关闭。T29(计划外微单元):两处过期自述更正(9d011ade · 9b1e8aa8)。
  • 段 8e · 收口(T21–T23):本节即其第一件;T22 = 全批八闸(含真构建 ⇒ 懒侧这一次必须判)+ 三条验收 + 二分清单 + 收口评审;T23 = 未参与交付者的独立复核。T31 / T32 是收口前的两个补正单元(5018c7ab · 01a381cb · 291b7111 · 396b5e5c)。

验收(三条主线的兑现度 + T21 落库时的八闸读数)

🔴 「三条验收」的口径:批 8 的「三条验收」= 三条主线的验收(计划 ## Global Constraints 二 逐字写死:「本批的「三条验收」= 三条主线的验收……不是规格 §11 的 11 条整册验收 —— 那 11 条逐条登记去向」)。⇒ 规格 §10 批 8 行的「11 条验收全达标」一律按加注读,不得声称「11 条全达标」(规格 §10 / §14 的就地加注见下「规格漂移纠正」段)。

# 主线 判据(计划逐字) T21 落库时的机器读数 兑现度
一 两条「规格已交、实现未做」的能力 「带证据三轨」有实现(模型 + 视图 + 容器取数,E1/E2/E3 三条口径各有机器判据)且「审校模式」有实现(模式位 + 纯 CSS 覆盖 + 三出口) 四个新件的专属判据件全部在盘且入全量:noteEvidenceModel.test.ts · NoteEvidenceTrackView.test.tsx · NotesReadingColumn.evidence.test.tsx · proofreadMode.test.ts + proofreadMode.dom.test.tsx;🔴 注册表第三项:views/registry.ts:141 逐字 note: ["raw", "cardflow", "evidence"](T21 逐行直读);全量 vitest 235 文件 / 2300 passed / 0 failed / 0 pending(T21 亲测,命令 npx vitest run --reporter=json --outputFile=<绝对路径>,cwd = app/,时点 17:34:02+08:00) ✅ 成立
二 观感/像素面收编 「观感仪器已入库且可复跑」,且 14 条观感欠账逐条有读数或具名归属(「有读数」≠「已统一 / 已修好」) 仪器:scripts/viewport-probe.mjs 在盘、298 行(T21 实测 countLines())、app/package.json:11 的 check:visual 入口在盘;仪器自检 9/9 ✅(innerWidth===--width · dpr · 500px 定块 · 文本哨兵 90 · 阳性对照 1 · 阴性对照每次现造随机串 = 0 · emulatedMedia 实测 == --reduced-motion · --probe canary 16px · fonts.status=loaded)引自 task-13-report.md §3.2,T21 未独立复跑仪器;两套独立读法交叉对拍 28 个属性格 ⇒ 不一致 = 0(引自同报告 §3.3)。14 条逐条落位见下「14 条观感欠账的逐条落位」表 ✅ 成立(含「有读数 ≠ 已统一」的限定)
三 治理余项 「四条治理余项各自落地或明确关账(CI 挂载 · validate-all.mjs · SURFACE_TAG_REGISTRY (file,tier) · subject ≤50 · 散文探针转正)」 四条 4/4 落地:① CI 挂载(G2 脚本域两闸 + G6 散文探针单列 step)⇒ pr-check.yml:197 / :202 / :211(T21 逐行直读)② validate-all.mjs ⇒ 已删(Test-Path = False)③ (file, tier) ⇒ 键已改(surfaceResidual.ts 逐字含 键 = \${file} ${tier}`),不变量差异 0 ④ **subject ≤50** ⇒ commitlint.config.js:16` 逐字在盘。⚠️ 括号里是 5 个名字、槽位是 4 个(「CI 挂载」槽内含 G2 + G6 两件)—— 按 5 名对 4 槽读,不构成缺口
另计 段 8f 的四项用户裁决(不并入三条主线,但必须单列兑现度) U1 音频两条 · U2 凭据槽代码路径 · U3 docs/tech-debt/ 归档 · U4 观感按需入口 U1 = a 都修 ✅(配置通道 + 面板真开关 + 会话结束清理同源 + 删会话两条路径级联清音频;注册表 311 → 312 经用户裁决 A 授权)· U2 = c 删除 ✅(只移除代码路径;已存密钥数据保留)· U3 = a 归档 ✅(夹内 README.md 5,839 B · review-2026-09-11.md 191,980 B · tech-debt.md 26,374 B;归档件 sha256 d185caff… / HEAD blob 52ad1d01… 三口径同值 —— 引自 §25.1)· U4 = d 入库 + 按需入口 + 写死触发条件 ✅(且不接 husky / 不进 CI)· U5 = 沿用「跳过」 🔴 ⇒ 7 条真机类继续登记、不假装完成 ✅ 4/4 成立;U5 明示未覆盖

🔴 规格 §11「11 条整册验收」与本批的关系(逐条登记去向,不得合并):§11-1(4 个 >600 行 → 0;>300 行 100% 在豁免表内)⇒ 本批只读:line-limits --full 0 / 121 / 121(T21 亲测)· §11-6 ⇒ 🔴 本批把它从 2 推进到 3(见下就地加注)· §11-7(47 条逐个有结论)⇒ 本批只读(registry 312/312/0 是唯一相关读数)· §11-8 ⇒ 本批零改动(见下就地加注)· §11-11(tsc 0 错 · vitest 全绿 · cargo test 全绿)⇒ T21 亲测三条全绿(见八闸与附闸)· 其余 6 条(§11-2/3/4/5/9/10)本批未触碰、未复跑 ⇒ 不进本批的兑现度声明。

14 条观感欠账的逐条落位(主线二的兑现面;「有读数」≠「已统一 / 已修好」)

# 欠账 批 8 的读数 / 归属 来源
1 两套模式常量并存(「归一 = 逻辑归一;观感统一未做」) 读到读数:用户裁决 D1/D2/D3/D5 = 保持现状 ⇒ 预览 13px / 工作台 12px 并存 §23.1
2 两条链 7 档里 6 档不同、唯 li 相同 复现;🔴 限定:属性级有 5 格实际相同 ⇒ 「6 档不同」是档级结论 task-13-report.md §2.3 / §4
3 markdownLine.ts 含 6 个原始 hex 且在颜色守卫域外 登记 + 具名归属(cc08c95f)· 域外机制证据 = 守卫只覆盖 ui/primitives/*.css §23.2 立案 B · task-13-report.md §6
4 Surface 逐处迁移的可见变化 读到读数(表值):圆角就地 6→8 9 处 · 边框 #e5e7eb → --ed-border 14 处 · 近白底 8 处 · boxShadow 20 处(含 1 处有损)· 遮罩 1 处 · 墨度 2.54:1 → 5.13:1(186 处) task-14-report.md §四③
5 批 7 的七条展示面零观感验收、零同名测试 出图:主轮 17 组 PNG + JSON 一一配对;补轮 tmp/t15/ 57 文件 / 2,645,258 B(PNG/JSON 配对、孤儿 0) §30.1 / §32.7
6 D 组六条展示面「设计决定」而非裁决(充分性未判) 机器不可判 ⇒ 只能出图 + 人判(几何读数逐条在 §30.1) §30.1 · 本段「诚实代价」
7 🔴 掉地项:AiConversationDock 的方向性投影登记给批 5,而批 5 已收口 T16 本批认领 + 明确归属(bbd41795)⇒ 不再掉一次 §24.1
8 Text 字号越界存量(551 / 123) 读到读数:常量 == Σ 表 · 文件数 == 键数 · 锚条目数 == 冻结文件数 —— 三连通全 true task-14-report.md §四③
9 弱化灰存量(63 / 43) 读到读数:同上三连通全 true 同上
10 圆角 26 / 5 / 4 三档不在任何棘轮内 登记 + 具名归属 §24.1 · task-16-report.md
11 暗档 data-theme 实际生效(今天只有定义、无写入方) 登记;🔴 仪器不可达(全入库域 0 处设该属性) §23.2 立案 B
12 真实帧率 / Flip 几何位移 / 切视图卡顿 登记(只登记、不编造弱判据) motion.md 的不可判清单
13 三档「看起来不一样」 登记(同上) 同上
14 真机 1280×800 / 最小尺寸夹取 🔴 U5 沿用「跳过」 ⇒ 只登记、7 条不假装完成 §30.4

🔴 三条验收里凡涉及真机的部分:真机 / WebView2 冒烟由用户裁决跳过(U5) ⇒ 上表 #5 / #6 / #14 的「端到端」全部止于 jsdom / Rust 单测 / headless Edge 层;「有读数」≠「已统一」≠「已真机验证」。

八闸(T21 落库时在工作树上串行实测,逐条给命令 + exit + 读数 + 时点;🔴 不是全批终态,终态由 T22 出)

八闸的集合 = 计划 ### 表 1 的 8 条(line-limits --full · check-command-registry · docs-check · tsc --noEmit · check-bundle-budget · bundle-eager-graph · check-exemption-prose(批 8 T17 起为 CI step,仍不进八闸对账) · git status --porcelain + HEAD)。🔴 check-exemption-prose 是「附闸」,不是八闸成员(G6 逐字)。 公共口径:树 = 工作树(git status --porcelain 为空)· HEAD = 396b5e5c · 分支 dev · 时点 = 2026-09-13T17:32–17:34 +08:00 · 🔴 app/dist mtime = 2026-09-13T15:55:56+08:00`(T24 的真实构建产物;T21 未重建 dist ⇒ 第 ⑤ 闸的懒侧判定本就不成立,见下)。

# 闸 命令 exit 读数(逐字)
① 行数 node scripts/line-limits.mjs --full 0 ✅ line-limits(--full · 数值一致):>600 硬限 0(棘轮内)· 301–600 档 121 · 登记条目 121
② 命令注册 node scripts/check-command-registry.mjs 0 ✅ 命令注册一致:定义 312 / 注册 312 / 重复 0
③ 文档 node scripts/docs-check.mjs 0 docs-check: 扫描 284 个 Markdown 文件(检查 181 个,archive 快照与豁免清单除外) + 五条 ✅ + ✅ docs-check 通过
④ 类型 cd app; npx tsc --noEmit 0 (无输出 = 0 错)
⑤ 包体 node scripts/check-bundle-budget.mjs --no-build 0 首屏 106.23 kB(原始 333,231 B;gzip 106,225 B;余量 93.78 kB)· 懒侧 39 chunk / 639,868 B ⇒ 🔴 懒侧预算 ⏭ 未判
⑥ eager 图 node scripts/bundle-eager-graph.mjs 0 首屏静态可达应用源文件:113 · 首屏拉入的 npm 包:7(@gsap/react · @tauri-apps/api · @tauri-apps/plugin-dialog · gsap · react · react-dom · views)
⑦ 附闸 · 散文探针 node scripts/check-exemption-prose.mjs 0 ✅ 散文「**312 条**」== 门禁「定义 312」(docs/standards/line-limit-exemptions.md:44) · ✅ App.tsx 登记 563 == countLines 563(…:23) · ✅ 散文与真源一致(…批 8 T17 起为 CI 门禁、单列 step,仍不进 husky)
⑧ 卫生 + 时点 git status --porcelain / git rev-parse --short HEAD 0 空 / 396b5e5c(分支 dev)

🔴 第 ⑤ 闸的懒侧为什么是 ⏭ 未判(逐字纪律):--no-build 的读数按脚本自己的口径不可用于懒侧判据(scripts/lazyBudget.json 的 scope 字段逐字:「🔴 必须在新鲜构建产物上判定……本判据的合格调用 = 不带 --no-build」)⇒ 🔴 本节不得写「懒侧已达标」;懒侧的真判定是 T22 的独占窗口那一件事。当前工具只能给出一条旁证:639,868 B 这个数与冻结上限逐字节相等(见下「懒侧基线」段)。 🔴 app/dist 的 mtime 不是时点载体(承 T15 的当场复现,§30.7):内容哈希 f490c2bbdabf0c9ded388c194a187589f1566165f6dbf118535a5563c9f22a(108 文件 / 3,427,748 B)在 17/17 + 补轮 10/10 读数中相同,而 mtime 在会话内变过(07:28:38Z → 07:55:56Z,T24 重建)而字节数不变 ⇒ 上表第 ⑤ 闸读的是一个 mtime 已被改写过的 dist;它的内容哈希与 T15 的 27 份读数同表可比。 🔴 八闸的「全绿」不是全绿:W1 那类负载敏感红是「一次读数」判不了的 —— T21 本节只跑一次冷跑(全量 vitest 0 失败)⇒ 🔴 按 R-FLAKE 三条(≥3 次重复 + 与某可观测量相关 + 该文件不在写集内)判,本节这一次跑不足以判定任何 flake 的状态 ⇒ 不得据本节写「flake 已消失」。

附闸 / 非八闸读数(逐条给出命令与来源)

  • cargo test --test app_lib_tests(T21 亲测,cwd = app/src-tauri,时点 17:34:48+08:00)⇒ 2378 passed; 0 failed; 6 ignored; 0 measured; 0 filtered out; finished in 9.27s,exit 0。逐段可查:T25 之前 2360 → T25 2363 → T27 2371 → T28 2378(引自 §4.1 的控制方台账;T21 只亲测了终值 2378)。
  • 前端全量 vitest(T21 亲测,npx vitest run --reporter=json --outputFile=<绝对路径>,cwd = app/,时点 17:34:02+08:00)⇒ testResults.length = 235 文件 · numTotalTests = 2300 · numPassedTests = 2300 · numFailedTests = 0 · numPendingTests = 0 · success = true · exit 0。🔴 与 T27 时点的 235 文件 / 2299 passed 差 +1 ⇒ 差额归因 = T31 的 291b7111(useViewMemory.test.ts 206 → 230 行,补 evidence 键的记忆持久化覆盖,V2 用例 13 → 14) —— 两个读数都留、各带时点(引自 §35.3 / §39.1;T21 只亲测了 HEAD 时点的 2300)。🔴 仪器口径:numTotalTestFiles 字段不存在(批 5 起即如此)⇒ 文件数一律读 testResults.length。
  • cargo clippy -- -D warnings(= CI 的原样命令,pr-check.yml:136-144)(T21 亲测,cwd = app/src-tauri,时点 17:35:10+08:00)⇒ 🔴 exit 101 · error: could not compile entropydecrease (lib) due to 15 previous errors · warning 侧只有 1 条既有 cargo 警告(lib.rs 同时属于 lib 与 integration-test 两个 target,非 clippy error)。🔴 T21 逐条复算落在 10 个文件(ai_proofread.rs · asr_confusion.rs · asr_pass2.rs ×2 · commands_asr_confusion.rs · commands_proofread.rs ×4 · commands_session_note.rs · commands_web_inbox.rs ×2 · db_completion.rs · db_migrations.rs · db_task_index.rs)⇒ 🔴 台账 §36.4 第 2 条写「散在 9 个文件」与实测不符:真值 = 10 个文件(其 §36.2 表自身也是 10 个文件;差额 1、成因 = 计数口径;台账原文保留)。
  • git ls-files 域(T21 亲测,时点 17:33+08:00)⇒ 1,639(计划期 1,616;T24 时点 1,634 ⇒ T25 +1 · T27 +2 · T28 +2 = 1,639,域计数闭合)。
  • ⚠️ 凡上表未亲测的读数,本节一律标明「引自」:cargo test 的逐段中间值(2360/2363/2371)· clippy 的「批 8 净贡献 = 0 条新诊断 / 集合差 EMPTY」· git ls-files 的逐段增量 · 归因链的中间树读数。🔴 T21 未在 711ad639 树上重跑 clippy(需要在旧树上重建)⇒ 「净贡献 0」是引用口径,不是本单元的自证。

懒侧基线的两个时点(🔴 本节最有价值的一条读数)

时点 冻结值 归属 / 授权
批 7 T12 的 7a 段收口 limit 636,243 · chunk 37 · 族 37 0a503cc8(引自 lazyBudget.json 的 semantics 字段)
批 7 T22 全批收口重冻 limit 637,501 · chunk 37 · 族 38 55f502fa(🔥 这就是「批 7 收口 637,501」的由来;🔴 它不是「批 8 的基线」 —— generatedFrom 里那句曾被写成「批 8 的基线」,已按 lazyBudget.json 现文更正)
批 8 第 1 次重冻 = T8(8b 段收口) 族 38 → 40 · 总量 637,501 → 639,314 · chunk 37 → 39 08b1afda(T21 亲测:该提交在 git log -- scripts/lazyBudget.json 内)· 🔴 依据 §C46.4「每收口一次、重冻一次」+ 控制方的逐次授权(§21.1:§C32.3 ② 的「总上限只许降」被逐次授权解除,附六条硬条件,含 vendor-* 五族零增长)
🔴 批 8 第 2 次重冻 = T10(容器片收口) NotesPage- 48,693 → 49,219(+526)· 总量 639,314 → 639,868(+554)· chunk 39 → 39(不变) 73348055(T21 亲测在 git log -- scripts/lazyBudget.json 内)· 授权同 §C46.4 逐次授权 · 机制:EVIDENCE_LOAD 是 NoteEvidenceTrackView.tsx 的唯一静态导入点 ⇒ 该视图 + 模型层并入宿主 NotesPage- 族(不合并则 chunk 数 39 → 40 ⇒ 换一条判据红 —— 这是设计取舍,不是随手抬预算)

🔴 现冻结值(T21 于 2026-09-13T17:33+08:00 直读 scripts/lazyBudget.json 逐值复核):族数 = 40 · lazyTotalGzipBytesMax = 639,868 · lazyChunkCountMax = 39 · Σ 逐族 gzipBytesMax = 640,941(比总量高 1,073 B)。vendor-* 五族上限逐字为 vendor-canvas- 58,784 · vendor-editor- 208,585 · vendor-gsap- 41,161 · vendor-katex- 79,915 · vendor-md- 50,622;shift- 族上限 212(chunkCount = 0 的死预算,承批 7 的登记,本批仍未清)。 🔴🔴 结构性发现(必须逐字进下一批的输入清单):重冻后的总量上限 == 实测值 —— 第 ⑤ 闸 --no-build 读到的懒侧合计 639,868 B 与 lazyTotalGzipBytesMax 639,868 逐字节相等 ⇒ 🔴 除 64 B 容差外零余量 ⇒ 任何新增懒侧字节必然判红。⚠️ 但这不是「懒侧已达标」(第 ⑤ 闸仍是 ⏭ 未判 —— --no-build 的读数不可用于该判据),而是「预算余量政策缺失」这一结构性问题:⇒ 🔴 下一批需要一条「预算余量政策」(例如:重冻时保留固定 slack,或把 shift- 的 212 B 死预算回收为共享余量)—— 登记为本批输出的下一批输入 #8。 🔴 逐族上限的陈旧度披露(承批 7 的登记,本批只读):批 7 的重冻后读数显示有 18 个族的实测已超各自上限、合计 +203 B(均在 64 B/族容差内 ⇒ 未判红)⇒ 登记为下一批的逐族重冻输入(总量上限不得抬高)。🔴 本批:T8 / T10 两次重冻只动 2 + 2 个族(恰 2 新增 + 恰 2 重冻 + 0 删除),其余族一字未动;vendor-* 五族逐族零增长(§21.2 / §21.1 的六条硬条件全部满足,STOP 未触发)。

规格漂移纠正(逐处,原文保留 + 就地加注)

漂移 落点
§10 批 8 行的「11 条验收全达标」= §11 的 11 条整册验收,不是批 8 的行内验收 ⇒ 批 8 只兑现与三条主线直接相关的部分;且该行的「新增动效规范章节」已在批 6 落地(docs/standards/motion.md,bffed928) 规格 §10 批 8 行之后整块加注(§10 加注块 A)
§11-6(会话与笔记各 ≥2 种):「带证据三轨」的实现已于批 8 交付 ⇒ 笔记 2 → 3 种;🔴 但「≥2」这条验收本身不因此改口径(2 ≥ 2 早已成立),且真机面仍未覆盖 规格 §11-6 的批 7 加注块之后就地加注(§11 加注块 B)
§11-8(标签能写进去 / 档位选完真生效且跨会话记住):批 8 对该条零改动;批 7 的代理判据结论仍然成立 ⇒ 🔴 不得把它读成「批 8 重新验证过」,也不得把批 8 的 U1 音频两条算进这一条 规格 §11-8 该行之后就地加注(§11 加注块 C)
§14 的文档清单行:docs/versions/v0.21.md(或 v0.20.14)行的实际落点 = docs/versions/v0.22.md,批 8 节已落;docs/standards/ 行的「新增动效规范章节」批 6 已落(批 8 只留 ui-ux-system.md / theme.md 的四层动效 / 三档强度回写,🔴 本批仍未做);ADR-034/035 与 ADR-010 两行的批 8 动作 规格 §14 的批 6 加注块之后就地加注(§14 加注块 D)
🔴 §12 的 :979(旧凭据槽 "default") 规格 §12 表内该行之后就地加注(§12 加注块 E)

🔴 本节删改措辞的处置声明(承 docs/standards/documentation.md:116-125):本单元的一切规格改动只有 + 行、− 列为 0;派单里凡出现「删掉 / 移除 / 改成」这类字面删改措辞,一律按「加注作废 / 加注更正」执行,并在报告里指出该措辞与「− 列为 0」的冲突 —— 不为迁就措辞去破该判据(T21 实测:本任务的派单措辞已按该纪律写成「终态加注」,未出现冲突;对照批 7 的 §C59.5 曾出现过一次)。

过程中纠正的计划错误(E8 序列,逐条带出处与落位)

口径:这是控制方对计划编制单元的错误计数(与「控制方自己的错误序列」是两条序列,勿混)。批 8 的计划勘误编号 = E8-1 … E8-25(承接批 7 的 ### 表 6b E-1–E-30)。E8-1 … E8-16 由 E8 单元与各实施单元落账(计划 ## E8 节 + task-e8-report.md / task-e8b-report.md),E8-17 … E8-25 由控制方在 §20.5 / §26.6 / §29.5 / §29.7 / §31 / §35.5 落账。🔴 共同根因一条:「卡片写下的机器断言从未真跑过」(§10.2 逐字称之为本批最重要的过程发现)。逐条摘录(全文见台账,本节只列根因各异者):

① E8-1 / E8-3 / E8-4 三连(§5 · §10):「期望红点」凭空推断(Task 1 的 M2/M3)· 「期望行号锚」偏 4 行(:236 实为 :232)· 🔴 「期望 diff 形态」在数学上不可达(给末尾无换行的文件补换行,git 必然重写末行 ⇒ 任何正确实现都拿不到 −0)⇒ 判据换成实质判据(git diff -w --numstat 为空 + countLines() 相等 + 空白行 Δ = 0 + 逐文件字节证明)。同源教训 = 批 7 的「锚点由变异体裁定,不由推理裁定」。 ② E8-2(§5):卡片的 re-export 指令不完整(只点名 countLines)⇒ 照做会静默收窄另外 6 个导出名;T1 自行修正为「导出面 7 名逐字不变」,登记为正例。 ③ E8-5 / E8-6 / E8-7(§14.2 / §14.3 · §14.3):卡片事实主张错且 E8 的系统扫描漏了它 · 卡片的变异体格自相矛盾 · 「三件恰 300 的脚本」已过时(T1 拆件后 line-limits.mjs = 204 · lib/lineScan.mjs = 122)⇒ 触发 E8b 针对性补扫。 ④ E8-11 / E8-12(§25 · §31.2):docs-check 的基线读数过期(281/181 → 282/182 → 284/181,最后一步由 T26 归档造成、已逐字登记在 docs/archive/2026-09-13/README.md:32 与 docs/archive/README.md:115)。 ⑤ E8-13 / E8-14 / E8-15 / E8-16 / E8-18(§20.5):Files: 与 Interfaces 自相矛盾 · 保护表写「豁免表 = 无人·全批零改动」而未预见 T11 需要 App.tsx 增长 · 卡面已被 T3 落库 · 写成「本任务追加」而父版本已含 · T24 目标③ × Files: 禁令互斥(处置 = 禁令优先)。 ⑥ E8-17 / E8-19 / E8-20 / E8-21 / E8-22 / E8-23 / E8-24 / E8-25(§22.4 / §28 / §29.5 / §29.7 / §31 / §35.5):Step 3 与卡片自己的 V3 互斥(裁定 = 判据面优先)· 🔴 保护表把豁免表登记为「无人(全批零改动)」且直接卡住 T28 · 🔴🔴 E8-20:T27 卡片的前提错 ——「面板上的开关」根本不存在(由此触发用户裁决 A)· E8-21:「AudioStoreConfig 全仓 10 处构造点」是标识符命中数、不是构造点(真值 = 3 处生产构造点)· E8-22:T22 收口卡的 lazyBudget.json 冻结读数已过期(卡片写 37 / 637,501,真值 40 族 / 639,868 / chunk 39)· E8-23:### 表 1 的两条读数亦已过期(App.tsx 卡片 549、实测 563)· E8-24:T27 卡片的「先例」指错了一个更近的先例(audio_preproc_config.rs)· 🔴 E8-25:卡片口径与门禁冲突(「净增 ≤ +5 可不同步」vs line-limits.mjs:167-172 的 (e) 精确相等)⇒ 口径写死:「凡在豁免表里登记了的文件,其行数的任何变化(含 ±1)都必须在同一次提交里原地同步该行数值」。 ⑦ 🔴 本序列的计数有两处口径必须并读:(a) §31.1 称 E8-22 为「本类错误第 21 处」、§35.5 称 E8-25 为「卡片勘误第 22 处」⇒ 「E8-N」与「卡片勘误第 M 处」是两条编号(后者含非 E8 编号的卡片勘误);(b) E8 序列里没有 E8-7 之外的跳号(台账 §14.3 有 E8-7)⇒ 1–25 连续。

诚实代价(不许省略)

  • 🔴 真机 / WebView2 冒烟由用户裁决跳过(U5) ⇒ 三条验收的「端到端」全部止于 jsdom / Rust 单测 / headless Edge 层;7 条真机类继续登记、不假装完成。不得出现「已真机确认」类表述。
  • 🔴 观感 / 像素面机器不可判 ⇒ 一切「有读数」≠「已统一」(主线二的判据逐字如此)。D 组六条展示面的「设计充分性」是人的决定(T15 只出图 + 几何读数;几何读数 ≠ 充分性判定)。headless Edge ≠ WebView2:仪器验的是 WebView2 引擎的渲染结果,不覆盖 IPC 壳 / 窗口层。
  • 🔴 一切「未判定」不得写成「全绿」:懒侧预算那一闸 = ⏭ 未判(本节八闸跑的是 --no-build)⇒ 不得写「懒侧已达标」。
  • 🔴 观感读数的两个适用边界(必须并读):① 夹具数据 vs 真实数据 —— T15 的受控三臂(natural 元素 203 / M1 空体 19 / fixture 263)证明夹具形状决定可达面,故凡「element count」类读数必须声明臂;② headless Edge vs WebView2 —— 见上。
  • 🔴 T15 / T15b 的两条实测边界(逐字登记,本批不下结论):
    1. finish_session 恢复条的自毁边界 = 测得区间 (5020, 5497] ms(7 点采样,页面内 performance.now(),非 --wait 参数;跨边界元素数 263 → 224)· 🔴 出图是在 1.5 s 内取的 ⇒ 图与「稳态」不是同一个东西(§30.4 U1 逐字要求 T21 记录本条)。
    2. update_knowledge_system 编辑面板横向溢出 16 px(scrollW 178 / clientW 162)· 🔴 三臂 0 px 差 ⇒ 结构性、不是夹具产物(F-long / F-short / F-empty 同为 178/162)· 根因 = KnowledgeSystemEditPanel.tsx:24 的 INPUT 对象缺 boxSizing:"border-box"(content-box 下 width:100% = 内容 162 + padding 12 + border 4 = 178)· 引入者 = 批 7 的 b72d4709(git merge-base --is-ancestor b72d4709 711ad639 成立 ⇒ 批 7 引入的回归,不是历史存量)· 🔴 本批不修(理由逐条见 §32.3:范围冻结 / 它落在零余量的 KnowledgePage- 族 / 判据形态留作下一批模板)。
  • 🔴 漂移红集的成员会漂移,不是固定名单(JS 侧 ≥5 个:SessionDetailPanel(W1 / W2)· components/notes/NotesReadingColumn.views · SessionViewHost · views/registryResolution.test.ts · KnowledgeGraphView;Rust 侧 ffmpeg::tests::run_captured_handles_large_output)—— 🔴 只有 W1 三件齐(冷红 / 热红 / 第 3 次绿);其余一律「未判定」,不得称为 flake。🔴 SessionDetailPanel 的 W1 与批 7 是同一条(§33.5 裁定)。
  • 🔴 [[ts:ms]] 的 RefineWorkbench 侧仍不可点 —— 与批 7 的「两侧芯片均已可点」两句必须并读(T21 用机器证据把两句分开):组件级已接线(RefineWorkbench.tsx:334-337 的 openChip 容器侧委托 + :450 / :469 / :483 三处 onClick;判据件 RefineWorkbench.test.tsx:280-294,断言失败语逐字「工作台侧芯片仍不可点(C10.2「不再算残余」未兑现)」)⇒ 批 7 那句说的是组件能力。🔴 而生产可达性分三种(T21 于 2026-09-13T17:5x+08:00 逐处直读):VersionPanel.tsx:215 转交 onOpenSessionAt(由 components/notes/NotesReadingColumn.parts.tsx:87 供值)⇒ 可点;AiRefineCard.tsx:225 不传 onOpenSessionAt ⇒ 不可点;NoteAiDialog.tsx:200 不传且 sessionId={undefined} ⇒ 不可点(openChip 同时要求 sessionId 与 onOpenSessionAt)⇒ 🔴 派单那句「RefineWorkbench 侧仍不可点」成立,且它说的正是批 7 登记的「两处页内 seek」(AiRefineCard / NoteAiDialog)。🔴 本批零改动这两处 ⇒ 登记为下一批输入。不得声称「[[ts:ms]] 全链已通」,也不得声称「批 7 的加注被推翻」。
  • 🔴 setTimeout(…, 0) 为负载敏感性观察项:T10 在 hooks/useNoteEvidence.ts:88 把「成功 / 失败的唯一出口」推迟到宏任务(setTimeout(…, 0))⇒ 用户可见结果不变(引自 task-10-report.md:187),但 🔴 宏任务延后在并发 / 负载下可能抖(本批已有红点集合漂移史)⇒ 控制方裁定双登记:① 进诚实边界 ② 列为「负载敏感性观察项」,并声称「若后续 NotesPage / NotesReadingColumn 相关件出现漂移红,第一嫌疑 = 它」(引自 task-10-report.md:285)。🔴 它不是缺陷、也不是 flake 判定;本批未做任何稳定性加固。
  • 🔴 本批的「全量绿」从来不是全绿:本批有已知 flake(W1 一族),且并行窗口内的瞬时红是一类现象、不是固定名单。T21 本节的一次冷跑 0 失败不构成任何 flake 的状态判定。
  • 🔴 app/dist 的 mtime 不是时点载体(T15 当场复现:mtime 变而内容哈希不变)⇒ 一切「dist 时点」必须用内容哈希,不得用 mtime。
  • 🔴 CI 的 clippy step 长期为红(独立债务,不在批 8 内):pr-check.yml:136-144 的原样命令 cargo clippy -- -D warnings ⇒ exit 101 · 15 errors,逐条 git blame 全部落在 2026-09-06 前后(1 条 2026-08-20),无一由批 8 引入(引自 §36.2 / §37.2;T21 亲测了 exit 101 与 15 errors,未独立复跑 blame 与两侧集合)。🔴 批 8 的净贡献 = 0 条新诊断(集合差 EMPTY —— 引自 §37.1,T21 未独立复核集合)。🔴 根因:本项目一直用 --all-targets(不带 -D warnings) 取「clippy 基线」,而 CI 用的是 -D warnings ⇒ 同一个门禁两个口径,基线永远「绿」而门禁永远「红」。⇒ 🔴 应报用户并决定是否另排一批。
  • 🔴 两次重冻 = 两次「总上限授权解除」,全部有据(§C46.4 逐次授权 + 六条硬条件)⇒ 🔴 本重冻不是守卫放宽;但 🔴 重冻后总量 == 实测 ⇒ 零余量(见「懒侧基线」段)⇒ 任何后续新增懒侧字节必红。
  • 🔴 一处本单元独立发现的台账偏差(如实登记):§36.4 第 2 条写 15 条 error「散在 9 个文件」⇒ T21 实测 = 10 个文件(§36.2 表自身也是 10 个文件)。差额 1、成因 = 计数口径;台账原文保留,此处即其更正。
  • 🔴 一处引述纪律(承 documentation.md:125):本节的 2378 / 2360 / 2363 / 2371 四个 cargo 读数里,只有 2378 是 T21 亲测,其余三个是引自控制方台账 §4.1;235 文件 / 2299 passed 是引自 T27 报告,T21 亲测的是 HEAD 时点的 235 / 2300。⇒ 引用时必须带时点,不得把两个数当成同一个。

未做(登记,逐条带归属批次)

🔴 口径:本节只收「本批该做而未做」与「下一批的具名输入」两类的并集,逐条带归属批次;不允许有「谁都没认领」的条目(承 §34 的欠账闸门扫描:46 命中逐条分流)。

A · 下一批输入(9 条,逐条带全部要素;出处 = 台账 §34.4)

  1. 🔴 16 px 横向溢出(真实观感缺陷) → 下一批:位点 app/src/components/KnowledgeSystemEditPanel.tsx:24 · 根因 INPUT 缺 boxSizing:"border-box" · 实测 scrollW 178 / clientW 162 / diff 16(三臂 0 px 差)· 引入 b72d4709(批 7)· 判据 = 探针复测 scrollW == clientW · 附带跑一次真构建确认 KnowledgePage- 族与懒侧总量仍在 +64 B 容差内。
  2. 🔴 finish_session 恢复条 5 s 自毁(观感 / 可达性) → 下一批:测得区间 (5020, 5497] ms · 跨边界元素 263 → 224 · 🔴 出图是在 1.5 s 内取的 ⇒ 图与「稳态」不同。
  3. 🔴 get_decision 越出 900 px 折叠线 98 px → 下一批:实测几何 290 × 215,bottom 1005 > 900 ⇒ 🔴 设计充分性机器不可判,留人判。
  4. 🔴 旧凭据数据在应用内永久不可达且不可清理 → 下一批(需新用户裁决):U2 的 (ii) 不做边界(无迁移即销毁不可逆)⇒ 本批只移除代码路径。
  5. 🔴 批 0d 的 browser profile 残留 → 下一批清理:.superpowers/sdd/2026-09-11-frontend-redesign-batch0d-primitives/tmp/{probe-chrome-profile,probe-prof-fix,probe-prof-plain,probe-prof-postfix} = 4 目录 / 695 文件 / 18,360,765 B(18.36 MB 十进制) · 🔴 纪律:收尾清 profile;确需留证的落 .superpowers/** 并登记大小。
  6. 🔴 T21(批 7)的 .md 剥注释口径未复现 → 低优先,留作口径核对(批 8 T3 如实登记「未复现」,评为正确的诚实边界)。
  7. 🔴 D4 / D6 两条单独立案 → 下一批:D4 = 两条链的 markdown 标记前缀泄漏(唯一改「用户读到的字」的一条:预览链把 ### 三级标题 带井号显示、工作台链把 > 引用一行 带大于号显示;不是回归 —— 迁移前就有的行为)· D6 = 6 个写死色值 / 颜色守卫域(没有任何现有 token 的亮档值等于这 6 个 hex;暗档今天不可达;守卫只覆盖 ui/primitives/*.css)。
  8. 🔴 懒侧预算余量政策 → 下一批:重冻后总量 == 实测 ⇒ 零余量 ⇒ 任何新增懒侧字节必红(详见本节「懒侧基线」段的结构性发现)。
  9. 🔴 观感仪器盲区 6 的自动检测 → 下一批:「陈旧 dist」本批做成硬纪律(跑前真构建),不做自动检测;🔴 懒侧守卫的执行者缺口仍未闭合(前置「跨构建环境字节漂移受控实测」至今未做 ⇒ 该技术债从批 7 继承到批 8 后仍为 open)。本批不新增门禁成员(计划 :162 逐字:八闸集合不变)⇒ 建常设探针不在本批范围。

B · 其他未做项(逐条带归属批次)

  • 🔴 §7.4「带证据三轨」的真机 / 像素面验证** → U5 未覆盖(实现已交付、端到端止于 jsdom / Rust 单测)。
  • 🔴 §4.3「审校模式」的实现已交付,但观感一致性未验证(U5)· 且它与 ProofreadPanel 一族的命名消歧只在规格加注与常量里(data-proofread-mode),没有产品文档级的说明。
  • 🔴 两处页内 seek(AiRefineCard / NoteAiDialog)→ 下一批(本批未做;批 7 已登记)。
  • 🔴 docs/product/ui-ux-system.md / theme.md 的四层动效 / 三档强度回写 → 下一批(批 6 登记、批 8 仍未做;批 8 只回写了审校模式那一节)。
  • 🔴 孤儿 sidecar(audio_store::cleanup 只按 .wav 过滤 ⇒ 1.wav.meta.json 永不被清理,:253 的统计同样不计 sidecar)→ 下一批(T28 自己的删除面已两件全清;具名归属 audio_store::cleanup)。
  • 🔴 audio_store.rs:162 的 let _ = std::fs::write(...)(忽略错误,与 AGENTS.md §4「空 catch / 忽略错误」相邻)→ 下一批(已点名、未改、未复制)。
  • 🔴 删除失败上报前端不可见(只到 stderr + 内部结构,不经 IPC)→ 下一批(产品面:要让用户看见需改 IPC 线格式 + 前端类型 ⇒ 另立单元)。
  • 🔴 保留期 / 预算目前无 UI 通道(JSON 可写)→ 下一批(配置通道已真,但只暴露 enabled 一个字段;判据形态已现成 = 照面板开关的三段式:落盘 → 回读 → 死分支复活)。
  • 🔴 删会话不删音频的「另一条链」5 处调用点(commands_photo:83/166/188 · commands_web:120 · commands_web_inbox:358 直呼 db.delete_session)→ 观察项,不扩面(这些类型从不写音频;SessionAudioWriter::create 唯一生产调用点 = live_session.rs)。
  • 🔴 pr-check.yml 的 paths-filter 缺口(根本没有 scripts/** glob)→ 下一批治理(T17 有意不补;控制方 G2 逐字「不补 glob」)。
  • 🔴 line-limits 的扫描域未扩(scripts/**/*.mjs 与 app/vite.config.ts 仍在域外)→ 下一批(扩域 = 独立的门禁政策变更)。
  • 🔴 SURFACE_TAG_REGISTRY 的两处 legacy 残值未迁(LiveImageStrip:109 / VersionPanel:135,登记为 legacy-registry-frozen)→ 下一批(T19 只开路、不迁移;🔴 不授权抬高 legacy 面)。
  • 🔴 @types/katex 是否仍为未使用的 devDependency → 下一批(侦察结论:它在 dependencies 且是 rehype-katex@7.0.1 的硬传递依赖 ⇒ 「未使用的 devDependency」这个前提不成立;本批未动 package.json 的依赖段)。
  • 🔴 Rust 回填 trim() 与前端 parseTags / allTags 不 trim 的不一致 → 下一批技术债(现网无影响 —— 唯一写端已 trim)。
  • 🔴 「subject ≤50」的牙齿口径:本批已装上(commitlint.config.js:16),🔴 但计数是 String.length(UTF-16 单元)⇒ emoji 算 2(对中文成立、对 emoji 偏严);且不追溯历史提交。
  • 🔴 docs/tech-debt/ → 已由用户裁决 U3 归档(不再是未决项);所有权仍属用户。
  • 🔴 U5 的 7 条真机类 → 继续登记、不假装完成。

C · 归 T22 / T23 的条目(收口链自己认领,出处 = 台账 §34.5)

# 条目 落点
1 🔴 D 组 6 条展示面的「设计充分性」把关:这 6 条是本计划新造的设计决定,不是裁决 🔴 T22 的收口评审件必须逐条给出这 6 条的处置(把关 or 逐字写明「机器不可判、留人判」),不得只写「已交付」
2 全量 vitest 的 W1 负载敏感 flake(SessionDetailPanel.test.tsx) 🔴 T22 的冷 + 热两次必须按 R-FLAKE 三条判;缺一 ⇒ 只写「未判定」
3 八闸集合 × CI job 集合的交集与差集 🔴 T22 报告必须列交集与差集,不得只写计数
4 漂移红集成员会漂移(≥5 个,只有 W1 三件齐) 🔴 T21 的 v0.22 批 8 节(本段即其落地)+ T22 报告都要逐字保留这条诚实边界
5 懒侧真预算判据(需真构建) 🔴 归 T22(它的独占窗口 + 真构建那一次)—— 本节第 ⑤ 闸据此写 ⏭ 未判

提交清单(63 个,5852cdc4^..396b5e5c;归组依据 = §段边界 + 逐提交 git show --name-only 的改动面 + subject)

归属 提交数 sha(按时间序)
8a · 地基与治理(计划 + T1–T5 + E8/E8b) 14 5852cdc4 · 7c1fcc41 · 50fde7bf · 547ffa1f · c5b5a8ec · 4966d9ee · 0c299fc7 · f1742399 · aa93655c · 42d53366 · 02ca571f · ea2d0762 · 72b07a91 · 527c11ef
8b · 主线一:两条能力(T6–T11) 14 f673bef7 · 3abe4cfc · 521a8487 · 6dfbfa72 · e0335072 · de1f43aa · 433c614a · b077d530 · 0916d126 · ffb7e28a · 8cc627de · 08b1afda · e493eac8 · 73348055
8c · 主线二:观感收编(T12–T16) 6 e430ad9b · c19418e7 · 4041eab5 · b7c34351 · bbd41795 · cc08c95f
8d · 主线三:治理余项(T17–T20) 9 01913605 · 5b692792 · 2da0b14d · 81304d52 · 0eae531f · aa93ceea · 110d980d · 0ffb46fd · 58829aec
8f · 用户裁决项落地(T24–T28 + T29) 16 335a6155 · 630d2bfa · ff181f99 · cb4686d1 · 9d011ade · 9b1e8aa8 · a054ec73 · ae3bba3e · af47f2e1 · 36128090 · bb080765 · 7df0d480 · 32942fb9 · 5a2170b0 · b0508d91 · 47e2b56e
8e · 收口(T31 · T32;不含 T21/T22/T23) 4 5018c7ab · 01a381cb · 291b7111 · 396b5e5c
合计 63 ——

注:⚠️ T21(本节)与 T22 / T23 的提交不在上表内(自引用,见本节开头的口径)⇒ 全批终态提交数与最终清单由 T22 出。🔴 「63」只在 T21 的落库时点成立;此后任何单元落库都会改变它。 ✅ 归组的机器自证:上表 63 个 sha 两两不重复,且与 git log --reverse --format=%h 711ad639..HEAD 的 63 项逐项相等(T21 于 2026-09-13T17:41+08:00 用脚本对拍;无遗漏、无多余)。 ⚠️ e493eac8 / 73348055 的段归属:两者都属段 8b(T10 的容器片 + 它的重冻),不是段 8c —— 判据 = lazyBudget.json 的 generatedFrom 逐字把第 4 次重冻归给「T10(容器片)」。

🔻 批 8 的真终态与三条入库边界(2026-09-13 加注 · 执行单元 T34;本节正文一字未改)

为什么有这一段:本节正文的读数全部是 T21 落库时点(git status --porcelain 为空 · HEAD 396b5e5c · 2026-09-13T17:32–17:41 +08:00)的值;本节 :966 / :1142 / :1154 逐字把「全批终态读数与最终提交清单由 T22 出」,而 T22 之后的两个回写提交(9ef6a432 · 7af07891)与 T22b 的第 3 次重冻(923657f3)再次改写了终态,其终态却只住在 gitignored 的 .superpowers/sdd/2026-09-13-frontend-redesign-batch8/task-22-report.md / closing-review.md ⇒ 🔴 新鲜克隆的读者从入库面看到的懒侧状态(639,868 / ⏭ 未判 / Σ640,941 / 「零余量」/「63 提交」)与入库真源 scripts/lazyBudget.json(640,072 / Σ641,173 / 66 提交)不一致,且入库面原本没有任何一句说明以哪个为准(独立复核 T23 的 Blocker B-0)。控制方裁定:必须回写(「以 lazyBudget.json 为准」这种口头约定本身也得写进入库面)。 🔴 以哪个为准(本加注唯一的效力条款):凡本节正文与 scripts/lazyBudget.json 冲突者,一律以 scripts/lazyBudget.json 为准 —— 它是机器可读的入库真源,scripts/check-bundle-budget.mjs 直接读它判据;本节正文的旧数字一律保留为「T21 落库时点读数」,不得因其过期而删除(承 docs/standards/documentation.md:121 的「原文 + 就地加注」)。 口径声明:本段是纯追加(git diff --numstat 的删除列 = 0)· 不新增文件 · 一切「取代 / 更正」一律以加注表达。下文凡未标「引自」者 = T34 于 2026-09-13T18:14–18:16 +08:00 亲测(工作树 · 分支 dev · 开工与收工 git status --porcelain 均为空);凡标「引自」者 = T34 未独立复跑。

一 · 批 8 的真终态(本节的「63 提交」与「懒侧 ⏭ 未判」两处按本段读)

# 事实 读数 口径 / 来源
1 批 8 最终提交数 66 git rev-list --count 711ad639..HEAD(T34 亲测 · HEAD = 923657f3 · 分支 dev)· 与本节 :965 的 63(T21 落库时点读数)不矛盾:63 + T21 的两条回写(9ef6a432 · 7af07891)+ T22b 的第 3 次重冻(923657f3)= 66
2 懒侧第 3 次重冻 = 923657f3 lazyTotalGzipBytesMax 639,868 → 640,072 · SettingsPage- 17,760 → 17,992 · Σ逐族 640,941 → 641,173 · lazyChunkCountMax 39 未动 · 族数 40 未动 控制方按 §C32.3 ② / §C46.4 逐次授权(授权来源 = 控制方对 T22 的 STOP S1 的裁定)· T34 直读 scripts/lazyBudget.json 复核:40 族 · 总量 640,072 · chunk 39 · Σ 641,173(Σ 比总量高 1,101 B;上一时点为 1,073 B)
3 🔴 懒侧真判(本批唯一一次 · 真构建)= exit 0 judged = true · pass = true · 总量 640,072 == 上限 640,072 · unlisted = [](0 个)· fails = [] · 超容差族 = 0(逐族红 0) · 首屏 106.22 kB 命令 node scripts/check-bundle-budget.mjs(不带 --no-build · cwd = 仓根)· 读数存档 .superpowers/sdd/2026-09-13-frontend-redesign-batch8/tmp/t22/t22b-v1-refreeze.json / t22b-v1-refreeze.txt / t22b-v1-verdict.md(均为 gitignored;T34 只读该存档、未独立复跑真构建)⇒ 🔴 本条取代本节 :1023 与 :1028 的「懒侧 ⏭ 未判」:⏭ 未判 是 T21 用 --no-build 跑出来的(脚本 scope 字段逐字禁止该调用用于懒侧判据),不是懒侧的真实结论
4 🔴 「零余量」的结构性结论仍然成立 重冻后 总量上限 == 实测值(640,072) 承本节 :1050 的结构性发现 ⇒ 下一批需要一条「预算余量政策」(本节 :1109 的下一批输入 #8 不因本次重冻而消解)—— 🔴 本次是「如实对齐实测」,不是放宽守卫,也不是给出余量(除 64 B 容差外仍零余量)
5 推高者 = 7df0d480(T27 的音频面板真开关 · 用户裁决 A) 受控对照(bb080765 = 7df0d480^ 的导出树 git archive + node_modules junction 真构建)把旧冻结总量逐字节复现为 639,868 ⇒ 🔴 本批确有新增字节,不是跨构建环境 / 工具链漂移 引自 .superpowers/sdd/2026-09-13-frontend-redesign-batch8/tmp/t22/ctl-vs-mine.md(MINE = 7af07891 真构建 ⇒ 640,072 / 17,992;逐族 Δ 之和 +204 == 总量 Δ,自洽)· T34 未复跑该对照构建

二 · SettingsPage- 那半的归属拆分(独立复核 T23 的 Important-1 · 必须与上表第 2 行并读)

🔴 scripts/lazyBudget.json 的 generatedFrom 现文逐字写「① 重冻 1 族 —— SettingsPage- 17,760 → 17,992(+232,== T22 真构建实测值)」;🔴 但该「+232」是「本次实测值 − 旧上限」的差,不是「本次实测值 − 改动前实测值」的差:受控对照实测 CONTROL = 17,767、旧上限 = 17,760 ⇒ 真实新增 = +225(T27 的必然后果),另 7 B 是改动前的既有溢出(bb080765 树上 SettingsPage- 已经 17,767 > 上限 17,760 ⇒ 超 7 B,在 64 B 容差内故当时不红)—— 🔴 那 7 B 不是 T27 的必然后果(引自 tmp/t22/ctl-vs-mine.md:37 与 t22b-v1-verdict.md;T34 未复跑该对照)。 🔴 逐字写明:「🔴 上限 == 本次实测这一条在逐族层含 7 B 的既有溢出;§C32.3 的条件④(『是该次改动的必然后果』)在 SettingsPage- 上只对 +225 成立」。 ⇒ 本重冻的授权依据不受影响(授权针对的是「懒侧真判首次执行即红、须如实对齐实测」这一整体),但 🔴 「+232」不得再被引用为「T27 的增量」:T27 的增量 = +225。

三 · 「本地绿 ≠ CI 绿」边界(独立复核 T23 的 Important-4 · 本批此前完全没有这一句)

🔴 逐字写明:「本批一切『全绿』全部是本地读数;🔴 CI 第一次运行尚未发生。」 事实:本批未 push —— git rev-parse origin/dev = cb4686d1(T34 亲测;它是段 8f 内的一个提交),git rev-list --count origin/dev..HEAD = 19 ⇒ cb4686d1 之后的 19 个提交(含 T21 / T22b 的全部回写与重冻)在 CI 上零运行。🔴 本批反而新增了 CI 挂载(.github/workflows/pr-check.yml::197-198 Line limits · :202-203 Command registry consistency · :211-212 Exemption table prose check,均由 T17 01913605 挂上)⇒ 新增的守卫本身也一次都没在 CI 上跑过。 🔴 已有的四条症状保留(不因本次加注而消解):① clippy 在 CI 恒红(pr-check.yml:136-144 的原样命令 cargo clippy -- -D warnings ⇒ 本机复跑 exit 101 · 15 errors,见本节 :1036 / :1091)② 懒侧在 CI 不判(:71-72 的包体闸是 --no-build · 首屏 only ⇒ CI 里永远打 ⏭ 未判)③ cargo 命令不同(CI 是 :135 的 cargo test -- --skip … 三条 skip,本地门禁口径是 cargo test --test app_lib_tests ⇒ 同一门禁两个口径,与本节 :1091 记的 clippy 那条同族)④ eager 闸无 CI 执行者(scripts/bundle-eager-graph.mjs 在 .github/ 下零命中 —— T34 实测)。

四 · 46 条 open 债务的分流去向(独立复核 T23 的 Important-2)

🔴 事实:本节 :1098 逐字承诺「不允许有『谁都没认领』的条目(承 §34 的欠账闸门扫描:46 命中逐条分流)」,🔴 但分流表只住在 gitignored 的批 8 台账里 ⇒ 本节(:963–:1158,196 行)命中的 TD-ID = 0(T34 实测:本节内 TD-ID 正则命中 0 处)⇒ 对外部读者与漏登等价。 ① 🔴 权威清单 = docs/archive/2026-09-13/tech-debt.md(滚动权威 · 入库;其夹内 README.md 逐字「本清单为当前唯一权威债务清单,归档日滚动更新」)—— 本节的分流若与该清单不一致,以该清单为准。 ② 批 8 的分流判据与逐条处置记在批 8 台账 .superpowers/sdd/2026-09-13-frontend-redesign-batch8/controller-rulings.md(§34)—— 🔴 它是 gitignored 的工作记录(.gitignore:29 的 .superpowers/),不是入库契约:本机读者可复核,新鲜克隆的读者读不到 ⇒ 🔴 该条缺口本身仍是 open(本段只是把它写进入库面,不等于已闭合)。 ③ 真实状态分布(T34 独立解析 docs/archive/2026-09-13/tech-debt.md 的「状态」列;countLines = 91 行 · 表格数据行 = 59):

状态(只取括号前的主状态词) 条数
open(含 open(部分兑现) 1 + open(子项部分兑现) 1) 46
closed(含 closed(部分兑现) 2) 10
carried(含 carried(实测余 2 处) 1) 3
合计 59

同一次解析的交叉核对:类型列 = 无意 27 / 有意 16 / 腐化 13 / 环境变化 2 / 预存 1;优先级列 = P2 24 / P3 18 / P1 13 / P0 4。 ⚠️ 两个「46」不是同一个测量,不得合并:本节 :1098 的 46 = 批 8 §34 欠账闸门扫描的命中数;上表的 46 = 权威清单里状态仍为 open 的数据行数(T34 独立解析)。两者今日同为 46 是巧合,不是同一集合 —— T34 未做两者的逐条对拍 ⇒ 🔴 不得据此声称「分流已闭合」或「欠账已清零」。 ⚠️ 顺带如实登记(T23 的「入库面命中 = 0」在本文档全文范围内需限定):docs/versions/v0.22.md 全文另有 1 处 TD-ID(TD-2026-09-11-H,:68,在批 8 节之外)⇒ 🔴 准确口径是「批 8 节内命中 = 0」,不是「本文档命中 = 0」。T34 未复核 T23 的其余 8 条 Minor。


批 0 其余部分(未落地)

规格 §10 的批 0 还包含:ADR-033~035(当前 docs/adr/ 最高为 ADR-032)· 豁免表纠偏 · 拆 4 个 >600 行文件 · 原语三层。这些不在 0-A / 0-B 范围内,后续子批次另行立计划。

跨批发现 · 本机工具链的读数陷阱与门禁真相(工具级,影响全项目)

陷阱 1 · 行数 —— Get-Content 会少算

本机 harness 的 pwsh 实为 Windows PowerShell 5.1(ANSI 码页 gb2312),Get-Content 会按 GBK 解码 UTF-8 文件并吞掉换行、把行数少算(实测:index.ts 19→12、paths.test.ts 130→112、NoteListView.tsx 654→609;全量 868 文件实测最大少算 56 行:live_session_pause.rs 353→297 —— 足以把越 300 红线的文件读成达标)。

文档域可远超此量级(2026-09-11 批 0-C1 补测):本批台账(.superpowers/sdd/2026-09-11-frontend-redesign-batch0c1-line-limits/progress.md,该目录不进 git)实测 真实 385 行 / Get-Content 报 247 行 —— 少算 138 行(36%),因为少算幅度随中文密度放大;Task 5 复测同一文件(已增至真实 494 行)时 Get-Content 报 356 行,两次差值同为 138 行 ⇒ 该偏差不随文件增长而收敛。⇒ 「禁用 Get-Content 数行」不是只对源码域成立。 ⇒ AGENTS.md §3 的「≤300 / >600」以 [System.IO.File]::ReadAllLines(path, UTF8).Count 为唯一口径(即 node scripts/line-limits.mjs);禁用 Get-Content、Measure-Object -Line(只数非空行)与字节 0x0A 计数(对末尾无换行的文件会少算 1,本仓实测 8 个这样的源文件)。该失真已造成一次真实险情(据此误判 IconName 未导出)。 治理侧(口径未定义、15 个 >600 硬限违规、豁免表数值过期)见 docs/tech-debt/review-2026-09-11.md;工具侧见批 0-B 台账。

⚠️ 上句故意不写成 Markdown 链接:该文件目前未入 git(docs/tech-debt/ 整个目录 0 tracked)。写成链接会让新克隆断链、并让 docs-check 在别人机器上变红 —— 而在本机因文件存在而通过(这类"本地绿、别处红"的掩盖正是本批要消灭的缺陷类)。该文件入库后可改回链接。🔻 2026-09-13 加注(T26 归档后补记):该目录已于批 8 归档到 docs/archive/2026-09-13/ ⇒ 「未入 git」已不成立,链接现可安全写为 review-2026-09-11.md;本行理由在当时成立,原文保留。

陷阱 2 · 退出码 —— 2>&1 | … 会把成功的原生命令报成失败

cargo(及任何往 stderr 写 warning 的原生命令)在 2>&1 | … 或管道下,其 stderr 会被 PowerShell 5.1 包装成 NativeCommandError,使整个管道以非零结束 —— 即使命令本身完全成功。 实测:cargo test 2>&1 | Select-Object -Last 40 报 exit 1,而同一次运行的单元测试是 2337 passed; 0 failed; 6 ignored、cargo test --doc 亦全绿;改用 2>file 重定向后 真实 exit = 0。 ⇒ 判定这类命令的结果必须用 2>file 重定向,或直接读 $LASTEXITCODE,绝不要用 2>&1 | …。 否则会把绿的门禁误报成失败(批 0 收尾时差点如此)。 顺带记两条预存 cargo warning(非批 0 引入):lib.rs 同时属于 lib target app_lib 与 integration-test target app_lib_tests(正是它触发了上述假象);src/db_task_index_tests.rs:6 的 unused import: super::*。

陷阱 3 · cargo test --lib 的测试二进制在本机启动即崩(2026-09-11 发现,非本系列引入)

实测:cargo test --lib 报 error: test failed, to rerun pass --lib,原因是进程尚未进入 main 就以 0xc0000139(STATUS_ENTRYPOINT_NOT_FOUND)退出——即原生 DLL 加载期失败,与 Rust 代码无关。 本机 DLL 现状(三处同名不同版本):C:\Windows\system32\onnxruntime.dll = 1.17(2026-09-09 出现)· ort/onnxruntime-win-x64-gpu_cuda12-1.28.0/lib/onnxruntime.dll = 1.27.1(但其 onnxruntime.lib 来自 1.28.0,import lib 与 DLL 版本不一致)· ort/onnxruntime-win-x64-1.28.0/lib/onnxruntime.dll = 1.28.0。 ⇒ 门禁请用 cargo test --test app_lib_tests:同一源码同一时刻该 target 可正常执行——2026-09-11 实测(空载机器)2357 passed / 0 failed / 6 ignored,exit 0,覆盖全部 #[cfg(test)] 模块(都是 #[path] 挂载到 lib.rs,与 lib target 同一份测试集)。

注意一项装载敏感的偶发失败:ffmpeg::tests::run_captured_handles_large_output 内含 10s 墙钟超时,同时跑 cargo build + vitest 时被拖超时失败,单独重跑 8.55s 通过 ⇒ 判定门禁时须串行执行(或单独复跑该用例再下结论)。 ⇒ 治本方向(未执行,留给依赖治理):把 ort/ 下的 DLL 与其 import lib 对齐到同一版本,并消除 system32 的同名抢占。本次 DeepSeek 修复的验证全程走 --test app_lib_tests,不受该问题影响。

陷阱 4 · 批 4 收口新增的五条仪器陷阱(2026-09-12,收口评审 M-7 + 收口修复单元实测;台账已入册 #36–#38)

  1. 🔴 --outputFile 的相对路径按 UI 根(app/)解析 ⇒ 断言器读不到 JSON 却仍 exit 0:在 app/ 下跑 node node_modules/vitest/vitest.mjs run --reporter=json --outputFile=<相对路径>,vitest 把结果写到 app/<相对路径>,断言器读进程 cwd 的 <相对路径> 时 ENOENT,若只打印不抛错就变成**「无证据的绿」(修复单元两次踩到,靠 harness 的 ENOENT 才暴露;它在 app/ 下误建的 .superpowers/** 已删除)。⇒ 纪律:--outputFile 一律传绝对路径;harness 在「JSON 不可读」时必须非零退出**。
  2. 🔴 本机没有 pwsh:只有 Windows PowerShell 5.1(pwsh -NoProfile -File x.ps1 ⇒ CommandNotFoundException,连 -File 都不可用)。⇒ 长脚本一律写成 .mjs 用 node 跑(比陷阱 1 的「吞换行」更强的一条;与台账 #34/#37 同源)。
  3. 🔴 「改用共享仪器」必须显式验证,否则只是把风险从两份变成一份看不见的:loadingRatchet.test.ts 原来逐字重写了一份 stripComments,含同一个 </x> 坏点,只因它的扫描域里恰好没有「两个闭合标签之间夹加载文案」的形态才没暴露;并入共享实现(sliceScan)时才发现 —— 因此必须同时补夹具(textRatchet ⑥ + loadingScan.isHandwritten 的两条夹具)。残余风险(本单元实测,未修,仅登记):app/src/ui/primitives/nativeButton.ratchet.test.ts:53+ 至今仍带一份私有 stripComments,其 isRegexStart 仍是旧版(白名单含 <、无 </x> 判定收紧),未被 ed07d491 覆盖;本单元实测该差异对 <button 计数今日无影响(两仪器在 HEAD / f6dd012f / 42e88740 三棵树上读数逐字相同:393/115 · 394/114 · 510/121),但属于同一类假阴的活样本,动它的单元须按本条纪律「两跑对拍」。
  4. 🟡 git commit --only -- <paths> 会提交未暂存的改动(与 git add -- 的直觉不同):提交前必须 git status --porcelain 确认工作树里只有要提交的那些文件(记录形态,不是缺陷)。
  5. 🟡 core.autocrlf=true 下新写文件的 LF 警告不影响行数:warning: LF will be replaced by CRLF the next time Git touches it;实测提交 blob 与工作树都是 0 个 CRLF(git show HEAD:<path> 的 \r\n 计数 = 0),行数读数不受影响。

陷阱 5 · 批 7 收口新增的三条提交/仪器陷阱(2026-09-13,T22 实测 + 控制方采信;台账入册 P-31 / P-32 / P-33)

  1. 🔴 P-31:vitest --outputFile 是异步写盘 ⇒ 读到的可能是上一跑的读数:T22 首版因此误读,自查后加 mtime 守卫 ⇒ 🎯 登记为正例(自查 + 修复 + 上报)。🔴 **与既有「陷阱 4 第 1 条」(P17:--outputFile 的相对路径按 app/ 解析 ⇒ 断言器 ENOENT 却仍 exit 0)配套使用:⇒ 纪律 = 读任何 --outputFile 产物前先查 mtime;路径一律绝对;JSON 不可读必须非零退出。两条合起来才封住「无证据的绿」。
  2. 🔴 P-32:PowerShell 5.1 的 Set-Content -Encoding UTF8 会写出 BOM ⇒ commitlint 把它读成 subject may not be empty 并拒绝提交。⇒ 纪律:写提交信息一律用 node fs.writeFileSync(p, s, "utf8")(或 git commit -F 读 node 写出的无 BOM 文件),不要用 Set-Content / Out-File -Encoding UTF8。
  3. 🔴🔴 P-33:update-ref 必须从独立脚本执行、且必须查退出码 —— T22 实测:PowerShell 传参把 update-ref 静默搞失败,而它没有查 $LASTEXITCODE ⇒ 表面成功、ref 未动(最危险的一类:自证看起来通过、提交其实不存在)。⇒ 纪律:一切 ref 移动走 node / 文件脚本,断言退出码,成功后立即 git rev-parse HEAD 回读验证。(与「陷阱 4 第 4 条」git commit --only 的形态同族 —— 都是原生命令的静默失败面。)

陷阱 6 · 「扫描即快照」的推断会系统性误报在飞单元(2026-09-13,批 7 收口;控制方驳回一次 STOP 后登记)

事实:批 7 的一个侦察单元主张「T22 的收口件(task-22-report.md / closing-review.md)不在盘上 ⇒ T22 跑过但报告从未落盘」,并据此提出 STOP。 控制方实测(决定性):扫描当时 tmp/t22/ 已含 lib/ logs/ trees/ 三目录、mtime 2026-09-13T03:53 ⇒ T22 仍在运行;两件随后于 04:04:39 / 04:05:27 落盘 ✅ ⇒ 🔴 不是「从未落盘」,是「尚未落盘」(该判定与其派生项一并作废)。T21 于终态回写时实测两件均在盘(109,327 B / 693 行 与 41,469 B / 323 行)。 🔴 纪律:对「某产物不存在」的判定,必须排除「该产物正在被生成中」这一可能 —— 至少查同名目录 / 同名文件的 mtime,或该单元是否仍在飞。本仓并行度很高,「扫描即快照」的推断会系统性误报在飞单元(本条与「诚实边界」里那句「未判定 ≠ 不存在」同族)。

工具链真相 1 · 本地提交门禁此前从未武装(2026-09-11,批 0-C1 Task 4 发现,已修正)

本克隆此前从未安装 husky —— core.hooksPath 为空、无 .git/hooks/pre-commit、无 node_modules ⇒ .husky/pre-commit(lint-staged)与 .husky/commit-msg(commitlint)在本机对所有提交都是静默失效的:不只是某个批次,而是历史上每一次提交,包括批 0-A / 0-B / 0-C1 的全部交付提交(旁证:控制方在本会话提交 40+ 次,从未见过任何 lint-staged / commitlint 输出)。⇒ 新克隆若未 npm install,门禁默认失效且无任何提示(不报错、不警告,提交照常成功)。 现状:已武装(npm install + npm run prepare)—— node_modules/ 与 .git/config 的 core.hooksPath=.husky/_ 两项环境变更都不进 git;此后提交会真被 pre-commit 与 commitlint 拦(★ 二轮后 pre-commit 跑的是 line-limits --full && docs-check,不再是 lint-staged —— 见下一段)(已取得实测拦截证据:(c) 超过 300 行但未登记:app/src/__probe-lines.ts(320 行)、husky - pre-commit script failed、HEAD 未动)。 同一轮还补了门禁自身的覆盖,并在终局评审后把接线方式整体换掉(2026-09-11 二轮,31b59239):.husky/pre-commit 现在不再经 lint-staged,而是每次提交都直跑 node scripts/line-limits.mjs --full && node scripts/docs-check.mjs(&& 串联,任一失败即以非零退出、husky 拦下提交)。package.json 的 lint-staged 块随之删除(devDependencies 里的 lint-staged 保留,留给将来的文件级任务)。 换法的三条理由:① 两个检查都是全树只读扫描、且忽略传入的文件参数(line-limits.mjs 只认 --write / --full)⇒ lint-staged「把暂存文件列表交给命令」的语义对它们零贡献,却带回 stash / git reset --hard / hide / auto-stage / .git/lint-staged_unstaged.patch 一整类风险(见「工具链真相 2」);② 用 --full 是为本地与 CI 同口径守 (e)「登记值 == 实测值」,而 --full 只读(写登记表只走 --write)⇒ 不会逼人每次提交重生成表;③ 门禁每次都跑全树,不再依赖 package.json 的 glob。 ⇒ 本文档此前那句「lint-staged 增加 {package.json,…} → --full 条目」不要读成「(e) 已在本地全时生效」:旧接线只在暂存到 {package.json, scripts/line-limits.mjs, docs/standards/line-limit-exemptions.md} 三者之一时才跑 --full,其余情况只跑默认模式(不守 (e))。实测:只暂存一个改动过的源文件时该段 0 files / [SKIPPED] ⇒ 同一暂存态下旧门禁 npx lint-staged exit 0,而新 hook exit 1 并报 (e) 行数不一致:app/src-tauri/src/lib.rs 声明 1025 / 实测 1026。另一处同类问题是 glob 假覆盖:app/**/*.{ts,tsx,rs} 命中 872 个 tracked 文件,而脚本扫描域只有 868 个 ⇒ 差 4 个(app/src-tauri/build.rs、app/src-tauri/examples/capture_ocr_diag.rs、app/vite.config.ts、app/vitest.config.ts)「命令跑了、文件却没被看见」。直跑全树消掉的是「命令跑了却看不见」这层假覆盖本身(glob 不再决定门禁视野),不是这 4 个文件:它们仍在 SCAN_DIRS(app/src + app/src-tauri/src)之外、长到 700 行本地仍绿 —— 改直跑后门禁依然看不到它们(扩域须另立批次,见计划「未做(登记)」)。(评审记录为 870 / 差 2 个,那是以 git ls-files 'app/**/*.ts' … 数的 —— git pathspec 的 ** 比 micromatch 少算 app/*.config.ts 两个文件;按 lint-staged 实际使用的 micromatch 复核是 872 / 差 4 个。) CI 兜底在修好前不成立(如实登记;2026-09-11 实地复核并更正根因):CI 从未跑过本批 —— 最近一次 PR Quality Check 运行停在 2026-09-09(run 34361436068,headSha 2089042b = origin/dev 的尖端),此后 dev 上的提交全部落在 CI 覆盖之外(截至 ac7dd15b 实测 78 个:git rev-list --count origin/dev..ac7dd15b —— 该值是移动值:31b59239 时 76、dd130dff 时 77 ⇒ 引用须带锚点,勿当现状)。该次运行的真实结果(gh run view 34361436068):changes = success、docs = failure、app-frontend / app-rust / website 三个 job 全部 skipped(改动只落 docs/**)、line-limits job 当时尚未存在(它由本批 7476fd0b 才加入);失败停在 docs job 的 Docs check 步骤 —— 该提交干净树上 docs-check 本身就是 exit 1(扫描 257 个 Markdown 文件,报「失效相对链接 20 处」,另有 5 个文件未收录索引的警告)。⇒ 本文档初稿的根因归因「继承来的 workflow 引用本仓不存在的路径(旧 job 为 client / ai-gateway / sync-service)」不成立,已更正:pr-check.yml 全部 15 个历史版本里都没有这些 job,那次运行的 changes 过滤路径也真实存在(唯一对不上的是写成仓根的 .docscheckignore,实际路径为 docs/.docscheckignore;该条 glob 惰性失效,且 docs/** 已覆盖同一批文件)。那套 client/ / ai-gateway / sync-service 的描述属于 scripts/validate-all.mjs(重构前遗留,步骤指向本仓不存在的 client/、server/ai-gateway、server/sync-service)—— 计划 L842 记对了,是本文档张冠李戴。「最近 5 次全 failure」属实,但要分清两层真实根因:更早 4 次(7b432c1e / 4fe09e08 / 02aba9a2 / 68bf43a1)失败在 app-rust job 的 Lint (clippy) 步骤(同次 cargo test 是 2334 passed / 0 failed),最近一次(2089042b)才失败在 docs。⇒ 推送后 CI 是否绿,本批未经实测:本地树当前 docs-check(267 文件 / 167 检查)与 line-limits --full 都 exit 0,但那次运行里 app-frontend / app-rust / website 全是 skipped ⇒ 这三个 job 推送后能否跑绿没有证据;本机以 CI 同一条命令复跑 cargo clippy -- -D warnings(clippy 0.1.96)仍 exit 101、15 个 error(manual_contains / needless_lifetimes / collapsible_if / too_many_arguments / type_complexity / unwrap_or_default / let_and_return / cloned_ref_to_slice_refs / manual_flatten)⇒ app-rust 大概率仍会红。故此处既不写「CI 恒红」、也不写「兜底已就位」。⇒ 在 CI 能真正跑绿之前,本地直跑 --full 是唯一生效的 (e) 守卫。

工具链真相 2 · 门禁的失败路径曾是破坏性的(lint-staged@15.5.0,2026-09-11 实测并加固)

lint-staged@15.5.0 默认 stash:true + hidePartiallyStaged:true,其失败路径是「先毁工作树,再赌一次还原」:git stash create + stash store 备份 → 跑任务 → 失败则 git reset --hard HEAD(清掉整个工作树)→ git stash apply --quiet --index <备份> 重建 → cleanup 把备份 stash drop(实现见 node_modules/lint-staged/lib/gitWorkflow.js 与 runAll.js)。 ⇒ 实测曾使未暂存改动当场消失:暂存一个故意越线的探针文件、同时在 docs/standards/README.md 留一处纯未暂存改动,提交 [FAILED] 后那处改动从工作树消失,且 git stash list 为空(只剩悬空 commit c85e00a1);git diff HEAD c85e00a1 证明备份里确实含该改动 ⇒ 还原那一半没兑现。复跑同一实验时内容侥幸还在,但整个文件被重写(LF→CRLF、sha256 变化)—— 「内容还在」是那次 apply 恰好成功,不是设计保证。 ⇒ 加固:.husky/pre-commit 改为 npx lint-staged --no-stash --no-hide-partially-staged(上游 --no-stash 本就 imply 关掉 hide;第二个 flag 仍写死,防将来 imply 变化后悄悄退回「藏了未暂存部分却没有备份可还原」—— 那条路失败时必丢)。加固后 lint-staged 在任何路径都不碰工作树与索引(不 stash create、不 reset --hard、不 checkout --force、不 stash drop),而拦截力不变(实测 [FAILED] + exit=1、husky - pre-commit script failed (code 1)、HEAD 未动、未暂存改动 sha256 前后相同)。 代价(须知):① 门禁看到的是工作树态,不再是「隐去未暂存部分的索引态」—— 本仓两个检查都是全树只读扫描,看工作树反而口径单一,故可接受;② 落在受管 glob 上的部分暂存文件会在跑完时被整文件 git add ⇒ 不丢内容,但抹掉「只提交一半」的意图(提交前看 git status,MM 会变成 M );③ 部分暂存时会残留 .git/lint-staged_unstaged.patch(没有步骤再删它)。 补救(失败后怀疑丢了改动):备份是一个 WIP on <分支>: <HEAD> 的悬空 commit —— git stash list 为空不代表它不存在:git fsck --dangling 列出悬空 commit → git diff --name-status HEAD <备份ID> 先确认确实含你的改动 → git stash apply --index <备份ID> 整份还原(索引 + 工作树),或 git checkout <备份ID> -- <path> 只取回单个文件。 ⚠️ 因此切勿运行 git gc --prune=now:这些悬空 commit 是万一丢失改动时的唯一找回途径(控制方那次丢失的改动,就是从 c85e00a1 找回来的)。 ★ 二轮后(2026-09-11,31b59239):上述整类风险已从路径上消失 —— .husky/pre-commit 不再调用 lint-staged(见「工具链真相 1」),故上面写死的 --no-stash / --no-hide-partially-staged 与本节「代价」的 ②「MM 跑完被整文件 git add」③「残留 .git/lint-staged_unstaged.patch」都不再适用(实测:部分暂存文件跑完仍是 MM、文件 sha256 前后相同)。本节「补救」一条仍然有效(历史悬空 commit 依旧存在,找回方式不变;git gc --prune=now 依旧禁止)。

边界(红线延续,全文见规格 §3)

  • 不写「自动替你决定」的能力;AI 一律默认关、可降级、须授权
  • 不为了动效牺牲可及性:三档强度 + 系统 reduced-motion 优先 + 环境层幅度上限 2%
  • 不为「活」而活:每个动效必须能归入四层纲领之一(响应 / 环境 / 编排 / 生长)