@modusensus/dsh-mneme 0.9.3 → 0.9.5

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.
Files changed (102) hide show
  1. package/README.md +56 -10
  2. package/bin/cli.mjs +215 -2
  3. package/docs/CONFIGURATION.md +10 -2
  4. package/docs/DAEMON.md +9 -2
  5. package/docs/DISTILL.md +66 -4
  6. package/docs/SHARE.md +552 -0
  7. package/docs/SLEEP.md +1 -1
  8. package/docs/STORAGE.md +1 -1
  9. package/lib/api-standalone.js +286 -8
  10. package/lib/api.js +254 -3
  11. package/lib/client.js +1000 -50
  12. package/lib/config.js +50 -1
  13. package/lib/document.js +15 -2
  14. package/lib/dream/decisions.js +88 -3
  15. package/lib/dream/sleep.js +63 -13
  16. package/lib/dream.js +66 -10
  17. package/lib/index.js +6 -1
  18. package/lib/inject.js +10 -25
  19. package/lib/lang.js +48 -6
  20. package/lib/memory-source.js +9 -0
  21. package/lib/organize.js +9 -3
  22. package/lib/pipeline.js +62 -1
  23. package/lib/profile-extract.js +161 -0
  24. package/lib/provenance-http.js +126 -0
  25. package/lib/serve.js +13 -0
  26. package/lib/service.js +70 -6
  27. package/lib/settings.js +17 -13
  28. package/lib/share-http.js +281 -0
  29. package/lib/share-import.js +234 -0
  30. package/lib/share.js +335 -0
  31. package/lib/store.js +272 -11
  32. package/lib/summarize.js +118 -8
  33. package/lib/tools.js +240 -1
  34. package/lib/user-settings.js +78 -0
  35. package/package.json +1 -1
  36. package/src/api-standalone.js +286 -8
  37. package/src/api.js +254 -3
  38. package/src/config.js +50 -1
  39. package/src/document.js +15 -2
  40. package/src/dream/decisions.js +88 -3
  41. package/src/dream/sleep.js +63 -13
  42. package/src/dream.js +66 -10
  43. package/src/index.js +6 -1
  44. package/src/inject.js +10 -25
  45. package/src/lang.js +48 -6
  46. package/src/memory-source.js +9 -0
  47. package/src/organize.js +9 -3
  48. package/src/pipeline.js +62 -1
  49. package/src/profile-extract.js +161 -0
  50. package/src/provenance-http.js +126 -0
  51. package/src/serve.js +13 -0
  52. package/src/service.js +70 -6
  53. package/src/settings.js +17 -13
  54. package/src/share-http.js +281 -0
  55. package/src/share-import.js +234 -0
  56. package/src/share.js +335 -0
  57. package/src/store.js +272 -11
  58. package/src/summarize.js +118 -8
  59. package/src/tools.js +240 -1
  60. package/src/user-settings.js +78 -0
  61. package/test/api.test.js +384 -3
  62. package/test/audit.test.js +2 -2
  63. package/test/cli-receive.test.js +390 -0
  64. package/test/cli-share.test.js +437 -0
  65. package/test/client-share.test.js +225 -0
  66. package/test/client.test.js +215 -6
  67. package/test/dedupe-candidate-window.test.js +180 -0
  68. package/test/dream-candidate-hybrid.test.js +2 -2
  69. package/test/dream-fence.test.js +164 -0
  70. package/test/dream.test.js +87 -5
  71. package/test/helpers/dream-mock.js +6 -2
  72. package/test/lang.test.js +11 -0
  73. package/test/llm-message-source.test.js +1 -1
  74. package/test/mint-source.test.js +1 -1
  75. package/test/organize-tool.test.js +232 -0
  76. package/test/persona-addressing.test.js +83 -0
  77. package/test/persona-settings.test.js +30 -8
  78. package/test/pipeline-r1r2.test.js +129 -0
  79. package/test/policy-epoch.test.js +2 -2
  80. package/test/profile-extract.test.js +269 -0
  81. package/test/provenance-http.test.js +184 -0
  82. package/test/readme-claims.test.js +45 -0
  83. package/test/reasoning-effort.test.js +10 -10
  84. package/test/scope-candidates.test.js +7 -4
  85. package/test/scope-state.test.js +130 -1
  86. package/test/serve.test.js +62 -0
  87. package/test/share-foreign-rows.test.js +144 -0
  88. package/test/share-http.test.js +144 -0
  89. package/test/share-import.test.js +577 -0
  90. package/test/share-imported-guard.test.js +311 -0
  91. package/test/share-imported-identity.test.js +111 -0
  92. package/test/share-pack.test.js +511 -0
  93. package/test/share-receive-http.test.js +756 -0
  94. package/test/share-routes.test.js +337 -0
  95. package/test/share-store.test.js +133 -0
  96. package/test/share-validate.test.js +101 -0
  97. package/test/standalone-api.test.js +524 -5
  98. package/test/summarize-parse-diagnostics.test.js +75 -0
  99. package/test/summarize.test.js +240 -2
  100. package/test/tools-dto-schema-matrix.test.js +48 -5
  101. package/test/tools.test.js +6 -1
  102. package/test/user-settings-preview.test.js +127 -0
