Skip to content

Commit 08b1afd

Browse files
committed
feat(views): 注册笔记第三视图并同步冻结键
注册笔记第三视图(`evidence`)并同步冻结键;同提交完成 §C32.3 ① 的**逐族重冻**(含两个新族登记 与总量上限上调 —— 🔴 本条经 §C46.4 逐次授权,授权方 = 控制方,时点 2026-09-13,理由 = 批 8 8b 段 的收口重冻;§C32.3 第 ③ 条「懒侧总上限不得抬高」本次由该授权解除)。 改动的两处(G1 双向对拍,只改一处必红): - views/registry.ts:NOTE_VIEWS 加第三项 { key: "evidence", label: "证据", icon: "clock", load: () => import("./note/NoteEvidenceTrackView") };FROZEN_VIEW_KEYS.note 加 "evidence"; 头注闭合批 5 的中间态。NoteViewSlot(4 字段)一字未改。 - 判据件期望值同步(只增不减):registry.test.ts 的 EXPECTED_KEYS.note 与阴性样本下标 2→3; registryResolution.test.ts 的 EXPECTED_LOAD_TARGETS 5→6、note 侧非默认视图 ["cardflow"]→ ["cardflow","evidence"]、G3③ 文案 5/5→6/6。 ① 推高者(逐字):**新增视图件 NoteEvidenceTrackView.tsx**(新族 NoteEvidenceTrackView- 1,470 B) + 它复用 utils/markdownLine.ts 后该模块被抽成**共享懒 chunk**(新族 markdownLine- 768 B, 原先落在 RefineLaunchDialog- 内,该族同批 −545 B) + 注册表第三项 spec 行本身(registry- +65 B / NotesPage- +18 B)。 ② 前后逐键 diff(旧上限 → 新上限 → 实测;base = ffb7e28 的受控对比,同脚本同基线): 新族 NoteEvidenceTrackView- (无) → 1,470 → 实测 1,470 新族 markdownLine- (无) → 768 → 实测 768 重冻 NotesPage- 48,627 → 48,693 → 实测 48,693 重冻 registry- 1,966 → 2,048 → 实测 2,048 计数 lazyChunkCountMax 37 → 39 → 实测 39 总量 lazyTotalGzipBytesMax 637,501 → 639,314 → 实测 639,314 其余 33 族上限**一字未动**(含 vendor-* 五族:58,784 / 208,585 / 41,161 / 79,915 / 50,622 逐值保留)。 ③ 总量上限:🔴 本次经控制方按 §C46.4 **逐次授权**解除 §C32.3 第 ③ 条(授权方 = 控制方 · 时点 2026-09-13 · 归属 = T8 的视图件与其注册表第三项);报告与 lazyBudget.json 的 semantics 字段均逐字登记该授权。 ④ 必然后果(受控对比,§17:同 base sha ffb7e28、同脚本、同基线、两棵导出树各一次真构建): 去掉本改动(tree2/control2)⇒ 两个新族**不存在**、NotesPage- 回落 48,675、registry- 回落 1,983 (两者均在旧上限 + 64 B 容差内)⇒ 越界是**该次改动的必然后果**,不是顺手抬预算; 🔴 vendor-* 五族逐族实测 Δ = 0(未触发 §C46.4 的 STOP 条件)。 落地后复跑真构建包体闸(2026-09-13T06:57Z 前后,**exit 0**):首屏 106,196 B = 106.20 kB (预算 200 kB,余 93.80 kB)· 懒侧 39 chunk / 639,314 B · **未归族 0 · 超上限族 0**; tsc exit 0;点名 8 文件 99/99 绿(只增不减)。
1 parent 0eae531 commit 08b1afd

4 files changed

Lines changed: 33 additions & 17 deletions

File tree

‎app/src/views/registry.test.ts‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,11 @@ import { ICON_NAMES } from "../ui/icons";
2626
import type { ObjectType } from "./registry";
2727
import { FROZEN_VIEW_KEYS, keysFor, viewsFor } from "./registry";
2828

