dsh-memu-memory 1.1.2 → 1.2.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.
Files changed (199) hide show
  1. package/AGENTS.md +8 -6
  2. package/README.md +50 -5
  3. package/README.zh.md +49 -5
  4. package/docs/active-memory-ab.md +385 -0
  5. package/docs/binding-lifecycle.md +99 -0
  6. package/docs/contributing.md +6 -4
  7. package/docs/emotion-model-spec.md +281 -0
  8. package/docs/env-and-commands.md +13 -0
  9. package/docs/host-api.md +35 -3
  10. package/docs/memory-semantics.md +40 -11
  11. package/docs/recall-benchmark.md +238 -0
  12. package/docs/troubleshooting.md +395 -366
  13. package/lib/active-memory.js +165 -0
  14. package/lib/activity-log.js +190 -0
  15. package/lib/backup.js +1103 -0
  16. package/lib/binding-diagnostics.js +635 -0
  17. package/lib/client.js +728 -58
  18. package/lib/consolidation-ledger.js +347 -0
  19. package/lib/consolidation-receipt.js +284 -0
  20. package/lib/consolidation-snapshot.js +274 -0
  21. package/lib/consolidation-worker.js +115 -0
  22. package/lib/curator.js +81 -37
  23. package/lib/cycle.js +43 -6
  24. package/lib/embedding-catalog.js +763 -0
  25. package/lib/embedding-download.js +407 -0
  26. package/lib/embedding-runtime.js +710 -0
  27. package/lib/engine.js +2 -2
  28. package/lib/index.js +36 -0
  29. package/lib/inject.js +232 -103
  30. package/lib/local-embedding-entry.js +145 -0
  31. package/lib/local-embedding-manager.js +267 -0
  32. package/lib/local-embedding-protocol.js +173 -0
  33. package/lib/local-embedding-worker.js +652 -0
  34. package/lib/local-vector-service.js +283 -0
  35. package/lib/memory.js +599 -57
  36. package/lib/memu-config.js +10 -22
  37. package/lib/memu.js +53 -19
  38. package/lib/mood.js +268 -39
  39. package/lib/paths.js +24 -0
  40. package/lib/preset-scope.js +1 -1
  41. package/lib/private.js +450 -29
  42. package/lib/prompts/private-consolidation.coding.md +1 -0
  43. package/lib/prompts/private-consolidation.md +1 -0
  44. package/lib/prompts/private-consolidation.mixed.md +1 -0
  45. package/lib/prompts/private-consolidation.rp.md +1 -0
  46. package/lib/prompts.js +4 -4
  47. package/lib/remote-summary.js +51 -25
  48. package/lib/rpc.js +54 -5
  49. package/lib/state.js +137 -172
  50. package/lib/tools.js +58 -7
  51. package/lib/vector-migration.js +878 -0
  52. package/lib/vector-profile.js +968 -0
  53. package/package.json +4 -2
  54. package/scripts/acceptance-local.mjs +7 -5
  55. package/scripts/active-memory-ab-live.mjs +655 -0
  56. package/scripts/active-memory-ab.mjs +1302 -0
  57. package/scripts/chain-matrix.mjs +537 -0
  58. package/scripts/check-all.mjs +29 -1
  59. package/scripts/check-doc-drift.mjs +353 -0
  60. package/scripts/diagnose-bindings.mjs +176 -0
  61. package/scripts/local-runtime-install.mjs +142 -0
  62. package/scripts/local-runtime-verify.mjs +56 -0
  63. package/scripts/local-vector-verify.mjs +93 -0
  64. package/scripts/recall-bench.mjs +813 -0
  65. package/scripts/repetition-ab-scenarios.mjs +93 -0
  66. package/scripts/repetition-detector-snapshot.mjs +314 -0
  67. package/scripts/repetition-eval-live.mjs +360 -0
  68. package/scripts/repetition-eval.mjs +702 -0
  69. package/tests/activation.test.mjs +89 -0
  70. package/tests/active-memory-ab.test.mjs +745 -0
  71. package/tests/active-memory.test.mjs +129 -0
  72. package/tests/activity-log.test.mjs +126 -0
  73. package/tests/activity-wiring.test.mjs +103 -0
  74. package/tests/appendix-b.test.mjs +212 -0
  75. package/tests/appendix-b2.test.mjs +166 -0
  76. package/tests/audit-regression.test.mjs +272 -0
  77. package/tests/audit-safety.test.mjs +227 -0
  78. package/tests/backend-compensation.test.mjs +272 -0
  79. package/tests/backup.test.mjs +793 -0
  80. package/tests/binding-diagnostics.test.mjs +720 -0
  81. package/tests/browser.test.mjs +366 -0
  82. package/tests/client-render.test.mjs +892 -0
  83. package/tests/coalesce.test.mjs +113 -0
  84. package/tests/config.test.mjs +159 -0
  85. package/tests/consolidation-credential.test.mjs +320 -0
  86. package/tests/consolidation-fork.test.mjs +357 -0
  87. package/tests/consolidation-ledger.test.mjs +298 -0
  88. package/tests/consolidation-snapshot.test.mjs +321 -0
  89. package/tests/consolidation-value.test.mjs +89 -0
  90. package/tests/context-scope.test.mjs +40 -0
  91. package/tests/cue.test.mjs +44 -0
  92. package/tests/curator-probe.test.mjs +433 -0
  93. package/tests/curator.test.mjs +150 -0
  94. package/tests/cycle.test.mjs +411 -0
  95. package/tests/disclosure.test.mjs +231 -0
  96. package/tests/doc-drift.test.mjs +222 -0
  97. package/tests/embedding-catalog.test.mjs +266 -0
  98. package/tests/embedding-download.test.mjs +391 -0
  99. package/tests/embedding-runtime.test.mjs +389 -0
  100. package/tests/emotion-chain.test.mjs +84 -0
  101. package/tests/emotion-contract.test.mjs +445 -0
  102. package/tests/engine.test.mjs +35 -0
  103. package/tests/fixtures/active-memory-ab/README.md +56 -0
  104. package/tests/fixtures/active-memory-ab/cases/01-clean-dense-turn.json +351 -0
  105. package/tests/fixtures/active-memory-ab/cases/02-clean-thin-turn.json +122 -0
  106. package/tests/fixtures/active-memory-ab/cases/03-clean-starved-small.json +125 -0
  107. package/tests/fixtures/active-memory-ab/cases/04-clean-large-thin.json +137 -0
  108. package/tests/fixtures/active-memory-ab/cases/05-clean-half-step.json +166 -0
  109. package/tests/fixtures/active-memory-ab/cases/06-clean-duplicate-reread.json +197 -0
  110. package/tests/fixtures/active-memory-ab/cases/07-clean-recent-recall.json +125 -0
  111. package/tests/fixtures/active-memory-ab/cases/08-global-relevant.json +111 -0
  112. package/tests/fixtures/active-memory-ab/cases/09-global-irrelevant-conflict.json +158 -0
  113. package/tests/fixtures/active-memory-ab/cases/10-no-human-turn.json +97 -0
  114. package/tests/fixtures/active-memory-ab/cases/11-clean-scale-100.json +137 -0
  115. package/tests/fixtures/active-memory-ab/cases/12-clean-scale-1000.json +137 -0
  116. package/tests/fixtures/active-memory-ab/cases/13-clean-scale-5000.json +137 -0
  117. package/tests/fixtures/active-memory-ab/cases/14-clean-scale-20000.json +137 -0
  118. package/tests/fixtures/active-memory-ab/lead-ai-reviewed-reference.json +191 -0
  119. package/tests/fixtures/active-memory-ab/manifest.json +199 -0
  120. package/tests/fixtures/recall-bench/01-paraphrase.json +184 -0
  121. package/tests/fixtures/recall-bench/02-exact.json +153 -0
  122. package/tests/fixtures/recall-bench/03-negation.json +173 -0
  123. package/tests/fixtures/recall-bench/04-no-answer.json +162 -0
  124. package/tests/fixtures/recall-bench/05-conflict.json +194 -0
  125. package/tests/fixtures/recall-bench/06-boundary.json +273 -0
  126. package/tests/fixtures/recall-bench/07-secret.json +191 -0
  127. package/tests/fixtures/recall-bench/08-coding.json +164 -0
  128. package/tests/fixtures/recall-bench-gold-candidates/01-paraphrase.json +193 -0
  129. package/tests/fixtures/recall-bench-gold-candidates/02-exact.json +197 -0
  130. package/tests/fixtures/recall-bench-gold-candidates/03-negation.json +244 -0
  131. package/tests/fixtures/recall-bench-gold-candidates/04-no-answer.json +189 -0
  132. package/tests/fixtures/recall-bench-gold-candidates/05-conflict.json +245 -0
  133. package/tests/fixtures/recall-bench-gold-candidates/06-boundary.json +279 -0
  134. package/tests/fixtures/recall-bench-gold-candidates/07-secret.json +224 -0
  135. package/tests/fixtures/recall-bench-gold-candidates/08-coding.json +218 -0
  136. package/tests/fixtures/repetition-eval/01-zh-rp.json +93 -0
  137. package/tests/fixtures/repetition-eval/02-en.json +97 -0
  138. package/tests/fixtures/repetition-eval/03-code.json +91 -0
  139. package/tests/fixtures/repetition-eval/04-names.json +116 -0
  140. package/tests/fixtures/repetition-eval/05-user-quote.json +96 -0
  141. package/tests/fixtures/repetition-eval/06-agreement.json +86 -0
  142. package/tests/graph-view.test.mjs +187 -0
  143. package/tests/graph.test.mjs +77 -0
  144. package/tests/hook-order.test.mjs +72 -0
  145. package/tests/humanlike.test.mjs +232 -0
  146. package/tests/hybrid-recall.test.mjs +92 -0
  147. package/tests/inbound.test.mjs +393 -0
  148. package/tests/inject-guide.test.mjs +364 -0
  149. package/tests/inject.test.mjs +222 -0
  150. package/tests/injection-budget-settings.test.mjs +35 -0
  151. package/tests/injection-budget.test.mjs +64 -0
  152. package/tests/injection-chain.test.mjs +191 -0
  153. package/tests/loader-register.mjs +3 -0
  154. package/tests/loader.mjs +12 -0
  155. package/tests/local-embedding-entry.test.mjs +95 -0
  156. package/tests/local-embedding-manager.test.mjs +476 -0
  157. package/tests/local-embedding-protocol.test.mjs +95 -0
  158. package/tests/local-embedding-worker.test.mjs +346 -0
  159. package/tests/managed-memory.test.mjs +536 -0
  160. package/tests/managed-runtime.test.mjs +40 -0
  161. package/tests/media.test.mjs +132 -0
  162. package/tests/migration-payload.test.mjs +42 -0
  163. package/tests/mood.test.mjs +109 -0
  164. package/tests/multiprocess.test.mjs +29 -0
  165. package/tests/new-session-gate.test.mjs +361 -0
  166. package/tests/package-shipping.test.mjs +84 -0
  167. package/tests/preset-scope.test.mjs +212 -0
  168. package/tests/prompts.test.mjs +250 -0
  169. package/tests/react-snapshot.test.mjs +23 -0
  170. package/tests/recall-bench.test.mjs +306 -0
  171. package/tests/remote.test.mjs +140 -0
  172. package/tests/rename.test.mjs +30 -0
  173. package/tests/repetition-detector-snapshot.test.mjs +231 -0
  174. package/tests/repetition-eval-live.test.mjs +177 -0
  175. package/tests/repetition-eval.test.mjs +373 -0
  176. package/tests/salient-date.test.mjs +142 -0
  177. package/tests/settings-beat.test.mjs +221 -0
  178. package/tests/short-term.test.mjs +166 -0
  179. package/tests/sidebar-beat.test.mjs +208 -0
  180. package/tests/sidebar-refresh.test.mjs +123 -0
  181. package/tests/sidebar.test.mjs +70 -0
  182. package/tests/snippet.test.mjs +47 -0
  183. package/tests/source-kind.test.mjs +52 -0
  184. package/tests/state.test.mjs +150 -0
  185. package/tests/stats.test.mjs +112 -0
  186. package/tests/storage.test.mjs +125 -0
  187. package/tests/stubs/dsh-llm.js +5 -0
  188. package/tests/stubs/dsh-session.js +7 -0
  189. package/tests/stubs/dsh-tools.js +101 -0
  190. package/tests/tool-schema.test.mjs +73 -0
  191. package/tests/tools.test.mjs +184 -0
  192. package/tests/ui-defaults.test.mjs +57 -0
  193. package/tests/update-fields.test.mjs +138 -0
  194. package/tests/vector-migration.test.mjs +733 -0
  195. package/tests/vector-profile.test.mjs +425 -0
  196. package/tests/visibility-migration.test.mjs +152 -0
  197. package/tests/webui-auth.test.mjs +454 -0
  198. package/tests/webui.test.mjs +164 -0
  199. package/tests/windows-env.test.mjs +89 -0
