pi-mega-compact 0.11.4 → 0.11.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 (307) hide show
  1. package/dist/extensions/dashboard-server/api-contracts/endpoints.js +19 -0
  2. package/dist/extensions/dashboard-server/api-contracts/memory.js +8 -0
  3. package/dist/extensions/dashboard-server/api-contracts/provider-cache.js +1 -0
  4. package/dist/extensions/dashboard-server/api-contracts/setup.js +10 -0
  5. package/dist/extensions/dashboard-server/index-reader.js +6 -2
  6. package/dist/extensions/dashboard-server/routes-cache.js +115 -55
  7. package/dist/extensions/dashboard-server/routes-memory.js +51 -0
  8. package/dist/extensions/dashboard-server/routes-repo.js +2 -2
  9. package/dist/extensions/dashboard-server/routes-setup.js +162 -0
  10. package/dist/extensions/dashboard-server/routes.js +2 -0
  11. package/dist/extensions/dashboard-server/server.js +7 -1
  12. package/dist/extensions/mega-commands.js +189 -1
  13. package/dist/extensions/mega-config.js +2 -0
  14. package/dist/extensions/mega-events/agent-handlers.js +19 -4
  15. package/dist/extensions/mega-events/compact-handlers.js +1 -0
  16. package/dist/extensions/mega-events/context-handler.js +37 -92
  17. package/dist/extensions/mega-events/context-hwm.js +51 -0
  18. package/dist/extensions/mega-events/error-classifier.js +16 -5
  19. package/dist/extensions/mega-events/mirror-append.js +107 -0
  20. package/dist/extensions/mega-events/outage-advisor.js +7 -1
  21. package/dist/extensions/mega-events/perf-handler.js +51 -1
  22. package/dist/extensions/mega-events/recall-tail.js +59 -0
  23. package/dist/extensions/mega-events/session-handlers.js +15 -8
  24. package/dist/extensions/mega-runtime/reset-runtime.js +5 -0
  25. package/dist/extensions/mega-runtime/runtime.js +6 -0
  26. package/dist/src/embedder.js +41 -2
  27. package/dist/src/memoryStats.js +75 -0
  28. package/dist/src/prefix-break.js +43 -0
  29. package/dist/src/pricing.js +1 -1
  30. package/dist/src/store/sqlite/perf-samples.js +144 -16
  31. package/dist/src/store/turns/memory-store.js +8 -0
  32. package/dist/src/store/turns/sqlite-store.js +14 -3
  33. package/dist/src/store/turns/types.js +18 -1
  34. package/dist/src/store/vectorIndex.js +26 -5
  35. package/extensions/dashboard-client/dist/assets/{AchievementTiles-vEo2MtE2.js → AchievementTiles-BoL7qBOJ.js} +2 -2
  36. package/extensions/dashboard-client/dist/assets/{AchievementTiles-vEo2MtE2.js.map → AchievementTiles-BoL7qBOJ.js.map} +1 -1
  37. package/extensions/dashboard-client/dist/assets/AchievementsTab-BFDE3HYc.js +2 -0
  38. package/extensions/dashboard-client/dist/assets/{AchievementsTab-DjxfYrDc.js.map → AchievementsTab-BFDE3HYc.js.map} +1 -1
  39. package/extensions/dashboard-client/dist/assets/CacheTab-eKVc-NV1.js +2 -0
  40. package/extensions/dashboard-client/dist/assets/CacheTab-eKVc-NV1.js.map +1 -0
  41. package/extensions/dashboard-client/dist/assets/{ConfigTab-Cm6ymbmx.js → ConfigTab-DDFE-ckA.js} +2 -2
  42. package/extensions/dashboard-client/dist/assets/{ConfigTab-Cm6ymbmx.js.map → ConfigTab-DDFE-ckA.js.map} +1 -1
  43. package/extensions/dashboard-client/dist/assets/{EventsTab-DXWl_YzI.js → EventsTab-B6UxZ7PM.js} +2 -2
  44. package/extensions/dashboard-client/dist/assets/{EventsTab-DXWl_YzI.js.map → EventsTab-B6UxZ7PM.js.map} +1 -1
  45. package/extensions/dashboard-client/dist/assets/{GameTab-BLDudcO5.js → GameTab-DehUX-KE.js} +2 -2
  46. package/extensions/dashboard-client/dist/assets/{GameTab-BLDudcO5.js.map → GameTab-DehUX-KE.js.map} +1 -1
  47. package/extensions/dashboard-client/dist/assets/{MaintenanceTab-DLkKCztn.js → MaintenanceTab-0GWRt4wn.js} +2 -2
  48. package/extensions/dashboard-client/dist/assets/{MaintenanceTab-DLkKCztn.js.map → MaintenanceTab-0GWRt4wn.js.map} +1 -1
  49. package/extensions/dashboard-client/dist/assets/{MetricsTab-Cq4u-rZF.js → MetricsTab-C3rwMVsN.js} +2 -2
  50. package/extensions/dashboard-client/dist/assets/{MetricsTab-Cq4u-rZF.js.map → MetricsTab-C3rwMVsN.js.map} +1 -1
  51. package/extensions/dashboard-client/dist/assets/OverviewTab-39O9_x5j.js +2 -0
  52. package/extensions/dashboard-client/dist/assets/{OverviewTab-D4kGvsiQ.js.map → OverviewTab-39O9_x5j.js.map} +1 -1
  53. package/extensions/dashboard-client/dist/assets/ReposTab-Cfj6Q5sH.js +2 -0
  54. package/extensions/dashboard-client/dist/assets/ReposTab-Cfj6Q5sH.js.map +1 -0
  55. package/extensions/dashboard-client/dist/assets/{SessionsTab-DZC2-GCn.js → SessionsTab-DXDTCi3r.js} +2 -2
  56. package/extensions/dashboard-client/dist/assets/{SessionsTab-DZC2-GCn.js.map → SessionsTab-DXDTCi3r.js.map} +1 -1
  57. package/extensions/dashboard-client/dist/assets/SetupTab-mMlfunJa.js +2 -0
  58. package/extensions/dashboard-client/dist/assets/SetupTab-mMlfunJa.js.map +1 -0
  59. package/extensions/dashboard-client/dist/assets/TimeSavedCard-Cw1dJ4e9.js +2 -0
  60. package/extensions/dashboard-client/dist/assets/TimeSavedCard-Cw1dJ4e9.js.map +1 -0
  61. package/extensions/dashboard-client/dist/assets/{TopicsTab-01G71hv1.js → TopicsTab-BAw972BV.js} +2 -2
  62. package/extensions/dashboard-client/dist/assets/{TopicsTab-01G71hv1.js.map → TopicsTab-BAw972BV.js.map} +1 -1
  63. package/extensions/dashboard-client/dist/assets/{TurnsTab-DLRg0LZT.js → TurnsTab-Cf5mGIdl.js} +2 -2
  64. package/extensions/dashboard-client/dist/assets/{TurnsTab-DLRg0LZT.js.map → TurnsTab-Cf5mGIdl.js.map} +1 -1
  65. package/extensions/dashboard-client/dist/assets/format-COjDIVGj.js +2 -0
  66. package/extensions/dashboard-client/dist/assets/format-COjDIVGj.js.map +1 -0
  67. package/extensions/dashboard-client/dist/assets/{index-BX0bcgLu.js → index-4gQ7auad.js} +10 -10
  68. package/extensions/dashboard-client/dist/assets/index-4gQ7auad.js.map +1 -0
  69. package/extensions/dashboard-client/dist/assets/pricing-CvE4NllQ.js +2 -0
  70. package/extensions/dashboard-client/dist/assets/pricing-CvE4NllQ.js.map +1 -0
  71. package/extensions/dashboard-client/dist/assets/{useSSE-BBYt5UPB.js → useSSE-DNgMuyP6.js} +2 -2
  72. package/extensions/dashboard-client/dist/assets/{useSSE-BBYt5UPB.js.map → useSSE-DNgMuyP6.js.map} +1 -1
  73. package/extensions/dashboard-client/dist/index.html +1 -1
  74. package/extensions/dashboard-client/src/App.tsx +4 -0
  75. package/extensions/dashboard-client/src/api/client.ts +14 -0
  76. package/extensions/dashboard-client/src/components/ActiveReposTable.tsx +21 -12
  77. package/extensions/dashboard-client/src/components/ProviderCacheCard.tsx +56 -0
  78. package/extensions/dashboard-client/src/components/SavingsByModelTable.tsx +38 -57
  79. package/extensions/dashboard-client/src/tabs/CacheTab.tsx +1 -0
  80. package/extensions/dashboard-client/src/tabs/SetupTab.tsx +355 -0
  81. package/extensions/dashboard-client/tsconfig.json +3 -2
  82. package/extensions/dashboard-client/vite.config.ts +2 -0
  83. package/extensions/dashboard-server/api-contracts/endpoints.ts +36 -3
  84. package/extensions/dashboard-server/api-contracts/index.ts +7 -0
  85. package/extensions/dashboard-server/api-contracts/memory.ts +27 -0
  86. package/extensions/dashboard-server/api-contracts/multi-repo.ts +231 -231
  87. package/extensions/dashboard-server/api-contracts/provider-cache.ts +37 -0
  88. package/extensions/dashboard-server/api-contracts/setup.ts +58 -0
  89. package/extensions/dashboard-server/index-reader.ts +138 -121
  90. package/extensions/dashboard-server/routes-cache.ts +161 -85
  91. package/extensions/dashboard-server/routes-memory.ts +63 -0
  92. package/extensions/dashboard-server/routes-repo.ts +36 -36
  93. package/extensions/dashboard-server/routes-setup.ts +181 -0
  94. package/extensions/dashboard-server/routes.ts +2 -0
  95. package/extensions/dashboard-server/server.ts +6 -0
  96. package/extensions/mega-commands.ts +211 -1
  97. package/extensions/mega-config.ts +10 -0
  98. package/extensions/mega-events/agent-handlers.ts +20 -4
  99. package/extensions/mega-events/compact-handlers.ts +1 -0
  100. package/extensions/mega-events/context-handler.ts +45 -110
  101. package/extensions/mega-events/context-hwm.ts +85 -0
  102. package/extensions/mega-events/error-classifier.ts +15 -4
  103. package/extensions/mega-events/mirror-append.ts +155 -0
  104. package/extensions/mega-events/outage-advisor.ts +11 -5
  105. package/extensions/mega-events/perf-handler.ts +79 -5
  106. package/extensions/mega-events/recall-tail.ts +88 -0
  107. package/extensions/mega-events/session-handlers.ts +14 -7
  108. package/extensions/mega-runtime/helpers.ts +12 -0
  109. package/extensions/mega-runtime/reset-runtime.ts +5 -0
  110. package/extensions/mega-runtime/runtime.ts +6 -0
  111. package/package.json +5 -2
  112. package/src/embedder.ts +42 -2
  113. package/src/memoryStats.ts +107 -0
  114. package/src/prefix-break.ts +83 -0
  115. package/src/pricing.ts +2 -2
  116. package/src/store/sqlite/perf-samples.ts +215 -22
  117. package/src/store/turns/memory-store.ts +10 -1
  118. package/src/store/turns/sqlite-store.ts +27 -15
  119. package/src/store/turns/types.ts +21 -0
  120. package/src/store/vectorIndex.ts +33 -4
  121. package/dist/extensions/conflict-scan.test.js +0 -115
  122. package/dist/extensions/dashboard-server/api-contracts.test.js +0 -884
  123. package/dist/extensions/dashboard-server/html.test.js +0 -52
  124. package/dist/extensions/dashboard-server/perf-server.test.js +0 -80
  125. package/dist/extensions/dashboard-server/routes-cache.test.js +0 -248
  126. package/dist/extensions/dashboard-server/server.test.js +0 -120
  127. package/dist/extensions/dashboard-server-s32.test.js +0 -181
  128. package/dist/extensions/dashboard-server.test.js +0 -339
  129. package/dist/extensions/mega-cache-replay.test.js +0 -400
  130. package/dist/extensions/mega-compact-s38.test.js +0 -1383
  131. package/dist/extensions/mega-compact.test.js +0 -1112
  132. package/dist/extensions/mega-events.test.js +0 -47
  133. package/dist/extensions/mega-game-cmds.test.js +0 -163
  134. package/dist/extensions/mega-runtime/snapshot.test.js +0 -127
  135. package/dist/extensions/mega-runtime/state.test.js +0 -266
  136. package/dist/extensions/mega-runtime/widget.test.js +0 -343
  137. package/dist/extensions/mega-shutdown-widget.test.js +0 -121
  138. package/dist/extensions/mega-teamrun.test.js +0 -156
  139. package/dist/extensions/mega-trim.test.js +0 -58
  140. package/dist/extensions/mega-turn-store.test.js +0 -68
  141. package/dist/src/boundary.test.js +0 -170
  142. package/dist/src/compact.test.js +0 -78
  143. package/dist/src/config/themes.test.js +0 -94
  144. package/dist/src/dedup/dedup.test.js +0 -41
  145. package/dist/src/dedup/l1.test.js +0 -50
  146. package/dist/src/dedup/raptor/buildHistory.test.js +0 -292
  147. package/dist/src/dedup/raptor/multilevel-serve.test.js +0 -229
  148. package/dist/src/dedup/raptor/multilevel.test.js +0 -238
  149. package/dist/src/dedup/raptor/promote.test.js +0 -69
  150. package/dist/src/dedup/raptor/raptor.test.js +0 -248
  151. package/dist/src/dedup/raptor/retrieval.test.js +0 -95
  152. package/dist/src/dedup/raptor/serve-gate.test.js +0 -298
  153. package/dist/src/dedup/sprint12.test.js +0 -219
  154. package/dist/src/dedup-engine.test.js +0 -472
  155. package/dist/src/driftDetection.test.js +0 -87
  156. package/dist/src/e2e.test.js +0 -698
  157. package/dist/src/engine.test.js +0 -111
  158. package/dist/src/extractive.test.js +0 -147
  159. package/dist/src/fork.test.js +0 -81
  160. package/dist/src/game/scoring.test.js +0 -98
  161. package/dist/src/httpEmbedder.test.js +0 -277
  162. package/dist/src/importance.test.js +0 -372
  163. package/dist/src/intent.test.js +0 -78
  164. package/dist/src/log.test.js +0 -42
  165. package/dist/src/mechanical-fix.test.js +0 -65
  166. package/dist/src/memory.test.js +0 -70
  167. package/dist/src/memoryConsolidate.test.js +0 -38
  168. package/dist/src/memoryOps.test.js +0 -129
  169. package/dist/src/memoryRecall.test.js +0 -171
  170. package/dist/src/memoryRoundtrip.test.js +0 -137
  171. package/dist/src/metrics/turns.test.js +0 -152
  172. package/dist/src/mirror/mirror.test.js +0 -185
  173. package/dist/src/raptor-inject-summaries.test.js +0 -162
  174. package/dist/src/ratio.bench.test.js +0 -897
  175. package/dist/src/recall.integration.test.js +0 -77
  176. package/dist/src/recall.test.js +0 -379
  177. package/dist/src/sprint14.test.js +0 -219
  178. package/dist/src/sprint4x-rag-verification.test.js +0 -93
  179. package/dist/src/store/compression.test.js +0 -139
  180. package/dist/src/store/memoryIndex.test.js +0 -51
  181. package/dist/src/store/migrate.test.js +0 -139
  182. package/dist/src/store/pgOpenGuard.test.js +0 -74
  183. package/dist/src/store/phase01.test.js +0 -81
  184. package/dist/src/store/phase04.test.js +0 -54
  185. package/dist/src/store/sprint10.test.js +0 -186
  186. package/dist/src/store/sqlite/game-achievements.test.js +0 -67
  187. package/dist/src/store/sqlite/game-scores.test.js +0 -106
  188. package/dist/src/store/sqlite/game-state.test.js +0 -76
  189. package/dist/src/store/sqlite/global-index.test.js +0 -136
  190. package/dist/src/store/sqlite/mechanical-fix.test.js +0 -146
  191. package/dist/src/store/sqlite/perf-samples.test.js +0 -146
  192. package/dist/src/store/sqlite/raptor.test.js +0 -106
  193. package/dist/src/store/sqlite/turns.test.js +0 -183
  194. package/dist/src/store/sqlite.cachehit.test.js +0 -55
  195. package/dist/src/store/sqlite.dbmaint.test.js +0 -158
  196. package/dist/src/store/sqlite.dbmirror.test.js +0 -184
  197. package/dist/src/store/turns/contract-compliance.test.js +0 -428
  198. package/dist/src/store/turns/memory-store.test.js +0 -9
  199. package/dist/src/store/turns/migrations.test.js +0 -138
  200. package/dist/src/store/turns/sqlite-store.test.js +0 -144
  201. package/dist/src/store/vectorIndex.test.js +0 -123
  202. package/dist/src/store.test.js +0 -161
  203. package/dist/src/supersede.test.js +0 -36
  204. package/dist/src/topics/cluster.test.js +0 -150
  205. package/dist/src/topics/store.test.js +0 -117
  206. package/dist/src/types.test.js +0 -9
  207. package/dist/src/vector-search-cache.test.js +0 -157
  208. package/dist/src/vectorStore.test.js +0 -479
  209. package/dist/src/wiki.test.js +0 -171
  210. package/extensions/conflict-scan.test.ts +0 -129
  211. package/extensions/dashboard-client/dist/assets/AchievementsTab-DjxfYrDc.js +0 -2
  212. package/extensions/dashboard-client/dist/assets/CacheTab-Dnpv94wq.js +0 -2
  213. package/extensions/dashboard-client/dist/assets/CacheTab-Dnpv94wq.js.map +0 -1
  214. package/extensions/dashboard-client/dist/assets/OverviewTab-D4kGvsiQ.js +0 -2
  215. package/extensions/dashboard-client/dist/assets/ReposTab-C0Wnrf2u.js +0 -2
  216. package/extensions/dashboard-client/dist/assets/ReposTab-C0Wnrf2u.js.map +0 -1
  217. package/extensions/dashboard-client/dist/assets/TimeSavedCard-UqljSyP-.js +0 -2
  218. package/extensions/dashboard-client/dist/assets/TimeSavedCard-UqljSyP-.js.map +0 -1
  219. package/extensions/dashboard-client/dist/assets/index-BX0bcgLu.js.map +0 -1
  220. package/extensions/dashboard-server/api-contracts.test.ts +0 -1065
  221. package/extensions/dashboard-server/html.test.ts +0 -62
  222. package/extensions/dashboard-server/perf-server.test.ts +0 -101
  223. package/extensions/dashboard-server/routes-cache.test.ts +0 -302
  224. package/extensions/dashboard-server/server.test.ts +0 -131
  225. package/extensions/dashboard-server-s32.test.ts +0 -195
  226. package/extensions/dashboard-server.test.ts +0 -382
  227. package/extensions/mega-cache-replay.test.ts +0 -526
  228. package/extensions/mega-compact-s38.test.ts +0 -1433
  229. package/extensions/mega-compact.test.ts +0 -1509
  230. package/extensions/mega-events.test.ts +0 -55
  231. package/extensions/mega-game-cmds.test.ts +0 -197
  232. package/extensions/mega-runtime/snapshot.test.ts +0 -139
  233. package/extensions/mega-runtime/state.test.ts +0 -262
  234. package/extensions/mega-runtime/widget.test.ts +0 -468
  235. package/extensions/mega-shutdown-widget.test.ts +0 -141
  236. package/extensions/mega-teamrun.test.ts +0 -176
  237. package/extensions/mega-trim.test.ts +0 -64
  238. package/extensions/mega-turn-store.test.ts +0 -108
  239. package/src/boundary.test.ts +0 -187
  240. package/src/compact.test.ts +0 -99
  241. package/src/config/themes.test.ts +0 -116
  242. package/src/dedup/dedup.test.ts +0 -46
  243. package/src/dedup/l1.test.ts +0 -57
  244. package/src/dedup/raptor/buildHistory.test.ts +0 -353
  245. package/src/dedup/raptor/multilevel-serve.test.ts +0 -273
  246. package/src/dedup/raptor/multilevel.test.ts +0 -325
  247. package/src/dedup/raptor/promote.test.ts +0 -82
  248. package/src/dedup/raptor/raptor.test.ts +0 -297
  249. package/src/dedup/raptor/retrieval.test.ts +0 -118
  250. package/src/dedup/raptor/serve-gate.test.ts +0 -348
  251. package/src/dedup/sprint12.test.ts +0 -242
  252. package/src/dedup-engine.test.ts +0 -670
  253. package/src/driftDetection.test.ts +0 -100
  254. package/src/e2e.test.ts +0 -843
  255. package/src/engine.test.ts +0 -123
  256. package/src/extractive.test.ts +0 -174
  257. package/src/fork.test.ts +0 -94
  258. package/src/game/scoring.test.ts +0 -103
  259. package/src/httpEmbedder.test.ts +0 -286
  260. package/src/importance.test.ts +0 -538
  261. package/src/intent.test.ts +0 -87
  262. package/src/log.test.ts +0 -47
  263. package/src/mechanical-fix.test.ts +0 -70
  264. package/src/memory.test.ts +0 -92
  265. package/src/memoryConsolidate.test.ts +0 -47
  266. package/src/memoryOps.test.ts +0 -148
  267. package/src/memoryRecall.test.ts +0 -194
  268. package/src/memoryRoundtrip.test.ts +0 -155
  269. package/src/metrics/turns.test.ts +0 -165
  270. package/src/mirror/mirror.test.ts +0 -240
  271. package/src/raptor-inject-summaries.test.ts +0 -228
  272. package/src/ratio.bench.test.ts +0 -1316
  273. package/src/recall.integration.test.ts +0 -96
  274. package/src/recall.test.ts +0 -467
  275. package/src/sprint14.test.ts +0 -245
  276. package/src/sprint4x-rag-verification.test.ts +0 -119
  277. package/src/store/compression.test.ts +0 -168
  278. package/src/store/memoryIndex.test.ts +0 -61
  279. package/src/store/migrate.test.ts +0 -158
  280. package/src/store/pgOpenGuard.test.ts +0 -89
  281. package/src/store/phase01.test.ts +0 -88
  282. package/src/store/phase04.test.ts +0 -58
  283. package/src/store/sprint10.test.ts +0 -214
  284. package/src/store/sqlite/game-achievements.test.ts +0 -80
  285. package/src/store/sqlite/game-scores.test.ts +0 -132
  286. package/src/store/sqlite/game-state.test.ts +0 -89
  287. package/src/store/sqlite/global-index.test.ts +0 -222
  288. package/src/store/sqlite/mechanical-fix.test.ts +0 -162
  289. package/src/store/sqlite/perf-samples.test.ts +0 -169
  290. package/src/store/sqlite/raptor.test.ts +0 -139
  291. package/src/store/sqlite/turns.test.ts +0 -218
  292. package/src/store/sqlite.cachehit.test.ts +0 -68
  293. package/src/store/sqlite.dbmaint.test.ts +0 -193
  294. package/src/store/sqlite.dbmirror.test.ts +0 -229
  295. package/src/store/turns/contract-compliance.test.ts +0 -562
  296. package/src/store/turns/memory-store.test.ts +0 -15
  297. package/src/store/turns/migrations.test.ts +0 -161
  298. package/src/store/turns/sqlite-store.test.ts +0 -161
  299. package/src/store/vectorIndex.test.ts +0 -140
  300. package/src/store.test.ts +0 -191
  301. package/src/supersede.test.ts +0 -42
  302. package/src/topics/cluster.test.ts +0 -176
  303. package/src/topics/store.test.ts +0 -132
  304. package/src/types.test.ts +0 -10
  305. package/src/vector-search-cache.test.ts +0 -190
  306. package/src/vectorStore.test.ts +0 -533
  307. package/src/wiki.test.ts +0 -217
