@remnic/core 9.69.88 → 9.69.90

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 (431) hide show
  1. package/dist/access-admin-ops-surface.js +74 -72
  2. package/dist/access-authorization-probe.js +75 -73
  3. package/dist/access-boundary.js +74 -72
  4. package/dist/access-cli.js +168 -165
  5. package/dist/access-cli.js.map +1 -1
  6. package/dist/access-extraction-force-flush.js +74 -72
  7. package/dist/access-http-briefing.js +75 -73
  8. package/dist/access-http-query.js +76 -74
  9. package/dist/access-http.js +98 -96
  10. package/dist/access-identity-continuity-surface.js +74 -72
  11. package/dist/access-lcm-surface.js +74 -72
  12. package/dist/access-mcp-output-schemas.d.ts.map +1 -1
  13. package/dist/access-mcp-output-schemas.js +1 -1
  14. package/dist/access-mcp.js +86 -84
  15. package/dist/access-memory-search-fanout.js +3 -3
  16. package/dist/access-namespace-preflight.js +74 -72
  17. package/dist/access-observe-write-category.js +11 -10
  18. package/dist/access-observe-write-surface.js +74 -72
  19. package/dist/access-offline-manifest.js +10 -9
  20. package/dist/access-operations-batch.js +76 -74
  21. package/dist/access-operations.js +83 -81
  22. package/dist/access-recall-concurrency.js +74 -72
  23. package/dist/access-recall-corpus-versions.d.ts +12 -0
  24. package/dist/access-recall-corpus-versions.d.ts.map +1 -0
  25. package/dist/access-recall-corpus-versions.js +10 -0
  26. package/dist/access-recall-diagnostics.js +5 -5
  27. package/dist/access-recall-response.d.ts +4 -0
  28. package/dist/access-recall-response.d.ts.map +1 -1
  29. package/dist/access-recall-response.js +74 -72
  30. package/dist/access-recall-surface.d.ts +8 -0
  31. package/dist/access-recall-surface.d.ts.map +1 -1
  32. package/dist/access-recall-surface.js +74 -72
  33. package/dist/access-schema.js +10 -9
  34. package/dist/access-service.d.ts +5 -0
  35. package/dist/access-service.d.ts.map +1 -1
  36. package/dist/access-service.js +74 -72
  37. package/dist/access-surface-catalog.js +76 -74
  38. package/dist/access-surface-catalog.js.map +1 -1
  39. package/dist/active-memory-bridge.js +3 -3
  40. package/dist/active-recall.js +27 -24
  41. package/dist/active-recall.js.map +1 -1
  42. package/dist/adapters/index.js +7 -7
  43. package/dist/adapters/registry.js +3 -3
  44. package/dist/{auto-sync-U5N3CB5Y.js → auto-sync-PAWBFQWL.js} +5 -5
  45. package/dist/briefing.js +19 -19
  46. package/dist/buffer.js +8 -8
  47. package/dist/calibration.js +2 -2
  48. package/dist/capabilities.d.ts +2 -1
  49. package/dist/capabilities.d.ts.map +1 -1
  50. package/dist/capabilities.js +1 -1
  51. package/dist/{capsule-crypto-YO5QJ6L3.js → capsule-crypto-7FJQINUR.js} +2 -2
  52. package/dist/causal-consolidation.js +19 -19
  53. package/dist/{chunk-BMXEBWBT.js → chunk-2EMROIXS.js} +2 -1
  54. package/dist/{chunk-BMXEBWBT.js.map → chunk-2EMROIXS.js.map} +1 -1
  55. package/dist/{chunk-MCTM4YPL.js → chunk-2FLFJTCI.js} +4 -2
  56. package/dist/chunk-2FLFJTCI.js.map +1 -0
  57. package/dist/{chunk-RDJ6C7NZ.js → chunk-2IWBHZ3H.js} +5 -5
  58. package/dist/{chunk-UP75KL3L.js → chunk-2JRB3Z5N.js} +2 -2
  59. package/dist/{chunk-BXLOS5AJ.js → chunk-2NLLXCJG.js} +2 -2
  60. package/dist/{chunk-KN6CIN7I.js → chunk-32HO62I4.js} +2 -2
  61. package/dist/{chunk-JLPNONPH.js → chunk-35A7GCHG.js} +2 -2
  62. package/dist/{chunk-MXCAJKMA.js → chunk-37ZQYFX4.js} +6 -6
  63. package/dist/{chunk-LW3HKRL7.js → chunk-3BTHXB7Z.js} +3 -3
  64. package/dist/{chunk-C7V3KPKJ.js → chunk-47LTKAGL.js} +2 -2
  65. package/dist/{chunk-3O5BB45T.js → chunk-4DXNOVNW.js} +10 -10
  66. package/dist/{chunk-65I2LZEK.js → chunk-4G2YCKLT.js} +2 -2
  67. package/dist/{chunk-OK52IY3W.js → chunk-4GEBLO7S.js} +10 -10
  68. package/dist/{chunk-M6C7SOR6.js → chunk-4I6PEEFA.js} +3 -3
  69. package/dist/{chunk-Z4TXB4K7.js → chunk-5BUCKFRE.js} +2 -2
  70. package/dist/{chunk-BGI4NUAO.js → chunk-5S7SNRSJ.js} +2 -2
  71. package/dist/{chunk-JVPWRNHA.js → chunk-5YR4UGF2.js} +5 -5
  72. package/dist/{chunk-YJ7MW627.js → chunk-6BG364RN.js} +2 -2
  73. package/dist/{chunk-D5BSQR63.js → chunk-76LNUSS5.js} +2 -2
  74. package/dist/{chunk-7CRUDH7G.js → chunk-77HNHT6S.js} +2 -2
  75. package/dist/{chunk-OWYHHW67.js → chunk-7XI2UJHL.js} +4 -4
  76. package/dist/{chunk-BJVO4H5C.js → chunk-7Z2UKRNJ.js} +4 -4
  77. package/dist/{chunk-2WLMWP2T.js → chunk-A3K2KKSG.js} +2 -2
  78. package/dist/chunk-A5ZYP4K5.js +130 -0
  79. package/dist/chunk-A5ZYP4K5.js.map +1 -0
  80. package/dist/{chunk-AWG3TIAY.js → chunk-ACCOC6UM.js} +2 -2
  81. package/dist/{chunk-3JDA3XF5.js → chunk-AEGNDL24.js} +2 -2
  82. package/dist/{chunk-2NAD4YCI.js → chunk-AEUMONCD.js} +2 -2
  83. package/dist/{chunk-C6U57KG4.js → chunk-AF5PW35O.js} +3 -3
  84. package/dist/{chunk-IOSZHHJC.js → chunk-ANGZWYL2.js} +6 -6
  85. package/dist/{chunk-K6T33R4Q.js → chunk-AXGJMDBS.js} +156 -7
  86. package/dist/chunk-AXGJMDBS.js.map +1 -0
  87. package/dist/{chunk-6LYAEM54.js → chunk-AXHU56C3.js} +2 -2
  88. package/dist/{chunk-GWM6T5EQ.js → chunk-BCGMG2RD.js} +2 -2
  89. package/dist/{chunk-HXCJF4XU.js → chunk-BFIZXFUG.js} +2 -2
  90. package/dist/{chunk-DBYAY6UW.js → chunk-BTOHGPHC.js} +3 -3
  91. package/dist/{chunk-5X4MXNEU.js → chunk-C6HPNPNK.js} +3 -3
  92. package/dist/{chunk-4MP7XR5J.js → chunk-CAKHZAXH.js} +2 -2
  93. package/dist/{chunk-YSBL7VPO.js → chunk-CDWFWOSZ.js} +2 -2
  94. package/dist/{chunk-QAW55ZHJ.js → chunk-CZ44FH45.js} +4 -4
  95. package/dist/{chunk-T3FMRLWQ.js → chunk-D5HQ3VEX.js} +4 -4
  96. package/dist/{chunk-S7LWX2PQ.js → chunk-DPG5HQLE.js} +4 -4
  97. package/dist/{chunk-C7ZDKWPS.js → chunk-DVSAMW5T.js} +3 -3
  98. package/dist/{chunk-WBYQA3VN.js → chunk-E5H4TM4Y.js} +3 -3
  99. package/dist/{chunk-4RL3JOB3.js → chunk-EEDI3OXB.js} +2 -2
  100. package/dist/{chunk-3TB2XQ3C.js → chunk-EUL3S3LE.js} +4 -4
  101. package/dist/{chunk-Q4AUIFUA.js → chunk-F23U5YE7.js} +7 -7
  102. package/dist/{chunk-ZZZ4I455.js → chunk-GDVORIFM.js} +2 -2
  103. package/dist/{chunk-QB57WIS6.js → chunk-GXETU7AE.js} +98 -73
  104. package/dist/chunk-GXETU7AE.js.map +1 -0
  105. package/dist/{chunk-SWBC3UER.js → chunk-HCPUVB7S.js} +3 -3
  106. package/dist/{chunk-R3X2T2LP.js → chunk-HFOY2SBG.js} +2 -2
  107. package/dist/{chunk-LU7E2MXE.js → chunk-HQCUUVG2.js} +20 -20
  108. package/dist/{chunk-FJLQXMTU.js → chunk-I6B3S62A.js} +2 -2
  109. package/dist/{chunk-RBITPCMK.js → chunk-IDSSDL4W.js} +9 -9
  110. package/dist/{chunk-OCFXVDBZ.js → chunk-IVEHY2VT.js} +54 -123
  111. package/dist/chunk-IVEHY2VT.js.map +1 -0
  112. package/dist/{chunk-B3OFQP5Y.js → chunk-IY47KPML.js} +6 -6
  113. package/dist/{chunk-AXC4WSF3.js → chunk-JDOBIFBK.js} +2 -2
  114. package/dist/{chunk-P2ODTYOF.js → chunk-JGXHQV5N.js} +3 -3
  115. package/dist/{chunk-7LNHRQKR.js → chunk-JLIGUFPF.js} +2 -2
  116. package/dist/{chunk-EDIH6X2P.js → chunk-JZ66PN72.js} +2 -2
  117. package/dist/{chunk-BLVR4WYU.js → chunk-KICEAGKM.js} +2 -2
  118. package/dist/{chunk-S2GE2K36.js → chunk-KNI4SGQE.js} +109 -96
  119. package/dist/chunk-KNI4SGQE.js.map +1 -0
  120. package/dist/{chunk-VDX2J7OX.js → chunk-KQAFEZQX.js} +2 -2
  121. package/dist/{chunk-PEBHPCX2.js → chunk-KTG23JDX.js} +2 -2
  122. package/dist/{chunk-BOZJD5PK.js → chunk-KYOZ5E6V.js} +2 -2
  123. package/dist/{chunk-2DLWLNO4.js → chunk-L3TZXELN.js} +4 -4
  124. package/dist/{chunk-VALKBYBN.js → chunk-M3N2TUZ7.js} +2 -2
  125. package/dist/{chunk-76M5OK7V.js → chunk-M7T2NKET.js} +5 -5
  126. package/dist/chunk-MSAI3Q7D.js +372 -0
  127. package/dist/chunk-MSAI3Q7D.js.map +1 -0
  128. package/dist/{chunk-Z5LP6ILP.js → chunk-MZAH3CBT.js} +2 -2
  129. package/dist/{chunk-QI7K7BZ5.js → chunk-NJW2ZG64.js} +2 -2
  130. package/dist/{chunk-CZJA2EQE.js → chunk-NSKXRTVZ.js} +2 -2
  131. package/dist/{chunk-4O4XCBOS.js → chunk-NUSQ3YEL.js} +2 -2
  132. package/dist/{chunk-4OQET73E.js → chunk-O57FCN42.js} +15 -15
  133. package/dist/{chunk-WKY7N3L7.js → chunk-OEBUAC3O.js} +10 -10
  134. package/dist/{chunk-Y23L4YJV.js → chunk-OEIA4IHU.js} +2 -2
  135. package/dist/{chunk-66DKTOBY.js → chunk-OGZC2WUX.js} +2 -2
  136. package/dist/{chunk-3SGTV7RD.js → chunk-P62DSJUK.js} +6 -6
  137. package/dist/{chunk-FKD656D2.js → chunk-PH2V7EXZ.js} +2 -2
  138. package/dist/{chunk-KKNZ7PUZ.js → chunk-QAIKLICT.js} +2 -2
  139. package/dist/{chunk-SSUDD72S.js → chunk-QPWUG2S3.js} +2 -2
  140. package/dist/{chunk-QI2E6ISQ.js → chunk-R2TVWQLR.js} +2 -2
  141. package/dist/chunk-R2TVWQLR.js.map +1 -0
  142. package/dist/{chunk-GZDTVYK2.js → chunk-R36IBI2M.js} +3 -3
  143. package/dist/{chunk-W3XXFPRI.js → chunk-R5B3OWI4.js} +64 -64
  144. package/dist/{chunk-VL4X7ZHC.js → chunk-RFIJRZ4K.js} +2 -2
  145. package/dist/{chunk-PWF4JXKD.js → chunk-RKDSELA3.js} +1 -1
  146. package/dist/chunk-RKDSELA3.js.map +1 -0
  147. package/dist/{chunk-AEHVZY3X.js → chunk-RPVHRZ5C.js} +2 -2
  148. package/dist/{chunk-X5SHE2O3.js → chunk-RVBLCU5C.js} +4 -4
  149. package/dist/{chunk-BUQKSQXL.js → chunk-S533KGX6.js} +5 -5
  150. package/dist/{chunk-STEOT4DI.js → chunk-SCPHU3RW.js} +7 -7
  151. package/dist/{chunk-LV5H6FTN.js → chunk-SFSD5Q6O.js} +3 -3
  152. package/dist/{chunk-AE5U5NMS.js → chunk-SMLKHXPF.js} +2 -2
  153. package/dist/{chunk-AEU4EQGV.js → chunk-T7R5HI6A.js} +1 -1
  154. package/dist/{chunk-H5BJWPUI.js → chunk-TVQZAQPE.js} +2 -2
  155. package/dist/{chunk-H56VY4BY.js → chunk-U36GYZ2P.js} +10 -5
  156. package/dist/chunk-U36GYZ2P.js.map +1 -0
  157. package/dist/{chunk-XOV7NRY5.js → chunk-U46P4UAR.js} +3 -3
  158. package/dist/{chunk-DZ42MDZE.js → chunk-UCJINCZT.js} +2 -2
  159. package/dist/{chunk-5E6RYRYW.js → chunk-UG5V3Z3R.js} +7 -7
  160. package/dist/{chunk-IW3RMBPB.js → chunk-VAOC6GHN.js} +2 -2
  161. package/dist/{chunk-6UQFJULG.js → chunk-VBNA2JEN.js} +2 -2
  162. package/dist/{chunk-HLB7GKGG.js → chunk-VOZNBQNL.js} +2 -2
  163. package/dist/{chunk-NYKIUQL6.js → chunk-WHIGRW7T.js} +2 -2
  164. package/dist/{chunk-AZSGSRIM.js → chunk-WHTMVTU4.js} +3 -3
  165. package/dist/{chunk-AERXJCOG.js → chunk-WL7N5VGG.js} +5 -5
  166. package/dist/{chunk-TFA6HPOA.js → chunk-WQUGCOKF.js} +4 -4
  167. package/dist/{chunk-A4VSOUCB.js → chunk-WTZQM74L.js} +5 -5
  168. package/dist/{chunk-DQEMWVMT.js → chunk-X7Y7WX73.js} +1 -1
  169. package/dist/{chunk-T2YX56QI.js → chunk-XWSUK5GL.js} +4 -4
  170. package/dist/{chunk-ACX55QDO.js → chunk-XYOT5GQU.js} +3 -3
  171. package/dist/{chunk-Z6EZCN6Z.js → chunk-Y7427SL7.js} +10 -10
  172. package/dist/{chunk-4KN2JLQV.js → chunk-YHZWVDP7.js} +2 -2
  173. package/dist/chunk-YVRQ5JRA.js +49 -0
  174. package/dist/chunk-YVRQ5JRA.js.map +1 -0
  175. package/dist/{chunk-5MNUBT7T.js → chunk-ZFTODDTX.js} +2 -2
  176. package/dist/{chunk-VVX5PZFS.js → chunk-ZHXSOMYH.js} +2 -2
  177. package/dist/{chunk-CRXRZA3G.js → chunk-ZQTYWSO3.js} +2 -2
  178. package/dist/cli.js +126 -122
  179. package/dist/coding/export-okf-codegraph.js +17 -17
  180. package/dist/compounding/engine.js +19 -19
  181. package/dist/config.d.ts.map +1 -1
  182. package/dist/config.js +27 -24
  183. package/dist/connectors/codex-materialize-runner.js +18 -18
  184. package/dist/connectors/index.js +20 -20
  185. package/dist/contradiction/index.js +3 -3
  186. package/dist/{contradiction-scan-TAGMOUQ2.js → contradiction-scan-GGRTVB7C.js} +3 -3
  187. package/dist/convergence-refresh.js +20 -20
  188. package/dist/conversation-index/backend.js +2 -2
  189. package/dist/corpus-watermark.js +20 -20
  190. package/dist/day-summary.js +2 -2
  191. package/dist/deep-recall-http-glue.js +11 -10
  192. package/dist/embedding-fallback.js +2 -2
  193. package/dist/entity-retrieval.js +19 -19
  194. package/dist/explicit-capture.js +2 -2
  195. package/dist/external-wiki-access.js +75 -73
  196. package/dist/extraction-judge.js +3 -3
  197. package/dist/extraction-normalization.js +3 -3
  198. package/dist/extraction-prompt.js +2 -2
  199. package/dist/extraction.js +32 -32
  200. package/dist/{first-start-migration-7OATHJKB.js → first-start-migration-OM3PHMZO.js} +2 -2
  201. package/dist/harmonic-retrieval.js +1 -1
  202. package/dist/index.d.ts +1 -1
  203. package/dist/index.d.ts.map +1 -1
  204. package/dist/index.js +198 -195
  205. package/dist/lcm/engine.js +4 -4
  206. package/dist/lcm/index.js +10 -10
  207. package/dist/local-llm-config.js +1 -1
  208. package/dist/local-llm.js +3 -3
  209. package/dist/location/index.js +20 -20
  210. package/dist/maintenance/memory-governance.js +18 -18
  211. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +18 -18
  212. package/dist/maintenance/rebuild-memory-projection.js +19 -19
  213. package/dist/memory-browse-operations.js +75 -73
  214. package/dist/memory-browse.js +5 -5
  215. package/dist/namespaces/migrate.js +19 -19
  216. package/dist/namespaces/principal.js +2 -2
  217. package/dist/namespaces/search.js +13 -13
  218. package/dist/namespaces/storage.js +18 -18
  219. package/dist/offline-sync-changeset-generations.d.ts +82 -0
  220. package/dist/offline-sync-changeset-generations.d.ts.map +1 -0
  221. package/dist/offline-sync-changeset-generations.js +21 -0
  222. package/dist/offline-sync-changeset-generations.js.map +1 -0
  223. package/dist/offline-sync-embedding-generation.d.ts +50 -0
  224. package/dist/offline-sync-embedding-generation.d.ts.map +1 -1
  225. package/dist/offline-sync-embedding-generation.js +4 -2
  226. package/dist/offline-sync-impression-drain.js +5 -5
  227. package/dist/offline-sync-snapshot-stream.js +5 -4
  228. package/dist/offline-sync.d.ts +12 -1
  229. package/dist/offline-sync.d.ts.map +1 -1
  230. package/dist/offline-sync.js +6 -5
  231. package/dist/operator-doctor-corpus.js +21 -21
  232. package/dist/operator-toolkit.js +39 -36
  233. package/dist/orchestration/compression-guideline-coordinator.js +2 -2
  234. package/dist/orchestration/maintenance.js +33 -33
  235. package/dist/orchestration/orchestrator-helpers.d.ts +1 -0
  236. package/dist/orchestration/orchestrator-helpers.d.ts.map +1 -1
  237. package/dist/orchestration/recall-entry.d.ts.map +1 -1
  238. package/dist/orchestration/recall-search-pipeline.d.ts.map +1 -1
  239. package/dist/orchestrator.js +168 -165
  240. package/dist/outcome-boost-config.d.ts +17 -0
  241. package/dist/outcome-boost-config.d.ts.map +1 -0
  242. package/dist/outcome-boost-config.js +1 -0
  243. package/dist/outcome-boost-config.js.map +1 -0
  244. package/dist/qmd.js +4 -4
  245. package/dist/recall-explain-renderer.js +3 -3
  246. package/dist/recall-navigate-access.js +2 -2
  247. package/dist/recall-navigate-disclosure.js +2 -2
  248. package/dist/recall-navigate.js +2 -2
  249. package/dist/recall-navigation-operations.js +75 -73
  250. package/dist/recall-navigation.js +74 -72
  251. package/dist/recall-state-view-admission.js +5 -5
  252. package/dist/recall-why-service.js +9 -9
  253. package/dist/recall-why.js +3 -3
  254. package/dist/recall-xray-cli.js +4 -4
  255. package/dist/recall-xray-renderer.js +3 -3
  256. package/dist/recall-xray.js +2 -2
  257. package/dist/rerank-outcome.d.ts +73 -0
  258. package/dist/rerank-outcome.d.ts.map +1 -0
  259. package/dist/rerank-outcome.js +28 -0
  260. package/dist/rerank-outcome.js.map +1 -0
  261. package/dist/{resolution-K4A3VPKZ.js → resolution-BROE3TRO.js} +4 -4
  262. package/dist/resolution-BROE3TRO.js.map +1 -0
  263. package/dist/resume-bundles.js +28 -25
  264. package/dist/search/embed-helper.js +2 -2
  265. package/dist/search/factory.js +12 -12
  266. package/dist/search/index.js +18 -18
  267. package/dist/search/lancedb-backend.js +2 -2
  268. package/dist/search/meilisearch-backend.js +2 -2
  269. package/dist/search/orama-backend.js +2 -2
  270. package/dist/semantic-consolidation.js +19 -19
  271. package/dist/semantic-rule-promotion.js +18 -18
  272. package/dist/semantic-rule-verifier.js +18 -18
  273. package/dist/shared-context/manager.js +2 -2
  274. package/dist/source-agent-qualifier.js +26 -26
  275. package/dist/standup/build.js +18 -18
  276. package/dist/storage.js +17 -17
  277. package/dist/summarizer.js +4 -4
  278. package/dist/support-passport/index.js +77 -75
  279. package/dist/support-passport/offline-sync-guard.d.ts +6 -2
  280. package/dist/support-passport/offline-sync-guard.d.ts.map +1 -1
  281. package/dist/{tier-stats-VF6DS52E.js → tier-stats-M2FMMD2N.js} +2 -2
  282. package/dist/transfer/backup.js +2 -2
  283. package/dist/transfer/capsule-export.js +2 -2
  284. package/dist/transfer/capsule-import.js +2 -2
  285. package/dist/transfer/export-okf.js +18 -18
  286. package/dist/types.d.ts +4 -2
  287. package/dist/types.d.ts.map +1 -1
  288. package/dist/types.js +1 -1
  289. package/dist/verified-recall.js +18 -18
  290. package/dist/who-knows-cli.js +19 -19
  291. package/dist/who-knows.js +18 -18
  292. package/package.json +13 -3
  293. package/src/access-mcp-output-schemas.ts +2 -0
  294. package/src/access-recall-corpus-versions.ts +59 -0
  295. package/src/access-recall-response.ts +3 -0
  296. package/src/access-recall-surface.ts +22 -23
  297. package/src/access-service-raw-excerpt-read-gate.test.ts +1 -1
  298. package/src/access-service.ts +3 -0
  299. package/src/capabilities.test.ts +1 -0
  300. package/src/capabilities.ts +6 -8
  301. package/src/config.ts +3 -0
  302. package/src/index.ts +1 -1
  303. package/src/offline-sync-changeset-generations.test.ts +962 -0
  304. package/src/offline-sync-changeset-generations.ts +549 -0
  305. package/src/offline-sync-embedding-generation.ts +272 -4
  306. package/src/offline-sync.ts +75 -162
  307. package/src/orchestration/orchestrator-helpers.ts +1 -1
  308. package/src/orchestration/recall-entry.ts +32 -16
  309. package/src/orchestration/recall-internal.ts +2 -2
  310. package/src/orchestration/recall-search-pipeline.ts +3 -0
  311. package/src/outcome-boost-config.ts +16 -0
  312. package/src/recall-retrieval-failure.test.ts +456 -4
  313. package/src/rerank-outcome.test.ts +218 -0
  314. package/src/rerank-outcome.ts +219 -0
  315. package/src/support-passport/offline-sync-guard.ts +16 -2
  316. package/src/types.ts +3 -3
  317. package/dist/chunk-H56VY4BY.js.map +0 -1
  318. package/dist/chunk-K6T33R4Q.js.map +0 -1
  319. package/dist/chunk-MCTM4YPL.js.map +0 -1
  320. package/dist/chunk-OCFXVDBZ.js.map +0 -1
  321. package/dist/chunk-PWF4JXKD.js.map +0 -1
  322. package/dist/chunk-QB57WIS6.js.map +0 -1
  323. package/dist/chunk-QI2E6ISQ.js.map +0 -1
  324. package/dist/chunk-S2GE2K36.js.map +0 -1
  325. /package/dist/{capsule-crypto-YO5QJ6L3.js.map → access-recall-corpus-versions.js.map} +0 -0
  326. /package/dist/{auto-sync-U5N3CB5Y.js.map → auto-sync-PAWBFQWL.js.map} +0 -0
  327. /package/dist/{contradiction-scan-TAGMOUQ2.js.map → capsule-crypto-7FJQINUR.js.map} +0 -0
  328. /package/dist/{chunk-RDJ6C7NZ.js.map → chunk-2IWBHZ3H.js.map} +0 -0
  329. /package/dist/{chunk-UP75KL3L.js.map → chunk-2JRB3Z5N.js.map} +0 -0
  330. /package/dist/{chunk-BXLOS5AJ.js.map → chunk-2NLLXCJG.js.map} +0 -0
  331. /package/dist/{chunk-KN6CIN7I.js.map → chunk-32HO62I4.js.map} +0 -0
  332. /package/dist/{chunk-JLPNONPH.js.map → chunk-35A7GCHG.js.map} +0 -0
  333. /package/dist/{chunk-MXCAJKMA.js.map → chunk-37ZQYFX4.js.map} +0 -0
  334. /package/dist/{chunk-LW3HKRL7.js.map → chunk-3BTHXB7Z.js.map} +0 -0
  335. /package/dist/{chunk-C7V3KPKJ.js.map → chunk-47LTKAGL.js.map} +0 -0
  336. /package/dist/{chunk-3O5BB45T.js.map → chunk-4DXNOVNW.js.map} +0 -0
  337. /package/dist/{chunk-65I2LZEK.js.map → chunk-4G2YCKLT.js.map} +0 -0
  338. /package/dist/{chunk-OK52IY3W.js.map → chunk-4GEBLO7S.js.map} +0 -0
  339. /package/dist/{chunk-M6C7SOR6.js.map → chunk-4I6PEEFA.js.map} +0 -0
  340. /package/dist/{chunk-Z4TXB4K7.js.map → chunk-5BUCKFRE.js.map} +0 -0
  341. /package/dist/{chunk-BGI4NUAO.js.map → chunk-5S7SNRSJ.js.map} +0 -0
  342. /package/dist/{chunk-JVPWRNHA.js.map → chunk-5YR4UGF2.js.map} +0 -0
  343. /package/dist/{chunk-YJ7MW627.js.map → chunk-6BG364RN.js.map} +0 -0
  344. /package/dist/{chunk-D5BSQR63.js.map → chunk-76LNUSS5.js.map} +0 -0
  345. /package/dist/{chunk-7CRUDH7G.js.map → chunk-77HNHT6S.js.map} +0 -0
  346. /package/dist/{chunk-OWYHHW67.js.map → chunk-7XI2UJHL.js.map} +0 -0
  347. /package/dist/{chunk-BJVO4H5C.js.map → chunk-7Z2UKRNJ.js.map} +0 -0
  348. /package/dist/{chunk-2WLMWP2T.js.map → chunk-A3K2KKSG.js.map} +0 -0
  349. /package/dist/{chunk-AWG3TIAY.js.map → chunk-ACCOC6UM.js.map} +0 -0
  350. /package/dist/{chunk-3JDA3XF5.js.map → chunk-AEGNDL24.js.map} +0 -0
  351. /package/dist/{chunk-2NAD4YCI.js.map → chunk-AEUMONCD.js.map} +0 -0
  352. /package/dist/{chunk-C6U57KG4.js.map → chunk-AF5PW35O.js.map} +0 -0
  353. /package/dist/{chunk-IOSZHHJC.js.map → chunk-ANGZWYL2.js.map} +0 -0
  354. /package/dist/{chunk-6LYAEM54.js.map → chunk-AXHU56C3.js.map} +0 -0
  355. /package/dist/{chunk-GWM6T5EQ.js.map → chunk-BCGMG2RD.js.map} +0 -0
  356. /package/dist/{chunk-HXCJF4XU.js.map → chunk-BFIZXFUG.js.map} +0 -0
  357. /package/dist/{chunk-DBYAY6UW.js.map → chunk-BTOHGPHC.js.map} +0 -0
  358. /package/dist/{chunk-5X4MXNEU.js.map → chunk-C6HPNPNK.js.map} +0 -0
  359. /package/dist/{chunk-4MP7XR5J.js.map → chunk-CAKHZAXH.js.map} +0 -0
  360. /package/dist/{chunk-YSBL7VPO.js.map → chunk-CDWFWOSZ.js.map} +0 -0
  361. /package/dist/{chunk-QAW55ZHJ.js.map → chunk-CZ44FH45.js.map} +0 -0
  362. /package/dist/{chunk-T3FMRLWQ.js.map → chunk-D5HQ3VEX.js.map} +0 -0
  363. /package/dist/{chunk-S7LWX2PQ.js.map → chunk-DPG5HQLE.js.map} +0 -0
  364. /package/dist/{chunk-C7ZDKWPS.js.map → chunk-DVSAMW5T.js.map} +0 -0
  365. /package/dist/{chunk-WBYQA3VN.js.map → chunk-E5H4TM4Y.js.map} +0 -0
  366. /package/dist/{chunk-4RL3JOB3.js.map → chunk-EEDI3OXB.js.map} +0 -0
  367. /package/dist/{chunk-3TB2XQ3C.js.map → chunk-EUL3S3LE.js.map} +0 -0
  368. /package/dist/{chunk-Q4AUIFUA.js.map → chunk-F23U5YE7.js.map} +0 -0
  369. /package/dist/{chunk-ZZZ4I455.js.map → chunk-GDVORIFM.js.map} +0 -0
  370. /package/dist/{chunk-SWBC3UER.js.map → chunk-HCPUVB7S.js.map} +0 -0
  371. /package/dist/{chunk-R3X2T2LP.js.map → chunk-HFOY2SBG.js.map} +0 -0
  372. /package/dist/{chunk-LU7E2MXE.js.map → chunk-HQCUUVG2.js.map} +0 -0
  373. /package/dist/{chunk-FJLQXMTU.js.map → chunk-I6B3S62A.js.map} +0 -0
  374. /package/dist/{chunk-RBITPCMK.js.map → chunk-IDSSDL4W.js.map} +0 -0
  375. /package/dist/{chunk-B3OFQP5Y.js.map → chunk-IY47KPML.js.map} +0 -0
  376. /package/dist/{chunk-AXC4WSF3.js.map → chunk-JDOBIFBK.js.map} +0 -0
  377. /package/dist/{chunk-P2ODTYOF.js.map → chunk-JGXHQV5N.js.map} +0 -0
  378. /package/dist/{chunk-7LNHRQKR.js.map → chunk-JLIGUFPF.js.map} +0 -0
  379. /package/dist/{chunk-EDIH6X2P.js.map → chunk-JZ66PN72.js.map} +0 -0
  380. /package/dist/{chunk-BLVR4WYU.js.map → chunk-KICEAGKM.js.map} +0 -0
  381. /package/dist/{chunk-VDX2J7OX.js.map → chunk-KQAFEZQX.js.map} +0 -0
  382. /package/dist/{chunk-PEBHPCX2.js.map → chunk-KTG23JDX.js.map} +0 -0
  383. /package/dist/{chunk-BOZJD5PK.js.map → chunk-KYOZ5E6V.js.map} +0 -0
  384. /package/dist/{chunk-2DLWLNO4.js.map → chunk-L3TZXELN.js.map} +0 -0
  385. /package/dist/{chunk-VALKBYBN.js.map → chunk-M3N2TUZ7.js.map} +0 -0
  386. /package/dist/{chunk-76M5OK7V.js.map → chunk-M7T2NKET.js.map} +0 -0
  387. /package/dist/{chunk-Z5LP6ILP.js.map → chunk-MZAH3CBT.js.map} +0 -0
  388. /package/dist/{chunk-QI7K7BZ5.js.map → chunk-NJW2ZG64.js.map} +0 -0
  389. /package/dist/{chunk-CZJA2EQE.js.map → chunk-NSKXRTVZ.js.map} +0 -0
  390. /package/dist/{chunk-4O4XCBOS.js.map → chunk-NUSQ3YEL.js.map} +0 -0
  391. /package/dist/{chunk-4OQET73E.js.map → chunk-O57FCN42.js.map} +0 -0
  392. /package/dist/{chunk-WKY7N3L7.js.map → chunk-OEBUAC3O.js.map} +0 -0
  393. /package/dist/{chunk-Y23L4YJV.js.map → chunk-OEIA4IHU.js.map} +0 -0
  394. /package/dist/{chunk-66DKTOBY.js.map → chunk-OGZC2WUX.js.map} +0 -0
  395. /package/dist/{chunk-3SGTV7RD.js.map → chunk-P62DSJUK.js.map} +0 -0
  396. /package/dist/{chunk-FKD656D2.js.map → chunk-PH2V7EXZ.js.map} +0 -0
  397. /package/dist/{chunk-KKNZ7PUZ.js.map → chunk-QAIKLICT.js.map} +0 -0
  398. /package/dist/{chunk-SSUDD72S.js.map → chunk-QPWUG2S3.js.map} +0 -0
  399. /package/dist/{chunk-GZDTVYK2.js.map → chunk-R36IBI2M.js.map} +0 -0
  400. /package/dist/{chunk-W3XXFPRI.js.map → chunk-R5B3OWI4.js.map} +0 -0
  401. /package/dist/{chunk-VL4X7ZHC.js.map → chunk-RFIJRZ4K.js.map} +0 -0
  402. /package/dist/{chunk-AEHVZY3X.js.map → chunk-RPVHRZ5C.js.map} +0 -0
  403. /package/dist/{chunk-X5SHE2O3.js.map → chunk-RVBLCU5C.js.map} +0 -0
  404. /package/dist/{chunk-BUQKSQXL.js.map → chunk-S533KGX6.js.map} +0 -0
  405. /package/dist/{chunk-STEOT4DI.js.map → chunk-SCPHU3RW.js.map} +0 -0
  406. /package/dist/{chunk-LV5H6FTN.js.map → chunk-SFSD5Q6O.js.map} +0 -0
  407. /package/dist/{chunk-AE5U5NMS.js.map → chunk-SMLKHXPF.js.map} +0 -0
  408. /package/dist/{chunk-AEU4EQGV.js.map → chunk-T7R5HI6A.js.map} +0 -0
  409. /package/dist/{chunk-H5BJWPUI.js.map → chunk-TVQZAQPE.js.map} +0 -0
  410. /package/dist/{chunk-XOV7NRY5.js.map → chunk-U46P4UAR.js.map} +0 -0
  411. /package/dist/{chunk-DZ42MDZE.js.map → chunk-UCJINCZT.js.map} +0 -0
  412. /package/dist/{chunk-5E6RYRYW.js.map → chunk-UG5V3Z3R.js.map} +0 -0
  413. /package/dist/{chunk-IW3RMBPB.js.map → chunk-VAOC6GHN.js.map} +0 -0
  414. /package/dist/{chunk-6UQFJULG.js.map → chunk-VBNA2JEN.js.map} +0 -0
  415. /package/dist/{chunk-HLB7GKGG.js.map → chunk-VOZNBQNL.js.map} +0 -0
  416. /package/dist/{chunk-NYKIUQL6.js.map → chunk-WHIGRW7T.js.map} +0 -0
  417. /package/dist/{chunk-AZSGSRIM.js.map → chunk-WHTMVTU4.js.map} +0 -0
  418. /package/dist/{chunk-AERXJCOG.js.map → chunk-WL7N5VGG.js.map} +0 -0
  419. /package/dist/{chunk-TFA6HPOA.js.map → chunk-WQUGCOKF.js.map} +0 -0
  420. /package/dist/{chunk-A4VSOUCB.js.map → chunk-WTZQM74L.js.map} +0 -0
  421. /package/dist/{chunk-DQEMWVMT.js.map → chunk-X7Y7WX73.js.map} +0 -0
  422. /package/dist/{chunk-T2YX56QI.js.map → chunk-XWSUK5GL.js.map} +0 -0
  423. /package/dist/{chunk-ACX55QDO.js.map → chunk-XYOT5GQU.js.map} +0 -0
  424. /package/dist/{chunk-Z6EZCN6Z.js.map → chunk-Y7427SL7.js.map} +0 -0
  425. /package/dist/{chunk-4KN2JLQV.js.map → chunk-YHZWVDP7.js.map} +0 -0
  426. /package/dist/{chunk-5MNUBT7T.js.map → chunk-ZFTODDTX.js.map} +0 -0
  427. /package/dist/{chunk-VVX5PZFS.js.map → chunk-ZHXSOMYH.js.map} +0 -0
  428. /package/dist/{chunk-CRXRZA3G.js.map → chunk-ZQTYWSO3.js.map} +0 -0
  429. /package/dist/{resolution-K4A3VPKZ.js.map → contradiction-scan-GGRTVB7C.js.map} +0 -0
  430. /package/dist/{first-start-migration-7OATHJKB.js.map → first-start-migration-OM3PHMZO.js.map} +0 -0
  431. /package/dist/{tier-stats-VF6DS52E.js.map → tier-stats-M2FMMD2N.js.map} +0 -0