@@ -0,0 +1,238 @@
1
+ # 检索 benchmark(W6,provisional)
2
+
3
+ > **状态:provisional baseline,不是金标。** 本目录的 42 条样本全部是**合成草稿(synthetic draft)**,没有经过人工确认,不能称为 gold set。本文的分数只说明当前 local-lexical 管线在一组刻意构造的样本上的行为,不能代表真实 RP 对话或语义检索质量。
4
+
5
+ - 工作包:W6 · 检索 benchmark(P1,W7 的前置)
6
+ - 基线时间:2026-10-29T09:39:30Z(测试运行时钟)
7
+ - 基线提交:`afc970f934df`(HEAD;W6 文件尚未提交,工作区为 dirty)
8
+ - 包版本:`dsh-memu-memory@1.1.2`
9
+ - 数据集:42 条 / 8 个文件,SHA-256 `4b3d01898071073f318d815346b1af2758878900a2685355f6bd40445531a2b0`
10
+ - 后端:`local-lexical`;没有启用真实 embedding 或真实向量服务
11
+
12
+ ## 1. 结论(只读这一节)
13
+
14
+ 本次 provisional baseline:
15
+
16
+ | 指标 | 候选 id(candidate) | 最终注入 id(final injected) | 显式探针(explicit) |
17
+ |---|---:|---:|---:|
18
+ | Recall@3 | 1.000000 | 1.000000 | 1.000000 |
19
+ | MRR@3 | 0.984848 | 0.984848 | 1.000000 |
20
+ | 无答案误召回率 | 0.000000 | 0.000000 | n/a(无无答案样本) |
21
+ | 隔离违规 | 0 | 0 | 0 |
22
+ | 可答样本分母 | 33 | 33 | 5 |
23
+ | 无答案分母 | 9 | 9 | 0 |
24
+
25
+ 隔离违规总计 **0**。其中 forbidden id 检查次数:候选 20 + 最终注入 20 + 显式探针 0 = 40 次,命中 0 次。
26
+
27
+ 这些数字是**合成草稿上的 provisional baseline**。样本的 query 与条目文本存在刻意保留的词面线索,local-lexical 接近满分是预期现象,不是“检索质量已经解决”的证据。
28
+
29
+ ## 2. 运行方式
30
+
31
+ 脚本:`scripts/recall-bench.mjs`
32
+
33
+ ```bash
34
+ # 默认输出完整 JSON 到 stdout
35
+ node scripts/recall-bench.mjs
36
+
37
+ # 写出机器可读报告
38
+ node scripts/recall-bench.mjs --out artifacts/recall-bench.json
39
+
40
+ # 仅跑前 N 条;固定 seed;保留临时根用于检查
41
+ node scripts/recall-bench.mjs --samples 10 --seed 20261029 --work-root "$TMPDIR/recall-bench-inspect" --keep
42
+ ```
43
+
44
+ 参数:
45
+
46
+ | 参数 | 说明 |
47
+ |---|---|
48
+ | `--out FILE` | 写 JSON 报告;父目录自动创建。报告按 CRLF 写出 |
49
+ | `--work-root DIR` | 使用指定的空目录;必须是 `os.tmpdir()` 下的目录,否则拒绝运行 |
50
+ | `--seed N` | 替换 PRNG seed;默认 20261029 |
51
+ | `--samples N` | 只跑排序后的前 N 条;1..42 |
52
+ | `--keep` | 保留本次临时根(默认根在结束后删除;报告里的 `run.root` 可查看路径) |
53
+
54
+ 测试命令:
55
+
56
+ ```bash
57
+ node --import ./tests/loader-register.mjs --test tests/recall-bench.test.mjs
58
+ ```
59
+
60
+ 测试只验证 harness、样本结构、隔离、确定性和指标数学,不锁定上面的具体分数;分数变化不应让结构测试变成“追数字”。
61
+
62
+ ## 3. 合成样本集
63
+
64
+ 位置:`tests/fixtures/recall-bench/`,共 8 个 JSON 文件、42 条样本。每个 JSON 文件都带有 `status`,每条样本都带有 `draft`/`notGold`:
65
+
66
+ ```json
67
+ {
68
+ "status": "synthetic-draft-not-gold",
69
+ "draft": true,
70
+ "notGold": true
71
+ }
72
+ ```
73
+
74
+ | 子类 | 样本数 | 覆盖点 |
75
+ |---|---:|---|
76
+ | `paraphrase` | 6 | 同义改写、指代和口语化问法 |
77
+ | `exact` | 5 | 精确 title、精确 memory id |
78
+ | `negation` | 4 | 否定、旧状态不得被当成当前状态 |
79
+ | `no-answer` | 6 | 英文 query 对中文小型库,必须返回空 top-3 |
80
+ | `conflict` | 5 | 新旧冲突、pending review 不得当作已确认 |
81
+ | `boundary` | 6 | channelId / characterId / worldId / branchId / knownBy 边界 |
82
+ | `secret` | 5 | secret 自动隐藏 vs 显式召回;含 3 条自动无答案 |
83
+ | `coding` | 5 | 少量 coding 约束,防跨域退化 |
84
+ | **合计** | **42** | |
85
+
86
+ 每条的字段(脚本会逐项校验):
87
+
88
+ | 字段 | 含义 |
89
+ |---|---|
90
+ | `query` | 检索 query |
91
+ | `context` | 会话上下文(可为空对象;边界样本使用 channelId/characterId/worldId/branchId/knownBy 等) |
92
+ | `time` | 固定时钟;条目 ageDays/updatedDaysAgo 相对此时间计算 |
93
+ | `expectedIds` | 期望命中的 id;无答案样本为空数组 |
94
+ | `forbiddenIds` | 禁止出现在任何 top-3 的 id;计入隔离违规 |
95
+ | `noAnswer` | true 表示该样本必须无召回;无答案样本的 expectedIds 必须为空 |
96
+ | `subclass` | 上表八个子类之一 |
97
+ | `library` | 该样本可用的小型 library 子集(1–10 个 id),样本之间不复用 library,避免互相污染 |
98
+ | `explicitExpectedIds` | 可选;显式召回探针的期望 id(用于 secret 自动/显式差异) |
99
+ | `explicitForbiddenIds` | 可选;显式召回探针的禁止 id |
100
+
101
+ 数据是人工编写的合成内容(虚构人名、地点、约定),不包含真实聊天、真实用户记忆或可识别个人信息,可以安全入库。**它们仍不是人工确认样本。**
102
+
103
+ ## 4. 隔离与可复现设计
104
+
105
+ 每次 `runBenchmark`:
106
+
107
+ 1. 在 `os.tmpdir()` 下新建(或使用调用者提供的空)根目录;`--work-root` 也必须在 tmpdir 下。
108
+ 2. 把 `DSH_MEMU_HOME` 指向 `<root>/dsh-memu-home`,把 `DSH_MEMU_MEMORY_HOME` 指向 `<root>/dsh-memu-data`。结束后在 `finally` 中恢复原环境变量。
109
+ 3. 不读取、不打开、不写入用户真实 `dataDir()`。harness 没有“指向用户库”的参数;要评估真实库,必须先另做只读快照设计,当前未实现。
110
+ 4. 每条样本创建独立的 library(独立 `scopeKey`)和独立 session,写入独立 private index;样本声明的 `library` 子集只在本样本内可见。
111
+ 5. secret 显式探针使用第二套独立 library/session,避免 `purpose='explicit'` 的 `touchAccessMany` 访问计数影响自动召回;所有 `accessCount`、`injectCount` 都从 0 开始且只存在临时状态中。
112
+ 6. 固定时钟:`Date.now()` 被按样本 `time` 覆盖;固定随机:seeded mulberry32;默认 seed 20261029。
113
+ 7. 默认运行结束删除临时根;传 `work-root` 时保留,便于检查 `state.json`。
114
+
115
+ **隔离证据**:测试在测试自己的 `DSH_MEMU_HOME` 下放 sentinel 文件,运行两次 benchmark 后检查 sentinel 内容未变、该 home 下没有生成 `state.json`;同时检查 run root 下存在 `dsh-memu-data/state.json`,且 `metrics.isolation.violations === 0`。完整证据由测试输出和报告 JSON 共同提供,不靠口头声明。
116
+
117
+ **确定性**:同一数据 SHA-256、同一 seed、同一 config 的两次运行,候选/最终/显式指标与逐样本 top-3 完全一致(测试比较时剔除天然波动的 `latencyMs`;`startedAt` 和临时根路径也不会相同)。延迟不能承诺逐次相同。
118
+
119
+ ## 5. 指标定义
120
+
121
+ 三个投影分别计算,且都只看**前 3 个 id**:
122
+
123
+ - **候选 id**:`privateRecall({ purpose: 'automatic', topK: 20 })` 返回的 id 顺序的前 3 个。`candidateTop3` 是候选阶段指标。
124
+ - **最终注入 id**:`buildRecall(...)` 返回的 `ids` 的前 3 个。它可能受 `dedupeTurns`、`useGlobal`、token budget 和格式渲染影响,因此必须与候选分开记录。
125
+ - **显式探针**:对声明了 `explicitExpectedIds` 的样本,用独立 library/session 调 `privateRecall({ purpose: 'explicit' })` 的前 3 个;只用于 secret 自动/显式差异,不混入自动指标。
126
+
127
+ 定义与空集规则:
128
+
129
+ | 指标 | 分母 | 规则 |
130
+ |---|---|---|
131
+ | Recall@3 | `noAnswer=false` 的样本数(answerable) | 前 3 中至少有一个 `expectedIds` 即命中;命中样本数 / answerable |
132
+ | MRR@3 | 同上 | 第一个期望 id 的排名取倒数(1/rank);前 3 没有则为 0;求和 / answerable |
133
+ | 无答案误召回率 | `noAnswer=true` 的样本数 | 前 3 非空即误召回;误召回样本数 / noAnswer |
134
+ | 隔离违规 | 不设 rate 分母;报告 forbidden 检查次数 | 每个 `forbiddenIds` 在每个投影的 top-3 中出现一次记一次;必须为 0 |
135
+
136
+ - 某个分母为 0 时,对应 rate 输出 `0`,并在 `emptySet` 中标记为 `true`;不会用 0 冒充“完美”。
137
+ - `noAnswer=true` 的样本即使有 `forbiddenIds`,也不会进入 Recall/MRR 分母;其 top-3 非空同时会造成无答案误召回。
138
+ - `isolation.violations` 是 candidate、finalInjected、explicitProbe 三个投影的违规总和;`forbiddenDenominator` 是三个投影的 forbidden 检查次数总和。隔离要求是精确 0,不是“低于某个率”。
139
+
140
+ ## 6. Provisional baseline 明细
141
+
142
+ ### 6.1 总体
143
+
144
+ | 投影 | answerable | Recall@3 | MRR@3 | noAnswer | 无答案误召回率 | 隔离违规 | forbidden 检查 |
145
+ |---|---:|---:|---:|---:|---:|---:|---:|
146
+ | 候选 id | 33 | 1.000000 | 0.984848 | 9 | 0.000000 | 0 | 20 |
147
+ | 最终注入 id | 33 | 1.000000 | 0.984848 | 9 | 0.000000 | 0 | 20 |
148
+ | 显式探针 | 5 | 1.000000 | 1.000000 | 0 | n/a(空集) | 0 | 0 |
149
+
150
+ ### 6.2 按子类
151
+
152
+ 候选与最终注入在本次 baseline 中相同;下表列的是两者共同值(逐样本仍分别保存)。
153
+
154
+ | 子类 | 样本 | answerable / noAnswer | Recall@3 | MRR@3 | 无答案误召回 |
155
+ |---|---:|---:|---:|---:|---:|
156
+ | paraphrase | 6 | 6 / 0 | 1.000000 | 1.000000 | 0.000000 |
157
+ | exact | 5 | 5 / 0 | 1.000000 | 1.000000 | 0.000000 |
158
+ | negation | 4 | 4 / 0 | 1.000000 | 1.000000 | 0.000000 |
159
+ | no-answer | 6 | 0 / 6 | 0(空集) | 0(空集) | 0.000000 |
160
+ | conflict | 5 | 5 / 0 | 1.000000 | 0.900000 | 0.000000 |
161
+ | boundary | 6 | 6 / 0 | 1.000000 | 1.000000 | 0.000000 |
162
+ | secret | 5 | 2 / 3 | 1.000000 | 1.000000 | 0.000000 |
163
+ | coding | 5 | 5 / 0 | 1.000000 | 1.000000 | 0.000000 |
164
+
165
+ ### 6.3 延迟与预算
166
+
167
+ 延迟(`metrics.latency`):
168
+
169
+ - 后端:`local-lexical`
170
+ - 样本数:42
171
+ - 口径:单 Node 进程,`performance.now()` 包住每条样本的 automatic `privateRecall` + `buildRecall`;不是服务延迟,也不是网络/磁盘全链路延迟
172
+ - 本次:median **25.618 ms**,p95 **33.959 ms**
173
+ - 延迟随机器和运行波动,不属于确定性断言
174
+
175
+ Token 预算(只能称 estimate):
176
+
177
+ - 字段:`budget.estimate`(同时保留 `injectedTokenEstimateTotal` / `injectedTokenEstimateMean` 兼容字段)
178
+ - 方法:`lib/budget.js` 的 `estTokens`(CJK 约 1 token/字,Latin 约 3.4 字符/token)
179
+ - 本次:`injectedTokenTotal=4867`,`injectedTokenMeanPerSample=115.881`,`turnTokens=640`
180
+ - **这是估算,不是模型 tokenizer 的实测消耗。** 没有用真实 tokenizer;不得把它写成“实际用量”。
181
+
182
+ ## 7. 机器可读输出
183
+
184
+ `runBenchmark()` 返回 / CLI `--out` 写出的 JSON 包含:
185
+
186
+ - `schemaVersion`、`kind`、`ok`、`status`
187
+ - `dataset`:status、draft、notGold、sampleCount、fileCount、sha256、files
188
+ - `code`:git commit、packageVersion、worktree 说明
189
+ - `run`:startedAt、root、clock、randomSeed、random、sampleLimit
190
+ - `config`:backend、candidateTopK=20、privateTopK=3、turnTokens=640、relevanceThreshold=0.4、dedupeTurns=16、vectorPath
191
+ - `metrics`:candidate、finalInjected、explicitProbe、isolation、latency、bySubclass
192
+ - `budget`:`estimateOnly=true`、`estimate` 对象、flat estimate 字段与 note
193
+ - `samples`:每条样本的 `candidateIds`/`candidateTop3`、`injectedIds`/`injectedTop3`、`explicitIds`/`explicitTop3`、估计 token、延迟与状态
194
+
195
+ ## 8. 未验证项与限制
196
+
197
+ 以下都**未验证**,不能从本 baseline 推出:
198
+
199
+ 1. **人工金标**:42 条全是合成草稿,没有人工逐条核对、没有标注者一致性;不能叫 gold,也不能用作上线门槛。
200
+ 2. **真实用户库**:harness 不读取真实 `dataDir()`,没有在真实记忆上跑过;真实库的规模、噪声、重复、历史状态会改变结果。
201
+ 3. **真实语义/向量质量**:本次只有 local-lexical;`mockVectors` 仅标记管线接口,未调用真实 embedding。W7 的混合召回质量仍未验证。
202
+ 4. **模型 tokenizer / 实际 token 用量**:预算只来自字符估算;没有 tokenizer 版本或实测对照。
203
+ 5. **服务延迟**:25.618/33.959 ms 是本机单进程的 harness 耗时,不是 WebUI 或 API 后端服务延迟。
204
+ 6. **跨平台/并发**:只在当前 Windows 工作区和单进程测试;没有并发写、崩溃恢复、多个 session 同时运行的覆盖。
205
+ 7. **真实 RP 分布**:样本是人工设计的短查询,不能代表长篇 RP 的自然语言分布、长上下文和多轮注入历史。
206
+ 8. **生产排序**:本包只 import 生产函数做只读调用,没有改 `lib/memory.js`、`lib/inject.js` 或任何生产排序/权重;因此不能声称生产召回已被优化。
207
+ 9. **数据可迁移性**:样本只在小 library 子集(每条 1–10 条)内评测,不能外推到全局 library 排序。
208
+
209
+ ## 9. 回退与数据影响
210
+
211
+ - **生产代码/配置**:无改动。没有改排序、阈值、默认 backend、schema 或共享 `/api`。
212
+ - **用户数据**:无接触、无迁移、无写入。所有 benchmark 状态在 `os.tmpdir()` 的临时根下,默认运行后删除;`--work-root` 仅供调试,且仍必须在 tmpdir 下。
213
+ - **回退方式**:删除本包新增的 `scripts/recall-bench.mjs`、`tests/fixtures/recall-bench/`、`tests/recall-bench.test.mjs`、本文档即可;没有数据库或运行时状态需要回滚。
214
+ - 若要把本包提交到版本库,应先按仓库流程单独提交;当前 W6 工作区改动尚未 commit(见 `code.worktree`)。
215
+
216
+ ## 10. 人工金标候选(待审核,非 gold)
217
+
218
+ 除默认 42 条 `synthetic-draft-not-gold` 外,W6 另有一套 **40 条人工审核候选**:
219
+
220
+ - 位置:`tests/fixtures/recall-bench-gold-candidates/`(8 个文件、8 个子类各 5 条、64 个库条目)。
221
+ - 状态:`gold-candidate-pending-review`;每条 `draft=true`、`notGold=true`、`gold=false`、`review=pending`。
222
+ - 数据集 SHA-256:`c6f3a5461de357d8d6fd5a89ada3a068e82b08cb047251258abc32c9919bc8cf`。
223
+ - 审核表与逐条勾选流程由维护者本地保存,不随仓库分发(其中含候选内容)。
224
+ - 运行候选集:`node --import ./tests/loader-register.mjs scripts/recall-bench.mjs --fixture-dir tests/fixtures/recall-bench-gold-candidates`。
225
+
226
+ 候选集**不是** gold set。只有人工逐条确认、另行迁移状态并重算哈希后,才能讨论金标分数;当前测试只验证结构、隔离和 no-answer 空集,不锁定候选分数。默认数据集与默认 CLI 行为保持不变。
227
+
228
+ ## 11. W7 评测证据与生产边界
229
+
230
+ 旧 W7 混合召回设置 (`hybridRecall` / `hybridRecallMode`) 及其 LLM 重排生产接线已移除。当前 benchmark 只验证本地词法管线、候选资格/隔离、最终注入和预算估算;它不启用聊天/总结模型,也不把历史 LLM 实验当作生产路径。
231
+
232
+ 默认数据集的 42 条 synthetic-draft 样本在 2026-10-29 复跑结果与 §5 基线一致:candidate / final-injected 的 Recall@3 = 1、MRR@3 = 0.984848、no-answer 误召回 = 0、隔离违规 = 0;预算估算 `injectedTokenTotal=4867`、mean=115.881、`turnTokens=640`;数据集 SHA-256 未变 `4b3d01898071073f318d815346b1af2758878900a2685355f6bd40445531a2b0`。
233
+
234
+ 历史 W7 LLM 重排实验(2026-10-29,两轮;仅保留证据,不提供生产启用入口):同一 42 条 synthetic-draft 数据集,candidate / final-injected 的 Recall@3 = 1、MRR@3 = 0.984848、no-answer 误召回 = 0、隔离违规 = 0,两轮返回 id 序列相同。31 条走 hybrid-llm-rrf、11 条保持 local(6 条 no-answer、3 条 automatic secret 空集、2 条 exact id);55 个词法候选、32 个有效重排 id,23 个 local-only、0 个 semantic-only、32 个 shared,没有调用错误。4 条 top-3 顺序变化,top-1 不变。第一轮 median=4249.458 ms / p95=6102.986 ms,第二轮 median=4305.708 ms / p95=7804.750 ms;墙钟约 166 s / 184 s。预算仅估算:total=5096、mean=121.333、turnTokens=640(词法基线 total=4867、mean=115.881);不是实际 token 消耗,也不是有效性或上线许可。
235
+
236
+ W8(助手重复提示)已决定不做,理由与结论见 `AGENTS.md`;证据文档已删除,旧 LLM/重复提示实验与当前生产召回路径解耦,不应再通过 benchmark CLI 重跑。
237
+
238
+ 测试覆盖:`tests/hybrid-recall.test.mjs` 仅保留通用 RRF/fusion helper;managed vector 行为由 `tests/managed-memory.test.mjs` 覆盖。