package/docs/DISTILL.md CHANGED
@@ -111,10 +111,15 @@ distillRecords:
111
111
  **不读这个键**,跟同一条 `--older-than`(默认 7 天)走——两个窗口互不联动,想一次对齐就把
112
112
  `--older-than` 显式传成与 `retentionDays` 相同的值。
113
113
 
114
- 删记忆是另一条路:`store.remove(id)` 在事务内**显式**清掉它的溯源链接。之所以不靠
115
- `ON DELETE CASCADE`,是因为 `src/store.js` 从不启用 `PRAGMA foreign_keys`(全库唯一的
116
- `REFERENCES` 是 `recall_events → recall_runs`,翻这个 pragma 会顺带激活那条既有约束的
117
- 行为,不是本次改动的范围)。声明式约束保留在 schema 里作为意图记录,实际清理是显式的。
114
+ 删记忆是另一条路:`store.remove(id)` 在事务内**显式**清掉它的溯源链接。这条显式清理**不是**
115
+ 「外键没开才要手工补」——`createStore` 走 `new DatabaseSync(path)` 不带选项,而 node:sqlite 的
116
+ `enableForeignKeyConstraints` 默认为真(C1 实测:新库上 `PRAGMA foreign_keys` 返回 1,删父行
117
+ 确实级联清掉本表),所以 `ON DELETE CASCADE` 今天一直是**活的**。显式 DELETE 留着是为了不把
118
+ 清理押在一份没人钉过的驱动默认值上:连接哪天以 `enableForeignKeyConstraints: false` 打开,
119
+ 悬空链接只有那条 DELETE 挡得住(口径见 `src/store.js:278-283` 与 `:1387-1391` 的注释,
120
+ `deleteBySharePackId` 同处置)。本库一共**两条**外键,都是活的——这一条与
121
+ `recall_evals(recall_run_id) → recall_runs(id)`;此前本节写的 `recall_events` 那张表并不存在。
122
+ 声明式约束因此既是意图记录、也是今天实际生效的执行,两边不矛盾。
118
123
 
119
124
  `reclaim` 报告因此从两项变三项:
120
125
 
@@ -160,3 +165,60 @@ cleared: { dream_run_inputs, archived_embeddings, distill_records }
160
165
  - **启动期裁剪**:读装配后的 cfg(面板改了保留期也认),且默认关时不动手;
161
166
  - **白名单与往返**:两个键过 `settings` 校验(含范围外整数被拒),PUT 往返后 effective 读得回;
162
167
  - **轻量模式**:预设关 `enabled`、保留用户显式设的 `retentionDays`、不污染用户对象。