@@ -0,0 +1,218 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+ import { parseConfig } from "./config.js";
4
+ import type { MemoryFile, QmdSearchResult } from "./types.js";
5
+ import {
6
+ OUTCOME_STATE_OBSERVED,
7
+ OUTCOME_STATE_UNOBSERVED,
8
+ applyOutcomePriorScores,
9
+ blendOutcomeScore,
10
+ outcomePriorBoostActive,
11
+ parseOutcomeBoostWeight,
12
+ rerankWithOutcomePrior,
13
+ resolveOutcomeObservation,
14
+ scaleTextScore,
15
+ type OutcomeObservationState,
16
+ } from "./rerank-outcome.js";
17
+
18
+ // @ts-expect-error "bogus" is not an OutcomeObservationState
19
+ const badOutcomeState: OutcomeObservationState = "bogus";
20
+ void badOutcomeState;
21
+
22
+ function memory(counters: { mw_success?: number; mw_fail?: number }): MemoryFile {
23
+ return {
24
+ path: "facts/a.md",
25
+ content: "synthetic fact",
26
+ frontmatter: counters as MemoryFile["frontmatter"],
27
+ };
28
+ }
29
+
30
+ function result(path: string, score: number, namespace?: string): QmdSearchResult {
31
+ return { docid: path, path, snippet: "", score, namespace } as QmdSearchResult;
32
+ }
33
+
34
+ test("scaleTextScore clamps into [0, 1] without a batch min-max", () => {
35
+ assert.equal(scaleTextScore(0.4), 0.4);
36
+ assert.equal(scaleTextScore(2.5), 1);
37
+ assert.equal(scaleTextScore(-3), 0);
38
+ assert.equal(scaleTextScore(Number.NaN), 0);
39
+ assert.equal(scaleTextScore(Number.POSITIVE_INFINITY), 0);
40
+ });
41
+
42
+ test("UNOBSERVED is not the Memory Worth Beta prior", () => {
43
+ const unobserved = resolveOutcomeObservation(undefined);
44
+ assert.equal(unobserved.state, OUTCOME_STATE_UNOBSERVED);
45
+ assert.equal(blendOutcomeScore(1, unobserved, 0.5), 1);
46
+ assert.notEqual(blendOutcomeScore(1, unobserved, 0.5), 0.75);
47
+
48
+ const zeros = resolveOutcomeObservation({ success: 0, fail: 0 });
49
+ assert.equal(zeros.state, OUTCOME_STATE_UNOBSERVED);
50
+
51
+ const missing = resolveOutcomeObservation({});
52
+ assert.equal(missing.state, OUTCOME_STATE_UNOBSERVED);
53
+
54
+ const invalid = resolveOutcomeObservation({ success: Number.NaN, fail: 1 });
55
+ assert.equal(invalid.state, OUTCOME_STATE_UNOBSERVED);
56
+ const negative = resolveOutcomeObservation({ success: -1, fail: 2 });
57
+ assert.equal(negative.state, OUTCOME_STATE_UNOBSERVED);
58
+
59
+ const observed = resolveOutcomeObservation({ success: 0, fail: 1 });
60
+ assert.equal(observed.state, OUTCOME_STATE_OBSERVED);
61
+ assert.equal(observed.outcomeScore, 0);
62
+ assert.equal(blendOutcomeScore(1, observed, 0.5), 0.5);
63
+ assert.notEqual(blendOutcomeScore(1, observed, 0.5), 2 / 3);
64
+
65
+ const oneSided = resolveOutcomeObservation({ success: 2 });
66
+ assert.equal(oneSided.state, OUTCOME_STATE_OBSERVED);
67
+ assert.equal(oneSided.outcomeScore, 1);
68
+ });
69
+
70
+ test("pre-main unit gates cover ties, equal scores, and w=0 identity", () => {
71
+ const unobserved = resolveOutcomeObservation(undefined);
72
+ const observedZero = resolveOutcomeObservation({ success: 0, fail: 4 });
73
+ assert.equal(unobserved.state, OUTCOME_STATE_UNOBSERVED);
74
+ assert.equal(observedZero.state, OUTCOME_STATE_OBSERVED);
75
+ assert.equal(blendOutcomeScore(1.7, unobserved, 0), 1.7);
76
+ assert.equal(blendOutcomeScore(1.7, observedZero, 0), 1.7);
77
+ assert.equal(blendOutcomeScore(1.7, observedZero, 0.5), scaleTextScore(1.7) * 0.5);
78
+
79
+ const tied = rerankWithOutcomePrior(
80
+ [
81
+ { item: "left", textScore: 0.4, success: 3, fail: 1 },
82
+ { item: "right", textScore: 0.4, success: 0, fail: 9 },
83
+ ],
84
+ 0,
85
+ );
86
+ assert.deepEqual(
87
+ tied.map((row) => [row.item, row.score, row.state]),
88
+ [
89
+ ["left", 0.4, OUTCOME_STATE_OBSERVED],
90
+ ["right", 0.4, OUTCOME_STATE_OBSERVED],
91
+ ],
92
+ );
93
+
94
+ const equalBlend = rerankWithOutcomePrior(
95
+ [
96
+ { item: "first", textScore: 0.2, success: 1, fail: 1 },
97
+ { item: "second", textScore: 0.2, success: 1, fail: 1 },
98
+ ],
99
+ 0.5,
100
+ );
101
+ assert.deepEqual(
102
+ equalBlend.map((row) => row.item),
103
+ ["first", "second"],
104
+ );
105
+ assert.equal(equalBlend[0]?.score, equalBlend[1]?.score);
106
+ });
107
+
108
+ test("weight 0 keeps raw scores and original order", () => {
109
+ const ranked = rerankWithOutcomePrior(
110
+ [
111
+ { item: "a", textScore: 1.4, success: 0, fail: 5 },
112
+ { item: "b", textScore: 0.2 },
113
+ { item: "c", textScore: -1, success: 9, fail: 0 },
114
+ ],
115
+ 0,
116
+ );
117
+ assert.deepEqual(
118
+ ranked.map((row) => [row.item, row.score]),
119
+ [
120
+ ["a", 1.4],
121
+ ["b", 0.2],
122
+ ["c", -1],
123
+ ],
124
+ );
125
+ });
126
+
127
+ test("equal blended scores keep the original index order", () => {
128
+ const ranked = rerankWithOutcomePrior(
129
+ [
130
+ { item: "first", textScore: 1 },
131
+ { item: "second", textScore: 0, success: 1, fail: 0 },
132
+ ],
133
+ 1,
134
+ );
135
+ assert.deepEqual(
136
+ ranked.map((row) => row.item),
137
+ ["first", "second"],
138
+ );
139
+ assert.equal(ranked[0]?.score, ranked[1]?.score);
140
+ });
141
+
142
+ test("observed outcomes reorder above a weaker text score", () => {
143
+ const ranked = rerankWithOutcomePrior(
144
+ [
145
+ { item: "text", textScore: 0.9 },
146
+ { item: "worked", textScore: 0.2, success: 4, fail: 0 },
147
+ ],
148
+ 1,
149
+ );
150
+ assert.deepEqual(
151
+ ranked.map((row) => row.item),
152
+ ["worked", "text"],
153
+ );
154
+ });
155
+
156
+ test("parseOutcomeBoostWeight rejects invalid values and keeps zero", () => {
157
+ assert.equal(parseOutcomeBoostWeight(undefined), 0);
158
+ assert.equal(parseOutcomeBoostWeight(""), 0);
159
+ assert.equal(parseOutcomeBoostWeight("0"), 0);
160
+ assert.equal(parseOutcomeBoostWeight("0.3"), 0.3);
161
+ assert.throws(() => parseOutcomeBoostWeight(false), /outcomeBoostWeight/);
162
+ assert.throws(() => parseOutcomeBoostWeight("false"), /outcomeBoostWeight/);
163
+ assert.throws(() => parseOutcomeBoostWeight("1.5"), /outcomeBoostWeight/);
164
+ assert.throws(() => parseOutcomeBoostWeight(Number.NaN), /outcomeBoostWeight/);
165
+ assert.throws(() => rerankWithOutcomePrior([{ item: "a", textScore: 1 }], 1.2), /outcomeBoostWeight/);
166
+ });
167
+
168
+ test("parseConfig leaves the outcome boost off", () => {
169
+ const defaults = parseConfig({});
170
+ assert.equal(defaults.outcomeBoostEnabled, false);
171
+ assert.equal(defaults.outcomeBoostWeight, 0);
172
+ assert.equal(outcomePriorBoostActive(defaults), false);
173
+ assert.equal(parseConfig({ outcomeBoostEnabled: "false" }).outcomeBoostEnabled, false);
174
+ assert.equal(parseConfig({ outcomeBoostEnabled: "0" }).outcomeBoostEnabled, false);
175
+ assert.equal(parseConfig({ outcomeBoostWeight: "0" }).outcomeBoostWeight, 0);
176
+ assert.equal(outcomePriorBoostActive(parseConfig({ outcomeBoostEnabled: true, outcomeBoostWeight: 0 })), false);
177
+ assert.equal(outcomePriorBoostActive(parseConfig({ outcomeBoostEnabled: false, outcomeBoostWeight: 0.3 })), false);
178
+ assert.equal(outcomePriorBoostActive(parseConfig({ outcomeBoostEnabled: true, outcomeBoostWeight: 0.3 })), true);
179
+ assert.throws(() => parseConfig({ outcomeBoostWeight: "no" }), /outcomeBoostWeight/);
180
+ });
181
+
182
+ test("applyOutcomePriorScores is an identity at weight 0 and uses the namespace key", () => {
183
+ const untouched = [result("facts/a.md", 1.4, "ns-a"), result("facts/a.md", 0.2)];
184
+ const before = untouched.map((row) => ({ path: row.path, score: row.score, namespace: row.namespace }));
185
+ applyOutcomePriorScores(untouched, new Map(), { outcomeBoostWeight: 0 });
186
+ assert.deepEqual(
187
+ untouched.map((row) => ({ path: row.path, score: row.score, namespace: row.namespace })),
188
+ before,
189
+ );
190
+ const negative = [result("facts/a.md", 1.4)];
191
+ applyOutcomePriorScores(negative, new Map(), { outcomeBoostWeight: -1 });
192
+ assert.equal(negative[0]?.score, 1.4);
193
+ assert.throws(
194
+ () => applyOutcomePriorScores([result("facts/a.md", 1)], new Map(), { outcomeBoostWeight: 1.2 }),
195
+ /outcomeBoostWeight/,
196
+ );
197
+
198
+ const namespaced = resolveOutcomeObservation({ success: 0, fail: 1 });
199
+ assert.equal(namespaced.state, OUTCOME_STATE_OBSERVED);
200
+ assert.equal(namespaced.outcomeScore, 0);
201
+ const bare = resolveOutcomeObservation({ success: 8, fail: 0 });
202
+ assert.equal(bare.state, OUTCOME_STATE_OBSERVED);
203
+ assert.equal(bare.outcomeScore, 1);
204
+
205
+ const results = [result("facts/a.md", 1, "ns-a"), result("facts/a.md", 0.2)];
206
+ const memoryByPath = new Map<string, MemoryFile>([
207
+ ["ns-a\0facts/a.md", memory({ mw_success: 0, mw_fail: 1 })],
208
+ ["facts/a.md", memory({ mw_success: 8, mw_fail: 0 })],
209
+ ]);
210
+ applyOutcomePriorScores(results, memoryByPath, { outcomeBoostWeight: 1 });
211
+ // 0/1 is an observed rate of 0, not UNOBSERVED. The namespaced key must not
212
+ // read the bare-path 8/0 counters. At weight 1 the bare path (rate 1) sorts
213
+ // ahead of ns-a (rate 0).
214
+ assert.equal(results[0]?.namespace, undefined);
215
+ assert.equal(results[0]?.score, 1);
216
+ assert.equal(results[1]?.namespace, "ns-a");
217
+ assert.equal(results[1]?.score, 0);
218
+ });
@@ -0,0 +1,219 @@
1
+ /**
2
+ * H1 outcome-prior blend (issue #1958). Scaffolding only — no experiment runner.
3
+ *
4
+ * Text scores map onto [0, 1] with a fixed clamp. The clamp is not a batch
5
+ * min-max, so one candidate cannot move another's scale.
6
+ *
7
+ * UNOBSERVED (no past result) keeps that unit text score when the weight is
8
+ * positive. It does not use the Memory Worth Laplace prior (s+1)/(s+f+2).
9
+ * An observed result uses the maximum-likelihood rate success/(success+fail).
10
+ *
11
+ * Turning the blend on (enabled and weight > 0) clamps every candidate's text
12
+ * score into [0, 1] before mixing, including UNOBSERVED items. Raw scores
13
+ * outside that range can change order relative to the weight-0 path. Weight 0
14
+ * does not clamp.
15
+ *
16
+ * Weight 0 is an identity on the raw input score: same values, same order.
17
+ * The recall pipeline calls `applyOutcomePriorScores` only when
18
+ * `outcomeBoostEnabled === true` and the weight is greater than 0, so the
19
+ * production default stays on the existing sort.
20
+ */
21
+
22
+ import {
23
+ type RecallEnhancementConfigProjection,
24
+ resolveRecallEnhancementCapabilities,
25
+ } from "./capabilities.js";
26
+ import { coerceNumber } from "./connectors/coerce.js";
27
+ import { memoryForResult } from "./recall-memory-map.js";
28
+ import type { MemoryFile, QmdSearchResult } from "./types.js";
29
+
30
+ export const OUTCOME_STATE_UNOBSERVED = "UNOBSERVED" as const;
31
+ export const OUTCOME_STATE_OBSERVED = "OBSERVED" as const;
32
+
33
+ export type OutcomeObservationState =
34
+ | typeof OUTCOME_STATE_UNOBSERVED
35
+ | typeof OUTCOME_STATE_OBSERVED;
36
+
37
+ export interface OutcomeCounters {
38
+ success?: number;
39
+ fail?: number;
40
+ }
41
+
42
+ export interface OutcomeObservation {
43
+ state: OutcomeObservationState;
44
+ /** Present only for OBSERVED. Maximum-likelihood rate in [0, 1]. */
45
+ outcomeScore?: number;
46
+ }
47
+
48
+ export function scaleTextScore(score: number): number {
49
+ if (!Number.isFinite(score) || score <= 0) return 0;
50
+ if (score >= 1) return 1;
51
+ return score;
52
+ }
53
+
54
+ function finiteNonNegative(value: number | undefined): number | undefined {
55
+ if (value === undefined) return undefined;
56
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0) return undefined;
57
+ return value;
58
+ }
59
+
60
+ /**
61
+ * Both counters missing, explicit 0+0, or any present-but-invalid counter
62
+ * (non-finite or negative) is UNOBSERVED. One counter present and positive
63
+ * with the other missing is OBSERVED; the missing counter counts as 0.
64
+ */
65
+ export function resolveOutcomeObservation(
66
+ counters: OutcomeCounters | undefined,
67
+ ): OutcomeObservation {
68
+ if (!counters) return { state: OUTCOME_STATE_UNOBSERVED };
69
+ const successPresent = counters.success !== undefined;
70
+ const failPresent = counters.fail !== undefined;
71
+ if (!successPresent && !failPresent) return { state: OUTCOME_STATE_UNOBSERVED };
72
+
73
+ const success = finiteNonNegative(counters.success);
74
+ const fail = finiteNonNegative(counters.fail);
75
+ if (successPresent && success === undefined) return { state: OUTCOME_STATE_UNOBSERVED };
76
+ if (failPresent && fail === undefined) return { state: OUTCOME_STATE_UNOBSERVED };
77
+
78
+ const successes = success ?? 0;
79
+ const failures = fail ?? 0;
80
+ if (successes === 0 && failures === 0) return { state: OUTCOME_STATE_UNOBSERVED };
81
+ return {
82
+ state: OUTCOME_STATE_OBSERVED,
83
+ outcomeScore: successes / (successes + failures),
84
+ };
85
+ }
86
+
87
+ /**
88
+ * Weight 0 returns `textScore` unchanged. A positive weight clamps `textScore`
89
+ * into [0, 1] first. UNOBSERVED stays on that clamped value. OBSERVED mixes it
90
+ * with the success rate.
91
+ */
92
+ export function blendOutcomeScore(
93
+ textScore: number,
94
+ observation: OutcomeObservation,
95
+ weight: number,
96
+ ): number {
97
+ if (weight === 0) return textScore;
98
+ const textUnit = scaleTextScore(textScore);
99
+ if (observation.state === OUTCOME_STATE_UNOBSERVED || observation.outcomeScore === undefined) {
100
+ return textUnit;
101
+ }
102
+ return (1 - weight) * textUnit + weight * observation.outcomeScore;
103
+ }
104
+
105
+ export interface OutcomePriorCandidate<T> {
106
+ item: T;
107
+ textScore: number;
108
+ success?: number;
109
+ fail?: number;
110
+ }
111
+
112
+ export interface OutcomePriorRanked<T> {
113
+ item: T;
114
+ textScore: number;
115
+ score: number;
116
+ state: OutcomeObservationState;
117
+ originalIndex: number;
118
+ }
119
+
120
+ function assertOutcomeWeight(weight: number): void {
121
+ if (!Number.isFinite(weight) || weight < 0 || weight > 1) {
122
+ throw new Error(
123
+ `outcomeBoostWeight must be a finite number in [0, 1] (got ${JSON.stringify(weight)}).`,
124
+ );
125
+ }
126
+ }
127
+
128
+ function compareRanked(
129
+ left: { score: number; originalIndex: number },
130
+ right: { score: number; originalIndex: number },
131
+ ): number {
132
+ const leftScore = Number.isFinite(left.score) ? left.score : Number.NEGATIVE_INFINITY;
133
+ const rightScore = Number.isFinite(right.score) ? right.score : Number.NEGATIVE_INFINITY;
134
+ if (leftScore !== rightScore) return leftScore > rightScore ? -1 : 1;
135
+ if (left.originalIndex === right.originalIndex) return 0;
136
+ return left.originalIndex < right.originalIndex ? -1 : 1;
137
+ }
138
+
139
+ export function rerankWithOutcomePrior<T>(
140
+ candidates: readonly OutcomePriorCandidate<T>[],
141
+ weight: number,
142
+ ): OutcomePriorRanked<T>[] {
143
+ assertOutcomeWeight(weight);
144
+ const ranked = candidates.map((candidate, originalIndex) => {
145
+ const observation = resolveOutcomeObservation({
146
+ success: candidate.success,
147
+ fail: candidate.fail,
148
+ });
149
+ return {
150
+ item: candidate.item,
151
+ textScore: candidate.textScore,
152
+ score: blendOutcomeScore(candidate.textScore, observation, weight),
153
+ state: observation.state,
154
+ originalIndex,
155
+ };
156
+ });
157
+ if (weight === 0) return ranked;
158
+ ranked.sort(compareRanked);
159
+ return ranked;
160
+ }
161
+
162
+ export function outcomePriorBoostActive(
163
+ config: RecallEnhancementConfigProjection & { outcomeBoostWeight?: number },
164
+ ): boolean {
165
+ const weight = config.outcomeBoostWeight;
166
+ return (
167
+ resolveRecallEnhancementCapabilities(config).outcomeBoost === true &&
168
+ typeof weight === "number" &&
169
+ Number.isFinite(weight) &&
170
+ weight > 0
171
+ );
172
+ }
173
+
174
+ export function applyOutcomePriorScores(
175
+ results: QmdSearchResult[],
176
+ memoryByPath: ReadonlyMap<string, MemoryFile>,
177
+ config: { outcomeBoostWeight?: number },
178
+ ): void {
179
+ const weight = config.outcomeBoostWeight;
180
+ // Non-numbers, non-finite values, and negatives are a no-op. Zero is an
181
+ // identity. assertOutcomeWeight is the upper bound (> 1 throws); it is not
182
+ // a second copy of the positivity check.
183
+ if (typeof weight !== "number" || !Number.isFinite(weight) || weight < 0) return;
184
+ assertOutcomeWeight(weight);
185
+ if (weight === 0) return;
186
+ const ranked = results.map((result, originalIndex) => {
187
+ const memory = memoryForResult(memoryByPath, result);
188
+ const observation = resolveOutcomeObservation(
189
+ memory
190
+ ? { success: memory.frontmatter.mw_success, fail: memory.frontmatter.mw_fail }
191
+ : undefined,
192
+ );
193
+ return {
194
+ result,
195
+ originalIndex,
196
+ score: blendOutcomeScore(result.score, observation, weight),
197
+ };
198
+ });
199
+ ranked.sort(compareRanked);
200
+ const next = ranked.map((row) =>
201
+ row.score === row.result.score ? row.result : { ...row.result, score: row.score },
202
+ );
203
+ results.splice(0, results.length, ...next);
204
+ }
205
+
206
+ /**
207
+ * Absent / null / exact empty string → 0. A present value that is not a
208
+ * finite number in [0, 1] throws. Boolean false is not a zero weight.
209
+ */
210
+ export function parseOutcomeBoostWeight(raw: unknown): number {
211
+ if (raw === undefined || raw === null || raw === "") return 0;
212
+ const parsed = coerceNumber(raw, "outcomeBoostWeight");
213
+ if (parsed === undefined || parsed < 0 || parsed > 1) {
214
+ throw new Error(
215
+ `outcomeBoostWeight must be a number in [0, 1] (got ${JSON.stringify(raw)}).`,
216
+ );
217
+ }
218
+ return parsed;
219
+ }
@@ -26,10 +26,14 @@ type FrontmatterDecision = "allow" | "wait";
26
26
  interface SupportPassportOfflineSyncStorage {
27
27
  dir: string;
28
28
  readMemoryByPath(filePath: string): Promise<MemoryFile | null>;
29
- readOfflineSyncFile(filePath: string): Promise<Buffer>;
29
+ readOfflineSyncFile(filePath: string, opts?: { aadFilePath?: string }): Promise<Buffer>;
30
30
  digestOfflineSyncFile(filePath: string): Promise<{ sha256: string; bytes: number }>;
31
31
  writeOfflineSyncFile(filePath: string, content: Buffer): Promise<void>;
32
- writeOfflineSyncStagingFile(filePath: string, content: Buffer): Promise<void>;
32
+ writeOfflineSyncStagingFile(
33
+ filePath: string,
34
+ content: Buffer,
35
+ opts?: { aadFilePath?: string },
36
+ ): Promise<void>;
33
37
  writeOfflineSyncFileChunks(filePath: string, chunks: AsyncIterable<Buffer>): Promise<void>;
34
38
  deleteOfflineSyncFile(filePath: string, deletionMtimeMs?: number | null): Promise<void>;
35
39
  recordReplicatedDeletionRevision(filePath: string, mtimeMs: number): Promise<void>;
@@ -219,6 +223,16 @@ export async function applySupportPassportOfflineSyncChangeset(
219
223
  guard.assertContentAllowed(target.path, target.content);
220
224
  await storage.writeOfflineSyncFile(target.filePath, target.content);
221
225
  },
226
+ // Secure staging for embedding-generation replacement (#3150): staged
227
+ // ciphertext binds the FINAL published path, matching the snapshot apply.
228
+ writeStagingFile: async ({ filePath, content, finalAadFilePath }) =>
229
+ storage.writeOfflineSyncStagingFile(
230
+ filePath,
231
+ content,
232
+ finalAadFilePath === undefined ? undefined : { aadFilePath: finalAadFilePath },
233
+ ),
234
+ readStagingFile: async ({ filePath, finalAadFilePath }) =>
235
+ storage.readOfflineSyncFile(filePath, finalAadFilePath === undefined ? undefined : { aadFilePath: finalAadFilePath }),
222
236
  deleteFile: async (target) => {
223
237
  await guard.assertTargetAllowed(target);
224
238
  await storage.deleteOfflineSyncFile(target.filePath, target.mtimeMs ?? null);
package/src/types.ts CHANGED
@@ -10,9 +10,9 @@ import type { ReplicaPeersConfig } from "./replica-peers-config.js";
10
10
  import type { ExternalWikiRoot } from "./external-wiki-config.js";
11
11
  import type { StateViewResult } from "./recall-state-view.js";
12
12
  import type { ContradictionLocalizationConfig, ContradictionScanConfig } from "./contradiction-config.js";
13
- import type { GraphPathScoringConfig } from "./graph-path-scoring-config.js";
13
+ import type { GraphPathScoringConfig } from "./graph-path-scoring-config.js"; export type { GraphPathScoringConfig };
14
+ import type { OutcomeBoostConfig } from "./outcome-boost-config.js"; export type { OutcomeBoostConfig };
14
15
  export type { ContradictionLocalizationConfig, ContradictionScanConfig } from "./contradiction-config.js";
15
- export type { GraphPathScoringConfig } from "./graph-path-scoring-config.js";
16
16
  export type { BackgroundGenerationConfig } from "./background-generation-config.js";
17
17
  import type { BackgroundGenerationConfig } from "./background-generation-config.js";
18
18
  import type {
@@ -700,7 +700,7 @@ export interface PluginConfig
700
700
  RecallNavigationSettings,
701
701
  RecognitionTierSettings,
702
702
  SeedGraduationSettings,
703
- LocalLlmConfig {
703
+ LocalLlmConfig, OutcomeBoostConfig {
704
704
  openaiApiKey: string | undefined;
705
705
  openaiBaseUrl: string | undefined;
706
706
  backgroundGeneration?: BackgroundGenerationConfig;