29-
/** G1 的**独立**冻结清单(逐字字面量;顺序 = 计划给的 spec 顺序,`[0]` = 默认视图)。 */
29+
/** G1 的**独立**冻结清单(逐字字面量;顺序 = 计划给的 spec 顺序,`[0]` = 默认视图)。
30+
* 批 8 T8:笔记侧加第三项 `evidence`(「带证据三轨」;视图 = `views/note/NoteEvidenceTrackView.tsx`)。 */
3031
const EXPECTED_KEYS: Readonly<Record<ObjectType, readonly string[]>> = {
3132
session: ["raw", "tritrack", "proof", "cardflow", "preview"],
32-
note: ["raw", "cardflow"],
33+
note: ["raw", "cardflow", "evidence"],
3334
};
3435

3536
const TYPES: readonly ObjectType[] = ["session", "note"];
@@ -59,7 +60,7 @@ describe("G1 冻结表的三条不变式", () => {
5960
it("① 阴性样本:删项 / 多项 / 读空 各必红(走同一条判据)", () => {
6061
const dropped = EXPECTED_KEYS.session.filter((k) => k !== "cardflow");
6162
expect(keyDiff(dropped, EXPECTED_KEYS.session)).toEqual(["[3] cardflow → preview", "[4] preview → <缺>"]);
62-
expect(keyDiff([...EXPECTED_KEYS.note, "extra"], EXPECTED_KEYS.note)).toEqual(["[2] <缺> → extra"]);
63+
expect(keyDiff([...EXPECTED_KEYS.note, "extra"], EXPECTED_KEYS.note)).toEqual(["[3] <缺> → extra"]);
6364
expect(keyDiff([], EXPECTED_KEYS.session)).toHaveLength(5);
6465
});
6566

‎app/src/views/registry.ts‎

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,11 @@ export interface NoteViewSlot {
9393
* `NotePreviewView` 本体:`NotePreviewView` 的 props 是 `{sessionId, autoTaskId, onTaskStarted}`
9494
* (容器形态、自带取数),而注册表的 `P` 是 `SessionViewSlot`(纯注入槽)—— 两者不同形,
9595
* 直接指向它得到 `TS2322`。适配器把槽映射成 props(**不是**第二套取数),详见该文件头部。
96-
* @ai-context 笔记 spec 顺序:`raw` → `cardflow`。「带证据三轨」是 T13 的**条件项** —— T1 的探针
97-
* 判定「不存在逐段级『笔记 ↔ 证据』读取路径」⇒ **不进表**(C2:不许空壳视图)。
96+
* @ai-context 笔记 spec 顺序:`raw` → `cardflow` → `evidence`。**批 5 的中间态已闭合**:`evidence`
97+
* (「带证据三轨」)在批 8 落地 —— 模型层 T6(`note/noteEvidenceModel.ts`)· 视图层 T8(本项)
98+
* · 容器取数 T10。它的两处 DOM 契约(E1 每段带 `data-evidence-for`(**含无锚点段**)∧ **只有
99+
* 带锚点段**才渲染证据列;E2 命中 / 显式「无证据」)写在 `note/NoteEvidenceTrackView.tsx`
100+
* 的文件头;**无锚点是一等状态**(`raw` 仍是 `[0]` 默认视图 ⇒ 原文不丢,规格 §7.3①)。
98101
* @ai-context `FROZEN_VIEW_KEYS` 是**独立于实现的**冻结声明:`keysFor` 由 `viewsFor` 派生,冻结表
99102
* 逐字写死 ⇒ 二者对拍(G1)能同时抓住「实现偷偷增删视图」与「冻结表被手工改宽」。
100103
*/
@@ -111,6 +114,8 @@ const NOTE_VIEWS: readonly ViewSpec<NoteViewSlot>[] = [
111114
// 默认视图:**无 `load`**(同上);图标 = 文档 + 文字行
112115
{ key: "raw", label: "原文", icon: "notes", appliesTo: "note" },
113116
{ key: "cardflow", label: "卡片流", icon: "action", appliesTo: "note", load: () => import("./note/NoteCardFlowView") },
117+
// 「带证据三轨」(批 8 T8):吃 `NoteViewSlot`;候选轨由容器侧(T10)注入,视图自身零取数。
118+
{ key: "evidence", label: "证据", icon: "clock", appliesTo: "note", load: () => import("./note/NoteEvidenceTrackView") },
114119
];
115120

116121
/** 可用视图清单(按对象类型;`viewsFor(t)[0]` 恒为默认视图)。未知 `objectType` ⇒ `[]`(G5)。 */
@@ -133,5 +138,5 @@ export function keysFor(objectType: ObjectType): readonly string[] {
133138
/** 冻结的视图键清单(顺序 = spec 顺序,`[0]` = 默认视图)。增删视图必须**同时**改此处与 `viewsFor`。 */
134139
export const FROZEN_VIEW_KEYS: Readonly<Record<ObjectType, readonly string[]>> = {
135140
session: ["raw", "tritrack", "proof", "cardflow", "preview"],
136-
note: ["raw", "cardflow"],
141+
note: ["raw", "cardflow", "evidence"],
137142
};

‎app/src/views/registryResolution.test.ts‎

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,16 @@ import type { ObjectType, SessionViewSlot, ViewSpec } from "./registry";
3232
import { viewsFor } from "./registry";
3333

3434
/** G7 的**独立**期望:每个非默认 spec 的 `load` 目标模块(逐字路径字面量)。
35-
* ⚠️ 最后一项是**适配器**(`./session/SessionNotePreview`),不是 `NotePreviewView` 本体 ——
36-
* 后者 props 不同形(`TS2322`),见文件头 A1/A2 与 `SessionNotePreview.tsx` 的说明。 */
35+
* ⚠️ 第 4 项是**适配器**(`./session/SessionNotePreview`),不是 `NotePreviewView` 本体 ——
36+
* 后者 props 不同形(`TS2322`),见文件头 A1/A2 与 `SessionNotePreview.tsx` 的说明。
37+
* 批 8 T8:第 6 项 = 笔记侧第三视图(「带证据三轨」)。 */
3738
const EXPECTED_LOAD_TARGETS: readonly string[] = [
3839
"./session/SessionTriTrackView",
3940
"./session/SessionProofView",
4041
"./session/SessionCardFlowView",
4142
"./session/SessionNotePreview",
4243
"./note/NoteCardFlowView",
44+
"./note/NoteEvidenceTrackView",
4345
];
4446

4547
/** G7 的**独立**期望:注册表顶部允许出现的静态 import(全部是 `import type` ⇒ 0 运行时依赖边)。 */
@@ -101,15 +103,15 @@ describe("G3 每个 load() 都解析出真实模块(default 是组件函数)
101103
}
102104
});
103105

104-
it("note 侧 1 个非默认视图", async () => {
106+
it("note 侧 2 个非默认视图", async () => {
105107
const specs = viewsFor("note").filter((s) => s.load !== undefined);
106-
expect(specs.map((s) => s.key)).toEqual(["cardflow"]);
108+
expect(specs.map((s) => s.key)).toEqual(["cardflow", "evidence"]);
107109
for (const spec of specs) {
108110
expect(typeof (await loadDefault(spec)), `${spec.key} 的 load() 没有解析出 default 组件`).toBe("function");
109111
}
110112
});
111113

112-
it("G3③ 注册表覆盖的每个 load 目标文件此刻都真实存在(5/5 ⇒ 无一是空壳)", () => {
114+
it("G3③ 注册表覆盖的每个 load 目标文件此刻都真实存在(6/6 ⇒ 无一是空壳)", () => {
113115
const missing = EXPECTED_LOAD_TARGETS.filter((target) => {
114116
try {
115117
readFileSync(join(HERE, `${target}.tsx`), "utf8");

‎scripts/lazyBudget.json‎

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
{
2-
"generatedFrom": "node scripts/check-bundle-budget.mjs(**真构建**,不带 --no-build)· 源码 = c0bff722(批 7 全批收口树;T22 重冻)· 读数存档 .superpowers/sdd/2026-09-12-frontend-redesign-batch7-unwired/tmp/t22/logs/g5-bundle-budget-realbuild.txt(时点 2026-09-13T03:46Z · 懒侧 37 chunk / 637,501 B · 首屏 105.95 kB);上一版 = 950afd5a(T12 的 7a 段收口重冻,limit 636,243)· 再上一版 = cd800d63(T9,批次中段快照 634,316)",
2+
"generatedFrom": "node scripts/check-bundle-budget.mjs(**真构建**,不带 --no-build)· 源码 = 8cc627de(批 8 T8 的 O4① 落地树)+ T8 的注册表第三项(本提交)· 读数存档 .superpowers/sdd/2026-09-13-frontend-redesign-batch8/tmp/t8/b2-mine.json(受控对照 b2-control.json = base ffb7e28a 去掉 T8 的 6 件;时点 2026-09-13T06:53Z · 懒侧 39 chunk / 639,314 B · 首屏 106.20 kB);🔴 本版 = 批 8 **8b 段**的收口重冻(归属 = T8 的视图片 + 它的注册表第三项);上一版 = c0bff722(批 7 T22 全批收口重冻,limit 637,501)· 再上一版 = 950afd5a(批 7 T12 的 7a 段收口重冻,limit 636,243)· 再上一版 = cd800d63(批 7 T9,批次中段快照 634,316)",
33
"unit": "gzip = zlib.gzipSync level 6 · 族前缀 = 去掉 8 位内容 hash 的 chunk 名 + '-'(chunk 名带内容 hash,不稳定,不能当键)",
44
"scope": "🔴 必须在**新鲜构建**产物上判定(§C21.3):旧 dist 上的 --no-build 读数含时代残渣,上界会虚高(实测 +64,497 B)⇒ 本判据的合格调用 = 不带 --no-build(本脚本自行构建)或显式 --dist 指认受判产物",
5-
"semantics": "全部字段 = 实测**冻结值**,只许降(批 7 §C9.6 第 2 条 / §C10.4);写乐观「预算值」会立刻红。★ 上一轮(rulings §C46.4「每收口一次、重冻一次」· T12 于 0a503cc8)为**一次性、可归属的重冻**:4 族按收口树**真实构建**的实测值重冻(NoteMarkdown- · NotesPage- · RefineLaunchDialog- · SessionsPage-)+ 新族 NoteCardFlowWithSeek- 登记 + chunk 数 36 → 37 + 总量 634,316 → 636,243;🔴 vendor-* 五族逐族核对为「零增长」⇒ 未触发 §C46.4 条件⑤ 的 STOP。★★ **本轮(T22 于 c0bff722,控制方 2026-09-13 逐条授权)为该授权的第 2 次、也是 §C46.4 第 5 条所指的「批 8 基线」那一次**:2 族抬到终态**真构建**实测(KnowledgePage- 27,620 → 28,466 · NotesPage- 48,087 → 48,627)+ 补登遗漏族 lowConfidence-(100 B,chunk 本就在、只是未登记族)+ 总量 636,243 → 637,501;🔴 chunk 数 **37 → 37 不变**、其余 34 族上限**一字未动**(含全部 vendor-* 五族:58,784 / 208,585 / 41,161 / 79,915 / 50,622 逐值保留,实测 Δ ≤ +2 B)。归属 = T18(NoteTagsEditor/过滤面板着色)· T19(档位通道 90bb5f6a/c6a4cb7c)· T20(六条展示面 b72d4709 + 展示面与分件)· T23(片段归组 125eec85/5d59e332)· T17 尾(08717e84/02c32baa)。**批 8 的基线 = 本条所记的终态重冻值**(此后才是真正的硬棘轮)。",
6-
"lazyChunkCountMax": 37,
7-
"lazyTotalGzipBytesMax": 637501,
5+
"semantics": "全部字段 = 实测**冻结值**,只许降(批 7 §C9.6 第 2 条 / §C10.4);写乐观「预算值」会立刻红。★ 重冻谱系(§C46.4「每收口一次、重冻一次」):第 1 次 = 批 7 T12(0a503cc8)—— 4 族按收口树真构建实测重冻(NoteMarkdown- · NotesPage- · RefineLaunchDialog- · SessionsPage-)+ 新族 NoteCardFlowWithSeek- 登记 + chunk 36 → 37 + 总量 634,316 → 636,243;🔴 vendor-* 五族逐族核对为「零增长」⇒ 未触发 §C46.4 的 STOP。第 2 次 = 批 7 T22(c0bff722,控制方逐条授权)—— 2 族抬到终态真构建实测(KnowledgePage- 27,620 → 28,466 · NotesPage- 48,087 → 48,627)+ 补登遗漏族 lowConfidence-(100 B)+ 总量 636,243 → 637,501,chunk 数 37 → 37 不变;该版曾把自身写成「批 8 的基线」,🔻 该句按本条更正。★★ **本轮 = 第 3 次**,归属 = 批 8 **T8**(视图件 NoteEvidenceTrackView.tsx + 它的注册表第三项)、收口段 = **8b**、由控制方按 §C46.4 **逐次授权**(2026-09-13):① 登记 2 个新族 —— NoteEvidenceTrackView- **1,470 B** · markdownLine- **768 B**(后者 = 本视图复用 utils/markdownLine.ts 后被抽成共享懒 chunk 的**必然结果**,非新依赖)② 重冻 2 个越界族 —— NotesPage- 48,627 → **48,693** · registry- 1,966 → **2,048** ③ chunk 上限 37 → **39** ④ 总量 637,501 → **639,314**(🔴 §C32.3 第 ③ 条「懒侧总上限不得抬高」本次经控制方逐次授权解除:**授权方 = 控制方,时点 2026-09-13,理由 = 8b 段收口重冻的一次性授权**);🔴 vendor-* 五族**逐族零增长**(实测 Δ = 0:58,786 / 208,585 / 41,162 / 79,915 / 50,623)⇒ 未触发 §C46.4 的 STOP 条件;🔴 其余 33 族上限**一字未动**。**批 8 的基线 = 本条所记的终态重冻值**(此后才是真正的硬棘轮)。",
6+
"lazyChunkCountMax": 39,
7+
"lazyTotalGzipBytesMax": 639314,
88
"families": [
99
{
1010
"prefix": "ActionPage-",
@@ -46,13 +46,17 @@
4646
"prefix": "NoteCardFlowWithSeek-",
4747
"gzipBytesMax": 391
4848
},
49+
{
50+
"prefix": "NoteEvidenceTrackView-",
51+
"gzipBytesMax": 1470
52+
},
4953
{
5054
"prefix": "NoteMarkdown-",
5155
"gzipBytesMax": 3278
5256
},
5357
{
5458
"prefix": "NotesPage-",
55-
"gzipBytesMax": 48627
59+
"gzipBytesMax": 48693
5660
},
5761
{
5862
"prefix": "RefineLaunchDialog-",
@@ -122,9 +126,13 @@
122126
"prefix": "lowConfidence-",
123127
"gzipBytesMax": 100
124128
},
129+
{
130+
"prefix": "markdownLine-",
131+
"gzipBytesMax": 768
132+
},
125133
{
126134
"prefix": "registry-",
127-
"gzipBytesMax": 1966
135+
"gzipBytesMax": 2048
128136
},
129137
{
130138
"prefix": "shift-",

0 commit comments

Comments
 (0)