@remnic/core 9.69.49 → 9.69.51

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 (555) hide show
  1. package/dist/access-admin-ops-surface.d.ts +15 -14
  2. package/dist/access-admin-ops-surface.js +33 -33
  3. package/dist/access-audit.d.ts +1 -0
  4. package/dist/access-audit.js +2 -2
  5. package/dist/access-authorization-probe.d.ts +15 -14
  6. package/dist/access-authorization-probe.js +34 -34
  7. package/dist/access-boundary.d.ts +15 -14
  8. package/dist/access-boundary.js +33 -33
  9. package/dist/access-cli.js +97 -95
  10. package/dist/access-cli.js.map +1 -1
  11. package/dist/access-coding-context-resolution.d.ts +2 -1
  12. package/dist/access-extraction-force-flush.d.ts +15 -14
  13. package/dist/access-extraction-force-flush.js +33 -33
  14. package/dist/access-health-types.d.ts +2 -1
  15. package/dist/access-http-briefing.d.ts +15 -14
  16. package/dist/access-http-briefing.js +34 -34
  17. package/dist/access-http-lcm-compaction.d.ts +15 -14
  18. package/dist/access-http-lifecycle-flush.d.ts +15 -14
  19. package/dist/access-http-offline-stream.d.ts +15 -14
  20. package/dist/access-http-query.d.ts +3 -2
  21. package/dist/access-http-query.js +35 -35
  22. package/dist/access-http.d.ts +16 -15
  23. package/dist/access-http.js +53 -53
  24. package/dist/access-identity-continuity-surface.d.ts +12 -11
  25. package/dist/access-identity-continuity-surface.js +33 -33
  26. package/dist/access-lcm-surface.d.ts +15 -14
  27. package/dist/access-lcm-surface.js +33 -33
  28. package/dist/access-mcp-output-schemas.js +1 -1
  29. package/dist/access-mcp-shared-context-tools.d.ts +15 -14
  30. package/dist/access-mcp.d.ts +15 -14
  31. package/dist/access-mcp.js +44 -44
  32. package/dist/access-memory-search-fanout.d.ts +3 -2
  33. package/dist/{access-namespace-preflight-DqRw_g-8.d.ts → access-namespace-preflight-C1q3XuAc.d.ts} +1 -1
  34. package/dist/access-namespace-preflight.d.ts +4 -3
  35. package/dist/access-namespace-preflight.js +33 -33
  36. package/dist/access-observe-transcript.d.ts +12 -11
  37. package/dist/access-observe-write-category.d.ts +4 -3
  38. package/dist/access-observe-write-category.js +4 -4
  39. package/dist/access-observe-write-surface.d.ts +15 -14
  40. package/dist/access-observe-write-surface.js +33 -33
  41. package/dist/access-offline-manifest.d.ts +12 -11
  42. package/dist/access-operations-batch.js +35 -35
  43. package/dist/access-operations.d.ts +15 -14
  44. package/dist/access-operations.js +42 -42
  45. package/dist/access-recall-concurrency.d.ts +15 -14
  46. package/dist/access-recall-concurrency.js +33 -33
  47. package/dist/access-recall-response.d.ts +15 -14
  48. package/dist/access-recall-response.js +33 -33
  49. package/dist/access-recall-surface.d.ts +16 -15
  50. package/dist/access-recall-surface.js +33 -33
  51. package/dist/access-schema.d.ts +2 -1
  52. package/dist/access-schema.js +3 -3
  53. package/dist/{access-service-70VHaltr.d.ts → access-service-BZaC-RZw.d.ts} +9 -9
  54. package/dist/access-service-helpers.d.ts +15 -14
  55. package/dist/access-service.d.ts +15 -14
  56. package/dist/access-service.js +33 -33
  57. package/dist/access-surface-catalog.d.ts +15 -14
  58. package/dist/access-surface-catalog.js +35 -35
  59. package/dist/access-wearables-meetings-surface.d.ts +5 -4
  60. package/dist/action-confidence.d.ts +2 -1
  61. package/dist/active-memory-bridge.d.ts +2 -1
  62. package/dist/active-recall.d.ts +2 -1
  63. package/dist/active-recall.js +3 -2
  64. package/dist/active-recall.js.map +1 -1
  65. package/dist/activity/digest.d.ts +2 -1
  66. package/dist/ambient-provenance.d.ts +2 -1
  67. package/dist/artifact-search.d.ts +2 -1
  68. package/dist/background-generation.d.ts +2 -1
  69. package/dist/behavior-learner.d.ts +2 -1
  70. package/dist/behavior-signals.d.ts +2 -1
  71. package/dist/bootstrap.d.ts +12 -11
  72. package/dist/briefing-window.d.ts +3 -2
  73. package/dist/briefing.d.ts +3 -2
  74. package/dist/briefing.js +8 -8
  75. package/dist/buffer-surprise-report.d.ts +2 -1
  76. package/dist/buffer-turn-helpers.d.ts +2 -1
  77. package/dist/buffer.d.ts +3 -2
  78. package/dist/bulk-import/index.d.ts +4 -3
  79. package/dist/calibration.d.ts +2 -1
  80. package/dist/capabilities.d.ts +2 -1
  81. package/dist/{capsule-crypto-7FJQINUR.js → capsule-crypto-YO5QJ6L3.js} +2 -2
  82. package/dist/{catalog-Byi9prz9.d.ts → catalog-DK2eHhax.d.ts} +1 -1
  83. package/dist/causal-behavior.d.ts +2 -1
  84. package/dist/causal-consolidation.d.ts +2 -1
  85. package/dist/causal-consolidation.js +9 -9
  86. package/dist/causal-trajectory-graph.d.ts +2 -1
  87. package/dist/{chunk-6DYCSSHN.js → chunk-25HSEIEM.js} +2 -2
  88. package/dist/{chunk-PAQ7YGJY.js → chunk-2EICZYIG.js} +2 -2
  89. package/dist/{chunk-2IVHOQRY.js → chunk-2ERLN25A.js} +2 -2
  90. package/dist/{chunk-TUSY4KRE.js → chunk-2G2CVN2T.js} +29 -28
  91. package/dist/{chunk-TUSY4KRE.js.map → chunk-2G2CVN2T.js.map} +1 -1
  92. package/dist/{chunk-EST3J4LX.js → chunk-2SZBCM2S.js} +2 -2
  93. package/dist/{chunk-UB4UVALS.js → chunk-33SX6K3N.js} +2 -2
  94. package/dist/{chunk-P36WML7L.js → chunk-3QZRSEAM.js} +2 -2
  95. package/dist/chunk-4KQIWY4A.js +197 -0
  96. package/dist/chunk-4KQIWY4A.js.map +1 -0
  97. package/dist/{chunk-LBLXEFWK.js → chunk-4MN27537.js} +1 -1
  98. package/dist/chunk-4MN27537.js.map +1 -0
  99. package/dist/{chunk-JI5Q6EOY.js → chunk-6HCJWCA4.js} +5 -5
  100. package/dist/chunk-6VITOSPL.js +69 -0
  101. package/dist/chunk-6VITOSPL.js.map +1 -0
  102. package/dist/{chunk-OTGIAJQ2.js → chunk-6Z4OLQUO.js} +2 -2
  103. package/dist/{chunk-DHTOYRDE.js → chunk-6ZMIASYT.js} +2 -2
  104. package/dist/{chunk-UD6W67JM.js → chunk-72AV2H3R.js} +76 -25
  105. package/dist/chunk-72AV2H3R.js.map +1 -0
  106. package/dist/{chunk-KHLNIDWB.js → chunk-7TTOX6NW.js} +2 -2
  107. package/dist/{chunk-7VTQETLT.js → chunk-A33DLYNY.js} +2 -2
  108. package/dist/{chunk-QQA6VTOY.js → chunk-AH3OIMS7.js} +2 -2
  109. package/dist/{chunk-T3F2HWIG.js → chunk-AIVRD66I.js} +2 -2
  110. package/dist/{chunk-RBHQA2UU.js → chunk-BMAYH7F4.js} +487 -343
  111. package/dist/chunk-BMAYH7F4.js.map +1 -0
  112. package/dist/{chunk-WHSNLCRO.js → chunk-BULK6DGB.js} +2 -2
  113. package/dist/{chunk-2NLLXCJG.js → chunk-BXLOS5AJ.js} +2 -2
  114. package/dist/{chunk-K26LFJE4.js → chunk-CKBA2MWS.js} +2 -2
  115. package/dist/{chunk-TVVEYCNW.js → chunk-DAOMWGO2.js} +2 -2
  116. package/dist/{chunk-E64HBW7M.js → chunk-DLXBMXIB.js} +2 -2
  117. package/dist/{chunk-X7Y7WX73.js → chunk-DQEMWVMT.js} +1 -1
  118. package/dist/{chunk-T3OLYUU6.js → chunk-DQSVGTKB.js} +2 -2
  119. package/dist/{chunk-4WSR7MYV.js → chunk-DX63RFDJ.js} +2 -2
  120. package/dist/{chunk-SNOAFXKX.js → chunk-EBJL6HGR.js} +12 -4
  121. package/dist/chunk-EBJL6HGR.js.map +1 -0
  122. package/dist/{chunk-LX32KV2C.js → chunk-ETNC6TT6.js} +2 -2
  123. package/dist/{chunk-UE7L4EDU.js → chunk-HEKWNWNL.js} +3 -3
  124. package/dist/{chunk-ZDGSHXJU.js → chunk-IGDEKECC.js} +1 -1
  125. package/dist/{chunk-YKWWG3CM.js → chunk-ISA5U5AP.js} +2 -2
  126. package/dist/{chunk-3MX4GWJO.js → chunk-JGPG5UHM.js} +2 -2
  127. package/dist/{chunk-U3ZRHNNG.js → chunk-JHUODJRW.js} +2 -2
  128. package/dist/{chunk-5WIGM42T.js → chunk-JXSOB3SA.js} +2 -2
  129. package/dist/{chunk-YOC3EEZH.js → chunk-KAPYPTPS.js} +16 -16
  130. package/dist/{chunk-AOMVOC2E.js → chunk-KBHDV7P3.js} +3 -3
  131. package/dist/{chunk-2WMXZYMS.js → chunk-LIAKZGOY.js} +2 -2
  132. package/dist/{chunk-A7GQBJP5.js → chunk-LVFI5LG7.js} +7 -7
  133. package/dist/{chunk-EHUUXLLA.js → chunk-LX7KIJQF.js} +2 -2
  134. package/dist/{chunk-BHXY5FXL.js → chunk-LZI6FWZW.js} +8 -2
  135. package/dist/chunk-LZI6FWZW.js.map +1 -0
  136. package/dist/{chunk-EBLKS57G.js → chunk-MNF6PTNL.js} +2 -2
  137. package/dist/{chunk-LE2UESGS.js → chunk-MYDA2GA2.js} +2 -2
  138. package/dist/{chunk-XQFHKPNB.js → chunk-NROI5XMG.js} +2 -2
  139. package/dist/{chunk-N57PUWUE.js → chunk-NVW5ISEJ.js} +40 -40
  140. package/dist/{chunk-PSQRBCGR.js → chunk-NXSNFPYI.js} +2 -2
  141. package/dist/{chunk-LLFMZYFS.js → chunk-O4JFBEUL.js} +2 -2
  142. package/dist/{chunk-JVM3CEGL.js → chunk-OIK3YL2P.js} +3 -3
  143. package/dist/{chunk-C3YEB7CR.js → chunk-PLJ2MQFT.js} +7 -7
  144. package/dist/{chunk-DNAD57VY.js → chunk-PQWICTRO.js} +1 -1
  145. package/dist/chunk-PQWICTRO.js.map +1 -0
  146. package/dist/{chunk-Z2OKRO3E.js → chunk-PYTSGD5M.js} +2 -2
  147. package/dist/{chunk-VBRS7Z3O.js → chunk-Q6OC4UUT.js} +2 -2
  148. package/dist/{chunk-ZYZW46HZ.js → chunk-QRSC37NC.js} +5 -5
  149. package/dist/{chunk-AJLQH4RO.js → chunk-RIP2AOZW.js} +9 -9
  150. package/dist/{chunk-SYJZUVTN.js → chunk-SCM4VYJW.js} +3 -3
  151. package/dist/{chunk-76RTJ533.js → chunk-SMI2G3MA.js} +3 -3
  152. package/dist/{chunk-6VLOKESS.js → chunk-ST7FDKZT.js} +12 -2
  153. package/dist/chunk-ST7FDKZT.js.map +1 -0
  154. package/dist/{chunk-WGCASEEQ.js → chunk-SZ75IB2T.js} +2 -2
  155. package/dist/{chunk-FLZJMXFV.js → chunk-T73ZC7C5.js} +2 -2
  156. package/dist/{chunk-FVRZDZ7J.js → chunk-TNFDWJRS.js} +2 -2
  157. package/dist/{chunk-WNMVUWI7.js → chunk-TTFJQ5B5.js} +2 -2
  158. package/dist/{chunk-HIBNECBQ.js → chunk-UP3226JC.js} +6 -6
  159. package/dist/{chunk-NDWBT2VV.js → chunk-UVEBBXB5.js} +2 -2
  160. package/dist/{chunk-KQAFEZQX.js → chunk-VDX2J7OX.js} +2 -2
  161. package/dist/{chunk-AIKUSXIS.js → chunk-VLR4S5GF.js} +7 -7
  162. package/dist/{chunk-ZHXSOMYH.js → chunk-VVX5PZFS.js} +2 -2
  163. package/dist/{chunk-HS75MCQF.js → chunk-WUUGE7QC.js} +4 -4
  164. package/dist/{chunk-RS53SDCA.js → chunk-X25NTN3W.js} +2 -2
  165. package/dist/{chunk-PZHN7R35.js → chunk-XFXVIXDI.js} +2 -2
  166. package/dist/{chunk-YA5M7OC4.js → chunk-XHDQQ2TT.js} +2 -2
  167. package/dist/{chunk-IIDXU2CY.js → chunk-XRUOO7OT.js} +2 -2
  168. package/dist/{chunk-WVI43D54.js → chunk-YEIKOBOW.js} +15 -2
  169. package/dist/chunk-YEIKOBOW.js.map +1 -0
  170. package/dist/{chunk-JUOJGZPV.js → chunk-YIIW2OH2.js} +2 -2
  171. package/dist/{chunk-SKYYPVBW.js → chunk-YJJMJH6J.js} +8 -8
  172. package/dist/{cli-CdJiBilM.d.ts → cli-BHDMJqJS.d.ts} +5 -5
  173. package/dist/cli.d.ts +17 -16
  174. package/dist/cli.js +76 -75
  175. package/dist/coding/export-okf-codegraph.d.ts +2 -1
  176. package/dist/coding/export-okf-codegraph.js +7 -7
  177. package/dist/coding/pre-action-gate.d.ts +2 -1
  178. package/dist/compounding/engine.d.ts +3 -2
  179. package/dist/compounding/engine.js +8 -8
  180. package/dist/compounding/preference-consolidator.d.ts +2 -1
  181. package/dist/compression-optimizer.d.ts +2 -1
  182. package/dist/config.d.ts +2 -1
  183. package/dist/config.js +3 -2
  184. package/dist/connectors/codex-materialize-runner.d.ts +2 -1
  185. package/dist/connectors/codex-materialize-runner.js +8 -8
  186. package/dist/connectors/codex-materialize.d.ts +2 -1
  187. package/dist/connectors/index.d.ts +2 -1
  188. package/dist/connectors/index.js +8 -8
  189. package/dist/consolidation-provenance-check.d.ts +3 -2
  190. package/dist/consolidation-undo.d.ts +3 -2
  191. package/dist/contradiction/index.d.ts +5 -4
  192. package/dist/converge-config.d.ts +2 -1
  193. package/dist/convergence-refresh.d.ts +3 -2
  194. package/dist/convergence-refresh.js +10 -10
  195. package/dist/conversation-index/backend.d.ts +2 -1
  196. package/dist/conversation-index/chunker.d.ts +2 -1
  197. package/dist/conversation-index/faiss-adapter.d.ts +2 -1
  198. package/dist/conversation-index/indexer.d.ts +2 -1
  199. package/dist/conversation-index/search.d.ts +2 -1
  200. package/dist/corpus-watermark.d.ts +2 -1
  201. package/dist/corpus-watermark.js +10 -10
  202. package/dist/cross-lingual-recall.d.ts +2 -1
  203. package/dist/day-summary.d.ts +2 -1
  204. package/dist/deep-recall-http-glue.d.ts +15 -14
  205. package/dist/deep-recall-http-glue.js +4 -4
  206. package/dist/deep-recall-mcp-tools.d.ts +15 -14
  207. package/dist/deep-recall-policy-llm.d.ts +3 -2
  208. package/dist/deep-recall-seeds.d.ts +2 -1
  209. package/dist/deep-recall.js +2 -2
  210. package/dist/delinearize.d.ts +2 -1
  211. package/dist/dependency-propagation-config.d.ts +2 -1
  212. package/dist/{dependency-propagation-delivery-BgHy44WX.d.ts → dependency-propagation-delivery-BMkR4gmY.d.ts} +1 -1
  213. package/dist/direct-answer-wiring.d.ts +2 -1
  214. package/dist/direct-answer.d.ts +2 -1
  215. package/dist/directory-sidecars.d.ts +28 -2
  216. package/dist/directory-sidecars.js +9 -1
  217. package/dist/embedding-fallback.d.ts +2 -1
  218. package/dist/enrichment/index.d.ts +2 -1
  219. package/dist/entity-origin-fields.d.ts +2 -1
  220. package/dist/entity-retrieval.d.ts +3 -2
  221. package/dist/entity-retrieval.js +8 -8
  222. package/dist/entity-schema.d.ts +2 -1
  223. package/dist/episodic-context.d.ts +2 -1
  224. package/dist/eval-trajectory-contracts.d.ts +2 -1
  225. package/dist/eval-trajectory-store.d.ts +2 -1
  226. package/dist/eval-trajectory.d.ts +2 -1
  227. package/dist/explicit-capture.d.ts +12 -11
  228. package/dist/external-wiki-access.d.ts +15 -14
  229. package/dist/external-wiki-access.js +34 -34
  230. package/dist/external-wiki-collection-registration.d.ts +2 -1
  231. package/dist/external-wiki-collection.d.ts +2 -1
  232. package/dist/external-wiki-mcp-tools.d.ts +15 -14
  233. package/dist/extraction-error-classification.d.ts +2 -1
  234. package/dist/extraction-evidence-class.d.ts +2 -1
  235. package/dist/extraction-faithfulness.d.ts +3 -2
  236. package/dist/extraction-judge-telemetry.d.ts +3 -2
  237. package/dist/extraction-judge-training.d.ts +3 -2
  238. package/dist/extraction-judge.d.ts +3 -2
  239. package/dist/extraction-liveness.d.ts +2 -1
  240. package/dist/extraction-normalization.d.ts +2 -1
  241. package/dist/extraction-prompt.d.ts +2 -1
  242. package/dist/extraction-source-grounding-rules.d.ts +2 -1
  243. package/dist/extraction-source-grounding.d.ts +2 -1
  244. package/dist/extraction-span-config.d.ts +2 -1
  245. package/dist/extraction-span-materialize.d.ts +2 -1
  246. package/dist/extraction-span-wire.d.ts +2 -1
  247. package/dist/extraction.d.ts +3 -2
  248. package/dist/extraction.js +8 -8
  249. package/dist/fallback-llm-codex-subscription.d.ts +2 -1
  250. package/dist/fallback-llm.d.ts +2 -1
  251. package/dist/{generic-recall-paths-BoueWXYr.d.ts → generic-recall-paths-BCRtXU32.d.ts} +1 -1
  252. package/dist/graph-append-error.d.ts +2 -1
  253. package/dist/graph-dashboard-diff.d.ts +2 -1
  254. package/dist/graph-dashboard-key.d.ts +2 -1
  255. package/dist/graph-dashboard-parser.d.ts +2 -1
  256. package/dist/graph-edge-reinforcement.d.ts +2 -1
  257. package/dist/graph-jsonl.d.ts +2 -1
  258. package/dist/graph-path-reconstruction.d.ts +2 -1
  259. package/dist/graph-path-scoring.d.ts +2 -1
  260. package/dist/graph-snapshot.d.ts +2 -1
  261. package/dist/graph.d.ts +2 -1
  262. package/dist/harmonic-retrieval.js +1 -1
  263. package/dist/importance.d.ts +2 -1
  264. package/dist/importers/index.d.ts +2 -1
  265. package/dist/importers/test-utils.d.ts +2 -1
  266. package/dist/in-flight-reads.d.ts +2 -1
  267. package/dist/{index-cwbrXoxe.d.ts → index-DMNTW4W6.d.ts} +3 -3
  268. package/dist/index.d.ts +29 -26
  269. package/dist/index.js +149 -103
  270. package/dist/intent.d.ts +2 -1
  271. package/dist/lcm/engine.d.ts +2 -1
  272. package/dist/lcm/engine.js +3 -3
  273. package/dist/lcm/index.d.ts +2 -1
  274. package/dist/lcm/index.js +11 -11
  275. package/dist/lcm/tools.d.ts +2 -1
  276. package/dist/lifecycle.d.ts +2 -1
  277. package/dist/live-connectors-runner.d.ts +2 -1
  278. package/dist/{local-llm-B0vd_rp9.d.ts → local-llm-BXYC-mbU.d.ts} +1 -1
  279. package/dist/local-llm-helpers.d.ts +3 -2
  280. package/dist/local-llm.d.ts +3 -2
  281. package/dist/local-model-endpoint.d.ts +2 -1
  282. package/dist/location/index.d.ts +6 -5
  283. package/dist/location/index.js +10 -10
  284. package/dist/maintenance/memory-governance.d.ts +2 -1
  285. package/dist/maintenance/memory-governance.js +8 -8
  286. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +3 -2
  287. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +8 -8
  288. package/dist/maintenance/rebuild-memory-projection.d.ts +3 -2
  289. package/dist/maintenance/rebuild-memory-projection.js +9 -9
  290. package/dist/{maintenance-DJgQkoLh.d.ts → maintenance-zJiLsKBY.d.ts} +3 -3
  291. package/dist/mcp-memory-inspector-app.d.ts +15 -14
  292. package/dist/memory-action-policy.d.ts +2 -1
  293. package/dist/memory-browse-http-glue.d.ts +15 -14
  294. package/dist/memory-browse-mcp-tools.d.ts +15 -14
  295. package/dist/memory-browse-operations.js +34 -34
  296. package/dist/memory-browse.d.ts +2 -1
  297. package/dist/memory-browse.js +3 -3
  298. package/dist/memory-cache.d.ts +2 -1
  299. package/dist/memory-controller.d.ts +2 -1
  300. package/dist/memory-lifecycle-ledger-utils.d.ts +2 -1
  301. package/dist/memory-projection-store.d.ts +2 -1
  302. package/dist/memory-provenance.d.ts +2 -1
  303. package/dist/memory-snapshot.d.ts +2 -1
  304. package/dist/memory-subject-cli.d.ts +15 -14
  305. package/dist/memory-subject.d.ts +15 -14
  306. package/dist/memory-worth-outcomes.d.ts +3 -2
  307. package/dist/models-json.d.ts +2 -1
  308. package/dist/namespaces/migrate.d.ts +4 -3
  309. package/dist/namespaces/migrate.js +9 -9
  310. package/dist/namespaces/principal.d.ts +2 -1
  311. package/dist/namespaces/search.d.ts +2 -1
  312. package/dist/namespaces/search.js +4 -4
  313. package/dist/namespaces/storage.d.ts +4 -3
  314. package/dist/namespaces/storage.js +8 -8
  315. package/dist/native-knowledge.d.ts +2 -1
  316. package/dist/offline-sync-impression-drain.d.ts +2 -1
  317. package/dist/operator-doctor-corpus.d.ts +2 -1
  318. package/dist/operator-doctor-corpus.js +11 -11
  319. package/dist/operator-doctor-replica.d.ts +2 -1
  320. package/dist/operator-toolkit.d.ts +4 -3
  321. package/dist/operator-toolkit.js +19 -18
  322. package/dist/orchestration/compression-guideline-coordinator.d.ts +3 -2
  323. package/dist/orchestration/maintenance.d.ts +5 -4
  324. package/dist/orchestration/maintenance.js +16 -16
  325. package/dist/{orchestrator-Kx5zwNUm.d.ts → orchestrator-BTqT3F6X.d.ts} +10 -10
  326. package/dist/orchestrator.d.ts +12 -11
  327. package/dist/orchestrator.js +97 -95
  328. package/dist/patterns-cli.d.ts +2 -1
  329. package/dist/{pipeline-9SYxxign.d.ts → pipeline-CgO2Sd4O.d.ts} +1 -1
  330. package/dist/policy-runtime.d.ts +2 -1
  331. package/dist/proactive-contention.d.ts +3 -2
  332. package/dist/provenance.d.ts +2 -1
  333. package/dist/{public-http-Bvol6Jr4.d.ts → public-http-Dk1EA9ix.d.ts} +1 -1
  334. package/dist/{qmd-DjwuG9Xa.d.ts → qmd-CwxtVz64.d.ts} +1 -1
  335. package/dist/qmd-preflight.d.ts +3 -2
  336. package/dist/qmd-recall-cache.d.ts +2 -1
  337. package/dist/qmd.d.ts +3 -2
  338. package/dist/recall-audit-anomaly.d.ts +1 -0
  339. package/dist/recall-audit.d.ts +4 -0
  340. package/dist/recall-audit.js +1 -1
  341. package/dist/recall-composition-decision.d.ts +41 -0
  342. package/dist/recall-composition-decision.js +17 -0
  343. package/dist/recall-composition-decision.js.map +1 -0
  344. package/dist/recall-concurrency-config.d.ts +2 -1
  345. package/dist/recall-disclosure-escalation.d.ts +2 -1
  346. package/dist/recall-explain-renderer.d.ts +3 -1
  347. package/dist/recall-explain-renderer.js +3 -3
  348. package/dist/recall-memory-map.d.ts +2 -1
  349. package/dist/recall-navigate-access.d.ts +2 -1
  350. package/dist/recall-navigate-access.js +2 -2
  351. package/dist/recall-navigate-disclosure.d.ts +2 -1
  352. package/dist/recall-navigate-disclosure.js +2 -2
  353. package/dist/recall-navigate.d.ts +2 -1
  354. package/dist/recall-navigate.js +2 -2
  355. package/dist/recall-navigation-http-glue.d.ts +15 -14
  356. package/dist/recall-navigation-mcp-tools.d.ts +15 -14
  357. package/dist/recall-navigation-operations.js +34 -34
  358. package/dist/recall-navigation-renderer.d.ts +3 -1
  359. package/dist/recall-navigation.d.ts +3 -1
  360. package/dist/recall-navigation.js +33 -33
  361. package/dist/recall-planner-llm.d.ts +2 -1
  362. package/dist/recall-recognition-tier.d.ts +121 -0
  363. package/dist/recall-recognition-tier.js +42 -0
  364. package/dist/recall-recognition-tier.js.map +1 -0
  365. package/dist/recall-state-view-admission.d.ts +3 -2
  366. package/dist/recall-state-view-admission.js +3 -3
  367. package/dist/recall-state-view-anchors.d.ts +2 -1
  368. package/dist/recall-state.d.ts +2 -1
  369. package/dist/recall-tag-filter.d.ts +3 -1
  370. package/dist/recall-timings.d.ts +2 -1
  371. package/dist/recall-xray-cli.d.ts +3 -1
  372. package/dist/recall-xray-cli.js +4 -4
  373. package/dist/recall-xray-renderer.d.ts +3 -1
  374. package/dist/recall-xray-renderer.js +3 -3
  375. package/dist/recall-xray.d.ts +11 -1
  376. package/dist/recall-xray.js +2 -2
  377. package/dist/reconcile/cursor.d.ts +2 -1
  378. package/dist/reconcile/manifest.d.ts +2 -1
  379. package/dist/reconcile/plan.d.ts +2 -1
  380. package/dist/replay/normalizers/chatgpt.d.ts +2 -1
  381. package/dist/replay/normalizers/claude.d.ts +2 -1
  382. package/dist/replay/normalizers/openclaw.d.ts +2 -1
  383. package/dist/replay/normalizers/shared.d.ts +2 -1
  384. package/dist/replay/runner.d.ts +2 -1
  385. package/dist/replay/types.d.ts +2 -1
  386. package/dist/replica-divergence.d.ts +2 -1
  387. package/dist/replica-peers-config.d.ts +2 -1
  388. package/dist/resolve-auth-token.d.ts +2 -1
  389. package/dist/resume-bundles.js +4 -3
  390. package/dist/retrieval-agents.d.ts +3 -2
  391. package/dist/retrieval-tiers.d.ts +2 -1
  392. package/dist/routing/engine.d.ts +2 -1
  393. package/dist/routing/store.d.ts +2 -1
  394. package/dist/salvage-envelope.d.ts +2 -1
  395. package/dist/{scope-profiles-DPegZtRf.d.ts → scope-profiles-Bg1rB-Dp.d.ts} +1 -1
  396. package/dist/search/embed-helper.d.ts +2 -1
  397. package/dist/search/factory.d.ts +2 -1
  398. package/dist/search/factory.js +3 -3
  399. package/dist/search/index.d.ts +2 -1
  400. package/dist/search/index.js +7 -7
  401. package/dist/search/lancedb-backend.d.ts +2 -1
  402. package/dist/search/meilisearch-backend.d.ts +2 -1
  403. package/dist/search/noop-backend.d.ts +2 -1
  404. package/dist/search/orama-backend.d.ts +2 -1
  405. package/dist/search/port.d.ts +2 -1
  406. package/dist/search/remote-backend.d.ts +2 -1
  407. package/dist/{semantic-consolidation-DMzhKRYl.d.ts → semantic-consolidation-DEzRyeyn.d.ts} +1 -1
  408. package/dist/semantic-consolidation.d.ts +3 -2
  409. package/dist/semantic-consolidation.js +9 -9
  410. package/dist/semantic-rule-promotion.js +8 -8
  411. package/dist/semantic-rule-verifier.d.ts +2 -1
  412. package/dist/semantic-rule-verifier.js +8 -8
  413. package/dist/{service-E99KuPvi.d.ts → service-DGEIDOeD.d.ts} +2 -2
  414. package/dist/session-observer-bands.d.ts +2 -1
  415. package/dist/session-observer-state.d.ts +2 -1
  416. package/dist/shared-context/manager.d.ts +2 -1
  417. package/dist/signal.d.ts +2 -1
  418. package/dist/source-agent-qualifier.d.ts +2 -1
  419. package/dist/source-agent-qualifier.js +8 -8
  420. package/dist/standup/build.js +8 -8
  421. package/dist/{storage-BS7ux8F7.d.ts → storage-DNQWtOSM.d.ts} +1 -1
  422. package/dist/storage.d.ts +3 -2
  423. package/dist/storage.js +7 -7
  424. package/dist/subject-config.d.ts +2 -1
  425. package/dist/summarizer.d.ts +2 -1
  426. package/dist/summary-snapshot.d.ts +2 -1
  427. package/dist/support-passport/index.d.ts +18 -17
  428. package/dist/support-passport/index.js +36 -36
  429. package/dist/{tagging-BhOEcSXP.d.ts → tagging-CPVwgadt.d.ts} +2 -2
  430. package/dist/temporal-supersession.d.ts +3 -2
  431. package/dist/temporal-timeline-recall.d.ts +2 -1
  432. package/dist/temporal-validity.d.ts +2 -1
  433. package/dist/threading.d.ts +2 -1
  434. package/dist/tier-migration.d.ts +3 -2
  435. package/dist/tier-routing.d.ts +2 -1
  436. package/dist/topics.d.ts +2 -1
  437. package/dist/transcript.d.ts +2 -1
  438. package/dist/transfer/backup.js +2 -2
  439. package/dist/transfer/capsule-export.js +2 -2
  440. package/dist/transfer/capsule-import.js +2 -2
  441. package/dist/transfer/export-okf.d.ts +2 -1
  442. package/dist/transfer/export-okf.js +8 -8
  443. package/dist/trust-score-stage.d.ts +2 -1
  444. package/dist/trust-score.d.ts +2 -1
  445. package/dist/{types-DQ2H8gAC.d.ts → types-DCB90q3g.d.ts} +2 -1
  446. package/dist/types.d.ts +2 -1
  447. package/dist/types.js +1 -1
  448. package/dist/utility-runtime.d.ts +2 -1
  449. package/dist/verified-recall.js +8 -8
  450. package/dist/who-knows-cli.d.ts +15 -14
  451. package/dist/who-knows-cli.js +9 -9
  452. package/dist/who-knows.d.ts +15 -14
  453. package/dist/who-knows.js +8 -8
  454. package/dist/write-envelope.d.ts +2 -1
  455. package/package.json +2 -2
  456. package/src/access-mcp-output-schemas.ts +14 -1
  457. package/src/access-recall-response.ts +3 -0
  458. package/src/config.ts +5 -0
  459. package/src/directory-sidecars.test.ts +119 -0
  460. package/src/directory-sidecars.ts +110 -25
  461. package/src/experience/session-experience-recall.test.ts +228 -0
  462. package/src/experience/session-experience-recall.ts +60 -0
  463. package/src/index.ts +2 -0
  464. package/src/lifecycle/seed-graduation.test.ts +424 -0
  465. package/src/lifecycle/seed-graduation.ts +376 -0
  466. package/src/orchestration/recall-entry.ts +16 -2
  467. package/src/orchestration/recall-internal.ts +21 -18
  468. package/src/orchestration/recall-recognition-search.test.ts +290 -0
  469. package/src/orchestration/recall-recognition-search.ts +160 -0
  470. package/src/procedural/procedure-recall.ts +14 -3
  471. package/src/recall-audit.test.ts +34 -0
  472. package/src/recall-audit.ts +4 -0
  473. package/src/recall-composition-decision.test.ts +134 -0
  474. package/src/recall-composition-decision.ts +113 -0
  475. package/src/recall-recognition-tier.test.ts +306 -0
  476. package/src/recall-recognition-tier.ts +375 -0
  477. package/src/recall-xray-renderer.test.ts +17 -0
  478. package/src/recall-xray-renderer.ts +10 -0
  479. package/src/recall-xray.test.ts +28 -0
  480. package/src/recall-xray.ts +15 -0
  481. package/src/testing/subjects/recall-recognition-tier.test.ts +106 -0
  482. package/src/testing/subjects/seed-graduation.test.ts +128 -0
  483. package/src/types.ts +2 -0
  484. package/dist/chunk-6VLOKESS.js.map +0 -1
  485. package/dist/chunk-BHXY5FXL.js.map +0 -1
  486. package/dist/chunk-DNAD57VY.js.map +0 -1
  487. package/dist/chunk-LBLXEFWK.js.map +0 -1
  488. package/dist/chunk-RBHQA2UU.js.map +0 -1
  489. package/dist/chunk-SNOAFXKX.js.map +0 -1
  490. package/dist/chunk-UD6W67JM.js.map +0 -1
  491. package/dist/chunk-WVI43D54.js.map +0 -1
  492. /package/dist/{capsule-crypto-7FJQINUR.js.map → capsule-crypto-YO5QJ6L3.js.map} +0 -0
  493. /package/dist/{chunk-6DYCSSHN.js.map → chunk-25HSEIEM.js.map} +0 -0
  494. /package/dist/{chunk-PAQ7YGJY.js.map → chunk-2EICZYIG.js.map} +0 -0
  495. /package/dist/{chunk-2IVHOQRY.js.map → chunk-2ERLN25A.js.map} +0 -0
  496. /package/dist/{chunk-EST3J4LX.js.map → chunk-2SZBCM2S.js.map} +0 -0
  497. /package/dist/{chunk-UB4UVALS.js.map → chunk-33SX6K3N.js.map} +0 -0
  498. /package/dist/{chunk-P36WML7L.js.map → chunk-3QZRSEAM.js.map} +0 -0
  499. /package/dist/{chunk-JI5Q6EOY.js.map → chunk-6HCJWCA4.js.map} +0 -0
  500. /package/dist/{chunk-OTGIAJQ2.js.map → chunk-6Z4OLQUO.js.map} +0 -0
  501. /package/dist/{chunk-DHTOYRDE.js.map → chunk-6ZMIASYT.js.map} +0 -0
  502. /package/dist/{chunk-KHLNIDWB.js.map → chunk-7TTOX6NW.js.map} +0 -0
  503. /package/dist/{chunk-7VTQETLT.js.map → chunk-A33DLYNY.js.map} +0 -0
  504. /package/dist/{chunk-QQA6VTOY.js.map → chunk-AH3OIMS7.js.map} +0 -0
  505. /package/dist/{chunk-T3F2HWIG.js.map → chunk-AIVRD66I.js.map} +0 -0
  506. /package/dist/{chunk-WHSNLCRO.js.map → chunk-BULK6DGB.js.map} +0 -0
  507. /package/dist/{chunk-2NLLXCJG.js.map → chunk-BXLOS5AJ.js.map} +0 -0
  508. /package/dist/{chunk-K26LFJE4.js.map → chunk-CKBA2MWS.js.map} +0 -0
  509. /package/dist/{chunk-TVVEYCNW.js.map → chunk-DAOMWGO2.js.map} +0 -0
  510. /package/dist/{chunk-E64HBW7M.js.map → chunk-DLXBMXIB.js.map} +0 -0
  511. /package/dist/{chunk-X7Y7WX73.js.map → chunk-DQEMWVMT.js.map} +0 -0
  512. /package/dist/{chunk-T3OLYUU6.js.map → chunk-DQSVGTKB.js.map} +0 -0
  513. /package/dist/{chunk-4WSR7MYV.js.map → chunk-DX63RFDJ.js.map} +0 -0
  514. /package/dist/{chunk-LX32KV2C.js.map → chunk-ETNC6TT6.js.map} +0 -0
  515. /package/dist/{chunk-UE7L4EDU.js.map → chunk-HEKWNWNL.js.map} +0 -0
  516. /package/dist/{chunk-ZDGSHXJU.js.map → chunk-IGDEKECC.js.map} +0 -0
  517. /package/dist/{chunk-YKWWG3CM.js.map → chunk-ISA5U5AP.js.map} +0 -0
  518. /package/dist/{chunk-3MX4GWJO.js.map → chunk-JGPG5UHM.js.map} +0 -0
  519. /package/dist/{chunk-U3ZRHNNG.js.map → chunk-JHUODJRW.js.map} +0 -0
  520. /package/dist/{chunk-5WIGM42T.js.map → chunk-JXSOB3SA.js.map} +0 -0
  521. /package/dist/{chunk-YOC3EEZH.js.map → chunk-KAPYPTPS.js.map} +0 -0
  522. /package/dist/{chunk-AOMVOC2E.js.map → chunk-KBHDV7P3.js.map} +0 -0
  523. /package/dist/{chunk-2WMXZYMS.js.map → chunk-LIAKZGOY.js.map} +0 -0
  524. /package/dist/{chunk-A7GQBJP5.js.map → chunk-LVFI5LG7.js.map} +0 -0
  525. /package/dist/{chunk-EHUUXLLA.js.map → chunk-LX7KIJQF.js.map} +0 -0
  526. /package/dist/{chunk-EBLKS57G.js.map → chunk-MNF6PTNL.js.map} +0 -0
  527. /package/dist/{chunk-LE2UESGS.js.map → chunk-MYDA2GA2.js.map} +0 -0
  528. /package/dist/{chunk-XQFHKPNB.js.map → chunk-NROI5XMG.js.map} +0 -0
  529. /package/dist/{chunk-N57PUWUE.js.map → chunk-NVW5ISEJ.js.map} +0 -0
  530. /package/dist/{chunk-PSQRBCGR.js.map → chunk-NXSNFPYI.js.map} +0 -0
  531. /package/dist/{chunk-LLFMZYFS.js.map → chunk-O4JFBEUL.js.map} +0 -0
  532. /package/dist/{chunk-JVM3CEGL.js.map → chunk-OIK3YL2P.js.map} +0 -0
  533. /package/dist/{chunk-C3YEB7CR.js.map → chunk-PLJ2MQFT.js.map} +0 -0
  534. /package/dist/{chunk-Z2OKRO3E.js.map → chunk-PYTSGD5M.js.map} +0 -0
  535. /package/dist/{chunk-VBRS7Z3O.js.map → chunk-Q6OC4UUT.js.map} +0 -0
  536. /package/dist/{chunk-ZYZW46HZ.js.map → chunk-QRSC37NC.js.map} +0 -0
  537. /package/dist/{chunk-AJLQH4RO.js.map → chunk-RIP2AOZW.js.map} +0 -0
  538. /package/dist/{chunk-SYJZUVTN.js.map → chunk-SCM4VYJW.js.map} +0 -0
  539. /package/dist/{chunk-76RTJ533.js.map → chunk-SMI2G3MA.js.map} +0 -0
  540. /package/dist/{chunk-WGCASEEQ.js.map → chunk-SZ75IB2T.js.map} +0 -0
  541. /package/dist/{chunk-FLZJMXFV.js.map → chunk-T73ZC7C5.js.map} +0 -0
  542. /package/dist/{chunk-FVRZDZ7J.js.map → chunk-TNFDWJRS.js.map} +0 -0
  543. /package/dist/{chunk-WNMVUWI7.js.map → chunk-TTFJQ5B5.js.map} +0 -0
  544. /package/dist/{chunk-HIBNECBQ.js.map → chunk-UP3226JC.js.map} +0 -0
  545. /package/dist/{chunk-NDWBT2VV.js.map → chunk-UVEBBXB5.js.map} +0 -0
  546. /package/dist/{chunk-KQAFEZQX.js.map → chunk-VDX2J7OX.js.map} +0 -0
  547. /package/dist/{chunk-AIKUSXIS.js.map → chunk-VLR4S5GF.js.map} +0 -0
  548. /package/dist/{chunk-ZHXSOMYH.js.map → chunk-VVX5PZFS.js.map} +0 -0
  549. /package/dist/{chunk-HS75MCQF.js.map → chunk-WUUGE7QC.js.map} +0 -0
  550. /package/dist/{chunk-RS53SDCA.js.map → chunk-X25NTN3W.js.map} +0 -0
  551. /package/dist/{chunk-PZHN7R35.js.map → chunk-XFXVIXDI.js.map} +0 -0
  552. /package/dist/{chunk-YA5M7OC4.js.map → chunk-XHDQQ2TT.js.map} +0 -0
  553. /package/dist/{chunk-IIDXU2CY.js.map → chunk-XRUOO7OT.js.map} +0 -0
  554. /package/dist/{chunk-JUOJGZPV.js.map → chunk-YIIW2OH2.js.map} +0 -0
  555. /package/dist/{chunk-SKYYPVBW.js.map → chunk-YJJMJH6J.js.map} +0 -0