168
+
169
+ ## 10. 读出口:`/memory/provenance` 与 `distillRecords.enabled` 门(#421 写、#509 整改)
170
+
171
+ 两张表自 #399 起只有写入路径:库里有答案、`service.provenanceFor` 能查,外部拿不到——
172
+ 「这条记忆是从哪几句蒸出来的」只能开 sqlite 手写 JOIN。#421 补上读出口,两个入口共用
173
+ 一份实现:
174
+
175
+ - 宿主内面板路由 `GET /api/dsh-mneme/memory/provenance`(`policy: token`);
176
+ - Bearer 数据面 `GET /memory/provenance?id=<memoryId>`(daemon 与宿主外部访问同享)。
177
+
178
+ 口径只写在 `src/provenance-http.js` 一处,两个壳都调它——#411 已经为 reclaim / share 各
179
+ 踩过一次「两张皮整段复制必然漂移」,`test/provenance-http.test.js` 的静态锁把「错误码字面
180
+ 量与开关判据只许出现在本模块、两个壳都真的把 `config` 转交进来、读侧判据与写侧
181
+ `src/summarize.js:988` 逐字同源」写成断言。
182
+
183
+ **形状**:一个链接一个窗口 `{session_id, seq_start, seq_end, created_at, records[]}`,
184
+ `records` 是区间内的逐条会话原文(按 `seq` 升序、不越界)。没有链接的记忆返回**空
185
+ `windows`**——「不是蒸馏来的」是有效答案,不是错误;未知 id 同样回空 `windows`(读端点
186
+ 不替调用方判断记忆是否存在)。到期裁剪后链接保留、指向空区间,面板据此显示「原文已过期」。
187
+
188
+ **开关门(#509 评审整改)**:读出口吃 `distillRecords.enabled`——与写侧**同一枚开关、同一
189
+ 个判据表达式**(`config?.distillRecords?.enabled === true`,读侧唯一一份在
190
+ `isDistillRecordsEnabled`)。此前全树只有 `src/index.js:270`(启动期裁剪)与
191
+ `src/summarize.js:988`(写入)行为性读它,读出口一处都不读,于是「把 distill_records 关
192
+ 掉」的实际语义是*不再写、也永久不再删*,却还多一个能把历史原文读出去的口。状态码阶梯:
193
+
194
+ | 状态码 | 含义 | 为什么不是别的 |
195
+ |---|---|---|
196
+ | `401` | 没带 token | 两个壳各自的门,在共用模块之前 |
197
+ | `400 {"error":"missing-id"}` | 缺 `id` | 语法畸形,与服务端状态无关,所以排在功能开关之前(与 reclaim 的 `invalid-json` 同档) |
198
+ | `409 {"error":"distill-records-disabled"}` | 用户关了 `distillRecords.enabled` | 与 `src/api.js:525` 的 `profileExtractEnabled` 同型:**用户关了 = 409,装配坏了 = 503**,两个答案必须可区分(`src/index.js:589-591`) |
199
+ | `503 {"error":"provenance-unavailable"}` | service 上没这两个方法(headless / 旧装配) | 「没接线」不是「这条记忆没有来源」,两种空必须分开读数 |
200
+ | `200` | `{memoryId, windows}` | 空 `windows` = 不是蒸馏来的 |
201
+
202
+ **为什么不是 404**:本端点被明确设计成永远不就「这条记忆是否存在」作断言(缺 id 是 400、
203
+ 未知 id 是 200 + 空 windows),而 404 在本仓已有稳定含义——未知路由与资源不存在
204
+ (`/memories/:id`、`entity-not-found`)。把「功能关了」塞进 404,调用方会在状态码这个
205
+ 被代理 / 监控 / 重试逻辑唯一读取的通道上,把它读成「这条记忆不存在」;那两种误读的后续
206
+ 动作完全不同(一个去开开关,一个去查这条记忆)。409 也不给 200 的形状加说明性键——响应
207
+ 体只多一个 `windows`,开关状态走状态码通道。
208
+
209
+ **生效节奏**:`cfg` 是启动期冻结值(面板改开关与 `panel_mode` 一样在下次启动生效),读写
210
+ 两侧取的是同一份快照,所以两道门永不分歧;该键在 settings 白名单与 `NESTED_FLAG_PATHS`
211
+ 里都登记着,面板会显示「待重启」(#481「面板开着、功能却不注入」的教训)。
212
+
213
+ **daemon 这一面**:`src/serve.js` 把 `feature_flags` 里的 `distillRecords.enabled` 展开进
214
+ cfg(与宿主 `index.js:217-233` 同款展开,只取蒸馏这一组),与宿主共用同一个 memory.db 与
215
+ 同一份 kv——面板开着,daemon 就读得到。残留不对称:daemon 结构上看不到宿主的 bundle
216
+ config,所以「只写在部署侧 bundle 配置里打开、从没在面板点过」的用户,宿主认、daemon 不
217
+ 认(每个请求回 409)。这不是故障,写进 `docs/DAEMON.md` 的那条已知边界。
218
+
219
+ **关开关 ≠ 删除已留存原文**(本轮之后唯一诚实的表述):这道门只封 HTTP 读路径。关掉后
220
+ `src/index.js:270` 跳过启动期裁剪,已留的 `distill_records` 行永久冻在盘上,任何能摸到
221
+ memory.db 的进程仍可读;唯一出路是 `dsh-mneme reclaim`(`src/maintenance.js` 不读这个
222
+ 键,手动可删)或重新开启后的启动裁剪。把「关 = 删掉」写进任何文档都是谎话。后续可做的
223
+ 是让裁剪与写开关解耦(`retentionDays` 有值就裁,无论 `enabled`),那是让开关语义完全诚实
224
+ 的唯一修法,超出本轮范围。