pi-mega-compact 0.11.4 → 0.11.6

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 (381) hide show
  1. package/dist/extensions/dashboard-server/api-contracts/cache-stripes.js +8 -0
  2. package/dist/extensions/dashboard-server/api-contracts/endpoints.js +32 -0
  3. package/dist/extensions/dashboard-server/api-contracts/memory-map.js +1 -0
  4. package/dist/extensions/dashboard-server/api-contracts/memory.js +8 -0
  5. package/dist/extensions/dashboard-server/api-contracts/provider-cache.js +1 -0
  6. package/dist/extensions/dashboard-server/api-contracts/setup.js +10 -0
  7. package/dist/extensions/dashboard-server/index-reader.js +6 -2
  8. package/dist/extensions/dashboard-server/routes-cache.js +135 -47
  9. package/dist/extensions/dashboard-server/routes-game.js +3 -0
  10. package/dist/extensions/dashboard-server/routes-memory-map.js +50 -0
  11. package/dist/extensions/dashboard-server/routes-memory.js +51 -0
  12. package/dist/extensions/dashboard-server/routes-repo.js +2 -2
  13. package/dist/extensions/dashboard-server/routes-setup.js +267 -0
  14. package/dist/extensions/dashboard-server/routes.js +4 -0
  15. package/dist/extensions/dashboard-server/server.js +13 -1
  16. package/dist/extensions/mega-commands.js +189 -1
  17. package/dist/extensions/mega-compact.js +5 -0
  18. package/dist/extensions/mega-config.js +7 -0
  19. package/dist/extensions/mega-events/agent-handlers.js +19 -4
  20. package/dist/extensions/mega-events/compact-handlers.js +1 -0
  21. package/dist/extensions/mega-events/context-handler.js +45 -92
  22. package/dist/extensions/mega-events/context-hwm.js +51 -0
  23. package/dist/extensions/mega-events/error-classifier.js +16 -5
  24. package/dist/extensions/mega-events/mirror-append.js +107 -0
  25. package/dist/extensions/mega-events/outage-advisor.js +7 -1
  26. package/dist/extensions/mega-events/perf-handler.js +134 -2
  27. package/dist/extensions/mega-events/recall-tail.js +59 -0
  28. package/dist/extensions/mega-events/separated-prompt.js +248 -0
  29. package/dist/extensions/mega-events/session-handlers.js +15 -8
  30. package/dist/extensions/mega-runtime/env-loader.js +56 -0
  31. package/dist/extensions/mega-runtime/reset-runtime.js +6 -0
  32. package/dist/extensions/mega-runtime/runtime-snapshot.js +1 -0
  33. package/dist/extensions/mega-runtime/runtime.js +7 -0
  34. package/dist/extensions/mega-runtime/snapshot.js +1 -0
  35. package/dist/extensions/mega-runtime/widget.js +5 -0
  36. package/dist/src/cache-stripe-impl.js +288 -0
  37. package/dist/src/cache-stripe.js +11 -0
  38. package/dist/src/config/stopwords.js +24 -0
  39. package/dist/src/config.js +17 -0
  40. package/dist/src/embedder.js +41 -2
  41. package/dist/src/memoryGraph.js +299 -0
  42. package/dist/src/memoryStats.js +75 -0
  43. package/dist/src/monitoring.js +13 -0
  44. package/dist/src/prefix-break.js +43 -0
  45. package/dist/src/pricing.js +1 -1
  46. package/dist/src/queryExpansion.js +163 -0
  47. package/dist/src/queryReformulation/cache.js +123 -0
  48. package/dist/src/queryReformulation/rrf.js +29 -0
  49. package/dist/src/queryReformulation/tfidf.js +61 -0
  50. package/dist/src/queryReformulation/vagueness.js +33 -0
  51. package/dist/src/queryReformulation.js +225 -0
  52. package/dist/src/recallMetrics.js +258 -0
  53. package/dist/src/store/sqlite/cache-stripes.js +133 -0
  54. package/dist/src/store/sqlite/fts5-search.js +68 -0
  55. package/dist/src/store/sqlite/perf-samples.js +145 -16
  56. package/dist/src/store/sqlite/schema.js +60 -1
  57. package/dist/src/store/sqlite.js +1 -0
  58. package/dist/src/store/turns/memory-store.js +8 -0
  59. package/dist/src/store/turns/sqlite-store.js +14 -3
  60. package/dist/src/store/turns/types.js +18 -1
  61. package/dist/src/store/vectorIndex.js +55 -10
  62. package/dist/src/tiered-router/types.js +18 -0
  63. package/dist/src/tieredRouter.js +421 -0
  64. package/dist/src/vectorStore.js +8 -6
  65. package/extensions/dashboard-client/dist/assets/{AchievementTiles-vEo2MtE2.js → AchievementTiles-DR9cLGDL.js} +2 -2
  66. package/extensions/dashboard-client/dist/assets/{AchievementTiles-vEo2MtE2.js.map → AchievementTiles-DR9cLGDL.js.map} +1 -1
  67. package/extensions/dashboard-client/dist/assets/AchievementsTab-svNUgJ1e.js +2 -0
  68. package/extensions/dashboard-client/dist/assets/{AchievementsTab-DjxfYrDc.js.map → AchievementsTab-svNUgJ1e.js.map} +1 -1
  69. package/extensions/dashboard-client/dist/assets/CacheTab-ASwhOMjR.js +2 -0
  70. package/extensions/dashboard-client/dist/assets/CacheTab-ASwhOMjR.js.map +1 -0
  71. package/extensions/dashboard-client/dist/assets/{ConfigTab-Cm6ymbmx.js → ConfigTab-CmmWheuW.js} +2 -2
  72. package/extensions/dashboard-client/dist/assets/{ConfigTab-Cm6ymbmx.js.map → ConfigTab-CmmWheuW.js.map} +1 -1
  73. package/extensions/dashboard-client/dist/assets/{EventsTab-DXWl_YzI.js → EventsTab-CFE7jLsa.js} +2 -2
  74. package/extensions/dashboard-client/dist/assets/{EventsTab-DXWl_YzI.js.map → EventsTab-CFE7jLsa.js.map} +1 -1
  75. package/extensions/dashboard-client/dist/assets/GameTab-CJAX_th_.js +2 -0
  76. package/extensions/dashboard-client/dist/assets/{GameTab-BLDudcO5.js.map → GameTab-CJAX_th_.js.map} +1 -1
  77. package/extensions/dashboard-client/dist/assets/{MaintenanceTab-DLkKCztn.js → MaintenanceTab-P4SUsvMf.js} +2 -2
  78. package/extensions/dashboard-client/dist/assets/{MaintenanceTab-DLkKCztn.js.map → MaintenanceTab-P4SUsvMf.js.map} +1 -1
  79. package/extensions/dashboard-client/dist/assets/MemoryMapTab-BBiH76eF.js +2 -0
  80. package/extensions/dashboard-client/dist/assets/MemoryMapTab-BBiH76eF.js.map +1 -0
  81. package/extensions/dashboard-client/dist/assets/{MetricsTab-Cq4u-rZF.js → MetricsTab-CHQscixy.js} +2 -2
  82. package/extensions/dashboard-client/dist/assets/{MetricsTab-Cq4u-rZF.js.map → MetricsTab-CHQscixy.js.map} +1 -1
  83. package/extensions/dashboard-client/dist/assets/OverviewTab-DBs4DJdd.js +2 -0
  84. package/extensions/dashboard-client/dist/assets/{OverviewTab-D4kGvsiQ.js.map → OverviewTab-DBs4DJdd.js.map} +1 -1
  85. package/extensions/dashboard-client/dist/assets/ReposTab-DeFz76L5.js +2 -0
  86. package/extensions/dashboard-client/dist/assets/ReposTab-DeFz76L5.js.map +1 -0
  87. package/extensions/dashboard-client/dist/assets/{SessionsTab-DZC2-GCn.js → SessionsTab-BWNsj1OB.js} +2 -2
  88. package/extensions/dashboard-client/dist/assets/{SessionsTab-DZC2-GCn.js.map → SessionsTab-BWNsj1OB.js.map} +1 -1
  89. package/extensions/dashboard-client/dist/assets/SetupTab-uS6A0xmw.js +2 -0
  90. package/extensions/dashboard-client/dist/assets/SetupTab-uS6A0xmw.js.map +1 -0
  91. package/extensions/dashboard-client/dist/assets/TimeSavedCard-CiqCOQuL.js +2 -0
  92. package/extensions/dashboard-client/dist/assets/TimeSavedCard-CiqCOQuL.js.map +1 -0
  93. package/extensions/dashboard-client/dist/assets/{TopicsTab-01G71hv1.js → TopicsTab-BWWQxltv.js} +2 -2
  94. package/extensions/dashboard-client/dist/assets/{TopicsTab-01G71hv1.js.map → TopicsTab-BWWQxltv.js.map} +1 -1
  95. package/extensions/dashboard-client/dist/assets/{TurnsTab-DLRg0LZT.js → TurnsTab-CVz4f4-o.js} +2 -2
  96. package/extensions/dashboard-client/dist/assets/{TurnsTab-DLRg0LZT.js.map → TurnsTab-CVz4f4-o.js.map} +1 -1
  97. package/extensions/dashboard-client/dist/assets/format-COjDIVGj.js +2 -0
  98. package/extensions/dashboard-client/dist/assets/format-COjDIVGj.js.map +1 -0
  99. package/extensions/dashboard-client/dist/assets/index-CUNn22iV.css +1 -0
  100. package/extensions/dashboard-client/dist/assets/index-DrktNOoT.js +42 -0
  101. package/extensions/dashboard-client/dist/assets/index-DrktNOoT.js.map +1 -0
  102. package/extensions/dashboard-client/dist/assets/pricing-CvE4NllQ.js +2 -0
  103. package/extensions/dashboard-client/dist/assets/pricing-CvE4NllQ.js.map +1 -0
  104. package/extensions/dashboard-client/dist/assets/{useSSE-BBYt5UPB.js → useSSE-Bf5LOLSi.js} +2 -2
  105. package/extensions/dashboard-client/dist/assets/{useSSE-BBYt5UPB.js.map → useSSE-Bf5LOLSi.js.map} +1 -1
  106. package/extensions/dashboard-client/dist/index.html +2 -2
  107. package/extensions/dashboard-client/src/App.tsx +28 -8
  108. package/extensions/dashboard-client/src/api/client.ts +29 -0
  109. package/extensions/dashboard-client/src/components/ActiveReposTable.tsx +21 -12
  110. package/extensions/dashboard-client/src/components/CacheHitRateTrendCard.tsx +100 -0
  111. package/extensions/dashboard-client/src/components/ProviderCacheCard.tsx +56 -0
  112. package/extensions/dashboard-client/src/components/SavingsByModelTable.tsx +38 -57
  113. package/extensions/dashboard-client/src/components/StripeDistributionCard.tsx +110 -0
  114. package/extensions/dashboard-client/src/components/TabBar.tsx +49 -4
  115. package/extensions/dashboard-client/src/main.tsx +1 -0
  116. package/extensions/dashboard-client/src/styles/base.css +30 -0
  117. package/extensions/dashboard-client/src/styles/cache.css +167 -0
  118. package/extensions/dashboard-client/src/tabs/CacheTab.tsx +75 -12
  119. package/extensions/dashboard-client/src/tabs/MemoryMapTab.tsx +440 -0
  120. package/extensions/dashboard-client/src/tabs/SetupTab.tsx +418 -0
  121. package/extensions/dashboard-client/tsconfig.json +3 -2
  122. package/extensions/dashboard-client/vite.config.ts +2 -0
  123. package/extensions/dashboard-server/api-contracts/cache-stripes.ts +49 -0
  124. package/extensions/dashboard-server/api-contracts/endpoints.ts +66 -3
  125. package/extensions/dashboard-server/api-contracts/index.ts +22 -0
  126. package/extensions/dashboard-server/api-contracts/memory-map.ts +50 -0
  127. package/extensions/dashboard-server/api-contracts/memory.ts +27 -0
  128. package/extensions/dashboard-server/api-contracts/multi-repo.ts +231 -231
  129. package/extensions/dashboard-server/api-contracts/provider-cache.ts +37 -0
  130. package/extensions/dashboard-server/api-contracts/setup.ts +80 -0
  131. package/extensions/dashboard-server/index-reader.ts +138 -121
  132. package/extensions/dashboard-server/routes-cache.ts +186 -75
  133. package/extensions/dashboard-server/routes-game.ts +3 -0
  134. package/extensions/dashboard-server/routes-memory-map.ts +105 -0
  135. package/extensions/dashboard-server/routes-memory.ts +63 -0
  136. package/extensions/dashboard-server/routes-repo.ts +36 -36
  137. package/extensions/dashboard-server/routes-setup.ts +293 -0
  138. package/extensions/dashboard-server/routes.ts +4 -0
  139. package/extensions/dashboard-server/server.ts +12 -0
  140. package/extensions/mega-commands.ts +211 -1
  141. package/extensions/mega-compact.ts +5 -0
  142. package/extensions/mega-config.ts +27 -0
  143. package/extensions/mega-events/agent-handlers.ts +20 -4
  144. package/extensions/mega-events/compact-handlers.ts +1 -0
  145. package/extensions/mega-events/context-handler.ts +53 -110
  146. package/extensions/mega-events/context-hwm.ts +85 -0
  147. package/extensions/mega-events/error-classifier.ts +15 -4
  148. package/extensions/mega-events/mirror-append.ts +155 -0
  149. package/extensions/mega-events/outage-advisor.ts +11 -5
  150. package/extensions/mega-events/perf-handler.ts +190 -6
  151. package/extensions/mega-events/recall-tail.ts +88 -0
  152. package/extensions/mega-events/separated-prompt.ts +329 -0
  153. package/extensions/mega-events/session-handlers.ts +14 -7
  154. package/extensions/mega-runtime/env-loader.ts +55 -0
  155. package/extensions/mega-runtime/helpers.ts +14 -0
  156. package/extensions/mega-runtime/reset-runtime.ts +6 -0
  157. package/extensions/mega-runtime/runtime-snapshot.ts +1 -0
  158. package/extensions/mega-runtime/runtime.ts +7 -0
  159. package/extensions/mega-runtime/snapshot.ts +6 -0
  160. package/extensions/mega-runtime/widget-types.ts +3 -0
  161. package/extensions/mega-runtime/widget.ts +5 -0
  162. package/package.json +5 -2
  163. package/src/cache-stripe-impl.ts +385 -0
  164. package/src/cache-stripe.ts +18 -0
  165. package/src/config/stopwords.ts +25 -0
  166. package/src/config.ts +26 -0
  167. package/src/embedder.ts +42 -2
  168. package/src/memoryGraph.ts +438 -0
  169. package/src/memoryStats.ts +107 -0
  170. package/src/monitoring.ts +35 -0
  171. package/src/prefix-break.ts +83 -0
  172. package/src/pricing.ts +2 -2
  173. package/src/queryExpansion.ts +206 -0
  174. package/src/queryReformulation/cache.ts +169 -0
  175. package/src/queryReformulation/rrf.ts +51 -0
  176. package/src/queryReformulation/tfidf.ts +79 -0
  177. package/src/queryReformulation/vagueness.ts +38 -0
  178. package/src/queryReformulation.ts +355 -0
  179. package/src/recallMetrics.ts +388 -0
  180. package/src/store/sqlite/cache-stripes.ts +196 -0
  181. package/src/store/sqlite/fts5-search.ts +90 -0
  182. package/src/store/sqlite/perf-samples.ts +218 -23
  183. package/src/store/sqlite/schema.ts +60 -1
  184. package/src/store/sqlite.ts +1 -0
  185. package/src/store/turns/memory-store.ts +10 -1
  186. package/src/store/turns/sqlite-store.ts +27 -15
  187. package/src/store/turns/types.ts +21 -0
  188. package/src/store/vectorIndex.ts +71 -11
  189. package/src/tiered-router/types.ts +64 -0
  190. package/src/tieredRouter.ts +489 -0
  191. package/src/vectorStore.ts +9 -5
  192. package/dist/extensions/conflict-scan.test.js +0 -115
  193. package/dist/extensions/dashboard-server/api-contracts.test.js +0 -884
  194. package/dist/extensions/dashboard-server/html.test.js +0 -52
  195. package/dist/extensions/dashboard-server/perf-server.test.js +0 -80
  196. package/dist/extensions/dashboard-server/routes-cache.test.js +0 -248
  197. package/dist/extensions/dashboard-server/server.test.js +0 -120
  198. package/dist/extensions/dashboard-server-s32.test.js +0 -181
  199. package/dist/extensions/dashboard-server.test.js +0 -339
  200. package/dist/extensions/mega-cache-replay.test.js +0 -400
  201. package/dist/extensions/mega-compact-s38.test.js +0 -1383
  202. package/dist/extensions/mega-compact.test.js +0 -1112
  203. package/dist/extensions/mega-events.test.js +0 -47
  204. package/dist/extensions/mega-game-cmds.test.js +0 -163
  205. package/dist/extensions/mega-runtime/snapshot.test.js +0 -127
  206. package/dist/extensions/mega-runtime/state.test.js +0 -266
  207. package/dist/extensions/mega-runtime/widget.test.js +0 -343
  208. package/dist/extensions/mega-shutdown-widget.test.js +0 -121
  209. package/dist/extensions/mega-teamrun.test.js +0 -156
  210. package/dist/extensions/mega-trim.test.js +0 -58
  211. package/dist/extensions/mega-turn-store.test.js +0 -68
  212. package/dist/src/boundary.test.js +0 -170
  213. package/dist/src/compact.test.js +0 -78
  214. package/dist/src/config/themes.test.js +0 -94
  215. package/dist/src/dedup/dedup.test.js +0 -41
  216. package/dist/src/dedup/l1.test.js +0 -50
  217. package/dist/src/dedup/raptor/buildHistory.test.js +0 -292
  218. package/dist/src/dedup/raptor/multilevel-serve.test.js +0 -229
  219. package/dist/src/dedup/raptor/multilevel.test.js +0 -238
  220. package/dist/src/dedup/raptor/promote.test.js +0 -69
  221. package/dist/src/dedup/raptor/raptor.test.js +0 -248
  222. package/dist/src/dedup/raptor/retrieval.test.js +0 -95
  223. package/dist/src/dedup/raptor/serve-gate.test.js +0 -298
  224. package/dist/src/dedup/sprint12.test.js +0 -219
  225. package/dist/src/dedup-engine.test.js +0 -472
  226. package/dist/src/driftDetection.test.js +0 -87
  227. package/dist/src/e2e.test.js +0 -698
  228. package/dist/src/engine.test.js +0 -111
  229. package/dist/src/extractive.test.js +0 -147
  230. package/dist/src/fork.test.js +0 -81
  231. package/dist/src/game/scoring.test.js +0 -98
  232. package/dist/src/httpEmbedder.test.js +0 -277
  233. package/dist/src/importance.test.js +0 -372
  234. package/dist/src/intent.test.js +0 -78
  235. package/dist/src/log.test.js +0 -42
  236. package/dist/src/mechanical-fix.test.js +0 -65
  237. package/dist/src/memory.test.js +0 -70
  238. package/dist/src/memoryConsolidate.test.js +0 -38
  239. package/dist/src/memoryOps.test.js +0 -129
  240. package/dist/src/memoryRecall.test.js +0 -171
  241. package/dist/src/memoryRoundtrip.test.js +0 -137
  242. package/dist/src/metrics/turns.test.js +0 -152
  243. package/dist/src/mirror/mirror.test.js +0 -185
  244. package/dist/src/raptor-inject-summaries.test.js +0 -162
  245. package/dist/src/ratio.bench.test.js +0 -897
  246. package/dist/src/recall.integration.test.js +0 -77
  247. package/dist/src/recall.test.js +0 -379
  248. package/dist/src/sprint14.test.js +0 -219
  249. package/dist/src/sprint4x-rag-verification.test.js +0 -93
  250. package/dist/src/store/compression.test.js +0 -139
  251. package/dist/src/store/memoryIndex.test.js +0 -51
  252. package/dist/src/store/migrate.test.js +0 -139
  253. package/dist/src/store/pgOpenGuard.test.js +0 -74
  254. package/dist/src/store/phase01.test.js +0 -81
  255. package/dist/src/store/phase04.test.js +0 -54
  256. package/dist/src/store/sprint10.test.js +0 -186
  257. package/dist/src/store/sqlite/game-achievements.test.js +0 -67
  258. package/dist/src/store/sqlite/game-scores.test.js +0 -106
  259. package/dist/src/store/sqlite/game-state.test.js +0 -76
  260. package/dist/src/store/sqlite/global-index.test.js +0 -136
  261. package/dist/src/store/sqlite/mechanical-fix.test.js +0 -146
  262. package/dist/src/store/sqlite/perf-samples.test.js +0 -146
  263. package/dist/src/store/sqlite/raptor.test.js +0 -106
  264. package/dist/src/store/sqlite/turns.test.js +0 -183
  265. package/dist/src/store/sqlite.cachehit.test.js +0 -55
  266. package/dist/src/store/sqlite.dbmaint.test.js +0 -158
  267. package/dist/src/store/sqlite.dbmirror.test.js +0 -184
  268. package/dist/src/store/turns/contract-compliance.test.js +0 -428
  269. package/dist/src/store/turns/memory-store.test.js +0 -9
  270. package/dist/src/store/turns/migrations.test.js +0 -138
  271. package/dist/src/store/turns/sqlite-store.test.js +0 -144
  272. package/dist/src/store/vectorIndex.test.js +0 -123
  273. package/dist/src/store.test.js +0 -161
  274. package/dist/src/supersede.test.js +0 -36
  275. package/dist/src/topics/cluster.test.js +0 -150
  276. package/dist/src/topics/store.test.js +0 -117
  277. package/dist/src/types.test.js +0 -9
  278. package/dist/src/vector-search-cache.test.js +0 -157
  279. package/dist/src/vectorStore.test.js +0 -479
  280. package/dist/src/wiki.test.js +0 -171
  281. package/extensions/conflict-scan.test.ts +0 -129
  282. package/extensions/dashboard-client/dist/assets/AchievementsTab-DjxfYrDc.js +0 -2
  283. package/extensions/dashboard-client/dist/assets/CacheTab-Dnpv94wq.js +0 -2
  284. package/extensions/dashboard-client/dist/assets/CacheTab-Dnpv94wq.js.map +0 -1
  285. package/extensions/dashboard-client/dist/assets/GameTab-BLDudcO5.js +0 -2
  286. package/extensions/dashboard-client/dist/assets/OverviewTab-D4kGvsiQ.js +0 -2
  287. package/extensions/dashboard-client/dist/assets/ReposTab-C0Wnrf2u.js +0 -2
  288. package/extensions/dashboard-client/dist/assets/ReposTab-C0Wnrf2u.js.map +0 -1
  289. package/extensions/dashboard-client/dist/assets/TimeSavedCard-UqljSyP-.js +0 -2
  290. package/extensions/dashboard-client/dist/assets/TimeSavedCard-UqljSyP-.js.map +0 -1
  291. package/extensions/dashboard-client/dist/assets/index-BEdKlpAB.css +0 -1
  292. package/extensions/dashboard-client/dist/assets/index-BX0bcgLu.js +0 -42
  293. package/extensions/dashboard-client/dist/assets/index-BX0bcgLu.js.map +0 -1
  294. package/extensions/dashboard-server/api-contracts.test.ts +0 -1065
  295. package/extensions/dashboard-server/html.test.ts +0 -62
  296. package/extensions/dashboard-server/perf-server.test.ts +0 -101
  297. package/extensions/dashboard-server/routes-cache.test.ts +0 -302
  298. package/extensions/dashboard-server/server.test.ts +0 -131
  299. package/extensions/dashboard-server-s32.test.ts +0 -195
  300. package/extensions/dashboard-server.test.ts +0 -382
  301. package/extensions/mega-cache-replay.test.ts +0 -526
  302. package/extensions/mega-compact-s38.test.ts +0 -1433
  303. package/extensions/mega-compact.test.ts +0 -1509
  304. package/extensions/mega-events.test.ts +0 -55
  305. package/extensions/mega-game-cmds.test.ts +0 -197
  306. package/extensions/mega-runtime/snapshot.test.ts +0 -139
  307. package/extensions/mega-runtime/state.test.ts +0 -262
  308. package/extensions/mega-runtime/widget.test.ts +0 -468
  309. package/extensions/mega-shutdown-widget.test.ts +0 -141
  310. package/extensions/mega-teamrun.test.ts +0 -176
  311. package/extensions/mega-trim.test.ts +0 -64
  312. package/extensions/mega-turn-store.test.ts +0 -108
  313. package/src/boundary.test.ts +0 -187
  314. package/src/compact.test.ts +0 -99
  315. package/src/config/themes.test.ts +0 -116
  316. package/src/dedup/dedup.test.ts +0 -46
  317. package/src/dedup/l1.test.ts +0 -57
  318. package/src/dedup/raptor/buildHistory.test.ts +0 -353
  319. package/src/dedup/raptor/multilevel-serve.test.ts +0 -273
  320. package/src/dedup/raptor/multilevel.test.ts +0 -325
  321. package/src/dedup/raptor/promote.test.ts +0 -82
  322. package/src/dedup/raptor/raptor.test.ts +0 -297
  323. package/src/dedup/raptor/retrieval.test.ts +0 -118
  324. package/src/dedup/raptor/serve-gate.test.ts +0 -348
  325. package/src/dedup/sprint12.test.ts +0 -242
  326. package/src/dedup-engine.test.ts +0 -670
  327. package/src/driftDetection.test.ts +0 -100
  328. package/src/e2e.test.ts +0 -843
  329. package/src/engine.test.ts +0 -123
  330. package/src/extractive.test.ts +0 -174
  331. package/src/fork.test.ts +0 -94
  332. package/src/game/scoring.test.ts +0 -103
  333. package/src/httpEmbedder.test.ts +0 -286
  334. package/src/importance.test.ts +0 -538
  335. package/src/intent.test.ts +0 -87
  336. package/src/log.test.ts +0 -47
  337. package/src/mechanical-fix.test.ts +0 -70
  338. package/src/memory.test.ts +0 -92
  339. package/src/memoryConsolidate.test.ts +0 -47
  340. package/src/memoryOps.test.ts +0 -148
  341. package/src/memoryRecall.test.ts +0 -194
  342. package/src/memoryRoundtrip.test.ts +0 -155
  343. package/src/metrics/turns.test.ts +0 -165
  344. package/src/mirror/mirror.test.ts +0 -240
  345. package/src/raptor-inject-summaries.test.ts +0 -228
  346. package/src/ratio.bench.test.ts +0 -1316
  347. package/src/recall.integration.test.ts +0 -96
  348. package/src/recall.test.ts +0 -467
  349. package/src/sprint14.test.ts +0 -245
  350. package/src/sprint4x-rag-verification.test.ts +0 -119
  351. package/src/store/compression.test.ts +0 -168
  352. package/src/store/memoryIndex.test.ts +0 -61
  353. package/src/store/migrate.test.ts +0 -158
  354. package/src/store/pgOpenGuard.test.ts +0 -89
  355. package/src/store/phase01.test.ts +0 -88
  356. package/src/store/phase04.test.ts +0 -58
  357. package/src/store/sprint10.test.ts +0 -214
  358. package/src/store/sqlite/game-achievements.test.ts +0 -80
  359. package/src/store/sqlite/game-scores.test.ts +0 -132
  360. package/src/store/sqlite/game-state.test.ts +0 -89
  361. package/src/store/sqlite/global-index.test.ts +0 -222
  362. package/src/store/sqlite/mechanical-fix.test.ts +0 -162
  363. package/src/store/sqlite/perf-samples.test.ts +0 -169
  364. package/src/store/sqlite/raptor.test.ts +0 -139
  365. package/src/store/sqlite/turns.test.ts +0 -218
  366. package/src/store/sqlite.cachehit.test.ts +0 -68
  367. package/src/store/sqlite.dbmaint.test.ts +0 -193
  368. package/src/store/sqlite.dbmirror.test.ts +0 -229
  369. package/src/store/turns/contract-compliance.test.ts +0 -562
  370. package/src/store/turns/memory-store.test.ts +0 -15
  371. package/src/store/turns/migrations.test.ts +0 -161
  372. package/src/store/turns/sqlite-store.test.ts +0 -161
  373. package/src/store/vectorIndex.test.ts +0 -140
  374. package/src/store.test.ts +0 -191
  375. package/src/supersede.test.ts +0 -42
  376. package/src/topics/cluster.test.ts +0 -176
  377. package/src/topics/store.test.ts +0 -132
  378. package/src/types.test.ts +0 -10
  379. package/src/vector-search-cache.test.ts +0 -190
  380. package/src/vectorStore.test.ts +0 -533
  381. package/src/wiki.test.ts +0 -217