@@ -0,0 +1,375 @@
1
+ /**
2
+ * Full-index recognition tier (issue #2975, foundation slice).
3
+ *
4
+ * distill-kura's recall does not search — it recognizes: the entire
5
+ * namespace index (one line per memory: id + description) goes into a
6
+ * single prompt and a small model names which entries bear on the
7
+ * question. Keyword/vector search misses same-subject-different-words
8
+ * cases; a recognizer that reads the whole index cannot miss what it
9
+ * can see (~500 entries ≈ 6k tokens, sub-second locally).
10
+ *
11
+ * This slice ships the deterministic tier machinery only — nothing on
12
+ * the live recall path reads it yet, so recall behavior is unchanged:
13
+ * - a compact per-namespace index persisted at
14
+ * `<namespace memoryDir>/state/index_recognition.json` with
15
+ * build/save/load; loading is total: missing, corrupt, wrong-shape,
16
+ * or future-version indexes all yield `null`, never an error;
17
+ * - the tier decision, pure on (index, maxEntries): index present and
18
+ * at or under the entry threshold → recognition; absent or above →
19
+ * the vector tier, no error thrown;
20
+ * - the runner: renders the FULL index into one prompt, asks the
21
+ * recognizer for ids, keeps only ids the index actually carries, and
22
+ * returns them in index order — never recognizer order;
23
+ * - loud degradation: a recognizer that fails falls back to vector
24
+ * search labeled `recognizer_unavailable` (quiet degradation is
25
+ * worse than degradation).
26
+ *
27
+ * Determinism rules:
28
+ * - the decision is a pure function of (index, maxEntries) — no clock,
29
+ * no I/O, no locale;
30
+ * - an empty index short-circuits: no model call, zero candidates;
31
+ * - the prompt and the returned ids are byte-identical across runs
32
+ * with unchanged inputs.
33
+ *
34
+ * Host contract for the wiring slices:
35
+ * - maintenance slice: build/save the index at memory write time from
36
+ * each memory's id + description line (a recognition trigger — proper
37
+ * nouns, numbers, landmines, the conclusion reached — not a summary),
38
+ * serializing writes the way temporal-index does (op chain + lock);
39
+ * saveRecognitionIndex here is single-writer and does not lock;
40
+ * - recall slice: for each recalled namespace call
41
+ * recallViaRecognitionTier with the recognizer (one small-model call)
42
+ * and the existing vector search as the fallback; expand picks
43
+ * through the graph neighborhood, merge through the normal pipeline
44
+ * (filters → rerank → budget), and record tier = recognition plus any
45
+ * degraded fallback in xray;
46
+ * - config keys recallRecognitionTier (default false) and
47
+ * recognitionIndexMaxEntries (default 500) gate the wiring.
48
+ */
49
+ import { promises as fsp } from "node:fs";
50
+ import path from "node:path";
51
+ import { coerceBooleanLike, coerceNumber } from "./connectors/coerce.js";
52
+ import { log } from "./logger.js";
53
+
54
+ export const DEFAULT_RECALL_RECOGNITION_TIER = false;
55
+ export const DEFAULT_RECOGNITION_INDEX_MAX_ENTRIES = 500;
56
+ export const RECOGNITION_INDEX_VERSION = 1;
57
+ const RECOGNITION_INDEX_FILE = "index_recognition.json";
58
+
59
+ export const RECOGNITION_PROMPT_HEADER =
60
+ "Memory index — one line per memory. Name the ids that bear on the question.";
61
+ export const RECOGNITION_PROMPT_FOOTER =
62
+ "Answer with the relevant ids only, comma-separated. If none bear on the question, answer with nothing.";
63
+
64
+ export interface RecognitionIndexEntry {
65
+ /** Stable memory id. Candidates always come back in index order. */
66
+ id: string;
67
+ /** One-line recognition trigger; not a summary (issue #2975 swap test). */
68
+ description: string;
69
+ }
70
+
71
+ export interface RecognitionIndex {
72
+ version: number;
73
+ entries: RecognitionIndexEntry[];
74
+ }
75
+
76
+ /**
77
+ * Config fields this tier owns, mixed into `PluginConfig` (issue #2975) so
78
+ * the keys live beside their parsers instead of growing `types.ts`.
79
+ */
80
+ export interface RecognitionTierSettings {
81
+ /** Small namespaces recall by recognizing against the whole compact index instead of vector search; parsed now, wiring lands in a later slice. Default false. */
82
+ recallRecognitionTier: boolean;
83
+ /** Max entries a namespace's recognition index may carry for the tier to engage (inclusive). Default 500. */
84
+ recognitionIndexMaxEntries: number;
85
+ }
86
+
87
+ export function parseRecallRecognitionTier(raw: unknown): boolean {
88
+ return coerceBooleanLike(raw, "recallRecognitionTier") === true;
89
+ }
90
+
91
+ export function parseRecognitionIndexMaxEntries(raw: unknown): number {
92
+ if (raw === undefined || raw === null) return DEFAULT_RECOGNITION_INDEX_MAX_ENTRIES;
93
+ const n = coerceNumber(raw, "recognitionIndexMaxEntries");
94
+ if (n === undefined || !Number.isFinite(n) || n < 1) {
95
+ throw new Error(
96
+ `Invalid recognitionIndexMaxEntries: expected an integer >= 1, got ${JSON.stringify(raw)}`,
97
+ );
98
+ }
99
+ return Math.floor(n);
100
+ }
101
+
102
+ /** On-disk location of a namespace's recognition index. */
103
+ export function recognitionIndexPath(memoryDir: string): string {
104
+ return path.join(memoryDir, "state", RECOGNITION_INDEX_FILE);
105
+ }
106
+
107
+ /**
108
+ * Normalize raw records into a recognition index: blank/whitespace ids
109
+ * are dropped, descriptions are trimmed, and the first record for an id
110
+ * wins. Input order is preserved — it is the recognition order.
111
+ */
112
+ export function buildRecognitionIndex(
113
+ records: ReadonlyArray<{ id?: string | null; description?: string | null }>,
114
+ ): RecognitionIndex {
115
+ const seen = new Set<string>();
116
+ const out: RecognitionIndexEntry[] = [];
117
+ for (const record of records) {
118
+ const id = typeof record.id === "string" ? record.id.trim() : "";
119
+ if (id.length === 0 || seen.has(id)) continue;
120
+ seen.add(id);
121
+ out.push({
122
+ id,
123
+ description: typeof record.description === "string" ? record.description.trim() : "",
124
+ });
125
+ }
126
+ return { version: RECOGNITION_INDEX_VERSION, entries: out };
127
+ }
128
+
129
+ /**
130
+ * Persist a recognition index. Single-writer: the maintenance slice that
131
+ * owns index writes must serialize calls the way temporal-index does.
132
+ */
133
+ export async function saveRecognitionIndex(
134
+ memoryDir: string,
135
+ index: RecognitionIndex,
136
+ ): Promise<void> {
137
+ const file = recognitionIndexPath(memoryDir);
138
+ await fsp.mkdir(path.dirname(file), { recursive: true });
139
+ await fsp.writeFile(file, `${JSON.stringify(index, null, 2)}\n`, "utf8");
140
+ }
141
+
142
+ function isRecognitionIndex(raw: unknown): raw is RecognitionIndex {
143
+ if (typeof raw !== "object" || raw === null) return false;
144
+ const candidate = raw as { version?: unknown; entries?: unknown };
145
+ if (candidate.version !== RECOGNITION_INDEX_VERSION) return false;
146
+ if (!Array.isArray(candidate.entries)) return false;
147
+ return candidate.entries.every(
148
+ (entry) =>
149
+ typeof entry === "object" &&
150
+ entry !== null &&
151
+ typeof (entry as RecognitionIndexEntry).id === "string" &&
152
+ typeof (entry as RecognitionIndexEntry).description === "string",
153
+ );
154
+ }
155
+
156
+ /**
157
+ * Load a namespace's recognition index. Total: a missing, corrupt,
158
+ * wrong-shape, or future-version file all return `null` so the caller
159
+ * falls back to vector search without an error.
160
+ */
161
+ export async function loadRecognitionIndex(memoryDir: string): Promise<RecognitionIndex | null> {
162
+ try {
163
+ const raw = await fsp.readFile(recognitionIndexPath(memoryDir), "utf8");
164
+ const parsed: unknown = JSON.parse(raw);
165
+ if (isRecognitionIndex(parsed)) return parsed;
166
+ log.warn(
167
+ `recognition index ignored at ${RECOGNITION_INDEX_FILE}: unexpected shape; falling back to vector search`,
168
+ );
169
+ return null;
170
+ } catch {
171
+ return null;
172
+ }
173
+ }
174
+
175
+ export type RecognitionRecallTier = "recognition" | "vector";
176
+ export type RecognitionTierReason =
177
+ | "index_absent"
178
+ | "index_above_threshold"
179
+ | "index_within_threshold";
180
+
181
+ export interface RecognitionTierDecision {
182
+ tier: RecognitionRecallTier;
183
+ reason: RecognitionTierReason;
184
+ /** Entries the decision considered; 0 when the index is absent. */
185
+ entriesConsidered: number;
186
+ /** Threshold in force. */
187
+ maxEntries: number;
188
+ }
189
+
190
+ /**
191
+ * Deterministic tier choice, pure on (index, maxEntries). The threshold
192
+ * is inclusive: an index of exactly maxEntries entries still recognizes
193
+ * (a threshold-sized index is the designed working set, not an overrun).
194
+ */
195
+ export function decideRecognitionTier(
196
+ index: RecognitionIndex | null,
197
+ opts: { maxEntries: number },
198
+ ): RecognitionTierDecision {
199
+ const maxEntries = Math.max(1, Math.floor(opts.maxEntries));
200
+ if (index === null) {
201
+ return { tier: "vector", reason: "index_absent", entriesConsidered: 0, maxEntries };
202
+ }
203
+ if (index.entries.length > maxEntries) {
204
+ return {
205
+ tier: "vector",
206
+ reason: "index_above_threshold",
207
+ entriesConsidered: index.entries.length,
208
+ maxEntries,
209
+ };
210
+ }
211
+ return {
212
+ tier: "recognition",
213
+ reason: "index_within_threshold",
214
+ entriesConsidered: index.entries.length,
215
+ maxEntries,
216
+ };
217
+ }
218
+
219
+ /** Render the full index, one line per entry, in index order. */
220
+ export function renderRecognitionIndex(entries: ReadonlyArray<RecognitionIndexEntry>): string {
221
+ return entries.map((entry) => `${entry.id}: ${entry.description}`).join("\n");
222
+ }
223
+
224
+ /** The single recognition prompt: header, the FULL index, the question, the answer shape. */
225
+ export function buildRecognitionPrompt(
226
+ query: string,
227
+ entries: ReadonlyArray<RecognitionIndexEntry>,
228
+ ): string {
229
+ return [
230
+ RECOGNITION_PROMPT_HEADER,
231
+ renderRecognitionIndex(entries),
232
+ `Question: ${query}`,
233
+ RECOGNITION_PROMPT_FOOTER,
234
+ ].join("\n\n");
235
+ }
236
+
237
+ function dedupeOrdered(tokens: string[]): string[] {
238
+ const seen = new Set<string>();
239
+ const out: string[] = [];
240
+ for (const token of tokens) {
241
+ if (token.length > 0 && !seen.has(token)) {
242
+ seen.add(token);
243
+ out.push(token);
244
+ }
245
+ }
246
+ return out;
247
+ }
248
+
249
+ const TRAILING_PUNCTUATION: Record<string, true> = { ".": true, ",": true, ";": true, ":": true };
250
+
251
+ /**
252
+ * Strip trailing sentence punctuation in linear time. A quantified anchored
253
+ * regex (`/[.,;:]+$/`) backtracks polynomially on recognizer output made of
254
+ * many separators, and that output is uncontrolled model text.
255
+ */
256
+ function stripTrailingPunctuation(value: string): string {
257
+ let end = value.length;
258
+ while (end > 0 && TRAILING_PUNCTUATION[value.charAt(end - 1)]) end -= 1;
259
+ return value.slice(0, end);
260
+ }
261
+
262
+ /**
263
+ * Parse recognizer output into ordered unique id tokens. Accepts a JSON
264
+ * string array or comma/whitespace-separated ids, and strips sentence
265
+ * punctuation so prose wrappers do not corrupt ids. Tokens that are not
266
+ * real ids are dropped later by validation against the index.
267
+ */
268
+ export function parseRecognizerIds(output: string | null | undefined): string[] {
269
+ if (typeof output !== "string") return [];
270
+ const text = output.trim();
271
+ if (text.length === 0) return [];
272
+ if (text.startsWith("[")) {
273
+ try {
274
+ const parsed: unknown = JSON.parse(text);
275
+ if (Array.isArray(parsed)) {
276
+ return dedupeOrdered(
277
+ parsed
278
+ .filter((item): item is string => typeof item === "string")
279
+ .map((item) => stripTrailingPunctuation(item.trim()).trim()),
280
+ );
281
+ }
282
+ } catch {
283
+ // Fall through to separator parsing.
284
+ }
285
+ }
286
+ return dedupeOrdered(
287
+ text
288
+ .split(/[\s,]+/)
289
+ .map((token) => stripTrailingPunctuation(token.replace(/^[•\-*\d.)\]]+/, "")).trim()),
290
+ );
291
+ }
292
+
293
+ /** One model call over the full index; supplied by the wiring slice. */
294
+ export type Recognizer = (prompt: string) => Promise<string | null | undefined>;
295
+
296
+ export interface RecognitionRunResult {
297
+ /** Recognized ids, validated against the index, in index order. */
298
+ ids: string[];
299
+ /** Recognizer tokens the index does not carry (hallucinated ids). */
300
+ dropped: string[];
301
+ /** True when no model call was made (empty index). */
302
+ skipped: boolean;
303
+ }
304
+
305
+ /**
306
+ * Run the recognition pass: the FULL index goes into one prompt, the
307
+ * recognizer names ids, unknown ids are dropped, and the kept ids come
308
+ * back in index order so downstream merging stays deterministic.
309
+ */
310
+ export async function runRecognitionTier(
311
+ query: string,
312
+ entries: ReadonlyArray<RecognitionIndexEntry>,
313
+ recognize: Recognizer,
314
+ ): Promise<RecognitionRunResult> {
315
+ if (entries.length === 0) {
316
+ return { ids: [], dropped: [], skipped: true };
317
+ }
318
+ const raw = parseRecognizerIds(await recognize(buildRecognitionPrompt(query, entries)));
319
+ const byId = new Map(entries.map((entry) => [entry.id, entry]));
320
+ const picked = new Set(raw.filter((token) => byId.has(token)));
321
+ return {
322
+ ids: entries.filter((entry) => picked.has(entry.id)).map((entry) => entry.id),
323
+ dropped: dedupeOrdered(raw.filter((token) => !byId.has(token))),
324
+ skipped: false,
325
+ };
326
+ }
327
+
328
+ export interface RecognitionTierOutcome<TVector> {
329
+ decision: RecognitionTierDecision;
330
+ /** Recognition picks, index order; empty on the vector tier. */
331
+ ids: string[];
332
+ /** Vector-tier results from the fallback; empty on the recognition tier. */
333
+ vectorResults: TVector[];
334
+ /**
335
+ * Set when recognition was routed but the recognizer failed and the
336
+ * vector tier served the recall instead — loud degradation.
337
+ */
338
+ degraded?: "recognizer_unavailable";
339
+ }
340
+
341
+ /**
342
+ * The wiring-seam composition for one namespace: load the index, decide
343
+ * the tier, then either recognize against the full index or run the
344
+ * caller's vector search. Never throws for index problems; a failing
345
+ * recognizer degrades to vector search labeled `recognizer_unavailable`.
346
+ */
347
+ export async function recallViaRecognitionTier<TVector>(args: {
348
+ memoryDir: string;
349
+ query: string;
350
+ maxEntries: number;
351
+ recognize: Recognizer;
352
+ vectorSearch: () => Promise<TVector[]>;
353
+ }): Promise<RecognitionTierOutcome<TVector>> {
354
+ const index = await loadRecognitionIndex(args.memoryDir);
355
+ const decision = decideRecognitionTier(index, { maxEntries: args.maxEntries });
356
+ if (index === null || decision.tier === "vector") {
357
+ return { decision, ids: [], vectorResults: await args.vectorSearch() };
358
+ }
359
+ try {
360
+ const run = await runRecognitionTier(args.query, index.entries, args.recognize);
361
+ return { decision, ids: run.ids, vectorResults: [] };
362
+ } catch (err) {
363
+ log.warn(
364
+ `recognition tier degraded to vector search: recognizer failed${
365
+ err instanceof Error ? ` (${err.message})` : ""
366
+ }`,
367
+ );
368
+ return {
369
+ decision,
370
+ ids: [],
371
+ vectorResults: await args.vectorSearch(),
372
+ degraded: "recognizer_unavailable",
373
+ };
374
+ }
375
+ }
@@ -615,3 +615,20 @@ test("renderXrayText tier-explain block matches shared helper output", async ()
615
615
  assert.ok(nullText.includes(line));
616
616
  }
