dsh-gokifu-compact 1.9.1 → 1.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,7 +1,121 @@
1
1
  # 更新记录
2
2
 
3
+ ## 1.9.3 — 2026-10-30
4
+
5
+ ### 修 README 版本行(1.9.2 的发布缺陷)
6
+
7
+ 1.9.2 的 npm 包里 `README.md` 第 3 行仍写着「当前版本 1.9.1」—— 用户装上包后第一眼看到的就是错的版本号。
8
+ 本版**只修这一处**:`README.md` 第 3 行 = **1.9.3**,与 `package.json` 的 `version` 一致。
9
+
10
+ - 代码零改动:`src/`、`scripts/`、`lib/` 与 1.9.2 逐字节相同。包内其余差异只有 `package.json` 的版本号、
11
+ `README.md`(本修复),以及 `docs/` 两份维护文档的最终稿。
12
+ - 发布门禁新增硬断言:`README.md` 的「当前版本:x.y.z」必须等于 `package.json` 的 `version`,不一致即拒绝发布。
13
+ - 单测 **378 项全绿**(含 task-59 的测试夹具改造;`test/` 不进包)。
14
+
15
+ ## 1.9.2 — 2026-10-30
16
+
17
+ ### ⚠ 破坏性契约变化:`graph.json` 不再是「最新状态」
18
+
19
+ **1.9.2 起,落盘拆成「上一回合基线 + 当前增量」:**
20
+
21
+ | 文件 | 内容 |
22
+ |---|---|
23
+ | `graph.json` | **上一个回合边界**的完整基线 |
24
+ | `graph.json.delta.jsonl` | 本回合的增量帧,一帧一行 `<baseHash16>\t<checksum31>\t<json>` |
25
+
26
+ `graph.json` 只在**回合边界**(`agent/status idle`)落一次;回合内每一步只追加 delta 帧。
27
+ ⇒ **外部工具若只 `JSON.parse(graph.json)`,会少一个回合的数据。** 最新状态 = 基线 + 按序重放 delta
28
+ (`fromJSON` → `decodeDeltaFrames(text, baseHash)` → `applyDelta`,三个函数在 `src/graph.mjs`)。
29
+ README 新增「graph.json 契约(外部工具必读)」一节,含三条余量(短回合写放大 / dirty>100 flush / `appendFileSync` 跨平台)。
30
+
31
+ ### P3 · flush 写放大 ×800–975 治理(增量 delta + index 追加 + dirty 节点)
32
+
33
+ - `graph.json.delta.jsonl`:每步只追加 dirty 节点/边(绝对 upsert)+ 标量 + order 追加;
34
+ 合并阈值 `max(64KB, 基线 20%)`,超过则写新基线(`tmp` → `rename`)并清空 delta
35
+ - 崩溃安全:帧带 `baseHash`(generation 保护,基线重写后旧帧整体忽略)+ `checksum31`
36
+ (半写帧就地停止并截断到最后一个好帧)+ 幂等重放(同一批帧重放多次结果相同)
37
+ - `index.md` 稳态**追加**增量段(~200–800 B/次),fold / 首次 / 缺失 / >256KB 时全量重建;
38
+ `nodes/*.md` 稳态不写,只记 pending,fold 时只写 dirty
39
+ - 实测(三张真实图 × 60 步 + 1 回合边界):写放大 **×80.16 / ×70.04 / ×61.75 → ×37.41 / ×33.31 / ×30.75**;
40
+ 稳态每步写 **10.5–11.8 KB → 591–713 B(−94%)**;fold 后 flush **429–836 ms → 9.4–22.9 ms**
41
+ (5–20 个 dirty 节点)/ **76.5–88.8 ms**(100 个)
42
+ - 测试:`test/persist-incremental.test.mjs` **8 项**(重放等价 / 幂等 / 半写帧 / generation 保护 /
43
+ index 增量 / engine 端到端 / nodes dirty)
44
+ - 已知边界:**极短回合(<10 步)** 每回合的全量基线摊销不足,写放大仍可能 >×50;
45
+ `appendFileSync` 跨平台原子性未验证
46
+
47
+ ### P4 · 首屏 `state` 的 graph.json 解析缓存
48
+
49
+ - `src/ui.mjs` 新增 `(绝对路径, mtimeMs, size) → 聚合摘要` 缓存 + `pruneGraphCache()`:
50
+ 改文件必失效(同 mtime 但 size 不同也失效)
51
+ - 133 图 / 33 MB 实测:热路径 p50 **140.5 ms → 20.9 ms**(另一轮 **242.5 → 51.1**);
52
+ 冷路径也更快(**170.7 → 101.3** / **386.4 → 196.7**);`state` 响应 **3,648 B 逐字相同**
53
+ - 测试:`test/ui-perf.test.mjs` **10 项**
54
+
55
+ ### P5 · 生产口径 token 预算与 `pickFallback`
56
+
57
+ - `renderLedger` 新增 `fallback` 三态(`none` / `over-budget` / `impossible`)+ `overBudgetBy`:
58
+ **不再静默返回超预算文本** —— 调用方拿到的每个结果都能区分「预算内 / 兜底超限 / 无解」
59
+ - `pickFallback` 择优顺序固定:预算内优先 → tokens 最小 → 平手列得多;全超选最省并标 `over-budget`;
60
+ 无非空文本返回 `null`(`impossible`)
61
+ - 生产口径(`treeDir` = 真实会话目录、`maxTokens=500`,133 图):
62
+ **>500 = 24/133(与 1.9.1 HEAD 的 24 相同,新增 0)**、avg **444.80**(HEAD 430.85,+13.95 ≤ +20)、
63
+ max **905**(与 HEAD 完全相同)。24 张全部是 L4/L5 兜底档 —— 正文本身 >1500 字符,不是预算记账 bug
64
+ - 测试:`test/ledger-budget.test.mjs` **7 项**
65
+
66
+ ### P6a · `TRACE:` 行绝对路径改相对,回收 avg +17 tok/图
67
+
68
+ - `TRACE:` 从 `D:\DeepSeek Harness\home\chess-context\sessions\<sid>/index.md …`(137.7 字符)
69
+ 改成 `sessions/<sid>/index.md`(57.5 字符),`traceRoot` 可配置(默认无前缀,生产传 `sessions`)
70
+ - 生产口径 133 图:avg **445.08 → 429.64(−15.44 tok/图)**;over500 **24 → 18**;max **905 → 878**;
71
+ 逐会话 85 便宜 / 7 变贵(5 个是 TRACE 变短后落进更低档位、列了更多内容)/ 41 不变;
72
+ `renderFacts` **133 图 0 差异**
73
+ - 测试:`test/trace-relative.test.mjs` **7 项**(Windows 盘符 / POSIX 用户名路径 / traceRoot 可配置 / 不泄漏绝对路径 …)
74
+
75
+ ### P6-A · 悬空边只在分析中排除(不剪数据)
76
+
77
+ - 新增 `classifyDangling()`(`residue` / `live-unsettled` / `from-broken` / `none`)与 `danglingStats()`;
78
+ **只过滤显示,不改 `graph.json`**
79
+ - 判定:`residue := to==null && age>10min`;**`live_unsettled`(untested 且 ≤10 分钟)必须保留可见**
80
+ —— 这是 Lead 批准的**更保守**口径(keeper 先 settle 结果、`step/end` 才回填 `to`,
81
+ 按字面公式会把刚结算的新鲜失败当场隐藏)
82
+ - `from` 悬空 **214 条**(全在 `5acafe42`,`mergeNodeInto` 老 bug)单独标记,不混入 `to=null` residue
83
+ - 实测(133 图):热清单**无终点失败边 158 → 0**;avg **−18.98**;over500 **17 → 17**;max **878 → 878**;
84
+ 全库 `residue 5,566 / liveUnsettled 1 / fromBroken 214`
85
+ - `renderFacts` **仍列全部失败边**(失败记忆不丢),新增 `DANGLING_RESIDUE: N` / `FROM_DANGLING: 214` /
86
+ `LIVE_UNSETTLED: N` 显式计数
87
+ - 测试:`test/dangling-exclusion.test.mjs` **8 项**
88
+
89
+ ### P7 · `fallback` 与 `traceRoot` 接进 engine / doctor(不留死开关)
90
+
91
+ - `src/engine.mjs`:新增配置 `hotLedgerTraceRoot`(schema 默认 `"sessions"`),生产 `renderLedger` 调用传
92
+ `traceRoot: "sessions"` ⇒ 生产热清单 `TRACE:` 为 `sessions/<sid>/index.md`,不泄漏盘符/用户名
93
+ - engine **消费** `fallback`:`over-budget` → warn 日志含 `overBudgetBy=` / `budget=`;
94
+ `impossible` → error;`ledgerBudgetMetrics` 累计并原子落盘 `<graphDir>/ledger-budget.json`;
95
+ 提供 `getLedgerBudgetStats()` / `onLedgerBudget` 钩子(可测,不静默)
96
+ - `scripts/doctor.mjs`:新增「热清单预算(fallback)」项,显示 `none / over-budget / impossible` 分布与
97
+ `maxOverBudgetBy`;字段缺失写「未采集」;`impossible > 0` 记 error
98
+ - 测试:`test/engine-harness.test.mjs` 增至 **25 项**(+4 条 P7 接线用例)
99
+
100
+ ### S2b · `no-exit` 弱成功按 N1 收窄
101
+
102
+ - `verifier.classify()` 的 shell 分支:`[exit code]` 存在时行为不变;**无退出码时默认给 `weak:"shell"`**,
103
+ 命中 N1 任一规则则不给。`result` **永远是 `unverified`**(不进已验证事实)
104
+ - N1 八条 veto 规则集中在 `SHELL_WEAK_VETO_RULES` 一处(id + 说明 + 正则):末行自报非零 / 末行 `Node.js vX` /
105
+ 尾部 node 栈迹 / `command not found`·`No such file`·`cannot stat` / 行首 `SyntaxError|AssertionError|…` /
106
+ `FAILED (failures=N)` 等;规则表可测试、可追溯
107
+ - 真实采样:全标 weak 的误报率 **2.94% → 收窄后约 0.49%**(≈48/9762 条假进展)
108
+ - 测试:`test/weak-shell.test.mjs` **13 项**(每条规则命中/不命中 + 旧图兼容 + renderFacts 不变 + 变异自检)
109
+
110
+ ### 测试
111
+
112
+ - `node test/run.mjs`:**373 passed / 0 failed**(30 个测试文件,`EXIT 0`;2026-10-30 03:2x 实测)
113
+ - 新增测试文件:`persist-incremental`(8) · `ui-perf`(10) · `ledger-budget`(7) · `trace-relative`(7) ·
114
+ `dangling-exclusion`(8) · `weak-shell`(13);`engine-harness` 21 → **25**
115
+
3
116
  ## 1.9.1 — 2026-10-29
