@a9i5k4/dsh-auto-memory 3.0.0 → 3.1.0
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/README.md +30 -13
- package/README.zh-CN.md +30 -13
- package/docs/FRONTEND-CO-CREATION.md +191 -0
- package/docs/GM53-HOMEPAGE-PROMPT.md +323 -0
- package/docs/HANDBOOK.md +88 -52
- package/docs/HOMEPAGE-CONTENT-FOR-GM53.md +299 -0
- package/docs/PROMO-PROMPT-3.0.md +100 -0
- package/docs/USER-GUIDE.en.md +11 -11
- package/docs/USER-GUIDE.zh-CN.md +11 -11
- package/docs/WHITEPAPER.md +207 -0
- package/docs/screenshots/promo/promo-0-banner-v3.png +0 -0
- package/docs/screenshots/promo/promo-0-banner-v4.png +0 -0
- package/docs/screenshots/promo/promo-1b-auto-recall.png +0 -0
- package/lib/activation-host.js +69 -10
- package/lib/board-mode.js +1 -1
- package/lib/client.js +1697 -285
- package/lib/config-io.js +156 -0
- package/lib/context-bridge.js +3 -0
- package/lib/context-host.js +23 -10
- package/lib/degrade.js +385 -0
- package/lib/dsh-home.js +143 -0
- package/lib/episodic-store.js +142 -18
- package/lib/evidence-store.js +8 -1
- package/lib/fact-store.js +484 -43
- package/lib/hub-io.js +217 -0
- package/lib/index-sync.js +13 -1
- package/lib/index.js +1730 -202
- package/lib/intent-clean-safe.js +258 -40
- package/lib/l0-extract.js +231 -16
- package/lib/m4-corpus.js +8 -2
- package/lib/m7-index-sync-host.js +8 -1
- package/lib/memory-envelope.js +6 -1
- package/lib/memory-hub.js +164 -17
- package/lib/memory-index.js +4 -2
- package/lib/note-status-apply.js +118 -0
- package/lib/note-status.js +204 -0
- package/lib/procedure-store.js +333 -31
- package/lib/procedure-switch.js +38 -0
- package/lib/python-sidecar-client.js +314 -11
- package/lib/recall-fusion.js +83 -12
- package/lib/rules-edit.js +159 -0
- package/lib/semantic-decide.js +41 -8
- package/lib/semantic-js.js +51 -6
- package/lib/shadow-host.js +3 -5
- package/lib/skill-export-host.js +153 -0
- package/lib/skill-export.js +239 -0
- package/lib/storage-manage.js +6 -0
- package/lib/temporal-parse.js +191 -159
- package/lib/tier0-catalog.js +45 -3
- package/lib/wb-contract.js +198 -2
- package/lib/wb-sidecar.js +54 -3
- package/package.json +6 -2
- package/docs/internal/ACCEPT-35-LIVE.md +0 -143
- package/docs/internal/ACCEPTANCE-20260914.md +0 -90
- package/docs/internal/ARCH-REVIEW-BRIEF.md +0 -411
- package/docs/internal/ARCH-REVIEW-REQUEST.md +0 -201
- package/docs/internal/ARCH-REVIEW-ROUND2.md +0 -169
- package/docs/internal/ARCH-REVIEW-ROUND3.md +0 -206
- package/docs/internal/ART-DIRECTION-WIREFRAME.md +0 -181
- package/docs/internal/AUDIT-WB-GRAPH-FULL-20260916.md +0 -314
- package/docs/internal/CONCURRENCY-INVESTIGATION-20260917.md +0 -192
- package/docs/internal/CROSS-SESSION-SEARCH-PATH-DECISION.md +0 -72
- package/docs/internal/CROSS-SESSION-SEARCH-RESEARCH.md +0 -131
- package/docs/internal/CUA-VISION-FIX-NOTES.md +0 -78
- package/docs/internal/DECISIONS-20260914-SESSION.md +0 -269
- package/docs/internal/DESIGN-OVERHAUL-PRE-RESEARCH.md +0 -292
- package/docs/internal/DESIGN-P1-STATE-COMMIT-20260915.md +0 -219
- package/docs/internal/DIRECTION-CHECK-WB-GRAPH-20260916.md +0 -132
- package/docs/internal/FEEDBACK-TO-DSHAPI-RELAY.md +0 -13
- package/docs/internal/GH-DISCUSSION-5732-COMMENT.md +0 -74
- package/docs/internal/GPT-ACCEPTANCE-PROMPT-20260916.md +0 -352
- package/docs/internal/GPT-REVIEW-PROMPT.md +0 -216
- package/docs/internal/GROUP-DIGEST-SETUP.md +0 -62
- package/docs/internal/GROUP-LISTENER-SETUP.md +0 -49
- package/docs/internal/GROUP-WEBHOOK-SETUP.md +0 -93
- package/docs/internal/HANDOFF-TO-ZCODE.md +0 -168
- package/docs/internal/KICKOFF-P0.md +0 -254
- package/docs/internal/MASTER-PLAN-3.0.md +0 -411
- package/docs/internal/MEMORY-MUTATION-AND-INDEX-DESIGN.md +0 -85
- package/docs/internal/MERGE-CONFLICT-SCAN-20260914.md +0 -222
- package/docs/internal/NEXT-VERSION-TODO.md +0 -95
- package/docs/internal/OFFICIAL-DISCUSSION-DRAFT.md +0 -80
- package/docs/internal/PENDING-FIXES-20260916.md +0 -289
- package/docs/internal/RAG-KARPATHY-PROGRAM.md +0 -229
- package/docs/internal/RELEASE-PROCESS.md +0 -99
- package/docs/internal/REPORT-P0-NIGHTLY.md +0 -212
- package/docs/internal/REPORT-P5-ACCEPTANCE.md +0 -31
- package/docs/internal/REPORT-WB-GRAPH-NIGHTLY.md +0 -153
- package/docs/internal/REVIEW-WB-GRAPH-SELF.md +0 -81
- package/docs/internal/ROADMAP-20260917-WEEK.md +0 -305
- package/docs/internal/ROADMAP.md +0 -106
- package/docs/internal/RUN-P0-NIGHTLY.md +0 -227
- package/docs/internal/S10-CONSTRUCTION-HANDOFF-20260917.md +0 -175
- package/docs/internal/S10-GAPS-PLAIN-20260917.md +0 -125
- package/docs/internal/SEMANTIC-ARCHITECTURE-SPEC.md +0 -360
- package/docs/internal/SESSION-FILE-REPAIR-PROTOCOL.md +0 -90
- package/docs/internal/SUBAGENT-REPORT-ROUTING-PRE-RESEARCH.md +0 -261
- package/docs/internal/THREE-LAYER-CONTRACT.md +0 -210
- package/docs/internal/TODO-BACKLOG.md +0 -263
- package/docs/internal/TODO-GRAPH.html +0 -715
- package/docs/internal/TODO-GRAPH.html.bak-20260914-v2 +0 -493
- package/docs/internal/TODO-GRAPH.html.bak-20260915-alsfix +0 -710
- package/docs/internal/TODO-GRAPH.html.bak-20260915-p1 +0 -710
- package/docs/internal/TODO-GRAPH.html.bak-20260915-p6a-rev +0 -703
- package/docs/internal/TODO-GRAPH.html.bak-20260915-wshint +0 -710
- package/docs/internal/TODO-GRAPH.html.bak-20260916-batch +0 -715
- package/docs/internal/WB-FORMAT-CONVENTION.md +0 -112
- package/docs/internal/WB-GRAPH-DECISIONS-20260914.md +0 -71
- package/docs/internal/WB-GRAPH-INTEGRATION-PLAN.md +0 -386
- package/docs/internal/WB-GRAPH-RESEARCH-BRIEF.md +0 -118
- package/docs/internal/WB-GRAPH-RESEARCH-EXTERNAL.md +0 -228
- package/docs/internal/WB-GRAPH-RESEARCH-LOCAL.md +0 -190
- package/docs/internal/reviews/CLAIM-VERIFICATION-20260914.md +0 -56
- package/docs/internal/reviews/PLAN-gpt6astra-round2-20260914.md +0 -787
- package/docs/internal/reviews/REVIEW-gpt6astra-20260914.md +0 -112
- package/docs/internal/reviews/ROUND3-REVIEW-INTEGRATION-20260914.md +0 -230
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# dsh-auto-memory 白皮书
|
|
2
|
+
|
|
3
|
+
> **版本**:3.0.0 · **日期**:2026-09-20 · **许可**:BSD-3-Clause
|
|
4
|
+
>
|
|
5
|
+
> **本文是什么**:一份**约束性文档**。它把「这个插件到底建了什么、它有哪些已知边界」
|
|
6
|
+
> 讲清楚,并把一条**核心不变量**显式成文——因为**约束不落纸,就一定会再被违反一次**。
|
|
7
|
+
>
|
|
8
|
+
> **本文不是什么**:不是宣传材料(宣传看 README),不是 API 文档(看 `FEATURE-INVENTORY.md`),
|
|
9
|
+
> 不是论文(看 `M7-RESEARCH-PAPER.md`)。
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 0. 一句话
|
|
14
|
+
|
|
15
|
+
> **同一份记忆字节,同时喂给三个消费者。任何一处写入,都要同时满足三套约束。**
|
|
16
|
+
|
|
17
|
+
这是本插件全部工程复杂度的来源,也是历史上绝大多数 bug 的来源。
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 1. 核心不变量
|
|
22
|
+
|
|
23
|
+
### 1.1 三个消费者
|
|
24
|
+
|
|
25
|
+
记忆在磁盘上是纯 Markdown 明文。但同一份字节被三个**语义不同**的消费方读取:
|
|
26
|
+
|
|
27
|
+
| # | 消费者 | 怎么读 | 对字节的要求 |
|
|
28
|
+
|---|---|---|---|
|
|
29
|
+
| ① | **注入面** | 每轮自动注入进上下文 | 必须**干净、短、有结构**;乱码与超长行会污染上下文 |
|
|
30
|
+
| ② | **检索面** | 词法 + 语义双路召回 | 必须有**可切分的锚点结构**;锚点被破坏则召回精度下降 |
|
|
31
|
+
| ③ | **语义面** | digest 供语义模型编码 | 必须**可重复生成**;同一输入必须产出同一 digest |
|
|
32
|
+
|
|
33
|
+
### 1.2 约束
|
|
34
|
+
|
|
35
|
+
> **一处写入,三处生效。** 写入方必须同时保证:
|
|
36
|
+
> 1. 注入面拿到的字节在**预算内且无污染**;
|
|
37
|
+
> 2. 检索面能按锚点**正确切条**;
|
|
38
|
+
> 3. 语义面的 digest 能**正确失效并重建**。
|
|
39
|
+
|
|
40
|
+
### 1.3 为什么这条不变量危险
|
|
41
|
+
|
|
42
|
+
因为它**大多是静默降级**:
|
|
43
|
+
|
|
44
|
+
- 注入进了一段乱码 → 模型读到噪音,**不报错**;
|
|
45
|
+
- 锚点被写坏 → 召回少了几条,**不报错**;
|
|
46
|
+
- digest 没失效 → 语义召回用了旧向量,**不报错**。
|
|
47
|
+
|
|
48
|
+
**不爆的时候,完全看不出来。** 这就是为什么必须有一条显式约束 + 一批针对性断言。
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## 2. 一次真实事故(本不变量的代价)
|
|
53
|
+
|
|
54
|
+
这是本项目最典型的一类 bug,值得完整记录。
|
|
55
|
+
|
|
56
|
+
### 2.1 现象
|
|
57
|
+
|
|
58
|
+
用户在面板「日志」页签看到**乱码**;同时记忆文件侧也出现异常内容。
|
|
59
|
+
|
|
60
|
+
### 2.2 根因
|
|
61
|
+
|
|
62
|
+
**两条写入通路,只修了一条。**
|
|
63
|
+
|
|
64
|
+
- 该插件有**两条互不相干**的写入通路:`procedure`(技能)线与 `fact`(事实)线;
|
|
65
|
+
- 早先的清洗器只接进了 `procedure` 线;
|
|
66
|
+
- `fact` 线的三个入口(`crossFeed` 的 fact 分支 / `factCandidateFromRow` / `hubFlushTick` 的回写)**从来没有过清洗器**;
|
|
67
|
+
- 于是脏数据既进了 `facts.json`,又经回写污染了 `MEMORY.md`。
|
|
68
|
+
|
|
69
|
+
> **教训**:「修了一条通路」不等于「另一条受保护」。
|
|
70
|
+
> 只修**具名入口**是治标;把清洗**下沉到写原语**才是治本。
|
|
71
|
+
|
|
72
|
+
### 2.3 处置
|
|
73
|
+
|
|
74
|
+
- **当时**:在三个已知入口设防,补清洗器 + 新增判据族;
|
|
75
|
+
- **根治(在途)**:把 `sanitizeForWrite` 下沉到写原语(`appendText` / `writeFull`),
|
|
76
|
+
使**全部写入路径自动受保护**——不再依赖「记得给新通路接上清洗器」;
|
|
77
|
+
- 存量脏数据按**用户拍板**采用 `skip` 并留痕,**不做「清洗后照写」**。
|
|
78
|
+
|
|
79
|
+
> **为什么不做清洗后照写**:那等于悄悄改数据,并丢失「曾出现脏 fact」这一诊断事实。
|
|
80
|
+
> 本项目纪律是 **fail-soft 必须留痕、不得静默改写**。
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## 3. 系统的实际形态(截至 3.0.0)
|
|
85
|
+
|
|
86
|
+
### 3.1 规模(全部经代码自核)
|
|
87
|
+
|
|
88
|
+
| 项 | 数量 | 说明 |
|
|
89
|
+
|---|---|---|
|
|
90
|
+
| 模型工具 | **17** | 15 个基础 + 2 个条件注册(`memory_expand_pre` / `memory_trace_pre` 仅在 `boardMode=graph` 时注册) |
|
|
91
|
+
| HTTP 路由 | **49** | 全部 loopback-only;插件层外部访问返回 403,宿主层为 401——**两者都是预期行为** |
|
|
92
|
+
| 设置键 | **98** | 其中 **60** 个可在设置页写入 |
|
|
93
|
+
| 面板页签 | **12** | 概览 / 日志 / 唤起回顾 / 记忆中枢 / 存储管理 / 笔记 / 白板 / 反思 / 接续 / 日历 / 检索 / 工作区 |
|
|
94
|
+
| 插槽注册 | **6** | 侧栏入口 / 浮层面板 / 弹窗 / 接续卡 / 设置分区 / 会话页看板 |
|
|
95
|
+
| 运行时依赖 | **0** | 本插件自身不引入任何 npm 运行时依赖 |
|
|
96
|
+
| 浏览器侧 | 单文件 | `lib/client.js`,纯 ESM,**无构建步骤** |
|
|
97
|
+
|
|
98
|
+
### 3.2 两条线
|
|
99
|
+
|
|
100
|
+
- **pre 开发线**(本仓):profile 以 `link:` 挂载 ⇒ **开发树就是活的宿主代码**
|
|
101
|
+
- **REL 发布线**(`_publish_dsh-auto-memory`):发布时做 `_pre` 后缀擦除与残留闸门
|
|
102
|
+
|
|
103
|
+
> ⚠️ **「PR merge ≠ 修复落地」的结构性根源**:仓内裸名 `lib/*.js` 是历史遗留的**互引孤岛**
|
|
104
|
+
> (零活引用,唯一例外 `ws-overview-rank.js`),宿主只 import `-pre.js` 版本。
|
|
105
|
+
> **改错副本 = 改了不生效。** 这是本仓最易踩的坑,已写入约束清单。
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## 4. 已知边界(诚实清单)
|
|
110
|
+
|
|
111
|
+
### 4.1 特性默认值(★ 3.0.0 起有翻转,旧文档口径已失效)
|
|
112
|
+
|
|
113
|
+
> **警告**:本表在 3.0.0 有过一次**批量默认值翻转**。任何沿用 3.0 之前口径的文档
|
|
114
|
+
> (包括早期 README 与第三方说明)都会写错。以下数值**经代码自核**
|
|
115
|
+
> (`tools/verify-defaults.mjs` / `tools/verify-experimental.mjs`)。
|
|
116
|
+
|
|
117
|
+
| 特性 | 键 | **当前默认** | 备注 |
|
|
118
|
+
|---|---|---|---|
|
|
119
|
+
| 交接白板 + 账本 | `handoffEnabled` | **`true`(开)** | ★ 3.0.0 由 `false` **翻转为 `true`** |
|
|
120
|
+
| 白板看板(5 泳道) | `boardMode` | `'graph'` | 默认新版看板 |
|
|
121
|
+
| 水位测量窗口 | `waterLevelWindowTokens` | `0` | `0` = 自动沿用官方窗口容量 |
|
|
122
|
+
| 水位阈值 | `waterLevelThreshold` | `0.75` | — |
|
|
123
|
+
| 水位提示 | `waterLevelAdvisory` | `true` | — |
|
|
124
|
+
| 水位自动写账本 | `waterLevelAutoHandoff` | `true` | — |
|
|
125
|
+
| **自动接续** | `autoContinueEnabled` | **`false`(关)** | 与白板**已解耦**,各自独立 |
|
|
126
|
+
| 自动固化 | `autoConsolidate` | `true` | — |
|
|
127
|
+
| Tier-0 常驻目录 | `tier0CatalogEnabled` | `true` | 预算 400 tok / 占比 25% |
|
|
128
|
+
| 注入总开关 | `injectEnabled` | `true` | 预算 8000 字符 |
|
|
129
|
+
| 记忆中枢 | `memoryHubEnabled` | `true` | — |
|
|
130
|
+
| **机械流程切片** | `hubMechanicalProcedureFeedEnabled` | **`false`(关)** | T10 关停;向导内有标「不推荐」的回退开关 |
|
|
131
|
+
| 主动联想 | `associativeMemoryEnabled` | `false`(关) | 需显式开启 |
|
|
132
|
+
| 无人值守 | `unattendedMode` | `false`(关) | — |
|
|
133
|
+
| 容量上限 | `noteCapacityChars` / `userCapacityChars` | 各 **24000** | 2026-09-18 由 12000 上调 |
|
|
134
|
+
|
|
135
|
+
**白板默认翻转的理由**(代码注释原文):README 与用户手册早已对外声称「交接默认开启」,
|
|
136
|
+
而代码默认是关——**文档与实现长期不一致**;且白板/账本是 3.0 的招牌能力,
|
|
137
|
+
出厂关着等于新用户看不到它。
|
|
138
|
+
|
|
139
|
+
> **这条本身就是「约束不落纸」的又一个样本**:文档写「默认开」、代码写「默认关」,
|
|
140
|
+
> 双方各自都以为自己是权威,一直没人发现。
|
|
141
|
+
|
|
142
|
+
### 4.2 有测试、无接线
|
|
143
|
+
|
|
144
|
+
项目内发现**一套协议库三件套**(acceptance / ledger-criteria / state-commit)
|
|
145
|
+
被 smoke 测试养着,但 `index.js` **未引用**。属「有测试、无接线」——
|
|
146
|
+
留作后续整合,当前不影响功能。
|
|
147
|
+
|
|
148
|
+
### 4.3 两条路由无 UI 消费者
|
|
149
|
+
|
|
150
|
+
`/subagent-gc` 与 `/activation-inbox-pre`:**能力在、UI 未接**。
|
|
151
|
+
|
|
152
|
+
### 4.4 前端回归网极薄
|
|
153
|
+
|
|
154
|
+
146 个测试套件里,**仅 3 个**断言 React 组件行为。
|
|
155
|
+
这意味着**前端改动几乎不受回归保护**——重构前需先补特征化测试。
|
|
156
|
+
(这也是「前端交给社区共创」的前提条件之一,见 `FRONTEND-CO-CREATION.md`。)
|
|
157
|
+
|
|
158
|
+
### 4.5 授权边界
|
|
159
|
+
|
|
160
|
+
| 资产 | 许可 | 说明 |
|
|
161
|
+
|---|---|---|
|
|
162
|
+
| 本项目代码 | BSD-3-Clause | — |
|
|
163
|
+
| 角色设定「溟月」 | **CC BY-NC-SA 4.0** | 原作者 **上善无形**;**非商业 + 相同方式共享**,比代码许可更严格 |
|
|
164
|
+
| 参考项目(RhineLabUI 等) | MIT | **仅覆盖其程序代码**,不覆盖 3D 模型 / Blender 工程 / 原片素材 / 游戏品牌 |
|
|
165
|
+
|
|
166
|
+
> **角色许可与代码许可是两件独立的事,不可合并成一句「本项目采用 XX 许可」。**
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## 5. 写给后续写入者(约束清单)
|
|
171
|
+
|
|
172
|
+
任何新增**写入路径**的人(包括 AI 自己)请逐条自查:
|
|
173
|
+
|
|
174
|
+
- [ ] **三面同时满足**:注入面干净、检索面锚点完好、语义面 digest 正确失效
|
|
175
|
+
- [ ] **走写原语**:不绕过 `appendText` / `writeFull` 的校验与事务
|
|
176
|
+
- [ ] **fail-soft 必须留痕**:禁止静默吞异常(本项目有 `DEGRADE_RING` 降级台账)
|
|
177
|
+
- [ ] **不得静默改写**:脏数据 `skip` 并留痕,不要「清洗后照写」
|
|
178
|
+
- [ ] **改对副本**:`-pre.js` 才是活代码,裸名文件是孤岛
|
|
179
|
+
- [ ] **配置写入唯一出口**:`saveConfigPatch` → `POST /config`
|
|
180
|
+
- [ ] **开关解耦**:单开关不得顺带改变其它功能行为
|
|
181
|
+
- [ ] **新旧并存**:已发布的 3.0.0 有真实用户 ⇒ 必须保留开关回退路径
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## 6. 本白皮书与其它文档的分工
|
|
186
|
+
|
|
187
|
+
| 文档 | 回答什么 |
|
|
188
|
+
|---|---|
|
|
189
|
+
| **本文** | 「有哪些**不能违反**的约束、哪些**已知边界**」 |
|
|
190
|
+
| `FEATURE-INVENTORY.md` | 「有哪些功能、住在哪一行」 |
|
|
191
|
+
| `ARCHITECTURE-FOR-ZCODE-20260920.md` | 「代码结构是怎样的」 |
|
|
192
|
+
| `M7-RESEARCH-PAPER.md` | 「为什么这样设计、实验数据如何」 |
|
|
193
|
+
| `FRONTEND-CO-CREATION.md` | 「外部贡献者能改什么、怎么改」 |
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## 7. 结论
|
|
198
|
+
|
|
199
|
+
本项目的「完工」有两层含义:
|
|
200
|
+
|
|
201
|
+
- **功能层面的完工**:功能已稳定,3.0.0 已发布,全量回归 PASS。
|
|
202
|
+
- **认知层面的完工**:**本文** —— 把约束与边界写下来,让后续任何人(含 AI)
|
|
203
|
+
不必靠口口相传就能避开已知的雷。
|
|
204
|
+
|
|
205
|
+
> **约束不落纸,就一定会再被违反一次。**
|
|
206
|
+
|
|
207
|
+
这句话是本文存在的全部理由。
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/lib/activation-host.js
CHANGED
|
@@ -19,7 +19,9 @@ import {
|
|
|
19
19
|
import { createActivationInboxPre, ActivationInboxRegistry, REFERENCE_TAIL_COOLDOWN_STEPS_V1 } from './activation-inbox-state.js'
|
|
20
20
|
import { createAccessEvidencePre } from './context-bridge.js'
|
|
21
21
|
import path from 'node:path'
|
|
22
|
+
import { resolveDshHomeForEnginePre } from './dsh-home.js'
|
|
22
23
|
import { buildSourceCatalog, loadCorpusSnapshot, CorpusRegistry, canonicalize } from './m4-corpus.js'
|
|
24
|
+
import { resolveProcedureInjectEnabledPre } from './procedure-switch.js'
|
|
23
25
|
|
|
24
26
|
/** §11 capability 快照版本。 */
|
|
25
27
|
export const CAPABILITY_SNAPSHOT_V1 = 'capability_v1'
|
|
@@ -49,7 +51,12 @@ export function createActivationHost(opts = {}) {
|
|
|
49
51
|
// 现改为按身份分片:投影按 sessionId、miv 按 wsRef。**只增 key 维度,不改任何判定口径**。
|
|
50
52
|
const mivCacheByWs = new Map() // wsRef -> miv(每个工作区各记一份,不再互相踢)
|
|
51
53
|
const pathsByKey = new Map()
|
|
54
|
+
// ★#84(2026-09-20):`≤16 最小投影` —— 原实现在超出上限时**静默 shift**,
|
|
55
|
+
// 于是「诊断面看不到最近事件」没有任何痕迹;排查时会误判成「压根没产生事件」。
|
|
56
|
+
// 现补 `volatileDropped` 计数并具名化上限。
|
|
52
57
|
const volatileEvents = [] // ≤16 最小投影
|
|
58
|
+
let volatileDropped = 0
|
|
59
|
+
const VOLATILE_MAX_V1 = 16
|
|
53
60
|
const stats = { injected: 0, injectedAccepted: 0, injectedRejected: 0, claims: 0, claimFails: 0, rendered: 0, delivered: 0, seenCreated: 0, seenSkippedNoProv: 0, errors: 0 }
|
|
54
61
|
|
|
55
62
|
function effectiveEnabled() {
|
|
@@ -69,14 +76,17 @@ export function createActivationHost(opts = {}) {
|
|
|
69
76
|
return 'invalid'
|
|
70
77
|
}
|
|
71
78
|
function dshHome() {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
return base ? path.join(base, '.dsh') : '.'
|
|
79
|
+
// ★#86-3:统一口径。原实现全失败时返回 '.'(**与其余站点不同**);
|
|
80
|
+
// __homedirFn 注入点由 resolveDshHomeForEnginePre 保留,测试兼容。
|
|
81
|
+
return resolveDshHomeForEnginePre(engine)
|
|
76
82
|
}
|
|
77
83
|
function pushEvent(entry) {
|
|
78
84
|
volatileEvents.push({ at: Date.now(), ...entry })
|
|
79
|
-
if (volatileEvents.length >
|
|
85
|
+
if (volatileEvents.length > VOLATILE_MAX_V1) {
|
|
86
|
+
volatileEvents.shift()
|
|
87
|
+
// ★#84:丢弃必须留痕(否则「看不到事件」无法区分「没产生」与「被挤掉」)
|
|
88
|
+
volatileDropped++
|
|
89
|
+
}
|
|
80
90
|
}
|
|
81
91
|
function capturePaths(runtimeKey, p) {
|
|
82
92
|
pathsByKey.set(String(runtimeKey || ''), {
|
|
@@ -202,6 +212,9 @@ export function createActivationHost(opts = {}) {
|
|
|
202
212
|
if (!engine._tierGateHitsBySession || typeof engine._tierGateHitsBySession.set !== 'function') {
|
|
203
213
|
engine._tierGateHitsBySession = new Map()
|
|
204
214
|
}
|
|
215
|
+
// ★2026-09-20 移植(issue #94⑤ / PR #100):Map.set 对既有键**不刷新插入序** ⇒
|
|
216
|
+
// keys().next() 淘汰的是「最老创建」而非「最久未用」,最活跃会话反被逐出。
|
|
217
|
+
engine._tierGateHitsBySession.delete(sid)
|
|
205
218
|
engine._tierGateHitsBySession.set(sid, projection)
|
|
206
219
|
// 兼容投影:保留旧字段指向"最近一次投递",供旧诊断面板/测试继续可读(只增不改语义)。
|
|
207
220
|
engine._tierGateHits = projection
|
|
@@ -234,7 +247,10 @@ export function createActivationHost(opts = {}) {
|
|
|
234
247
|
*/
|
|
235
248
|
function pumpClaimed(box, req) {
|
|
236
249
|
const c2 = box.claim({
|
|
237
|
-
|
|
250
|
+
// ★ issue #75 CC-11 修复:用**只读**步号,不再自增。
|
|
251
|
+
// pump 总是紧跟在同键 `stepFor`(offer 时)之后同步调用 ⇒ 读到的就是刚烘焙 TTL 的那个步。
|
|
252
|
+
// 旧实现此处再 `stepFor` 一次 ⇒ 同一步内凭空消耗 2 步 TTL(见 currentStepOf 注释)。
|
|
253
|
+
nowStep: currentStepOf(req.sessionId, req.workspaceKey),
|
|
238
254
|
currentContextVersion: req.contextVersion,
|
|
239
255
|
currentMemoryIndexVersion: req.memoryIndexVersion,
|
|
240
256
|
})
|
|
@@ -312,7 +328,11 @@ export function createActivationHost(opts = {}) {
|
|
|
312
328
|
const hub = engine._memoryHub
|
|
313
329
|
if (!hub || !hub.stores || !hub.stores.procedures) return null
|
|
314
330
|
if (engine.config.memoryHubEnabled !== true) return null
|
|
315
|
-
|
|
331
|
+
// B-2:旧键 procedurePromotionEnabled 是**语义错配的兼容别名**(键名写的是「技能固化与晋升」,
|
|
332
|
+
// 实际控制的是「主动唤起」这条臂是否开启),统一交给接口契约模块 lib/procedure-switch.js
|
|
333
|
+
// 解析:新键 procedureInjectEnabled 优先,缺省回退旧键,两键都缺省按开启处理;
|
|
334
|
+
// 显式关闭过总闸的仍然在此短路。此处只替换开关解析口径,不新增任何前置条件。
|
|
335
|
+
if (!resolveProcedureInjectEnabledPre(engine.config)) return null
|
|
316
336
|
const actives = hub.stores.procedures.activeProcedures()
|
|
317
337
|
if (!actives.length) return null
|
|
318
338
|
const candIds = new Set()
|
|
@@ -348,12 +368,39 @@ export function createActivationHost(opts = {}) {
|
|
|
348
368
|
return { ok: true, request }
|
|
349
369
|
}
|
|
350
370
|
const stepsByRuntime = new Map()
|
|
371
|
+
/**
|
|
372
|
+
* 步进计数器的**唯一键格式**(issue#58 修复,2026-09-19)。
|
|
373
|
+
* 旧实现:写入侧用 `sessionId + '|ws:' + workspaceKey`,而删除侧 `disposeRuntime` 用
|
|
374
|
+
* `String(runtimeKey)`(= `session:<sid>`)⇒ **两个键空间永不相交** ⇒ 删除是空操作,
|
|
375
|
+
* `stepsByRuntime` 只增不减(「会话×工作区」一条,进程内永不回收)。
|
|
376
|
+
* 现在格式收敛到这一处,写入与删除共用,杜绝再次漂移。
|
|
377
|
+
*/
|
|
378
|
+
function stepKeyOf(sessionId, workspaceKey) {
|
|
379
|
+
return String(sessionId || '') + '|ws:' + String(workspaceKey || '')
|
|
380
|
+
}
|
|
351
381
|
function stepFor(sessionId, workspaceKey) {
|
|
352
|
-
const key = sessionId
|
|
382
|
+
const key = stepKeyOf(sessionId, workspaceKey)
|
|
353
383
|
const n = (stepsByRuntime.get(key) || 0) + 1
|
|
354
384
|
stepsByRuntime.set(key, n)
|
|
355
385
|
return n
|
|
356
386
|
}
|
|
387
|
+
/**
|
|
388
|
+
* ★ issue #75 CC-11 修复(2026-09-19):**只读**当前步(不自增)。
|
|
389
|
+
*
|
|
390
|
+
* 动机:`stepFor` 是自增器(+1 写回)。而「注入即泵」路径是
|
|
391
|
+
* `finishInject` 先 `offerActivation({nowStep: stepFor(...)})` 烘焙 TTL 起点,
|
|
392
|
+
* 紧接着**同一同步块内** `pumpClaimed` 又调一次 `stepFor` 去 claim
|
|
393
|
+
* ⇒ **offer 与 pump 各消耗 1 步而零时间流逝** ⇒ `expiresAtStep` 按第一次烘焙、
|
|
394
|
+
* 判定却用第二次 ⇒ TTL 窗口凭空少 1 步(实测 ttl=3 的自然投递窗由 2 次机会缩为 1;
|
|
395
|
+
* ttl=2 的 rollback 场景整包必死)。
|
|
396
|
+
*
|
|
397
|
+
* 语义上「同步 offer + pump」是**同一步内**的投递动作,不该消耗 2 步 TTL。
|
|
398
|
+
* 因此给 pump 侧提供只读版本:它总是紧跟在同键的 `stepFor` 之后调用,
|
|
399
|
+
* 读到的必然是刚自增过的那个值(≥1),不会读到 0。
|
|
400
|
+
*/
|
|
401
|
+
function currentStepOf(sessionId, workspaceKey) {
|
|
402
|
+
return stepsByRuntime.get(stepKeyOf(sessionId, workspaceKey)) || 0
|
|
403
|
+
}
|
|
357
404
|
|
|
358
405
|
/**
|
|
359
406
|
* agent/pre-step(§8):先校验当前 cursor/index/TTL 再 claim;claimed packet 存 runtime 态,
|
|
@@ -371,6 +418,8 @@ export function createActivationHost(opts = {}) {
|
|
|
371
418
|
const miv = currentMiv(identity.workspaceKey)
|
|
372
419
|
box.setCursor({ contextVersion: runtime.contextVersion, memoryIndexVersion: miv || undefined })
|
|
373
420
|
const nowStep = stepFor(identity.sessionId, identity.workspaceKey)
|
|
421
|
+
// issue#58:把步进键登记进 runtime 态,供 disposeRuntime 精确回收(否则计数器只增不减)。
|
|
422
|
+
const stepKeyHere = stepKeyOf(identity.sessionId, identity.workspaceKey)
|
|
374
423
|
const c = box.claim({
|
|
375
424
|
nowStep,
|
|
376
425
|
currentContextVersion: runtime.contextVersion,
|
|
@@ -379,6 +428,7 @@ export function createActivationHost(opts = {}) {
|
|
|
379
428
|
let st = runtimeState.get(runtime.key)
|
|
380
429
|
if (!st) { st = { step: 0, claimed: null }; runtimeState.set(runtime.key, st) }
|
|
381
430
|
st.step = nowStep
|
|
431
|
+
st.stepKey = stepKeyHere
|
|
382
432
|
if (c.ok) { st.claimed = { packet: c.packet, inbox: box }; stats.claims++ }
|
|
383
433
|
else {
|
|
384
434
|
// 2026-08-28 浏览器实测修复:claim 失败(none-pending 等)不得清掉已存在的 claimed——
|
|
@@ -505,9 +555,18 @@ export function createActivationHost(opts = {}) {
|
|
|
505
555
|
} catch (e) { stats.errors++; return { ok: false, reason: 'internal-error' } }
|
|
506
556
|
}
|
|
507
557
|
|
|
558
|
+
/**
|
|
559
|
+
* 单 runtime 清理。issue#58 修复(2026-09-19):**必须清掉步进计数器**。
|
|
560
|
+
* 旧实现 `stepsByRuntime.delete(String(runtimeKey))` 是坏键(见 `stepKeyOf` 注释)⇒ 空操作。
|
|
561
|
+
* 现在优先用创建时登记的 `stepKey`;同时保留 runtimeKey 形态的删除,
|
|
562
|
+
* 兼容「调用方直接传 step-key」的情况(两条都删,代价为零)。
|
|
563
|
+
*/
|
|
508
564
|
function disposeRuntime(runtimeKey) {
|
|
509
|
-
|
|
510
|
-
|
|
565
|
+
const k = String(runtimeKey)
|
|
566
|
+
const st = runtimeState.get(k)
|
|
567
|
+
runtimeState.delete(k)
|
|
568
|
+
if (st && st.stepKey) stepsByRuntime.delete(st.stepKey)
|
|
569
|
+
stepsByRuntime.delete(k)
|
|
511
570
|
}
|
|
512
571
|
function disposeAll(reason) {
|
|
513
572
|
runtimeState.clear()
|
package/lib/board-mode.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* - boardMode = 'legacy'(默认) | 'graph'(新版看板 dsh-graph + sidecar + 遍历工具)。
|
|
9
9
|
* - **开关解耦**(用户硬性规则): boardMode 只决定"白板线新能力是否激活",
|
|
10
10
|
* 不顺带改变任何其他功能行为; legacy 模式下一切行为与 P5 收官时**字节级一致**。
|
|
11
|
-
* - graph_* 工具(dsh-graph vendor)与
|
|
11
|
+
* - graph_* 工具(dsh-graph vendor)与 memory_expand/memory_trace(P3)
|
|
12
12
|
* 仅在 boardMode='graph' 时注册; P2 sidecar 仅在 'graph' 时写盘。
|
|
13
13
|
* - fail closed: 非法值一律按 legacy(旧行为), 绝不猜。
|
|
14
14
|
*/
|