617
617
  });
618
+
619
+ test("#2972 xray text and markdown surface degradation only when present", () => {
620
+ const healthy = minimalSnapshot();
621
+ const degraded = {
622
+ ...minimalSnapshot(),
623
+ degradation: {
624
+ state: "degraded" as const,
625
+ reason: "budget-clipped" as const,
626
+ },
627
+ };
628
+ const healthyText = renderXrayText(healthy);
629
+ assert.equal(healthyText.includes("degradation:"), false);
630
+ assert.match(renderXrayText(degraded), /degradation: degraded\/budget-clipped/);
631
+ assert.equal(renderXrayMarkdown(healthy).includes("| Degradation |"), false);
632
+ assert.match(renderXrayMarkdown(degraded), /\| Degradation \| degraded\/budget-clipped \|/);
633
+ });
634
+
@@ -108,6 +108,11 @@ export function renderXrayText(snapshot: RecallXraySnapshot | null): string {
108
108
  lines.push(
109
109
  `budget: ${snapshot.budget.used} / ${snapshot.budget.chars} chars`,
110
110
  );
111
+ if (snapshot.degradation) {
112
+ lines.push(
113
+ `degradation: ${snapshot.degradation.state}/${snapshot.degradation.reason}`,
114
+ );
115
+ }
111
116
 
112
117
  lines.push("");
113
118
  lines.push("--- filters ---");
@@ -247,6 +252,11 @@ export function renderXrayMarkdown(
247
252
  lines.push(
248
253
  `| Budget | ${snapshot.budget.used} / ${snapshot.budget.chars} chars |`,
249
254
  );
255
+ if (snapshot.degradation) {
256
+ lines.push(
257
+ `| Degradation | ${snapshot.degradation.state}/${snapshot.degradation.reason} |`,
258
+ );
259
+ }
250
260
 
251
261
  lines.push("");
252
262
  lines.push("## Filters");
@@ -650,3 +650,31 @@ test("RecallXrayBuilder clones the trust projection so the snapshot surfaces it
650
650
  "quarantine reason preserved so exclusion never looks like 'no result' (rule 34)",
651
651
  );
652
652
  });