4
117
 
118
+
5
119
  ### 修图坍缩:全库 61.3% 的边是自环(三份独立评估共同指向)
6
120
 
7
121
  事故:`worldstate.touch(paths)` 收到的是**单个路径字符串**(`engine.mjs` 的
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # dsh-GOkifu-compact
2
2
 
3
- > 当前版本:**`1.9.1`** · npm [`dsh-gokifu-compact`](https://www.npmjs.com/package/dsh-gokifu-compact) · [GitHub Releases](https://github.com/MYCF711/dsh-GOkifu-compact/releases) · 更新记录见 [CHANGELOG.md](CHANGELOG.md)
3
+ > 当前版本:**`1.9.3`** · npm [`dsh-gokifu-compact`](https://www.npmjs.com/package/dsh-gokifu-compact) · [GitHub Releases](https://github.com/MYCF711/dsh-GOkifu-compact/releases) · 更新记录见 [CHANGELOG.md](CHANGELOG.md)
4
4
 
5
5
  **DSH 的棋谱式上下文压缩后端 —— 把「历史 → 一段摘要」换成「历史 → 可复盘的棋谱 DAG + 每步只有 323 tokens 的热清单」。**
6
6
 
@@ -8,7 +8,7 @@
8
8
  热清单 323 tokens (2000 边压力测试;旧版全量渲染 28,800)
9
9
  失败保留 8 / 8 (真实模型对照;官方 8 段模板 4.67 / 8)
10
10
  清单开销 0.2% of prompt (v1.3.1 起;事故会话的旧版是 21.3%)
11
- 验证 316 项单测 · 真实包 8/8 · 真实进程 fold 3~6/6
11
+ 验证 378 项单测 · 真实包 8/8 · 真实进程 fold 3~6/6
12
12
  ```
13
13
 
14
14
  GO = 围棋,kifu = 棋谱,compact = 压缩。一局棋下完,棋谱上不只有落子顺序,还有每一手的评语。
@@ -50,6 +50,38 @@ GO = 围棋,kifu = 棋谱,compact = 压缩。一局棋下完,棋谱上不
50
50
  | 失败记录 | 融进散文摘要,模型可以丢 | 规则抽取 + 逐字注入,模型无权丢 |
51
51
  | 热上下文 | 无 | 323 tokens / 步,带语义标记与报错原文 |
52
52
 
53
+ ### ⚠ 棋谱落盘:`graph.json` 的语义(1.9.2 起)
54
+
55
+ **`graph.json` 不再代表「最新状态」,而是「上一回合基线 + 当前增量」。**
56
+
57
+ ```
58
+ 每次都重写整图(≤1.9.1) 增量落盘(1.9.2 起)
59
+ graph.json = 最新 graph.json = 上一个回合边界的完整基线
60
+ graph.json.delta.jsonl = 本回合的增量帧(带 baseHash + checksum)
61
+ (两者合并 = 最新状态)
62
+ ```
63
+
64
+ **⇒ 它在回合内落后一回合。** 任何直接 `JSON.parse(graph.json)` 当「最新」的脚本,**都会少一回合的数据**。
65
+ `graph.json` 只在**回合边界**(`agent/status idle`)落一次完整快照;回合内的每一步只往
66
+ `graph.json.delta.jsonl` 追加一帧。
67
+
68
+ | 你要什么 | 怎么拿 |
69
+ |---|---|
70
+ | **最新状态**(推荐) | **基线 + 增量一起读**:`fromJSON(graph.json 文本)` → 用基线内容哈希 `decodeDeltaFrames(delta 文本, baseHash)` → 逐帧 `applyDelta(g, frame)`。三个函数都在 `src/graph.mjs`(插件源码随包发布:`node_modules/dsh-gokifu-compact/src/graph.mjs`) |
71
+ | 上一回合基线(做 diff / 审计) | 直接读 `graph.json` 可以,但**要说明「这是基线不是最新」** |
72
+ | 崩溃安全 | 每帧带 `baseHash`(generation)+ `checksum31`:半写帧解码时就地停止,加载时把 delta 截到最后一条好帧;**旧 generation 的帧整体忽略** |
73
+
74
+ **为什么这样设计**:写放大从 **×80 / ×70 / ×62** 降到 **×37 / ×33 / ×31**(三张真实图 60 步 + 1 回合边界),
75
+ fold 后 flush 从 **429–836 ms** 降到 **≤95 ms**;代价是「读的人必须知道这是增量结构」。
76
+
77
+ **三条已知余量(选型时要知道)**
78
+
79
+ 1. **短回合写放大**:每回合边界落一份完整基线(0.5–0.6 MB)。真实分布 p50=40 步/回合 ⇒ 写放大 ≈×20–25;
80
+ 但**极短回合(<10 步,p10=13.9)**摊销不足,写放大仍可能 >×50。
81
+ 2. **dirty > 100 的 flush**:fold 后只写 dirty 节点 —— 5–20 个 dirty 时 **9–23 ms**,100 个时约 **87–89 ms**
82
+ (改前全量 429–836 ms)。dirty 数极大时收益收窄。
83
+ 3. **`appendFileSync` 的原子性依赖 OS**:本机 NTFS 上 1 KB 级追加已过半写测试;**跨平台(尤其网络文件系统)未验证**。
84
+
53
85
  ### 热上下文长什么样
54
86
 
55
87
  每步 `agent/pre-step` 注入(内容不变时复用;变了就**就地替换**上一条,surface 永远只有一条):
@@ -251,7 +251,7 @@ pageContent { max-width:980px; margin:0 auto; padding:24px 28px 48px; display:fl
251
251
  修法:改用 `fileURLToPath(new URL(...))`(实测得到 `D:\主工作区\...\src\ui.mjs`,读 `../package.json` 得 `1.9.1` ✓)。
252
252
  > 编号说明:§三 已占用 S10(安装器 link)与 S11(文档同步),本条记为 **S10′**,在本轮任务表里是独立一行。
253
253
 
254
- > **已实施(2026-10-29 22:4x,S10′ 子代理)**:`src/ui.mjs:22` 加 `fileURLToPath`、`:24-34` 新增 `HERE`、`:322` 改读 `HERE` 下的 `../package.json`(行号为修复后;旧实现是 `308-315` 那一行)。新增 `test/version-path.test.mjs`(4 用例 / 32 条运行时断言 / 零跳过)——`node test/run.mjs version-path` **4/0 [exit 0]**,变异回旧表达式 **2/2 [exit 1]**;全量 `node test/run.mjs` **168/0 [exit 0]**;真实 HTTP 入口 `/gokifu/api` state 返回 **`version: "1.9.1"`**(`client.js:197` 渲染 `v1.9.1`)。live profile 两文件 sha256 未变。证据见仓库根 `计划表.md` §S10′ 完成证据(**注:`计划表.md` 在仓库根、不在 npm 包的 `files` 内,包内读者请查仓库** —— 原本这里是 `[计划表 §S10′ 完成证据](../计划表.md)` 的链接,安装包里会 404,2026-10-30 04:2x 按 WS-RELEASE-EXEC 的 V4 项改为纯文本引用)。
254
+ > **已实施(2026-10-29 22:4x,S10′ 子代理)**:`src/ui.mjs:22` 加 `fileURLToPath`、`:24-34` 新增 `HERE`、`:322` 改读 `HERE` 下的 `../package.json`(行号为修复后;旧实现是 `308-315` 那一行)。新增 `test/version-path.test.mjs`(4 用例 / 32 条运行时断言 / 零跳过)——`node test/run.mjs version-path` **4/0 [exit 0]**,变异回旧表达式 **2/2 [exit 1]**;全量 `node test/run.mjs` **168/0 [exit 0]**;真实 HTTP 入口 `/gokifu/api` state 返回 **`version: "1.9.1"`**(`client.js:197` 渲染 `v1.9.1`)。live profile 两文件 sha256 未变。证据见仓库根 `计划表.md` §S10′ 完成证据(**注:`计划表.md` 在仓库根、不在 npm 包的 `files` 内,包内读者请查仓库** —— 原本这里是 `[计划表 §S10′ 完成证据](../计划表.md)` 的链接,安装包里会 404,2026-10-30 02:3x 按 WS-RELEASE-EXEC 的 V4 项改为纯文本引用)。
255
255
  > 测试侧附带事实:本机 `os.tmpdir()` 是 8.3 短名 `ADMINI~1`,`~` 编码成 `%7E` ⇒ **连纯 ASCII 临时目录也会踩同一坑**,故 ASCII 对照组只比转换结果、不建真实文件。
256
256
 
257
257
  ### 8.8 复跑
@@ -1502,7 +1502,7 @@ renderLedger(g, { maxTokens: 500, markers: "semantic", treeDir: <该会话真实
1502
1502
 
1503
1503
  ---
1504
1504
 
1505
- ## 三十 · 冻结线收口定稿(2026-10-30 04:1x)· 只写当前决定
1505
+ ## 三十 · 冻结线收口定稿(2026-10-30 02:3x)· 只写当前决定
1506
1506
 
1507
1507
  > 逐项证据见根 `计划表.md` §五十八–§六十一。
1508
1508
 
@@ -1540,3 +1540,345 @@ renderLedger(g, { maxTokens: 500, markers: "semantic", treeDir: <该会话真实
1540
1540
 
1541
1541
  - 只记录决定;**不含新测量**。
1542
1542
  - **未验证**:task-47(C-13 reviewer 判定)、task-48(合并树 delta)均未出结论;`ws-s6` / `ws-release-verify` 仍未落盘;运行期重启未验证(贯穿全篇的同一项)。
1543
+
1544
+ > ✅ **2026-10-30 02:45 全部解**:task-43 **PASS/ACCEPT**、task-44 **PASS/ACCEPT**、task-45 **PASS/ACCEPT WITH CAVEATS**、**task-47 PASS/ACCEPT**、**task-48 PASS/ACCEPT**、**task-49 PASS**(发布基线 `dfb255da…`);`ws-s6`(200 行)与 `ws-release-verify`(214 行)**均已落盘并已入表**。详见根 `计划表.md` §六十二–§七十一。
1545
+
1546
+ ---
1547
+
1548
+ ## 三十一 · 发布就绪与 **1.9.1 已发布**(2026-10-30 02:45)· 只写当前决定
1549
+
1550
+ > 逐项证据见根 `计划表.md` §六十三 / §六十六 / §六十七 / §六十八 / §七十。
1551
+
1552
+ ### 31.1 定稿:**1.9.1 已发布成功**
1553
+
1554
+ | 步 | 结果 |
1555
+ |---|---|
1556
+ | `npm publish` | **exit 0**,未遇 OTP |
1557
+ | registry | **`1.9.1` 可见**;**`dist.shasum = `dfb255da9d48b0785efd40d8c32b69b9e8ce6447`**、integrity `sha512-KwHekUYQ…` **与 task-49 基线一致**;`dist-tags.latest = 1.9.1` |
1558
+ | commit / push | `571a994e1bce6181bc4b34e0893f44c727af1cd6`;`053a98a..571a994` exit 0 |
1559
+ | tag / Release | annotated **`v1.9.1` → `571a994`** 已 push;Release 已建 |
1560
+
1561
+ ### 31.2 定稿:发布门禁的四条硬线(G1–G4)
1562
+
1563
+ | 门 | 结果 |
1564
+ |---|---|
1565
+ | **G1** | `node test/run.mjs` **316 passed / 0 failed(24 文件)** |
1566
+ | **G2** | `verify-install` **16/16** |
1567
+ | **G3** | `check-maintenance` —— **publish 前 5 通过/1 失败(缺 tag,exit 1)→ 打 tag 后 6 通过/0 失败(exit 0)** |
1568
+ | **G4** | `npm pack` **61 文件 / 407,712 B(unpacked 1,035,272 B)/ shasum `dfb255da…`** |
1569
+
1570
+ **⇒ 定稿纪律(G3 的教训):「红灯在发布前」有两种 —— 一种是真缺陷,一种是「顺序依赖的必然」。区分办法是问「这个红灯会在哪个动作之后自然消失」。** G3 消失于 tag;「缺 CHANGELOG 节」这类不会自己消失,那才是真缺陷。
1571
+
1572
+ ### 31.3 定稿:五项 V 系列处置
1573
+
1574
+ | 项 | 决定 |
1575
+ |---|---|
1576
+ | **V4** `docs/方案-持续优化.md` → `../计划表.md` 包内死链 | ✅ **已修**(改为纯文本引用;复扫包内 14 个 md:**真实死链 0 条**) |
1577
+ | **V5** `HANDOFF.md` 过期 | **单独立项**(只改两行会「看起来新」的误导,见 §31.5) |
1578
+ | **V8** `files` 排除维护侧材料 | **本轮不改**(1.9.1 保持现包形态,62.3% 维护材料被接受) |
1579
+ | **V9** 补 `v1.9.0` tag | **不补** |
1580
+ | **V10** | 不阻断 |
1581
+
1582
+ ### 31.4 定稿:C-13 与测试完整性的收口
1583
+
1584
+ - **C-13** 三轨全过:implementer 12 项自测 → **install 只读复核 6/6 变异真红** → **reviewer task-47 PASS/ACCEPT**(`--strict` **133 checked/15 failed/exit 1**;带豁免 **0 failed/applied 17/entries 17/exit 0**;6 类反例全过)。
1585
+ - **测试完整性**:`selfloop` 假绿已改显式断言(删 WORKING 必红)、**L4/L5 裁决现被 ledger/markers 双测试覆盖**(改裁决必红)、**24 文件 194 用例 0 零断言/0 早退/0 skip**。
1586
+
1587
+ ### 31.5 定稿:本文件自身的两条已知问题(诚实登记)
1588
+
1589
+ 1. **`HANDOFF.md` 整体过期**(顶部仍是 v1.3.5 的紧急提示)⇒ **只改两行会制造「看起来新」的误导**,须整篇重写(单独立项)。
1590
+ 2. **`docs/` 占包内容 62.3%** ⇒ **本文件的任何一行都改变发布包**(§三十二)。
1591
+
1592
+ ---
1593
+
1594
+ ## 三十二 · **冻结期与「基线先于写入」的顺序错误**(2026-10-30 02:4x)· 只写当前决定
1595
+
1596
+ ### 32.1 事故(**这不再是事故,是已固化的流程教训**)
1597
+
1598
+ `ws-release-exec` 提 **V4**(包内死链)→ lead 判「交 scribe」→ **我按最小修复改了 `docs/方案-持续优化.md:254` 一行** → **该文件在 npm `files` 内 ⇒ 包内容变了** → **`npm pack` shasum 从 `e9be1e2d…` 变了** → **task-24 刚出的 G4 基线立刻作废** → 新建 **task-49 re-gate**。
1599
+
1600
+ **⇒ 定性:修复本身是对的,错的是时机。这不算「改错」,算「顺序错」。**
1601
+
1602
+ ### 32.2 定稿:发布冻结令的正确顺序(**两步,不可颠倒**)
1603
+
1604
+ 1. **先冻结写入面**(列出 `files` 内的全部可写文件并锁死)
1605
+ 2. **再打基线**(`npm pack` / 全树指纹)
1606
+
1607
+ **⇒ 「冻结令不写清『哪些文件在包内』就等于没冻结」。** 本次是「先打基线、后改包内文档」,自己把基线作废了。
1608
+
1609
+ ### 32.3 定稿:冻结期的写入面划分
1610
+
1611
+ | 面 | 处置 |
1612
+ |---|---|
1613
+ | `files` 内(`src` / `lib` / `scripts` / `docs` / `evidence` / `CHANGELOG` / `QUICKSTART` / `LICENSE`) | ⛔ **冻结** —— 改一行就作废基线 |
1614
+ | **仓库根 `计划表.md`**(不在 `files`) | ✅ **可写** —— 冻结期所有记录写这里 |
1615
+ | `tmp/dsh-gokifu-compact/scribe-buffer/` | ✅ 可写 —— 待并入内容先缓冲 |
1616
+
1617
+ ### 32.4 定稿:re-gate 的验收手法(**可复用**)
1618
+
1619
+ **不只看 shasum 变没变,要看「文件数 / 体积差」是否与「声称的改动量」吻合。**
1620
+
1621
+ | 指标 | task-24(旧) | task-49(新) | 变化 |
1622
+ |---|---:|---:|---|
1623
+ | entryCount | 61 | 61 | **0** |
1624
+ | unpackedSize | 1,034,996 | **1,035,272** | **+276 B** |
1625
+ | tarball | 407,580 | **407,712** | **+132 B** |
1626
+
1627
+ ⇒ **两个体积增量与「一行文本从链接改成纯文本」同量级** ⇒ **反证无其他成分混入包**。若差几十 KB,就说明有未承认的改动。
1628
+
1629
+ ### 32.5 定稿:全树指纹 START == END(最强的时间窗口证据)
1630
+
1631
+ task-49 用 `sha256( src/*.mjs + lib/*.js + scripts/*.mjs + package.json + README + CHANGELOG + .gitignore + **docs/*.md** + test/*.mjs )` = **`21ac4459…`**,门禁开始与结束**两次完全一致**;`git status` 计数 **42 == 42**。
1632
+ **⇒ 它同时覆盖 `docs/*.md`,正好能抓到「文档被改」这类问题。建议以后所有门禁都按这个做法。**
1633
+
1634
+ ### 32.6 定稿:发布后纪律
1635
+
1636
+ - **发布已完成 ⇒ 本文件恢复可写**(lead 明确授权)。
1637
+ - **但每次再发布(1.9.2 / 1.10.x)前必须重走「冻结 → 打基线 → re-gate」。**
1638
+ - **写前按最新的树基线记录** —— 发布后 docs 写入不再影响已发布包,**但会影响下一次发布的基线**。
1639
+
1640
+ ### 32.7 本节边界
1641
+
1642
+ - 只记录决定与教训;**不含新测量**。
1643
+ - 只记录决定与教训;**不含新测量**。
1644
+ - **未验证**:task-50(发布后验收,verifier 独立做)未出结论;`npx dsh-gokifu-compact install` 到真实 profile 未执行;运行期重启未验证。
1645
+
1646
+ > ✅ **2026-10-30 03:0x 更新**:**task-50 已 PASS**(`dist.shasum` 逐位相同、tag annotated 三处 commit 一致、空目录 `npm pack` 解包 61 文件/407,712 B/sha1 相同、清单双向 `only-in` 为空、解包后 `doctor` 错误 0/警告 1/exit 0)。详见根 `计划表.md` §七十五。
1647
+
1648
+ ---
1649
+
1650
+ ## 三十三 · 1.9.2 工作定稿:P3 / P4 / P5 / P6 与一条**契约变化**(2026-10-30 03:0x)· 只写当前决定
1651
+
1652
+ > 逐项证据见根 `计划表.md` §七十四 / §七十六–§八十四。**本节只写决定与必须落地的约定。**
1653
+
1654
+ ### 33.1 定稿:已验收的切片(1.9.2 累计)
1655
+
1656
+ | 切片 | 结论 | 关键数字 |
1657
+ |---|---|---|
1658
+ | **P2 索引化**(task-38) | ✅ 已验收(task-48) | `renderIndexMd` 133/133、`renderNodeMd` 7843/7843 逐字节;5000 边 **3506.8→4.26 ms** |
1659
+ | **P4 首屏 state 缓存**(task-40) | ✅ 已验收(task-52) | warm p50 **124.4 → 9.3 ms**、cold **158 → 90.8 ms**、`state` **3648 B 逐字相同**;**同 size 只改 mtime 必失效** |
1660
+ | **P3 增量落盘**(task-39) | ✅ 已验收(task-51) | 写放大 **×80.16→37.41 / ×70.04→33.31 / ×61.75→30.75**;fold 后 flush ≤**95.3 ms**(100 dirty);**崩溃探针 5 项全过** |
1661
+ | **P5 token 预算三态**(task-41) | 执行方完成(待 task-54) | 生产口径 **24/133 新增 0**、avg **+13.95(≤+20)**;`fallback none 109 / over-budget 24 / impossible 0` |
1662
+ | **P6 悬空边**(task-30) | 设计已交付(P6-A 待 task-56 实施) | `to=null` **5,567 / 18,038(30.9%)**;**A 方案零风险** |
1663
+
1664
+ ### 33.2 🔴 定稿(**最重要**):**`graph.json` 的语义变了,必须写进维护文档**
1665
+
1666
+ **P3 落地后:`graph.json` 不再是「最新状态」,而是「上一回合基线 + 当前增量(`graph.delta.jsonl`)」。**
1667
+ ⇒ **它在回合内落后一回合。**
1668
+ **⇒ 任何直接读 `graph.json` 的外部工具会少一回合的数据。**
1669
+
1670
+ **必须落地的约定**:
1671
+ 1. **维护文档 / README 必须写明**:读取最新状态请走加载器(会合并增量),**不要直接 `JSON.parse(graph.json)` 当最新**。
1672
+ 2. **新增脚本若要读图,先确认走的是加载路径**。
1673
+ 3. **这是「行为契约变化」,不是性能优化** —— 性能收益可回滚,契约变化会影响所有下游消费者。
1674
+
1675
+ ### 33.3 定稿:三条必须保留的「余量/边界」声明
1676
+
1677
+ | # | 项 | 必须怎么写 |
1678
+ |---|---|---|
1679
+ | 1 | **写放大 ≤×50** | **只在这三张图(`e16faf2b` / `d393944b` / `5acafe42`)与「回合数 ≥10」时验证过**;**极短回合(<10 步)可能 >×50(p10=13.9)**;**全库分布未给** |
1680
+ | 2 | **fold 后 flush ≤100 ms** | **只在 `dirty ≤100` 时验证过**;**100 dirty 实测到 95.3 ms,余量仅 4.7 ms**;`dirty` 几百个会突破 |
1681
+ | 3 | **`appendFileSync` 的原子性** | **只在 Windows + 单进程崩溃场景测过**;**POSIX `O_APPEND` 的跨平台保证在 Windows 上不成立** |
1682
+
1683
+ ### 33.4 定稿:P6 的不变量(可作为通用范式)
1684
+
1685
+ ```
1686
+ residue(e) := e.to == null && (e.result !== "untested" || (now - e.ts) > STALE_MS)
1687
+ live_unsettled(e) := e.to == null && e.result === "untested" && (now - e.ts) <= STALE_MS
1688
+ STALE_MS = 10 * 60 * 1000
1689
+ ```
1690
+ **它的正确性建立在「状态的语义排他性」上(结算过的边必有终点;未结算只有 `untested` 一种合法形态),时间只是兜底。**
1691
+ **⇒ 定稿原则:凡是「清理/治理」类不变量,优先用状态语义判据,不要用「时间看起来旧」这类启发式。**
1692
+ **负向门禁**:`live_unsettled > 0` ⇒ **拒绝执行清理**。
1693
+
1694
+ ### 33.5 定稿:P6 方案选择
1695
+
1696
+ **A(保留但在分析中排除)立即做**(零风险、失败噪声 −100%、tokens −4.5%);**B(剪除)/ C(sidecar)等主人给停插件窗口** —— **要保留失败历史选 C,确认可丢选 B**。
1697
+ **优先处理 14 个 >80% 的会话**(都是 10-29 10:26 的历史会话)。
1698
+
1699
+ ### 33.6 定稿:本轮新立的口径纪律(**第 6 次「同一件事两个数」之后**)
1700
+
1701
+ | # | 量 | 两个数 | 消解维 |
1702
+ |---|---|---|---|
1703
+ | 1 | HEAD 生产口径 avg | 422.77 / 427.18 / 428.62 / 428.86 / 429.77 | **快照指纹** |
1704
+ | 2 | S2a 边际 token | +57.8 / +1.15 / +4.35 | **`treeDir` 口径** |
1705
+ | 3 | 全量 passed/failed | 245/11 … 354/0 | **时点 + 窗口稳定性** |
1706
+ | 4 | tewari 调用次数 | 3523 / 2459 | **插桩 vs 结构推导** |
1707
+ | 5 | S2b 计数 | 11,172/11,205;1,182/2,590 | **口径未统一(待定)** |
1708
+ | **6** | **悬空率** | **46.8% / 30.9%** | **分母(11,907 → 18,038)** |
1709
+
1710
+ **⇒ 第 6 条最危险:比例类指标会被分母漂移伪造成「改善」。**
1711
+ **⇒ 定稿纪律(最终版):任何计数/比例指标,报告里必须自带一行「定义式 + 分子 + 分母 + 时点」**,缺任一维视为不可引用。
1712
+
1713
+ ### 33.7 🔴 定稿:**1.9.2 不得带死开关**(lead 2026-10-30 03:0x 令;主表 P7-1 / task-58)
1714
+
1715
+ **「死开关」= 造出来了、但没有消费者的可配置项 / 状态字段 / 指标。**
1716
+ **本会话在 1.9.2 里出现了两次**:
1717
+
1718
+ | 次 | 实例 | 形态 |
1719
+ |---|---|---|
1720
+ | 1 | **P5**(task-41) | `fallback` / `overBudgetBy` / `budgetMax` **没有任何消费者**,只存在于 `renderLedger` 返回值与测试里 ⇒ **「不静默超预算」只完成可观测的一半** |
1721
+ | 2 | **P6a**(task-46) | **`traceRoot` 可配置但没有上游传值** ⇒ 生产走默认 `""`,**开关没拨** |
1722
+
1723
+ **⇒ 定稿(写死):1.9.2 不得带任何死开关。**
1724
+ **⇒ 验收硬要求(两条,缺一不可)**:
1725
+ 1. **每个新增的可配置项 / 状态字段 / 指标,验收必须写明「谁消费它」** —— 写不出消费者就不许进验收。
1726
+ 2. **必须有一条负向测试**:**不消费时测试必须红**(`traceRoot` 退回 `""` 必红、去掉 `fallback` 消费必红)。
1727
+
1728
+ **⇒ task-58(P7,blocked_by task-56)就是这条的执行项**:
1729
+ ① `engine` 传 `traceRoot:"sessions"`;② `engine` 消费 `fallback`(over-budget 日志/指标含 `overBudgetBy`,`impossible` 走 error);③ `doctor`/health 显示 `fallback` 分布与最大 `overBudgetBy`;④ 两条负向测试。
1730
+
1731
+ **📌 为什么「死开关」比「没造」更危险**:**它会让下一个读代码的人以为问题已解决** —— 一个存在但无人消费的 `fallback` 字段,**在验收单上和在代码里都「看起来完成了」**。
1732
+ **验收语(Lead 定):「造了仪表盘必须有人看」。**
1733
+
1734
+ ### 33.8 本节边界
1735
+
1736
+ - 只记录决定;**不含新测量**。
1737
+ - **未验证**:P5 的 `fallback` 是否有下游消费者(报告自认「未消费」);`impossible` 真实触发(0/133,且复核指出代码不可达);P6 的 B/C 未实施;**`traceRoot` 的运行期传值(task-58 之前一直未传)**;运行期收益全部未验证(贯穿全篇的同一项)。
1738
+
1739
+ ---
1740
+
1741
+ ## 三十四 · **1.9.2 发布前冻结顺序与验收清单**(2026-10-30 03:1x 定稿)
1742
+
1743
+ > 本节的顺序**不可颠倒**(教训来自 1.9.1:先打基线后改包内文档 ⇒ 基线作废,见 §三十二)。
1744
+
1745
+ ### 34.1 冻结线内容(**进 1.9.2 的切片**)
1746
+
1747
+ | 切片 | task | 状态 |
1748
+ |---|---|---|
1749
+ | **P3 增量落盘** | task-39 | ✅ 已验收(task-51) |
1750
+ | **P4 首屏 `state` 缓存** | task-40 | ✅ 已验收(task-52) |
1751
+ | **P5 token 预算三态** | task-41 | ✅ 已验收(task-54,有保留) |
1752
+ | **P6a TRACE 相对** | task-46 | ✅ 已验收(task-55,有保留) |
1753
+ | **P6-A 悬空边分析排除** | task-56 | 执行方完成 · **待 task-57 复核** |
1754
+ | **P7 死开关接线** | task-58 | 执行方完成 · **待 task-60 复核** |
1755
+ | **S2b no-exit 收窄** | task-27 | ✅ 已验收(task-53,有保留) |
1756
+
1757
+ ### 34.2 **明确不进 1.9.2 的**(写死,防止被临时加回来)
1758
+
1759
+ | 项 | 理由 |
1760
+ |---|---|
1761
+ | **task-59(`addUserNode` 返回语义,技术债)** | **低优先级、不挡发布**;它是「API 形状」问题,适合单独一轮改 |
1762
+ | **P6 的 B / C 方案(剪除 / sidecar 归档 5,567 条悬空边)** | **需停插件窗口 + 主人授权**;B 还会不可逆丢失 268 条失败边 |
1763
+ | **S1b(清理 2 张历史自环图)** | 同上,需停插件窗口 |
1764
+ | **`files` 瘦身(V8)** | 1.9.2 不动包形态,避免又一次基线作废 |
1765
+ | **`HANDOFF.md` 重写(V5)** | 单独立项(整篇重写,非改两行) |
1766
+
1767
+ ### 34.3 冻结顺序(**五步,必须按序**)
1768
+
1769
+ | 步 | 动作 | 为什么在这一步 |
1770
+ |---|---|---|
1771
+ | **1** | **等 task-57(P6-A 复核)与 task-60(P7 复核)双双 PASS** | 冻结线里最后两个未复核项;**复核未过就冻,冻的是不合格的树** |
1772
+ | **2** | **列出 `files` 内的全部可写面并锁死**(docs / evidence / src / lib / scripts / CHANGELOG / README / QUICKSTART / LICENSE) | **先冻面** —— 否则任何人改一行包内文件就作废基线 |
1773
+ | **3** | **出全树指纹**:`sha256(src/*.mjs + lib/*.js + scripts/*.mjs + package.json + README.md + CHANGELOG.md + .gitignore + docs/*.md + test/*.mjs)` | 沿用 task-49 §9.1 做法(**该指纹同时覆盖 `docs/*.md`,能抓「文档被改」**) |
1774
+ | **4** | **打基线**:`npm pack --dry-run --json` → 记 **entryCount / unpackedSize / size / shasum**,并逐文件记 sha256 | 基线只能在面锁死之后打 |
1775
+ | **5** | **re-gate**:G1 全量 / G2 `verify-install` / G3 `check-maintenance`(**publish 前必然红,属顺序问题**)/ G4 pack;**门禁 START==END 全树指纹一致** | 证「窗口内无人写盘」 |
1776
+
1777
+ ### 34.4 验收清单(**逐项打勾才许 publish**)
1778
+
1779
+ **A · 功能与测试**
1780
+ - [ ] 全量测试 **0 failed**(**稳定窗口**:无 teammate 在写 `src/`/`test/`;门禁前后全树指纹一致)
1781
+ - [ ] `verify-install` **16/16**
1782
+ - [ ] `doctor` **错误 0**(警告数记录在案)
1783
+ - [ ] 每个切片**至少一个变异体真红**(已各自在报告里给出,复核时确认)
1784
+
1785
+ **B · 语义与契约**
1786
+ - [ ] **`graph.json` 契约变化已进 README**(「上一回合基线 + 当前增量,回合内落后一回合,外部工具不得直接当最新」)
1787
+ - [ ] **无死开关**:`traceRoot` 有 engine 调用点、`fallback` 有消费者、`doctor` 能显分布(task-58 / task-60)
1788
+ - [ ] `renderFacts` 与基线一致(P6-A 除外,其改动有单独验收)
1789
+ - [ ] 生产口径:**超预算新增 0**、max 不增、avgDelta ≤ 上限;**CUR-only = 0**
1790
+
1791
+ **C · 包与发布物**
1792
+ - [ ] `npm pack` **61 文件**(若文件数变化须解释)
1793
+ - [ ] 包内 **`tmp/` 0、`test/` 0、密钥 0**
1794
+ - [ ] **包内死链 0**(口径:剥掉 ``` 围栏与 `行内代码` 后只匹配真 markdown 链接)
1795
+ - [ ] 版本一致性:`package.json` / `CHANGELOG` 顶部 / `README` 版本行 / npm latest / git tag 五处对齐
1796
+
1797
+ **D · git 与发布顺序**
1798
+ - [ ] `HEAD..origin/main = 0`(发布提交建立在 origin/main 之上)
1799
+ - [ ] 无敏感路径(`grep -iE 'key|token|secret|.env|credential'` = 0)
1800
+ - [ ] **顺序:commit → push → tag → publish → Release**(或明确把 G3 定义为 post-publish 复验)
1801
+
1802
+ ### 34.5 记帐纪律(每轮都必须执行)
1803
+
1804
+ 1. **数字必须带时点 + 批次**(`347/0` 与 `354/0` 与 `369/0` 与 `373/0` 都是真的,差的是窗口)。
1805
+ 2. **跨批不可比**:HEAD 的绝对 avg / over 会随图库增长漂移,**只有「同快照净增」是稳定判据**。
1806
+ 3. **双 sha**:被审版本与验收版本可能不同(如 P6a 的 `96b0bbce` vs 当前 `d71a1dab`),**报告必须写清锁哪一个**。
1807
+ 4. **每个 task 完成当轮回填主表状态列** —— 否则账本从「索引」退化为「笔记」。
1808
+
1809
+ ### 34.6 本节边界
1810
+
1811
+ - 只写顺序与清单;**不含新测量**。
1812
+ - **未验证**:task-57 / task-60 结论未出;冻结线的最终文件指纹与 shasum **必须届时现打**(本节故意不写具体数值,避免过期误导)。
1813
+
1814
+ > ✅ **2026-10-30 03:2x 全部解**:task-57(P6-A)与 task-60(P7)**均 PASS** ⇒ 冻结线全部复核点已过;**1.9.2 已发布**。详见下方 §三十五。
1815
+
1816
+ ---
1817
+
1818
+ ## 三十五 · ✅ **1.9.2 已发布定稿**(2026-10-30 03:22:55)· 只写事实与契约
1819
+
1820
+ > 逐项证据见根 `计划表.md` §九十六 / §九十七 与 `ws-release-1.9.2/REPORT.md`。
1821
+
1822
+ ### 35.1 发布事实
1823
+
1824
+ | 项 | 值 |
1825
+ |---|---|
1826
+ | **commit** | **`70b66ad1d0242ef580e9388705e03f7c3af7d4f6`**(24 文件;无 `tmp/`·`.harness`·`.engine-under-test`) |
1827
+ | **tag** | **`v1.9.2`**(annotated)→ `70b66ad` = `origin/main`;远端 tag 对象 `fe46cdbf…` |
1828
+ | **npm** | `dsh-gokifu-compact@1.9.2` · **shasum `6569803c47429cee2c906130a70b74b1f09522d4`** |
1829
+ | **包** | **61 文件 / 435,709 B / unpacked 1,108,665 B** · `latest = 1.9.2` |
1830
+ | **GitHub Release** | `https://github.com/MYCF711/dsh-GOkifu-compact/releases/tag/v1.9.2` |
1831
+ | **全树指纹** | **`902ddd58adf3282cb075b5ff14d733cc9f943281f3cd9cfb61c18fdadc2b5831`** |
1832
+
1833
+ **门禁**:G1 **373/0(30 文件)** · G2 **16/16** · G3 6/0/0 · G3b doctor 错误 0 / 警告 2 · G4 **61 文件**。**冻结副本 ↔ commit 后重打 `MATCH`**。
1834
+
1835
+ **冻结线内容**:P3 / P4 / P5 / P6a / P6-A / P7 / S2b(**不含 task-59,不含 P6 B/C**)。
1836
+
1837
+ ### 35.2 🔴 `graph.json` 契约变化(**外部工具必读**,已进 README + CHANGELOG)
1838
+
1839
+ 1. **`graph.json` = 上一回合基线的完整快照**;**`graph.json.delta.jsonl` = 本回合增量帧**(一帧一行 `<baseHash16>\t<checksum31>\t<json>`);
1840
+ 2. **回合内落后一回合** —— `graph.json` 只在**回合边界(`agent/status idle`)**落一次;**直接 `JSON.parse(graph.json)` 当「最新」会少一回合数据**;
1841
+ 3. **正确读法**:`fromJSON` → `decodeDeltaFrames(delta, baseHash)` → 逐帧 `applyDelta`(三函数在 `src/graph.mjs`,随包发布)。
1842
+
1843
+ **⇒ 这是「行为契约变化」而非纯性能优化:性能收益可回滚,契约变化影响所有下游消费者。**
1844
+
1845
+ ### 35.3 三条必须与契约一起引用的**余量**
1846
+
1847
+ | # | 余量 |
1848
+ |---|---|
1849
+ | 1 | **短回合(<10 步,p10 = 13.9)写放大仍可能 >×50** |
1850
+ | 2 | **`dirty > 100` 时 fold 后 flush ≈ 87–89 ms**(余量很小) |
1851
+ | 3 | **`appendFileSync` 跨平台(尤其网络文件系统)原子性未验证** |
1852
+
1853
+ ### 35.4 ✅ **`impossible` 口径三句**(此后引用必须三句齐全)
1854
+
1855
+ 1. **真实库分布**:**0 / 133**;
1856
+ 2. **夹具可产出**:**是**(task-60 临时 home 实测 **1 次**,doctor 显示 `none=3 / over-budget=2 / impossible=1`);
1857
+ 3. **「不可达」只在「真实数据形态」范围内成立** —— 不能写成「代码里不可能」。
1858
+
1859
+ ### 35.5 🔴 **第二个打包阻断**(本轮最有价值的工程发现)
1860
+
1861
+ **`src/.engine-under-test-p3.mjs`(57,914 B,P3 测试替身)会被打进 npm 包** —— 因为 `files` 里的 `"!src/.engine-under-test.mjs"` 是**精确文件名**,不匹配 `-p3` 后缀;而 **`.gitignore` 只管 git,不管 `npm pack`**。
1862
+ **修复**:`files` 增补 **`"!src/.engine-under-test-*.mjs"`** ⇒ **entryCount 62 → 61**。
1863
+
1864
+ **⇒ 定稿纪律:「git 忽略 ≠ npm 忽略」—— 两套机制互相独立。任何 `src/`/`test/` 下的替身或夹具文件必须同时在 `files` 里排除,且用通配符而非精确名。**
1865
+
1866
+ ### 35.6 冻结面最终 sha(**1.9.3 / 2.0 必须重打基线**)
1867
+
1868
+ ```
1869
+ README.md 03:21:41 14,351 B facdb92050806aa4…
1870
+ CHANGELOG.md 03:21:41 74,894 B 04c6949e907d3957…
1871
+ package.json 03:20:43 2,293 B d77519df2d6a8e01…
1872
+ docs/方案-持续优化.md 03:18:43 151,971 B 6d250f21582ff4b1…
1873
+ docs/草稿-持续优化.md 02:47:58 97,028 B 4955d4f7144c7e24…
1874
+ docs/计划表.md 01:47:25 3,114 B fed9cbc1a194365b…
1875
+ QUICKSTART.md 01:47:37 4,953 B b6c32c6e9cf60fc2…
1876
+ 发布包 shasum:6569803c… 全树指纹:902ddd58…
1877
+ ```
1878
+
1879
+ **⚠ 本文件(方案)每次被写都会产生新 sha ⇒ 下一次发布的基线只能在「届时冻结之后」重打,`6569803c` / `902ddd58` / 上列文档 sha 一律不能复用。**
1880
+
1881
+ ### 35.7 本节边界
1882
+
1883
+ - 只写事实与契约;**不含新测量**。
1884
+ - **未验证**:Release 正文内容;`git archive` 与工作树包差异(`01e358e1…` / 435,440 B)的完整成因;运行期收益(贯穿全篇的同一项)。