@@ -1,479 +0,0 @@
1
- import { test } from "node:test";
2
- import assert from "node:assert/strict";
3
- import { mkdtempSync, rmSync, writeFileSync, mkdirSync } from "node:fs";
4
- import { tmpdir } from "node:os";
5
- import { join } from "node:path";
6
- import { VectorStore, computeRegionHash, vectorStats, vectorDedupe, vectorWasInjected, vectorMarkInjected, vectorList, vectorTopSimilar, vectorRepoStats, vectorSearch } from "./vectorStore.js";
7
- import { TrigramEmbedder, cosineSimilarity, l2Normalize, defaultEmbedder, } from "./embedder.js";
8
- import { normalizeSessionId, decompressSmart } from "./store.js";
9
- const baseTmp = mkdtempSync(join(tmpdir(), "mc-test-"));
10
- // Each store() gets its own isolated state dir passed explicitly (no global
11
- // env var) so parallel/concurrent tests never share on-disk checkpoints.
12
- let counter = 0;
13
- function store(opts = {}) {
14
- const dir = join(baseTmp, `run-${counter++}`);
15
- return new VectorStore({ dedupSim: opts.dedupSim ?? 0.9, stateDir: dir });
16
- }
17
- test("cleanup temp dir", () => {
18
- assert.ok(baseTmp.startsWith(tmpdir()));
19
- });
20
- test("embedder is deterministic and normalized", () => {
21
- const e = defaultEmbedder();
22
- const a = e.embed("compact the session context");
23
- const b = e.embed("compact the session context");
24
- assert.deepEqual(a, b);
25
- const n = l2Normalize(a);
26
- const mag = Math.sqrt(n.reduce((s, x) => s + x * x, 0));
27
- assert.ok(Math.abs(mag - 1) < 1e-9);
28
- });
29
- test("cosine similarity is 1 for identical, <1 for different", () => {
30
- const e = new TrigramEmbedder();
31
- const a = e.embed("read src/server.ts and fix the bug");
32
- const b = e.embed("read src/server.ts and fix the bug");
33
- const c = e.embed("play a song on the guitar");
34
- assert.ok(Math.abs(cosineSimilarity(a, b) - 1) < 1e-9);
35
- assert.ok(cosineSimilarity(a, c) < 1);
36
- });
37
- test("add then search returns the planted checkpoint top-1", () => {
38
- const s = store();
39
- s.add({
40
- sessionId: "sess_abc",
41
- summary: "Investigated src/compact.ts and added truncation.",
42
- regionText: "user asked to investigate src/compact.ts assistant added truncate helper",
43
- keyDecisions: ["add truncate helper"],
44
- filesModified: ["src/compact.ts"],
45
- tokenEstimate: 1200,
46
- timestamp: 1000,
47
- });
48
- const hits = vectorSearch(s, "sess_abc", "src/compact.ts truncate helper", 3);
49
- assert.equal(hits.length, 1);
50
- assert.ok(hits[0].score > 0.5);
51
- assert.equal(hits[0].checkpoint.summary.includes("src/compact.ts"), true);
52
- });
53
- test("dedup by regionHash: identical region is not double-stored", () => {
54
- const s = store();
55
- const region = "the same conversation region text";
56
- const r1 = s.add({
57
- sessionId: "sess_dup",
58
- summary: "first",
59
- regionText: region,
60
- timestamp: 1,
61
- });
62
- const r2 = s.add({
63
- sessionId: "sess_dup",
64
- summary: "second",
65
- regionText: region,
66
- timestamp: 2,
67
- });
68
- assert.equal(r1.deduped, false);
69
- assert.equal(r2.deduped, true);
70
- assert.equal(r1.checkpoint.checkpointId, r2.checkpoint.checkpointId);
71
- assert.equal(vectorSearch(s, "sess_dup", "anything", 10).length, 1);
72
- });
73
- test("dedup cascade: summaryHash catches same-topic incremental compactions", () => {
74
- const s = store();
75
- const r1 = s.add({
76
- sessionId: "sess_sh",
77
- summary: "step 1",
78
- topicSummary: "User working on auth module refactor in src/auth.ts.",
79
- regionText: "first region text for step 1",
80
- timestamp: 100,
81
- });
82
- // Different regionText (incremental compaction adds messages), same topicSummary
83
- const r2 = s.add({
84
- sessionId: "sess_sh",
85
- summary: "step 2",
86
- topicSummary: "User working on auth module refactor in src/auth.ts.",
87
- regionText: "second region text for step 2 with additional messages",
88
- timestamp: 200,
89
- });
90
- assert.equal(r1.deduped, false);
91
- assert.equal(r2.deduped, true);
92
- assert.equal(r2.reason, "summaryHash");
93
- assert.equal(r1.checkpoint.checkpointId, r2.checkpoint.checkpointId);
94
- // Timestamp should be updated to the newer one
95
- assert.equal(r2.checkpoint.timestamp, 200);
96
- });
97
- test("dedup cascade: summaryHash dedup still stores only one checkpoint", () => {
98
- const s = store();
99
- const summary = "same summary for both adds";
100
- const ts = "some topic summary that is identical";
101
- s.add({ sessionId: "sess_sh2", summary, topicSummary: ts, regionText: "region a", timestamp: 1 });
102
- s.add({ sessionId: "sess_sh2", summary, topicSummary: ts, regionText: "region b", timestamp: 2 });
103
- assert.equal(vectorStats(s, "sess_sh2").checkpointCount, 1);
104
- });
105
- test("dedupe() sentinel returns true for a stored region", () => {
106
- const s = store();
107
- const region = "region for sentinel test";
108
- const hash = computeRegionHash(region);
109
- s.add({
110
- sessionId: "sess_sent",
111
- summary: "x",
112
- regionText: region,
113
- timestamp: 1,
114
- });
115
- assert.equal(vectorDedupe(s, "sess_sent", hash), true);
116
- assert.equal(vectorDedupe(s, "sess_sent", "deadbeef"), false);
117
- });
118
- test("near-duplicate collapse keeps only the top of a near-identical pair", () => {
119
- const s = store();
120
- s.add({
121
- sessionId: "sess_nd",
122
- summary: "alpha",
123
- regionText: "user investigated src/compact.ts and added a truncate helper for summaries",
124
- timestamp: 1,
125
- });
126
- s.add({
127
- sessionId: "sess_nd",
128
- summary: "beta",
129
- regionText: "user investigated src/compact.ts and added a truncate helper for the summaries",
130
- timestamp: 2,
131
- });
132
- const hits = vectorSearch(s, "sess_nd", "user investigated src/compact.ts and added a truncate helper for summaries", 5);
133
- assert.equal(hits.length, 1);
134
- });
135
- test("markInjected / wasInjected track injection", () => {
136
- const s = store();
137
- const r = s.add({
138
- sessionId: "sess_inj",
139
- summary: "y",
140
- regionText: "inject region",
141
- timestamp: 1,
142
- });
143
- assert.equal(vectorWasInjected(s, "sess_inj", r.checkpoint.checkpointId), false);
144
- vectorMarkInjected(s, "sess_inj", r.checkpoint.checkpointId);
145
- assert.equal(vectorWasInjected(s, "sess_inj", r.checkpoint.checkpointId), true);
146
- });
147
- test("normalizeSessionId handles null, prefixed, and uuid forms", () => {
148
- assert.match(normalizeSessionId("sess_abc"), /^sess_/);
149
- assert.equal(normalizeSessionId("sess_abc"), "sess_abc");
150
- assert.match(normalizeSessionId("550e8400-e29b-41d4-a716-446655440000"), /^sess_[0-9a-f]{16}$/);
151
- assert.match(normalizeSessionId(undefined), /^sess_[0-9a-f]{16}$/);
152
- });
153
- test("nextCheckpointId is sequential per session", () => {
154
- const s = store();
155
- const a = s.add({
156
- sessionId: "sess_seq",
157
- summary: "1",
158
- regionText: "r1",
159
- timestamp: 1,
160
- });
161
- const b = s.add({
162
- sessionId: "sess_seq",
163
- summary: "2",
164
- regionText: "r2",
165
- timestamp: 2,
166
- });
167
- assert.equal(a.checkpoint.checkpointId, "chkpt_001");
168
- assert.equal(b.checkpoint.checkpointId, "chkpt_002");
169
- });
170
- test("checkpoints survive a fresh store instance (on-disk)", () => {
171
- const dir = join(baseTmp, `run-${counter++}`);
172
- const s1 = new VectorStore({ dedupSim: 0.9, stateDir: dir });
173
- s1.add({
174
- sessionId: "sess_persist",
175
- summary: "persisted",
176
- regionText: "persist region text",
177
- timestamp: 1,
178
- });
179
- const s2 = new VectorStore({ dedupSim: 0.9, stateDir: dir }); // new instance, same disk state
180
- const hits = vectorSearch(s2, "sess_persist", "persist region text", 3);
181
- assert.equal(hits.length, 1);
182
- assert.equal(hits[0].checkpoint.summary, "persisted");
183
- });
184
- test("corrupt checkpoint file falls back to empty (no throw)", () => {
185
- const dir = join(baseTmp, `run-${counter++}`);
186
- mkdirSync(dir, { recursive: true });
187
- const file = join(dir, "sess_corrupt.checkpoints.json.gz");
188
- writeFileSync(file, Buffer.from("not a gzip"));
189
- const s = new VectorStore({ dedupSim: 0.9, stateDir: dir });
190
- assert.equal(vectorSearch(s, "sess_corrupt", "q", 3).length, 0);
191
- });
192
- test("stats reports counts, last checkpoint, and dedup rate", () => {
193
- const s = store();
194
- s.add({
195
- sessionId: "sess_stats",
196
- summary: "alpha",
197
- regionText: "region alpha text",
198
- tokenEstimate: 500,
199
- timestamp: 1,
200
- });
201
- s.add({
202
- sessionId: "sess_stats",
203
- summary: "beta",
204
- regionText: "region beta text",
205
- tokenEstimate: 700,
206
- timestamp: 2,
207
- });
208
- const st1 = vectorStats(s, "sess_stats");
209
- assert.equal(st1.checkpointCount, 2);
210
- assert.equal(st1.lastCheckpointId, "chkpt_002");
211
- assert.equal(st1.totalTokenEstimate, 1200);
212
- assert.equal(st1.injectedCount, 0);
213
- assert.equal(st1.dedupHitRate, 0);
214
- vectorMarkInjected(s, "sess_stats", "chkpt_001");
215
- const st2 = vectorStats(s, "sess_stats");
216
- assert.equal(st2.injectedCount, 1);
217
- assert.ok(Math.abs(st2.dedupHitRate - 0.5) < 1e-9);
218
- });
219
- test("tokensSaved = original − stored per session; deduped add saves the whole region", () => {
220
- const s = store();
221
- // Two genuinely new checkpoints. saved = original − stored.
222
- // cp1: orig 2000, stored 500 → saved 1500
223
- // cp2: orig 3000, stored 700 → saved 2300
224
- s.add({ sessionId: "sess_saved", summary: "alpha", regionText: "region alpha text", tokenEstimate: 500, originalTokenEstimate: 2000, timestamp: 1 });
225
- s.add({ sessionId: "sess_saved", summary: "beta", regionText: "region beta text", tokenEstimate: 700, originalTokenEstimate: 3000, timestamp: 2 });
226
- const st = vectorStats(s, "sess_saved");
227
- assert.equal(st.totalTokenEstimate, 1200, "Σ stored summaries");
228
- assert.equal(st.originalTokens, 5000, "Σ original region tokens");
229
- assert.equal(st.tokensSaved, 3800, "per-session saved = Σ(original − stored) = 1500 + 2300");
230
- assert.equal(st.dedupCollapsed, 0);
231
- assert.equal(st.dedupAttempts, 2);
232
- // A third add that dedups onto an existing region: whole original region (2000)
233
- // is discarded (nothing new stored) → repo saved grows by the full original,
234
- // dedupCollapsed bumps, and no new checkpoint row is created.
235
- const deduped = s.add({ sessionId: "sess_saved", summary: "alpha", regionText: "region alpha text", tokenEstimate: 500, originalTokenEstimate: 2000, timestamp: 3 });
236
- assert.ok(deduped.deduped, "identical region should dedup");
237
- const st3 = vectorStats(s, "sess_saved");
238
- // Per-session DB sum only covers stored rows (deduped adds create no row), so
239
- // the per-session figure is unchanged; the deduped save lands in the repo meta.
240
- assert.equal(st3.tokensSaved, 3800, "per-session DB sum unchanged by deduped add");
241
- assert.equal(st3.dedupCollapsed, 1, "deduped collapse counted");
242
- assert.equal(st3.dedupAttempts, 3);
243
- // Repo cumulative counter DID capture the deduped region's full original size.
244
- assert.equal(vectorRepoStats(s).tokensSaved, 3800 + 2000, "repo saved includes deduped original");
245
- });
246
- test("repoStats aggregates every session + counts deduped original tokens", () => {
247
- const dir = join(baseTmp, `repo-${counter++}`);
248
- const a = new VectorStore({ dedupSim: 0.9, stateDir: dir });
249
- const b = new VectorStore({ dedupSim: 0.9, stateDir: dir }); // same disk store, diff instance
250
- a.add({ sessionId: "sess_a", summary: "alpha", regionText: "region alpha text", tokenEstimate: 500, originalTokenEstimate: 2000, timestamp: 1 });
251
- b.add({ sessionId: "sess_b", summary: "beta", regionText: "region beta text", tokenEstimate: 700, originalTokenEstimate: 3000, timestamp: 2 });
252
- const repo = vectorRepoStats(a);
253
- assert.equal(repo.checkpointCount, 2, "checkpoints across both sessions");
254
- assert.equal(repo.sessionCount, 2, "two distinct sessions");
255
- assert.equal(repo.totalTokenEstimate, 1200, "Σ stored");
256
- assert.equal(repo.originalTokens, 5000, "Σ original");
257
- assert.equal(repo.tokensSaved, 3800, "repo saved = Σ(original − stored) = 1500 + 2300");
258
- assert.equal(repo.dedupCollapsed, 0);
259
- // A deduped add into sess_a: whole original region saved, no new row.
260
- const deduped = a.add({ sessionId: "sess_a", summary: "alpha", regionText: "region alpha text", tokenEstimate: 500, originalTokenEstimate: 2000, timestamp: 3 });
261
- assert.ok(deduped.deduped);
262
- const repo2 = vectorRepoStats(a);
263
- assert.equal(repo2.tokensSaved, 3800 + 2000, "deduped collapse adds full original region to repo saved");
264
- assert.equal(repo2.dedupCollapsed, 1);
265
- assert.equal(repo2.checkpointCount, 2, "still two stored checkpoints");
266
- });
267
- test("computeRegionHash normalizes whitespace before hashing", () => {
268
- const h1 = computeRegionHash("foo bar");
269
- const h2 = computeRegionHash("foo bar");
270
- const h3 = computeRegionHash(" foo bar ");
271
- assert.equal(h1, h2, "double space and single space should hash the same");
272
- assert.equal(h2, h3, "leading/trailing spaces should hash the same");
273
- // Sanity: different content still hashes differently.
274
- assert.notEqual(h1, computeRegionHash("foo baz"));
275
- });
276
- test("whitespace-variant region is deduplicated", () => {
277
- const s = store();
278
- const r1 = s.add({
279
- sessionId: "sess_ws",
280
- summary: "first",
281
- regionText: "user changed config.ts",
282
- timestamp: 1,
283
- });
284
- assert.equal(r1.deduped, false);
285
- const r2 = s.add({
286
- sessionId: "sess_ws",
287
- summary: "second",
288
- regionText: "user changed config.ts",
289
- timestamp: 2,
290
- });
291
- assert.equal(r2.deduped, true, "whitespace-variant should be deduplicated");
292
- assert.equal(vectorStats(s, "sess_ws").checkpointCount, 1, "only one checkpoint stored");
293
- });
294
- test("topSimilar returns n most similar checkpoints to the current (most recent)", () => {
295
- const s = store();
296
- s.add({
297
- sessionId: "sess_top",
298
- summary: "guitar",
299
- regionText: "play a song on the guitar",
300
- timestamp: 1,
301
- });
302
- s.add({
303
- sessionId: "sess_top",
304
- summary: "compact",
305
- regionText: "fix bug in src/compact.ts truncation",
306
- timestamp: 2,
307
- });
308
- // most recent (current) is chkpt_003, also about compact.ts but clearly
309
- // distinct content so L1 near-dup dedup does not collapse it.
310
- s.add({
311
- sessionId: "sess_top",
312
- summary: "current",
313
- regionText: "fix the buffer overflow in src/compact.ts by adding a bounds check before truncate",
314
- timestamp: 3,
315
- });
316
- const hits = vectorTopSimilar(s, "sess_top", 10);
317
- assert.equal(hits.length, 2); // two other checkpoints
318
- // The compact.ts checkpoint should rank above the guitar checkpoint
319
- assert.equal(hits[0].checkpoint.summary, "compact");
320
- assert.equal(hits[1].checkpoint.summary, "guitar");
321
- assert.ok(hits[0].score >= hits[1].score);
322
- });
323
- test("topSimilar excludes the current checkpoint itself", () => {
324
- const s = store();
325
- s.add({
326
- sessionId: "sess_self",
327
- summary: "a",
328
- regionText: "alpha region text one",
329
- timestamp: 1,
330
- });
331
- s.add({
332
- sessionId: "sess_self",
333
- summary: "b",
334
- regionText: "alpha region text two",
335
- timestamp: 2,
336
- });
337
- const hits = vectorTopSimilar(s, "sess_self", 5);
338
- assert.equal(hits.length, 1);
339
- assert.notEqual(hits[0].checkpoint.checkpointId, "chkpt_002"); // not the current
340
- });
341
- test("topSimilar returns empty for sessions with 0 or 1 checkpoints", () => {
342
- const s = store();
343
- assert.deepEqual(vectorTopSimilar(s, "sess_none", 5), []);
344
- s.add({
345
- sessionId: "sess_one",
346
- summary: "solo",
347
- regionText: "only checkpoint",
348
- timestamp: 1,
349
- });
350
- assert.deepEqual(vectorTopSimilar(s, "sess_one", 5), []);
351
- });
352
- test("topSimilar respects the n limit", () => {
353
- const s = store();
354
- const regions = [
355
- "the compiler optimized the hot loop with loop unrolling",
356
- "the database added a covering index to speed up queries",
357
- "the frontend introduced a virtualized list for large tables",
358
- "the api added rate limiting using a token bucket algorithm",
359
- "the worker pool now backpressures when the queue is overloaded",
360
- ];
361
- for (let i = 0; i < regions.length; i++) {
362
- s.add({
363
- sessionId: "sess_limit",
364
- summary: `c${i + 1}`,
365
- regionText: regions[i],
366
- timestamp: i + 1,
367
- });
368
- }
369
- const hits = vectorTopSimilar(s, "sess_limit", 2);
370
- assert.equal(hits.length, 2);
371
- });
372
- test("stats on empty session returns zeros and nulls", () => {
373
- const s = store();
374
- const st = vectorStats(s, "sess_empty");
375
- assert.equal(st.checkpointCount, 0);
376
- assert.equal(st.lastCheckpointId, undefined);
377
- assert.equal(st.totalTokenEstimate, 0);
378
- assert.equal(st.dedupHitRate, 0);
379
- });
380
- // --- Sprint 9: L0 content-addressable dedup -------------------------------
381
- test("L0 content-hash dedup: identical content under different regionText collapses to one row", () => {
382
- const s = store();
383
- const r1 = s.add({
384
- sessionId: "sess_l0",
385
- summary: "fix the parser",
386
- regionText: "user asked to fix the parser assistant patched src/parse.ts",
387
- timestamp: 1,
388
- });
389
- const r2 = s.add({
390
- sessionId: "sess_l0",
391
- summary: "fix the parser",
392
- regionText: " user asked to fix the parser assistant patched src/parse.ts ",
393
- timestamp: 2,
394
- });
395
- assert.equal(r1.deduped, false);
396
- assert.equal(r2.deduped, true);
397
- assert.equal(r2.reason, "contentHash");
398
- assert.equal(vectorList(s, "sess_l0").length, 1);
399
- });
400
- test("L0 content-hash dedup stores both hash fields and bumps timestamp on hit", () => {
401
- const s = store();
402
- const region = "the quick brown fox jumps over the lazy dog";
403
- s.add({ sessionId: "sess_l0ts", summary: "first", regionText: region, timestamp: 10 });
404
- const r2 = s.add({
405
- sessionId: "sess_l0ts",
406
- summary: "second",
407
- regionText: region,
408
- timestamp: 99,
409
- });
410
- assert.equal(r2.deduped, true);
411
- assert.equal(r2.reason, "contentHash");
412
- const cp = vectorList(s, "sess_l0ts")[0];
413
- assert.equal(cp.contentHash?.length, 64);
414
- assert.equal(cp.contentHash2?.length, 64);
415
- assert.equal(cp.contentHashVersion, 1);
416
- assert.equal(cp.timestamp, 99);
417
- });
418
- test("compressed_original roundtrips through versioned compression", () => {
419
- const s = store();
420
- const raw = "raw region text preserved for audit and replay";
421
- s.add({ sessionId: "sess_co", summary: "x", regionText: raw, timestamp: 1 });
422
- const cp = vectorList(s, "sess_co")[0];
423
- assert.ok(cp.compressedOriginal instanceof Buffer);
424
- const restored = decompressSmart(cp.compressedOriginal).toString("utf-8");
425
- assert.equal(restored, raw);
426
- });
427
- test("summaryHash is now full 64-hex SHA-256", () => {
428
- const s = store();
429
- const ts = "topic summary for same-topic incremental compaction";
430
- const r1 = s.add({
431
- sessionId: "sess_sh64",
432
- summary: "a",
433
- topicSummary: ts,
434
- regionText: "region alpha",
435
- timestamp: 1,
436
- });
437
- assert.equal(r1.checkpoint.summaryHash?.length, 64);
438
- const r2 = s.add({
439
- sessionId: "sess_sh64",
440
- summary: "b",
441
- topicSummary: ts,
442
- regionText: "region bravo",
443
- timestamp: 2,
444
- });
445
- assert.equal(r2.deduped, true);
446
- assert.equal(r2.reason, "summaryHash");
447
- });
448
- // --- Sprint 11: L1 MinHash/LSH near-duplicate dedup ------------------------
449
- test("L1 catches a one-word-diff near-duplicate that L0 misses", () => {
450
- const s = store();
451
- const r1 = s.add({
452
- sessionId: "sess_l1",
453
- summary: "user reviewed the auth module and merged the pull request",
454
- regionText: "user reviewed the authentication module and merged the pull request",
455
- timestamp: 1,
456
- });
457
- // One word inserted + different case/whitespace → L0 content-hash differs,
458
- // but the text is a near-duplicate caught by the L1 trigram verify.
459
- const r2 = s.add({
460
- sessionId: "sess_l1",
461
- summary: "user reviewed the auth module and merged the pull request",
462
- regionText: " USER reviewed the authentication module and merged the pull request now ",
463
- timestamp: 2,
464
- });
465
- assert.equal(r1.deduped, false);
466
- assert.equal(r2.deduped, true);
467
- assert.equal(r2.reason, "l1MinHash");
468
- assert.equal(vectorList(s, "sess_l1").length, 1);
469
- });
470
- test("L1 does NOT falsely dedup genuinely different content", () => {
471
- const s = store();
472
- s.add({ sessionId: "sess_l1b", summary: "a", regionText: "the database migration added three indexes", timestamp: 1 });
473
- const r2 = s.add({ sessionId: "sess_l1b", summary: "b", regionText: "the frontend added a dark mode toggle", timestamp: 2 });
474
- assert.equal(r2.deduped, false);
475
- assert.equal(vectorList(s, "sess_l1b").length, 2);
476
- });
477
- test("cleanup", () => {
478
- rmSync(baseTmp, { recursive: true, force: true });
479
- });
@@ -1,171 +0,0 @@
1
- /**
2
- * wiki.test.ts — S51C extractive wiki page tests. No network; temp dirs.
3
- * Includes the honest-boundary grep-assert (no ollama/llm/fetch) required by s47/s51.
4
- */
5
- import { test, beforeEach, afterEach } from "node:test";
6
- import assert from "node:assert/strict";
7
- import { mkdtempSync, rmSync, readFileSync, readdirSync } from "node:fs";
8
- import { tmpdir } from "node:os";
9
- import { join, dirname } from "node:path";
10
- import { fileURLToPath } from "node:url";
11
- import { extractiveSummary, generateWikiPage, buildWikiIndex } from "./wiki.js";
12
- let tmpDir;
13
- beforeEach(() => {
14
- tmpDir = mkdtempSync(join(tmpdir(), "mc-wiki-"));
15
- });
16
- afterEach(() => {
17
- rmSync(tmpDir, { recursive: true, force: true });
18
- });
19
- function mkTopic(id, label, termScores) {
20
- return { id, label, termScores, memoryCount: 0, lastUpdated: 0 };
21
- }
22
- function mkAssignment(memId, topicId, confidence = 0.8) {
23
- return {
24
- memoryId: memId,
25
- sessionId: "s",
26
- topicId,
27
- confidence,
28
- assignedAt: 0,
29
- method: "kmeans+tfidf",
30
- };
31
- }
32
- test("extractiveSummary returns top sentences joined", () => {
33
- const topic = mkTopic("t1", "sqlite", [{ term: "sqlite", score: 1 }]);
34
- const assignments = [mkAssignment("a", "t1"), mkAssignment("b", "t1")];
35
- const getContent = (id) => {
36
- if (id === "a")
37
- return "SQLite uses WAL mode. SQLite uses WAL mode. SQLite uses WAL mode.";
38
- if (id === "b")
39
- return "Postgres uses WAL mode. Postgres uses WAL mode.";
40
- return "";
41
- };
42
- const summary = extractiveSummary(topic, assignments, getContent);
43
- // Should be non-empty and contain at least one sentence
44
- assert.ok(summary.length > 0);
45
- assert.ok(summary.includes("WAL"));
46
- });
47
- test("extractiveSummary returns empty string when topic has no members", () => {
48
- const topic = mkTopic("t1", "empty", []);
49
- const summary = extractiveSummary(topic, [], () => "");
50
- assert.equal(summary, "");
51
- });
52
- test("generateWikiPage produces page with summary + key/recent memories", () => {
53
- const topic = mkTopic("t1", "sqlite", [{ term: "sqlite", score: 1 }]);
54
- const assignments = [
55
- mkAssignment("a", "t1", 0.9),
56
- mkAssignment("b", "t1", 0.5),
57
- ];
58
- const getMemoryInfo = (id) => {
59
- if (id === "a")
60
- return {
61
- content: "First memory content",
62
- timestamp: 100,
63
- importance: 0.9,
64
- };
65
- if (id === "b")
66
- return {
67
- content: "Second memory content",
68
- timestamp: 200,
69
- importance: 0.5,
70
- };
71
- return null;
72
- };
73
- const allTopics = [topic];
74
- const page = generateWikiPage(topic, assignments, getMemoryInfo, allTopics);
75
- assert.equal(page.topic.id, "t1");
76
- assert.equal(page.keyMemories.length, 2);
77
- // Key memories sorted by importance DESC
78
- assert.equal(page.keyMemories[0].importance, 0.9);
79
- // Recent memories sorted by timestamp DESC
80
- assert.equal(page.recentMemories[0].timestamp, 200);
81
- assert.equal(page.relatedTopics.length, 0);
82
- assert.ok(page.generatedAt > 0);
83
- });
84
- test("generateWikiPage finds related topics via co-occurrence", () => {
85
- const topicA = mkTopic("A", "topic-a", []);
86
- const topicB = mkTopic("B", "topic-b", []);
87
- const topicC = mkTopic("C", "topic-c", []);
88
- // Memory "shared" appears in both topicA and topicB → A and B are related.
89
- // Memory "a-only" only in topicA.
90
- // Memory "c-only" only in topicC (no overlap with A).
91
- const assignments = [
92
- mkAssignment("shared", "A"),
93
- mkAssignment("shared", "B"),
94
- mkAssignment("a-only", "A"),
95
- mkAssignment("c-only", "C"),
96
- ];
97
- const getMemoryInfo = (id) => ({
98
- content: `content for ${id}`,
99
- timestamp: 100,
100
- importance: 0.5,
101
- });
102
- const page = generateWikiPage(topicA, assignments, getMemoryInfo, [
103
- topicA,
104
- topicB,
105
- topicC,
106
- ]);
107
- // topicB should be related (shares "shared" with topicA); topicC should not.
108
- const relatedIds = page.relatedTopics.map((t) => t.id);
109
- assert.ok(relatedIds.includes("B"), `expected B in related topics, got ${relatedIds.join(",")}`);
110
- assert.ok(!relatedIds.includes("C"), `C has no co-occurrence with A, should not be related`);
111
- });
112
- test("buildWikiIndex aggregates topics + memory counts", () => {
113
- const topics = [mkTopic("t1", "sqlite", []), mkTopic("t2", "wal", [])];
114
- topics[0].memoryCount = 5;
115
- topics[1].memoryCount = 3;
116
- topics[0].lastUpdated = 1000;
117
- topics[1].lastUpdated = 2000;
118
- const idx = buildWikiIndex(topics);
119
- assert.equal(idx.totalTopics, 2);
120
- assert.equal(idx.totalMemories, 8);
121
- assert.equal(idx.topics.length, 2);
122
- assert.ok(idx.lastRebuildAt !== null);
123
- });
124
- test("buildWikiIndex handles empty topics", () => {
125
- const idx = buildWikiIndex([]);
126
- assert.equal(idx.totalTopics, 0);
127
- assert.equal(idx.totalMemories, 0);
128
- assert.equal(idx.lastRebuildAt, null);
129
- });
130
- test("honest boundary: no LLM/network/keyword-literals in src/wiki.ts", () => {
131
- const here = dirname(fileURLToPath(import.meta.url));
132
- const wikiPath = join(here, "..", "..", "src", "wiki.ts");
133
- const text = readFileSync(wikiPath, "utf8");
134
- const banned = [/ollama/i, /\bllm\b/i, /\bfetch\s*\(/, /\bhybrid\b/i];
135
- const fabricated = [
136
- "graphql",
137
- "docker",
138
- "stacktrace",
139
- "bottleneck",
140
- "trade-off",
141
- ];
142
- for (const re of banned) {
143
- assert.ok(!re.test(text), `wiki.ts must not contain ${re} (PREVENT-PI-004 / no-model boundary)`);
144
- }
145
- for (const word of fabricated) {
146
- assert.ok(!text.toLowerCase().includes(`"${word}"`), `wiki.ts must not hardcode fabricated taxonomy term "${word}"`);
147
- }
148
- });
149
- test("honest boundary: no LLM/Ollama/network in src/topics/* (non-test)", () => {
150
- const here = dirname(fileURLToPath(import.meta.url));
151
- // dist/src/wiki.test.js → ../../src/topics
152
- const topicsDir = join(here, "..", "..", "src", "topics");
153
- const files = readdirSync(topicsDir).filter((f) => f.endsWith(".ts") && !f.endsWith(".test.ts"));
154
- const banned = [/ollama/i, /\bllm\b/i, /\bfetch\s*\(/, /\bhybrid\b/i];
155
- const fabricated = [
156
- "graphql",
157
- "docker",
158
- "stacktrace",
159
- "bottleneck",
160
- "trade-off",
161
- ];
162
- for (const f of files) {
163
- const text = readFileSync(join(topicsDir, f), "utf8");
164
- for (const re of banned) {
165
- assert.ok(!re.test(text), `${f} must not contain ${re}`);
166
- }
167
- for (const word of fabricated) {
168
- assert.ok(!text.toLowerCase().includes(`"${word}"`), `${f} must not hardcode fabricated taxonomy term "${word}"`);
169
- }
170
- }
171
- });