653
+
654
+ test("#2972 healthy xray snapshot omits the degradation marker", () => {
655
+ const snapshot = buildXraySnapshot({
656
+ query: "q",
657
+ now: fixedNow,
658
+ snapshotIdGenerator: idGen(),
659
+ });
660
+ assert.equal("degradation" in snapshot, false);
661
+ assert.ok(!JSON.stringify(snapshot).includes("degradation"));
662
+ });
663
+
664
+ test("#2972 xray snapshot copies degradation and isolates caller mutation", () => {
665
+ const degradation = {
666
+ state: "degraded" as const,
667
+ reason: "budget-clipped" as const,
668
+ budget: { contextBudget: 20, fullChars: 100, deliveredChars: 20 },
669
+ };
670
+ const snapshot = buildXraySnapshot({
671
+ query: "q",
672
+ degradation,
673
+ now: fixedNow,
674
+ snapshotIdGenerator: idGen(),
675
+ });
676
+ assert.deepEqual(snapshot.degradation, degradation);
677
+ degradation.budget.deliveredChars = 0;
678
+ assert.equal(snapshot.degradation?.budget?.deliveredChars, 20);
679
+ });
680
+
@@ -24,6 +24,7 @@ import { estimateTokenCount } from "./token-estimate.js";
24
24
  import type { RecallDisclosure, RecallTierExplain } from "./types.js";