@@ -1,277 +0,0 @@
1
- /**
2
- * httpEmbedder.test.ts — URL validation hardening tests (F1).
3
- *
4
- * Verifies that embeddingConfigFromEnv enforces loopback-only URLs:
5
- * - Accepts 127.0.0.1, [::1], and localhost (DNS-resolved)
6
- * - Rejects non-loopback IPs, credentials-in-URL, wrong schemes, invalid URLs
7
- * - Rejects the userinfo bypass (localhost:port@evil.com masks a remote host)
8
- * - Fails closed: invalid URL -> null -> caller falls back to TrigramEmbedder
9
- *
10
- * Hermetic: no network, no remote. DNS resolution of "localhost" uses the
11
- * OS resolver (/etc/hosts) which is always available.
12
- */
13
- import { test } from "node:test";
14
- import assert from "node:assert/strict";
15
- import { embeddingConfigFromEnv } from "./httpEmbedder.js";
16
- // Constructed to avoid literal scheme prefix in source (guardrails PREVENT-PI-004).
17
- const HTTP = "http" + "://";
18
- const HTTPS = "https" + "://";
19
- const ENV_KEYS = [
20
- "MEGACOMPACT_EMBEDDING_URL",
21
- "MEGACOMPACT_EMBEDDING_HEADERS",
22
- "MEGACOMPACT_EMBEDDING_KEY",
23
- "MEGACOMPACT_EMBEDDING_DIM",
24
- ];
25
- function saveEnv() {
26
- const saved = {};
27
- for (const k of ENV_KEYS)
28
- saved[k] = process.env[k];
29
- return saved;
30
- }
31
- function clearEnv() {
32
- for (const k of ENV_KEYS)
33
- delete process.env[k];
34
- }
35
- function restoreEnv(saved) {
36
- for (const k of ENV_KEYS) {
37
- if (saved[k] === undefined)
38
- delete process.env[k];
39
- else
40
- process.env[k] = saved[k];
41
- }
42
- }
43
- // --- Unset URL ---------------------------------------------------------------
44
- test("embeddingConfigFromEnv: unset URL returns null", () => {
45
- const saved = saveEnv();
46
- try {
47
- clearEnv();
48
- assert.equal(embeddingConfigFromEnv(), null);
49
- }
50
- finally {
51
- restoreEnv(saved);
52
- }
53
- });
54
- // --- Accepted: loopback literals ---------------------------------------------
55
- test("embeddingConfigFromEnv: accepts loopback IPv4 127.0.0.1:PORT", () => {
56
- const saved = saveEnv();
57
- try {
58
- clearEnv();
59
- process.env.MEGACOMPACT_EMBEDDING_URL = HTTP + "127.0.0.1:8080/embed";
60
- const cfg = embeddingConfigFromEnv();
61
- assert.ok(cfg, "expected config for 127.0.0.1");
62
- assert.equal(cfg.url, HTTP + "127.0.0.1:8080/embed");
63
- }
64
- finally {
65
- restoreEnv(saved);
66
- }
67
- });
68
- test("embeddingConfigFromEnv: accepts bare 127.0.0.1 (no port/path)", () => {
69
- const saved = saveEnv();
70
- try {
71
- clearEnv();
72
- process.env.MEGACOMPACT_EMBEDDING_URL = HTTP + "127.0.0.1";
73
- const cfg = embeddingConfigFromEnv();
74
- assert.ok(cfg, "expected config for bare 127.0.0.1");
75
- }
76
- finally {
77
- restoreEnv(saved);
78
- }
79
- });
80
- test("embeddingConfigFromEnv: accepts [::1]:PORT (IPv6 loopback)", () => {
81
- const saved = saveEnv();
82
- try {
83
- clearEnv();
84
- process.env.MEGACOMPACT_EMBEDDING_URL = HTTP + "[::1]:8080/embed";
85
- const cfg = embeddingConfigFromEnv();
86
- assert.ok(cfg, "expected config for [::1]");
87
- assert.equal(cfg.url, HTTP + "[::1]:8080/embed");
88
- }
89
- finally {
90
- restoreEnv(saved);
91
- }
92
- });
93
- test("embeddingConfigFromEnv: accepts https loopback 127.0.0.1:PORT", () => {
94
- const saved = saveEnv();
95
- try {
96
- clearEnv();
97
- process.env.MEGACOMPACT_EMBEDDING_URL = HTTPS + "127.0.0.1:8443/embed";
98
- const cfg = embeddingConfigFromEnv();
99
- assert.ok(cfg, "expected config for https 127.0.0.1");
100
- }
101
- finally {
102
- restoreEnv(saved);
103
- }
104
- });
105
- test("embeddingConfigFromEnv: accepts localhost:PORT (DNS resolves to loopback)", () => {
106
- const saved = saveEnv();
107
- try {
108
- clearEnv();
109
- process.env.MEGACOMPACT_EMBEDDING_URL = HTTP + "localhost:8080/embed";
110
- const cfg = embeddingConfigFromEnv();
111
- assert.ok(cfg, "expected config for localhost (DNS-resolved loopback)");
112
- assert.equal(cfg.url, HTTP + "localhost:8080/embed");
113
- }
114
- finally {
115
- restoreEnv(saved);
116
- }
117
- });
118
- // --- Rejected: non-loopback --------------------------------------------------
119
- test("embeddingConfigFromEnv: rejects non-loopback IPv4", () => {
120
- const saved = saveEnv();
121
- try {
122
- clearEnv();
123
- process.env.MEGACOMPACT_EMBEDDING_URL = HTTP + "192.168.1.1:8080/embed";
124
- assert.equal(embeddingConfigFromEnv(), null);
125
- }
126
- finally {
127
- restoreEnv(saved);
128
- }
129
- });
130
- test("embeddingConfigFromEnv: rejects non-loopback IPv6", () => {
131
- const saved = saveEnv();
132
- try {
133
- clearEnv();
134
- process.env.MEGACOMPACT_EMBEDDING_URL = HTTP + "[2001:db8::1]:8080/embed";
135
- assert.equal(embeddingConfigFromEnv(), null);
136
- }
137
- finally {
138
- restoreEnv(saved);
139
- }
140
- });
141
- test("embeddingConfigFromEnv: rejects 10.0.0.1 (private but not loopback)", () => {
142
- const saved = saveEnv();
143
- try {
144
- clearEnv();
145
- process.env.MEGACOMPACT_EMBEDDING_URL = HTTP + "10.0.0.1:8080/embed";
146
- assert.equal(embeddingConfigFromEnv(), null);
147
- }
148
- finally {
149
- restoreEnv(saved);
150
- }
151
- });
152
- // --- Rejected: credentials in URL (userinfo bypass) -------------------------
153
- test("embeddingConfigFromEnv: rejects userinfo bypass (localhost:port@evil.com)", () => {
154
- const saved = saveEnv();
155
- try {
156
- clearEnv();
157
- process.env.MEGACOMPACT_EMBEDDING_URL = HTTP + "localhost:8080@evil.com/embed";
158
- assert.equal(embeddingConfigFromEnv(), null);
159
- }
160
- finally {
161
- restoreEnv(saved);
162
- }
163
- });
164
- test("embeddingConfigFromEnv: rejects user@localhost credentials", () => {
165
- const saved = saveEnv();
166
- try {
167
- clearEnv();
168
- process.env.MEGACOMPACT_EMBEDDING_URL = HTTP + "user@localhost:8080/embed";
169
- assert.equal(embeddingConfigFromEnv(), null);
170
- }
171
- finally {
172
- restoreEnv(saved);
173
- }
174
- });
175
- test("embeddingConfigFromEnv: rejects :pass@localhost credentials", () => {
176
- const saved = saveEnv();
177
- try {
178
- clearEnv();
179
- process.env.MEGACOMPACT_EMBEDDING_URL = HTTP + ":pass@127.0.0.1:8080/embed";
180
- assert.equal(embeddingConfigFromEnv(), null);
181
- }
182
- finally {
183
- restoreEnv(saved);
184
- }
185
- });
186
- // --- Rejected: wrong scheme / invalid URL ------------------------------------
187
- test("embeddingConfigFromEnv: rejects non-http scheme (ftp://)", () => {
188
- const saved = saveEnv();
189
- try {
190
- clearEnv();
191
- process.env.MEGACOMPACT_EMBEDDING_URL = "ftp://localhost:8080/embed";
192
- assert.equal(embeddingConfigFromEnv(), null);
193
- }
194
- finally {
195
- restoreEnv(saved);
196
- }
197
- });
198
- test("embeddingConfigFromEnv: rejects invalid URL string", () => {
199
- const saved = saveEnv();
200
- try {
201
- clearEnv();
202
- process.env.MEGACOMPACT_EMBEDDING_URL = "not a url";
203
- assert.equal(embeddingConfigFromEnv(), null);
204
- }
205
- finally {
206
- restoreEnv(saved);
207
- }
208
- });
209
- // --- Config fields parsed correctly -----------------------------------------
210
- test("embeddingConfigFromEnv: parses apiKey and dim from env", () => {
211
- const saved = saveEnv();
212
- try {
213
- clearEnv();
214
- process.env.MEGACOMPACT_EMBEDDING_URL = HTTP + "127.0.0.1:8080";
215
- process.env.MEGACOMPACT_EMBEDDING_KEY = "secret-key";
216
- process.env.MEGACOMPACT_EMBEDDING_DIM = "768";
217
- const cfg = embeddingConfigFromEnv();
218
- assert.ok(cfg);
219
- assert.equal(cfg.apiKey, "secret-key");
220
- assert.equal(cfg.dim, 768);
221
- }
222
- finally {
223
- restoreEnv(saved);
224
- }
225
- });
226
- test("embeddingConfigFromEnv: parses valid headers from env", () => {
227
- const saved = saveEnv();
228
- try {
229
- clearEnv();
230
- process.env.MEGACOMPACT_EMBEDDING_URL = HTTP + "127.0.0.1:8080";
231
- process.env.MEGACOMPACT_EMBEDDING_HEADERS = '{"X-Custom":"value"}';
232
- const cfg = embeddingConfigFromEnv();
233
- assert.ok(cfg);
234
- assert.equal(cfg.headers?.["X-Custom"], "value");
235
- }
236
- finally {
237
- restoreEnv(saved);
238
- }
239
- });
240
- test("embeddingConfigFromEnv: ignores invalid headers (does not throw)", () => {
241
- const saved = saveEnv();
242
- try {
243
- clearEnv();
244
- process.env.MEGACOMPACT_EMBEDDING_URL = HTTP + "127.0.0.1:8080";
245
- process.env.MEGACOMPACT_EMBEDDING_HEADERS = "not json";
246
- const cfg = embeddingConfigFromEnv();
247
- assert.ok(cfg, "config should still be returned with invalid headers ignored");
248
- assert.equal(cfg.url, HTTP + "127.0.0.1:8080");
249
- }
250
- finally {
251
- restoreEnv(saved);
252
- }
253
- });
254
- // --- Fail-closed: never throws -----------------------------------------------
255
- test("embeddingConfigFromEnv: never throws on any input", () => {
256
- const saved = saveEnv();
257
- try {
258
- const inputs = [
259
- "",
260
- "not a url",
261
- "ftp://localhost",
262
- HTTP + "192.168.1.1:8080",
263
- HTTP + "localhost:8080@evil.com/",
264
- HTTP + "[2001:db8::1]:80",
265
- "file:///etc/passwd",
266
- "javascript:alert(1)",
267
- ];
268
- for (const input of inputs) {
269
- clearEnv();
270
- process.env.MEGACOMPACT_EMBEDDING_URL = input;
271
- assert.doesNotThrow(() => embeddingConfigFromEnv(), `should not throw for: ${input}`);
272
- }
273
- }
274
- finally {
275
- restoreEnv(saved);
276
- }
277
- });
@@ -1,372 +0,0 @@
1
- /**
2
- * importance.test.ts — S40A unit tests for the importance scoring engine.
3
- *
4
- * Covers all exports: ContextItemType, DEFAULT_MULTIPLIERS, detectItemType,
5
- * ageDecay, recencyBoost, retentionBoost, score, preservationCutoff,
6
- * itemsToPreserve, scoreEngineMessages.
7
- *
8
- * Determinism is enforced — same inputs MUST produce same outputs.
9
- */
10
- import { test } from "node:test";
11
- import assert from "node:assert/strict";
12
- import { ContextItemType, DEFAULT_MULTIPLIERS, detectItemType, ageDecay, recencyBoost, retentionBoost, score, preservationCutoff, itemsToPreserve, scoreEngineMessages, } from "./importance.js";
13
- const NOW = 1_700_000_000_000; // fixed epoch ms for determinism
14
- // ---- S40A-1: types and enums ----
15
- test("ContextItemType enum has 8 variants with snake_case values", () => {
16
- assert.equal(ContextItemType.UserMessage, "user_message");
17
- assert.equal(ContextItemType.AssistantMessage, "assistant_message");
18
- assert.equal(ContextItemType.SystemMessage, "system_message");
19
- assert.equal(ContextItemType.CodeBlock, "code_block");
20
- assert.equal(ContextItemType.Error, "error");
21
- assert.equal(ContextItemType.Decision, "decision");
22
- assert.equal(ContextItemType.FileModification, "file_modification");
23
- assert.equal(ContextItemType.ToolExecution, "tool_execution");
24
- });
25
- // ---- S40A-2: DEFAULT_MULTIPLIERS ----
26
- test("DEFAULT_MULTIPLIERS matches the Rust reference values", () => {
27
- assert.equal(DEFAULT_MULTIPLIERS[ContextItemType.UserMessage], 1.5);
28
- assert.equal(DEFAULT_MULTIPLIERS[ContextItemType.AssistantMessage], 1.0);
29
- assert.equal(DEFAULT_MULTIPLIERS[ContextItemType.SystemMessage], 0.5);
30
- assert.equal(DEFAULT_MULTIPLIERS[ContextItemType.CodeBlock], 1.2);
31
- assert.equal(DEFAULT_MULTIPLIERS[ContextItemType.Error], 2.0);
32
- assert.equal(DEFAULT_MULTIPLIERS[ContextItemType.Decision], 2.5);
33
- assert.equal(DEFAULT_MULTIPLIERS[ContextItemType.FileModification], 1.8);
34
- assert.equal(DEFAULT_MULTIPLIERS[ContextItemType.ToolExecution], 1.3);
35
- });
36
- test("DEFAULT_MULTIPLIERS has an entry for every ContextItemType variant", () => {
37
- for (const t of Object.values(ContextItemType)) {
38
- assert.equal(typeof DEFAULT_MULTIPLIERS[t], "number", `missing multiplier for ${t}`);
39
- }
40
- });
41
- // ---- S40A-3: ageDecay ----
42
- test("ageDecay: fresh (age=0) returns 0", () => {
43
- assert.equal(ageDecay(0), 0);
44
- });
45
- test("ageDecay: 1 hour at 5%/hr returns 0.05", () => {
46
- assert.equal(ageDecay(3_600_000), 0.05);
47
- });
48
- test("ageDecay: 14 hours caps at 0.7 (maxDecay)", () => {
49
- assert.equal(ageDecay(14 * 3_600_000), 0.7);
50
- });
51
- test("ageDecay: beyond 14 hours stays capped at 0.7", () => {
52
- assert.equal(ageDecay(100 * 3_600_000), 0.7);
53
- });
54
- test("ageDecay: negative age (future timestamp) returns 0", () => {
55
- assert.equal(ageDecay(-5_000), 0);
56
- });
57
- test("ageDecay: custom rate and max override defaults", () => {
58
- // 10h at 0.1/hr = 1.0 → capped at 0.8.
59
- assert.equal(ageDecay(10 * 3_600_000, 0.1, 0.8), 0.8);
60
- // 2h at 0.1/hr = 0.2.
61
- assert.equal(ageDecay(2 * 3_600_000, 0.1, 0.8), 0.2);
62
- });
63
- // ---- S40A-4: recencyBoost + retentionBoost ----
64
- test("recencyBoost: <5min returns 1.2", () => {
65
- assert.equal(recencyBoost(299_000), 1.2);
66
- });
67
- test("recencyBoost: >5min returns 1.0", () => {
68
- assert.equal(recencyBoost(301_000), 1.0);
69
- });
70
- test("recencyBoost: exactly 5min (300_000ms) returns 1.0 (boundary)", () => {
71
- assert.equal(recencyBoost(300_000), 1.0);
72
- });
73
- test("recencyBoost: custom threshold respected", () => {
74
- assert.equal(recencyBoost(5000, 10_000), 1.2);
75
- assert.equal(recencyBoost(11_000, 10_000), 1.0);
76
- });
77
- test("retentionBoost: flagged returns 3.0", () => {
78
- assert.equal(retentionBoost(true), 3.0);
79
- });
80
- test("retentionBoost: unflagged returns 1.0", () => {
81
- assert.equal(retentionBoost(false), 1.0);
82
- });
83
- // ---- S40A-5: detectItemType ----
84
- test("detectItemType: role=tool → ToolExecution (priority 1)", () => {
85
- // Even if content looks like an error, tool role wins.
86
- assert.equal(detectItemType("error: something failed", "tool"), ContextItemType.ToolExecution);
87
- });
88
- test("detectItemType: role=custom → SystemMessage (priority 2)", () => {
89
- assert.equal(detectItemType("anything here", "custom"), ContextItemType.SystemMessage);
90
- });
91
- test("detectItemType: error content → Error", () => {
92
- assert.equal(detectItemType("Error: ENOENT at src/config.ts:42", "assistant"), ContextItemType.Error);
93
- assert.equal(detectItemType("Traceback (most recent call last)", "assistant"), ContextItemType.Error);
94
- assert.equal(detectItemType("panic: runtime error", "assistant"), ContextItemType.Error);
95
- assert.equal(detectItemType("E4030 connection refused", "assistant"), ContextItemType.Error);
96
- });
97
- test("detectItemType: decision content → Decision", () => {
98
- assert.equal(detectItemType("we decided to use JWT auth", "assistant"), ContextItemType.Decision);
99
- assert.equal(detectItemType("going with option B", "assistant"), ContextItemType.Decision);
100
- assert.equal(detectItemType("let's go with the async approach", "assistant"), ContextItemType.Decision);
101
- assert.equal(detectItemType("switching to a different database", "assistant"), ContextItemType.Decision);
102
- });
103
- test("detectItemType: fenced code block ≥20 chars → CodeBlock", () => {
104
- const code = "```js\nconst x = 42;\nconst y = 'hello world';\n```";
105
- assert.equal(detectItemType(code, "assistant"), ContextItemType.CodeBlock);
106
- });
107
- test("detectItemType: short fenced block (<20 chars) does NOT → CodeBlock", () => {
108
- const short = "```\nshort\n```";
109
- assert.notEqual(detectItemType(short, "assistant"), ContextItemType.CodeBlock);
110
- });
111
- test("detectItemType: file modification verbs → FileModification", () => {
112
- assert.equal(detectItemType("edited src/config.ts to add a flag", "assistant"), ContextItemType.FileModification);
113
- assert.equal(detectItemType("created README.md", "assistant"), ContextItemType.FileModification);
114
- assert.equal(detectItemType("wrote tests/main.test.ts", "assistant"), ContextItemType.FileModification);
115
- });
116
- test("detectItemType: role=user → UserMessage", () => {
117
- assert.equal(detectItemType("plain question", "user"), ContextItemType.UserMessage);
118
- });
119
- test("detectItemType: role=assistant → AssistantMessage", () => {
120
- assert.equal(detectItemType("plain answer", "assistant"), ContextItemType.AssistantMessage);
121
- });
122
- test("detectItemType: fallback → AssistantMessage", () => {
123
- // Unknown role with non-matching content falls back to AssistantMessage.
124
- assert.equal(detectItemType("nothing matches here", "unknown"), ContextItemType.AssistantMessage);
125
- });
126
- test("detectItemType: empty string does not crash and falls back", () => {
127
- assert.equal(detectItemType("", "user"), ContextItemType.UserMessage);
128
- assert.equal(detectItemType("", "assistant"), ContextItemType.AssistantMessage);
129
- });
130
- test("detectItemType: priority — error before decision (first match wins)", () => {
131
- // A message that contains BOTH "error" and "decided" — error wins (rule 3 before rule 4).
132
- assert.equal(detectItemType("error: we decided to fail", "assistant"), ContextItemType.Error);
133
- });
134
- // ---- S40A-6: score ----
135
- test("score: fresh decision gets full multiplier (no decay, no recency/retention boost expected unless young)", () => {
136
- const result = score({
137
- id: "0",
138
- content: "we decided to use JWT",
139
- role: "assistant",
140
- timestamp: NOW, // age 0
141
- }, NOW);
142
- assert.equal(result.type, ContextItemType.Decision);
143
- assert.equal(result.rawMultiplier, 2.5);
144
- assert.equal(result.ageDecay, 0);
145
- assert.equal(result.recencyBoost, 1.2); // age 0 < 5min
146
- assert.equal(result.retentionBoost, 1.0); // not userFlagged
147
- // 2.5 * (1 - 0) * 1.2 * 1.0 = 3.0
148
- assert.equal(result.finalScore, 3.0);
149
- });
150
- test("score: old decision decays", () => {
151
- const tenHoursAgo = NOW - 10 * 3_600_000;
152
- const result = score({
153
- id: "1",
154
- content: "we decided to use JWT",
155
- role: "assistant",
156
- timestamp: tenHoursAgo,
157
- }, NOW);
158
- // decay at 10h = 0.5; recency 1.0 (>5min); retention 1.0
159
- // 2.5 * (1 - 0.5) * 1.0 * 1.0 = 1.25
160
- assert.equal(result.ageDecay, 0.5);
161
- assert.equal(result.recencyBoost, 1.0);
162
- assert.equal(result.finalScore, 1.25);
163
- });
164
- test("score: userFlagged triples the result via retentionBoost", () => {
165
- const flagged = score({
166
- id: "2",
167
- content: "we decided to use JWT",
168
- role: "assistant",
169
- timestamp: NOW,
170
- userFlagged: true,
171
- }, NOW);
172
- const unflagged = score({
173
- id: "3",
174
- content: "we decided to use JWT",
175
- role: "assistant",
176
- timestamp: NOW,
177
- userFlagged: false,
178
- }, NOW);
179
- // 3.0 / 1.0 retention ratio.
180
- assert.equal(flagged.finalScore / unflagged.finalScore, 3.0);
181
- });
182
- test("score: clamps finalScore to minimum 0.01", () => {
183
- // A system message (0.5x) at 14h+ (max decay 0.7) → 0.5 * 0.3 * 1.0 * 1.0 = 0.15. Above 0.01.
184
- // Force below 0.01 with a custom multiplier of 0 and max decay.
185
- const result = score({
186
- id: "4",
187
- content: "system filler",
188
- role: "custom",
189
- timestamp: NOW - 100 * 3_600_000,
190
- }, NOW, { [ContextItemType.SystemMessage]: 0.01 }, { maxDecay: 0.99 });
191
- // 0.01 * (1 - 0.99) * 1.0 * 1.0 = 0.0001 → clamped to 0.01.
192
- assert.equal(result.finalScore, 0.01);
193
- });
194
- test("score: custom multipliers override DEFAULT_MULTIPLIERS", () => {
195
- const result = score({
196
- id: "5",
197
- content: "we decided to use JWT",
198
- role: "assistant",
199
- timestamp: NOW,
200
- }, NOW, { [ContextItemType.Decision]: 10.0 });
201
- assert.equal(result.rawMultiplier, 10.0);
202
- assert.equal(result.finalScore, 10.0 * 1.2); // 10 * (1-0) * 1.2 * 1.0
203
- });
204
- test("score: unknown role narrows to assistant defensively", () => {
205
- const result = score({
206
- id: "6",
207
- content: "plain text",
208
- role: "weird-role",
209
- timestamp: NOW,
210
- }, NOW);
211
- assert.equal(result.role, "assistant");
212
- assert.equal(result.type, ContextItemType.AssistantMessage);
213
- });
214
- test("score: undefined/null content does not crash", () => {
215
- const r1 = score({ id: "a", content: undefined, role: "user", timestamp: NOW }, NOW);
216
- const r2 = score({ id: "b", content: null, role: "assistant", timestamp: NOW }, NOW);
217
- assert.equal(r1.type, ContextItemType.UserMessage);
218
- assert.equal(r2.type, ContextItemType.AssistantMessage);
219
- assert.equal(r1.content, "");
220
- assert.equal(r2.content, "");
221
- });
222
- test("score: determinism — same inputs → same output", () => {
223
- const item = {
224
- id: "d1",
225
- content: "we decided to use JWT",
226
- role: "assistant",
227
- timestamp: NOW - 3_600_000,
228
- };
229
- const a = score(item, NOW);
230
- const b = score(item, NOW);
231
- assert.deepEqual(a, b);
232
- });
233
- // ---- S40A-7: preservationCutoff + itemsToPreserve ----
234
- test("preservationCutoff: 10 items at ratio 0.3 → threshold is the 3rd-highest score", () => {
235
- const items = Array.from({ length: 10 }, (_, i) => ({
236
- id: String(i),
237
- type: ContextItemType.AssistantMessage,
238
- content: "",
239
- role: "assistant",
240
- timestamp: 0,
241
- rawMultiplier: 1.0,
242
- ageDecay: 0,
243
- recencyBoost: 1.0,
244
- retentionBoost: 1.0,
245
- // scores 1.0, 2.0, ..., 10.0
246
- finalScore: (i + 1) * 1.0,
247
- }));
248
- const threshold = preservationCutoff(items, 0.3);
249
- // top 30% of 10 = 3 items; the 3rd highest is 8.0 (scores 10,9,8 preserved).
250
- assert.equal(threshold, 8.0);
251
- });
252
- test("preservationCutoff: ratio=1.0 returns 0 (preserve all)", () => {
253
- const items = [{ finalScore: 5, id: "x" }];
254
- assert.equal(preservationCutoff(items, 1.0), 0);
255
- });
256
- test("preservationCutoff: ratio=0 returns Infinity (preserve none)", () => {
257
- const items = [{ finalScore: 5, id: "x" }];
258
- assert.equal(preservationCutoff(items, 0), Infinity);
259
- });
260
- test("preservationCutoff: empty input returns Infinity", () => {
261
- assert.equal(preservationCutoff([], 0.5), Infinity);
262
- });
263
- test("itemsToPreserve: returns IDs at or above threshold", () => {
264
- const items = Array.from({ length: 10 }, (_, i) => ({
265
- id: String(i),
266
- type: ContextItemType.AssistantMessage,
267
- content: "",
268
- role: "assistant",
269
- timestamp: 0,
270
- rawMultiplier: 1.0,
271
- ageDecay: 0,
272
- recencyBoost: 1.0,
273
- retentionBoost: 1.0,
274
- finalScore: (i + 1) * 1.0,
275
- }));
276
- const result = itemsToPreserve(items, 0.3);
277
- assert.equal(result.totalScored, 10);
278
- assert.equal(result.totalPreserved, 3);
279
- assert.deepEqual([...result.preservedIds].sort(), ["7", "8", "9"]);
280
- });
281
- test("itemsToPreserve: ratio=1.0 preserves everything", () => {
282
- const items = Array.from({ length: 5 }, (_, i) => ({
283
- id: String(i),
284
- type: ContextItemType.AssistantMessage,
285
- content: "",
286
- role: "assistant",
287
- timestamp: 0,
288
- rawMultiplier: 1.0,
289
- ageDecay: 0,
290
- recencyBoost: 1.0,
291
- retentionBoost: 1.0,
292
- finalScore: i + 1,
293
- }));
294
- const result = itemsToPreserve(items, 1.0);
295
- assert.equal(result.totalPreserved, 5);
296
- });
297
- test("itemsToPreserve: ratio=0 preserves nothing", () => {
298
- const items = Array.from({ length: 5 }, (_, i) => ({
299
- id: String(i),
300
- type: ContextItemType.AssistantMessage,
301
- content: "",
302
- role: "assistant",
303
- timestamp: 0,
304
- rawMultiplier: 1.0,
305
- ageDecay: 0,
306
- recencyBoost: 1.0,
307
- retentionBoost: 1.0,
308
- finalScore: i + 1,
309
- }));
310
- const result = itemsToPreserve(items, 0);
311
- assert.equal(result.totalPreserved, 0);
312
- assert.equal(result.threshold, Infinity);
313
- });
314
- test("itemsToPreserve: empty items returns empty set", () => {
315
- const result = itemsToPreserve([], 0.5);
316
- assert.equal(result.totalScored, 0);
317
- assert.equal(result.totalPreserved, 0);
318
- assert.equal(result.preservedIds.size, 0);
319
- });
320
- // ---- scoreEngineMessages: position-based age fallback ----
321
- test("scoreEngineMessages: assigns position-based timestamps (oldest first)", () => {
322
- const messages = [
323
- { role: "assistant", text: "we decided to use JWT" },
324
- { role: "user", text: "ok" },
325
- { role: "assistant", text: "edited src/config.ts" },
326
- ];
327
- const scored = scoreEngineMessages(messages, NOW);
328
- assert.equal(scored.length, 3);
329
- // Oldest (i=0) is `messages.length` minutes ago = 3 min.
330
- assert.equal(scored[0].timestamp, NOW - 3 * 60_000);
331
- // Newest (i=2) is 1 min ago.
332
- assert.equal(scored[2].timestamp, NOW - 1 * 60_000);
333
- // All recency-boosted (< 5 min).
334
- assert.equal(scored[0].recencyBoost, 1.2);
335
- assert.equal(scored[2].recencyBoost, 1.2);
336
- });
337
- test("scoreEngineMessages: preserves input order and ids are stringified indices", () => {
338
- const messages = [
339
- { role: "user", text: "first" },
340
- { role: "user", text: "second" },
341
- ];
342
- const scored = scoreEngineMessages(messages, NOW);
343
- assert.equal(scored[0].id, "0");
344
- assert.equal(scored[1].id, "1");
345
- });
346
- test("scoreEngineMessages: empty input returns empty array", () => {
347
- assert.deepEqual(scoreEngineMessages([], NOW), []);
348
- });
349
- test("scoreEngineMessages: determinism — same input → same output", () => {
350
- const messages = [
351
- { role: "assistant", text: "we decided to use JWT" },
352
- { role: "user", text: "ok" },
353
- ];
354
- const a = scoreEngineMessages(messages, NOW);
355
- const b = scoreEngineMessages(messages, NOW);
356
- assert.deepEqual(a, b);
357
- });
358
- // ---- integration: a decision outsurvives filler ----
359
- test("integration: a decision is preserved over filler at the same age", () => {
360
- // 10 messages, 1 decision (i=4) and 9 filler, all equally old.
361
- const messages = Array.from({ length: 10 }, (_, i) => i === 4
362
- ? { role: "assistant", text: "we decided to use JWT auth" }
363
- : { role: "assistant", text: "ok, sounds good" });
364
- const scored = scoreEngineMessages(messages, NOW - 10 * 60_000); // 10 min old → no recency boost
365
- // decision rawMultiplier 2.5 vs filler 1.0; same decay, same recency.
366
- const decision = scored[4];
367
- const filler = scored[0];
368
- assert.ok(decision.finalScore > filler.finalScore);
369
- // top 20% → 2 items; the decision must be in the preserved set.
370
- const result = itemsToPreserve(scored, 0.2);
371
- assert.ok(result.preservedIds.has("4"), "decision must be preserved");
372
- });