25
25
  import type { StateLabel } from "./recall-state-view.js";
26
26
  import { isRecallDisclosure } from "./types.js";
27
+ import type { RecallContextDegradation } from "./recall-context-composition.js";
27
28
 
28
29
  /**
29
30
  * Estimate token cost of a payload for X-ray disclosure accounting.
@@ -282,6 +283,12 @@ export interface RecallXraySnapshot {
282
283
  * absent) means no peer profile was injected.
283
284
  */
284
285
  peerProfileInjection?: RecallXrayPeerProfileInjection | null;
286
+ /**
287
+ * Injected-context degradation (#2972). Absent on a healthy recall so
288
+ * the snapshot stays byte-stable. Budget warnings ride here, never
289
+ * in the injected text.
290
+ */
291
+ degradation?: RecallContextDegradation;
285
292
  }
286
293
 
287
294
  // ─── Builder ──────────────────────────────────────────────────────────────
@@ -300,6 +307,8 @@ export interface BuildXraySnapshotInput {
300
307
  traceId?: string;
301
308
  /** Peer-profile injection metadata (issue #679 completion). */
302
309
  peerProfileInjection?: RecallXrayPeerProfileInjection | null;
310
+ /** Injected-context degradation (#2972). Omit on a healthy recall. */
311
+ degradation?: RecallContextDegradation;
303
312
  /** Optional injected timestamp for deterministic tests. */
304
313
  now?: () => number;
305
314
  /** Optional injected id generator for deterministic tests. */
@@ -375,6 +384,12 @@ export function buildXraySnapshot(
375
384
  if (peerProfileInjection !== undefined) {
376
385
  out.peerProfileInjection = peerProfileInjection;
377
386
  }
387
+ if (input.degradation && typeof input.degradation === "object") {
388
+ out.degradation = { ...input.degradation };
389
+ if (input.degradation.budget) {
390
+ out.degradation.budget = { ...input.degradation.budget };
391
+ }
392
+ }
378
393
  return out;
379
394
  }
380
395
 
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Recognition-tier swap subject for the scenario-matrix harness (issue #2975).
3
+ *
4
+ * Every canonical row runs the real fetchQmdMemoryResultsWithRecognitionSwap
5
+ * seam twice: gate off (original fetch only, zero index I/O, zero recognizer
6
+ * calls) and gate on with an under-threshold index (one recognizer call, the
7
+ * namespace never reaches vector search). The scenario dimensions are
8
+ * orthogonal to this routing decision, so the same invariant holds per row.
9
+ */
10
+ import assert from "node:assert/strict";
11
+ import os from "node:os";
12
+ import path from "node:path";
13
+ import { mkdtemp, rm } from "node:fs/promises";
14
+
15
+ import {
16
+ fetchQmdMemoryResultsWithRecognitionSwap,
17
+ type RecognitionSearchDeps,
18
+ } from "../../orchestration/recall-recognition-search.js";
19
+ import { saveRecognitionIndex } from "../../recall-recognition-tier.js";
20
+ import type { QmdSearchResult } from "../../types.js";
21
+ import { type LifecycleSubject, type MatrixRow, runLifecycleMatrix } from "../lifecycle-matrix.js";
22
+ interface SwapState {
23
+ rowId: string;
24
+ dir: string;
25
+ deps: (enabled: boolean) => RecognitionSearchDeps;
26
+ fetchCalls: number;
27
+ recognizeCalls: number;
28
+ storageForCalls: number;
29
+ }
30
+
31
+ const subject: LifecycleSubject<SwapState> = {
32
+ async setup(row: MatrixRow): Promise<SwapState> {
33
+ const dir = await mkdtemp(path.join(os.tmpdir(), "remnic-recognition-subject-"));
34
+ await saveRecognitionIndex(dir, {
35
+ version: 1,
36
+ entries: [
37
+ { id: `m-${row.id}-a`, description: `trigger for ${row.id}-a` },
38
+ { id: `m-${row.id}-b`, description: `trigger for ${row.id}-b` },
39
+ ],
40
+ });
41
+ const state: SwapState = { rowId: String(row.id), dir, deps: undefined as never, fetchCalls: 0, recognizeCalls: 0, storageForCalls: 0 };
42
+ state.deps = (enabled) =>
43
+ ({
44
+ config: { recallRecognitionTier: enabled, recognitionIndexMaxEntries: 500 },
45
+ storageRouter: {
46
+ storageFor: async () => {
47
+ state.storageForCalls += 1;
48
+ return {
49
+ dir,
50
+ findExistingMemoryPaths: async (ids: string[]) =>
51
+ new Map(ids.map((id) => [id, [path.join(dir, `facts/${id}.md`)]])),
52
+ };
53
+ },
54
+ },
55
+ fastLlmForRerank: {
56
+ chatCompletion: async () => {
57
+ state.recognizeCalls += 1;
58
+ return { content: JSON.stringify([`m-${row.id}-a`, `m-${row.id}-b`]) };
59
+ },
60
+ },
61
+ fetchQmdMemoryResultsWithArtifactTopUp: async (): Promise<QmdSearchResult[]> => {
62
+ state.fetchCalls += 1;
63
+ return [{ docid: `default:vector.md`, namespace: "default", path: "vector.md", score: 1, snippet: "vector" }];
64
+ },
65
+ }) as unknown as RecognitionSearchDeps;
66
+ return state;
67
+ },
68
+
69
+ async exercise(state): Promise<void> {
70
+ const options = {
71
+ namespacesEnabled: true,
72
+ recallNamespaces: ["default"],
73
+ resolveNamespace: () => "default",
74
+ };
75
+
76
+ const off = await fetchQmdMemoryResultsWithRecognitionSwap(state.deps(false), "q", 5, 7, options);
77
+ assert.equal(off.length, 1);
78
+ assert.equal(state.fetchCalls, 1);
79
+ assert.equal(state.recognizeCalls, 0);
80
+ assert.equal(state.storageForCalls, 0);
81
+
82
+ const on = await fetchQmdMemoryResultsWithRecognitionSwap(state.deps(true), "q", 5, 7, options);
83
+ assert.equal(state.recognizeCalls, 1);
84
+ assert.equal(state.fetchCalls, 1, "recognition namespace must not reach vector fetch");
85
+ assert.deepEqual(on.map((r) => r.path).sort(), [`facts/m-${state.rowId}-a.md`, `facts/m-${state.rowId}-b.md`].sort());
86
+ },
87
+
88
+ async invariants(state): Promise<void> {
89
+ // Off-path again after the on-path run: still a pure passthrough.
90
+ const before = { fetch: state.fetchCalls, recognize: state.recognizeCalls, storage: state.storageForCalls };
91
+ await fetchQmdMemoryResultsWithRecognitionSwap(state.deps(false), "q", 5, 7, {
92
+ namespacesEnabled: true,
93
+ recallNamespaces: ["default"],
94
+ resolveNamespace: () => "default",
95
+ });
96
+ assert.equal(state.fetchCalls, before.fetch + 1);
97
+ assert.equal(state.recognizeCalls, before.recognize);
98
+ assert.equal(state.storageForCalls, before.storage);
99
+ },
100
+
101
+ async teardown(state): Promise<void> {
102
+ await rm(state.dir, { recursive: true, force: true });
103
+ },
104
+ };
105
+
106
+ runLifecycleMatrix("recall-recognition-tier", subject);