@remnic/core 9.3.613 → 9.3.614

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 (376) hide show
  1. package/dist/access-cli.js +58 -57
  2. package/dist/access-cli.js.map +1 -1
  3. package/dist/access-http.d.ts +4 -2
  4. package/dist/access-http.js +22 -22
  5. package/dist/access-mcp.d.ts +9 -2
  6. package/dist/access-mcp.js +19 -19
  7. package/dist/access-schema.d.ts +12 -12
  8. package/dist/access-schema.js +3 -3
  9. package/dist/{access-service-D2J9dh_9.d.ts → access-service-DGG_2xPK.d.ts} +1 -1
  10. package/dist/access-service.d.ts +2 -2
  11. package/dist/access-service.js +16 -16
  12. package/dist/active-recall.js +20 -3
  13. package/dist/active-recall.js.map +1 -1
  14. package/dist/adapters/index.js +4 -4
  15. package/dist/adapters/registry.js +2 -2
  16. package/dist/behavior-learner.js +2 -3
  17. package/dist/behavior-learner.js.map +1 -1
  18. package/dist/bootstrap.d.ts +1 -1
  19. package/dist/briefing.js +3 -3
  20. package/dist/buffer.d.ts +1 -1
  21. package/dist/buffer.js +1 -1
  22. package/dist/calibration.d.ts +5 -2
  23. package/dist/calibration.js +7 -5
  24. package/dist/calibration.js.map +1 -1
  25. package/dist/{capsule-crypto-7FJQINUR.js → capsule-crypto-YO5QJ6L3.js} +2 -2
  26. package/dist/causal-consolidation.d.ts +8 -2
  27. package/dist/causal-consolidation.js +13 -11
  28. package/dist/causal-consolidation.js.map +1 -1
  29. package/dist/{chunk-3BP57I6J.js → chunk-2F6NP3NT.js} +2 -1
  30. package/dist/{chunk-3BP57I6J.js.map → chunk-2F6NP3NT.js.map} +1 -1
  31. package/dist/{chunk-AU7Q3LSC.js → chunk-2QSZNTDO.js} +4 -4
  32. package/dist/{chunk-HSVJGWYS.js → chunk-2ROPI5OE.js} +2 -2
  33. package/dist/{chunk-C4SQJZAF.js → chunk-2SGJY2UY.js} +6 -3
  34. package/dist/chunk-2SGJY2UY.js.map +1 -0
  35. package/dist/{chunk-ZDTVJXIP.js → chunk-3MAONBX3.js} +13 -5
  36. package/dist/chunk-3MAONBX3.js.map +1 -0
  37. package/dist/{chunk-G3Z3QEF5.js → chunk-3PY7VHV7.js} +2 -2
  38. package/dist/chunk-3PY7VHV7.js.map +1 -0
  39. package/dist/{chunk-CF3ZF2YU.js → chunk-3QSU4NFF.js} +3 -3
  40. package/dist/{chunk-AJA46VX5.js → chunk-3T74IZB3.js} +11 -2
  41. package/dist/chunk-3T74IZB3.js.map +1 -0
  42. package/dist/{chunk-KVEVLBKC.js → chunk-4HFJQCJZ.js} +13 -8
  43. package/dist/chunk-4HFJQCJZ.js.map +1 -0
  44. package/dist/{chunk-KGK2QKWL.js → chunk-4R4KTDIE.js} +1 -1
  45. package/dist/chunk-4R4KTDIE.js.map +1 -0
  46. package/dist/{chunk-OI27U2HT.js → chunk-5BTCT236.js} +2 -2
  47. package/dist/{chunk-CO7ZO4TU.js → chunk-5VDJMYTF.js} +2 -2
  48. package/dist/{chunk-BFBF3XEF.js → chunk-6BDVBBBY.js} +33 -25
  49. package/dist/{chunk-BFBF3XEF.js.map → chunk-6BDVBBBY.js.map} +1 -1
  50. package/dist/{chunk-EAZGEEG2.js → chunk-6L46YAEZ.js} +45 -9
  51. package/dist/chunk-6L46YAEZ.js.map +1 -0
  52. package/dist/{chunk-YFS5OEKO.js → chunk-7MLB4NCL.js} +2 -2
  53. package/dist/{chunk-IOTENEVL.js → chunk-7YQFWOF7.js} +57 -50
  54. package/dist/chunk-7YQFWOF7.js.map +1 -0
  55. package/dist/{chunk-2QANQKSQ.js → chunk-ADNZVFXG.js} +15 -15
  56. package/dist/{chunk-LZ3VEOU5.js → chunk-AL4RAJL5.js} +22 -5
  57. package/dist/chunk-AL4RAJL5.js.map +1 -0
  58. package/dist/{chunk-557IAFPD.js → chunk-APRRL26Q.js} +2 -2
  59. package/dist/{chunk-QDDHYAKV.js → chunk-AZDOWD2L.js} +2 -2
  60. package/dist/{chunk-TH67Q46T.js → chunk-B6FDZPCF.js} +17 -9
  61. package/dist/chunk-B6FDZPCF.js.map +1 -0
  62. package/dist/{chunk-MLT75J5S.js → chunk-B6SU7YSE.js} +3 -3
  63. package/dist/{chunk-FXKPZ3H6.js → chunk-BPSGLMQ4.js} +2 -2
  64. package/dist/{chunk-2NLLXCJG.js → chunk-BXLOS5AJ.js} +2 -2
  65. package/dist/{chunk-NOMEVTUD.js → chunk-C6C7XVKG.js} +5 -4
  66. package/dist/chunk-C6C7XVKG.js.map +1 -0
  67. package/dist/{chunk-XKIQZXUB.js → chunk-CI7RKSRE.js} +7 -1
  68. package/dist/chunk-CI7RKSRE.js.map +1 -0
  69. package/dist/{chunk-IK34DVAC.js → chunk-CIOMS6DI.js} +2 -2
  70. package/dist/{chunk-2I5JGH3M.js → chunk-CYEPCZN5.js} +2 -2
  71. package/dist/{chunk-2I5JGH3M.js.map → chunk-CYEPCZN5.js.map} +1 -1
  72. package/dist/{chunk-JHMFYY7L.js → chunk-DCGT4FPP.js} +13 -5
  73. package/dist/chunk-DCGT4FPP.js.map +1 -0
  74. package/dist/{chunk-7DZRO2DC.js → chunk-DEPRLVLK.js} +2 -2
  75. package/dist/{chunk-CSKLPDN6.js → chunk-DEVUWMME.js} +52 -19
  76. package/dist/chunk-DEVUWMME.js.map +1 -0
  77. package/dist/{chunk-DHGSZ3UD.js → chunk-DGNQRNLL.js} +2 -2
  78. package/dist/{chunk-X7Y7WX73.js → chunk-DQEMWVMT.js} +1 -1
  79. package/dist/chunk-FAV25DUZ.js +12 -0
  80. package/dist/chunk-FAV25DUZ.js.map +1 -0
  81. package/dist/{chunk-ETUPBUHB.js → chunk-GDASG7NC.js} +2 -2
  82. package/dist/{chunk-L227SKTB.js → chunk-GDB4J2H3.js} +17 -1
  83. package/dist/chunk-GDB4J2H3.js.map +1 -0
  84. package/dist/{chunk-IP73YCZP.js → chunk-GLPBYIXN.js} +4 -2
  85. package/dist/chunk-GLPBYIXN.js.map +1 -0
  86. package/dist/{chunk-4HP7HIE3.js → chunk-HP5FMB6L.js} +2 -2
  87. package/dist/{chunk-EVZFIAPG.js → chunk-IBTZEBUD.js} +23 -10
  88. package/dist/chunk-IBTZEBUD.js.map +1 -0
  89. package/dist/{chunk-DOX2CG6Y.js → chunk-IEUU7O4F.js} +2 -2
  90. package/dist/{chunk-JNANKJLN.js → chunk-JOASJWQR.js} +2 -2
  91. package/dist/chunk-JOASJWQR.js.map +1 -0
  92. package/dist/{chunk-WSGF57U2.js → chunk-JQDZQ4TB.js} +2 -2
  93. package/dist/{chunk-HINSGUA7.js → chunk-KBL3JJR6.js} +9 -13
  94. package/dist/chunk-KBL3JJR6.js.map +1 -0
  95. package/dist/{chunk-W7L6HXUC.js → chunk-LXOM6IQU.js} +2 -2
  96. package/dist/{chunk-G6R5UD3Q.js → chunk-MGN7VHWQ.js} +42 -1
  97. package/dist/{chunk-G6R5UD3Q.js.map → chunk-MGN7VHWQ.js.map} +1 -1
  98. package/dist/{chunk-DLJ4IR6M.js → chunk-MHQC2WU2.js} +2 -2
  99. package/dist/chunk-MHQC2WU2.js.map +1 -0
  100. package/dist/{chunk-6JGNHWCI.js → chunk-OBIRVF36.js} +3 -3
  101. package/dist/{chunk-CHCA44C3.js → chunk-ODPLEWB6.js} +3 -3
  102. package/dist/chunk-ODPLEWB6.js.map +1 -0
  103. package/dist/{chunk-HENLZHIT.js → chunk-OIF36KGD.js} +7 -4
  104. package/dist/chunk-OIF36KGD.js.map +1 -0
  105. package/dist/{chunk-GUPISBV2.js → chunk-PP2JH3GP.js} +2 -2
  106. package/dist/{chunk-OXJBNGBK.js → chunk-PSUB67YB.js} +2 -2
  107. package/dist/{chunk-UWY7GIVS.js → chunk-PYIFUBRK.js} +45 -13
  108. package/dist/chunk-PYIFUBRK.js.map +1 -0
  109. package/dist/{chunk-KIB7SDIJ.js → chunk-Q6YIJGXJ.js} +2 -2
  110. package/dist/{chunk-PPPZY2EU.js → chunk-QEMCQFDW.js} +2 -2
  111. package/dist/{chunk-ZT3EGNLR.js → chunk-QPD426WT.js} +2 -2
  112. package/dist/{chunk-RLV3PQGH.js → chunk-QVO4YOB7.js} +6 -6
  113. package/dist/{chunk-GMAG2HS4.js → chunk-RG3LBSGH.js} +46 -9
  114. package/dist/chunk-RG3LBSGH.js.map +1 -0
  115. package/dist/{chunk-XSWKORGM.js → chunk-S53OYO3F.js} +3 -1
  116. package/dist/chunk-S53OYO3F.js.map +1 -0
  117. package/dist/{chunk-YCN4BVDK.js → chunk-SCPFRKIT.js} +4 -2
  118. package/dist/chunk-SCPFRKIT.js.map +1 -0
  119. package/dist/{chunk-HJNQQICM.js → chunk-T5XWMMU2.js} +107 -50
  120. package/dist/chunk-T5XWMMU2.js.map +1 -0
  121. package/dist/{chunk-NZPF2SYV.js → chunk-T7N6KQGS.js} +138 -5
  122. package/dist/chunk-T7N6KQGS.js.map +1 -0
  123. package/dist/{chunk-VJXSUAO7.js → chunk-TNOWU6RP.js} +13 -10
  124. package/dist/chunk-TNOWU6RP.js.map +1 -0
  125. package/dist/{chunk-PCI747N2.js → chunk-TZVQQTG4.js} +48 -19
  126. package/dist/chunk-TZVQQTG4.js.map +1 -0
  127. package/dist/{chunk-KQAFEZQX.js → chunk-VDX2J7OX.js} +2 -2
  128. package/dist/{chunk-IK7DCC5H.js → chunk-VMGLYN42.js} +2 -2
  129. package/dist/{chunk-5RPTH6AU.js → chunk-VPGUMLBA.js} +8 -7
  130. package/dist/chunk-VPGUMLBA.js.map +1 -0
  131. package/dist/{chunk-KM2A35EO.js → chunk-WB3LYXC5.js} +11 -7
  132. package/dist/chunk-WB3LYXC5.js.map +1 -0
  133. package/dist/{chunk-NSKYFGDL.js → chunk-X4QQB7O6.js} +2 -2
  134. package/dist/{chunk-HPWVAEET.js → chunk-X6IRLNOO.js} +3 -7
  135. package/dist/chunk-X6IRLNOO.js.map +1 -0
  136. package/dist/{chunk-46GJIW5M.js → chunk-XAZOWLW4.js} +5 -5
  137. package/dist/{chunk-46GJIW5M.js.map → chunk-XAZOWLW4.js.map} +1 -1
  138. package/dist/{chunk-XPSVGJYA.js → chunk-YRMKDTKF.js} +12 -9
  139. package/dist/chunk-YRMKDTKF.js.map +1 -0
  140. package/dist/{chunk-6ZZP4EJF.js → chunk-ZJR7VG5L.js} +3 -3
  141. package/dist/{chunk-6ZZP4EJF.js.map → chunk-ZJR7VG5L.js.map} +1 -1
  142. package/dist/{cli-OrfKXNU4.d.ts → cli-DWeu7eTY.d.ts} +6 -2
  143. package/dist/cli.d.ts +3 -3
  144. package/dist/cli.js +60 -59
  145. package/dist/compounding/engine.js +3 -3
  146. package/dist/compounding/preference-consolidator.js +39 -11
  147. package/dist/compounding/preference-consolidator.js.map +1 -1
  148. package/dist/config.js +1 -1
  149. package/dist/connectors/codex-materialize-runner.js +3 -3
  150. package/dist/connectors/index.js +3 -3
  151. package/dist/consolidation-provenance-check.js +1 -1
  152. package/dist/contradiction/index.js +4 -4
  153. package/dist/conversation-index/backend.js +2 -2
  154. package/dist/conversation-index/indexer.js +1 -1
  155. package/dist/cross-namespace-budget.js +1 -1
  156. package/dist/enrichment/index.js +1 -1
  157. package/dist/entity-retrieval.js +3 -3
  158. package/dist/evals.js +1 -1
  159. package/dist/explicit-capture.d.ts +1 -1
  160. package/dist/extraction-judge.js +8 -1
  161. package/dist/extraction.js +2 -2
  162. package/dist/fallback-llm.d.ts +23 -6
  163. package/dist/fallback-llm.js +5 -3
  164. package/dist/{first-start-migration-GYJWIH36.js → first-start-migration-FF7YFGRP.js} +6 -6
  165. package/dist/index.d.ts +3 -3
  166. package/dist/index.js +94 -93
  167. package/dist/index.js.map +1 -1
  168. package/dist/lcm/archive.js +2 -2
  169. package/dist/lcm/engine.js +5 -5
  170. package/dist/lcm/index.js +7 -7
  171. package/dist/lcm/summarizer.js +3 -3
  172. package/dist/maintenance/memory-governance-cron.d.ts +6 -4
  173. package/dist/maintenance/memory-governance-cron.js +1 -1
  174. package/dist/maintenance/memory-governance.js +3 -3
  175. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +3 -3
  176. package/dist/maintenance/rebuild-memory-projection.js +4 -4
  177. package/dist/mcp-memory-inspector-app.d.ts +2 -2
  178. package/dist/mcp-memory-inspector-app.js +1 -1
  179. package/dist/migrate/from-engram.js +1 -1
  180. package/dist/namespaces/migrate.js +16 -15
  181. package/dist/namespaces/search.js +12 -11
  182. package/dist/namespaces/storage.js +3 -3
  183. package/dist/network/webdav.d.ts +2 -0
  184. package/dist/network/webdav.js +1 -1
  185. package/dist/objective-state-writers.js +2 -2
  186. package/dist/operator-toolkit.d.ts +3 -1
  187. package/dist/operator-toolkit.js +21 -20
  188. package/dist/{orchestrator-DTRQG75J.d.ts → orchestrator-CqWOjfgl.d.ts} +46 -3
  189. package/dist/orchestrator.d.ts +1 -1
  190. package/dist/orchestrator.js +47 -44
  191. package/dist/patterns-cli.js +1 -1
  192. package/dist/qmd-recall-cache.d.ts +2 -0
  193. package/dist/qmd-recall-cache.js +1 -1
  194. package/dist/qmd.d.ts +37 -2
  195. package/dist/qmd.js +4 -1
  196. package/dist/recall-explain-renderer.js +3 -3
  197. package/dist/recall-planner-llm.d.ts +57 -0
  198. package/dist/recall-planner-llm.js +167 -0
  199. package/dist/recall-planner-llm.js.map +1 -0
  200. package/dist/recall-xray-cli.js +4 -4
  201. package/dist/recall-xray-renderer.js +3 -3
  202. package/dist/recall-xray.js +2 -2
  203. package/dist/resume-bundles.js +2 -2
  204. package/dist/retrieval-agents.js +2 -2
  205. package/dist/routing/store.js +1 -1
  206. package/dist/schemas.d.ts +22 -22
  207. package/dist/search/factory.js +11 -10
  208. package/dist/search/index.js +11 -10
  209. package/dist/search/lancedb-backend.d.ts +1 -1
  210. package/dist/search/lancedb-backend.js +3 -2
  211. package/dist/search/meilisearch-backend.d.ts +1 -1
  212. package/dist/search/meilisearch-backend.js +3 -2
  213. package/dist/search/noop-backend.d.ts +1 -1
  214. package/dist/search/noop-backend.js +1 -1
  215. package/dist/search/orama-backend.d.ts +1 -1
  216. package/dist/search/orama-backend.js +3 -2
  217. package/dist/search/port.d.ts +6 -1
  218. package/dist/search/port.js +7 -0
  219. package/dist/search/remote-backend.d.ts +1 -1
  220. package/dist/search/remote-backend.js +1 -1
  221. package/dist/semantic-consolidation.js +4 -4
  222. package/dist/semantic-rule-promotion.js +3 -3
  223. package/dist/semantic-rule-verifier.js +3 -3
  224. package/dist/session-observer-state.js +1 -1
  225. package/dist/storage.js +2 -2
  226. package/dist/summarizer.js +2 -2
  227. package/dist/temporal-index.js +1 -1
  228. package/dist/{tier-stats-SKML2OSF.js → tier-stats-3LYQ3VV5.js} +3 -3
  229. package/dist/transfer/backup.js +2 -2
  230. package/dist/transfer/capsule-export.js +2 -2
  231. package/dist/transfer/capsule-import.js +2 -2
  232. package/dist/transfer/export-sqlite.js +1 -1
  233. package/dist/transfer/types.d.ts +12 -12
  234. package/dist/types.d.ts +32 -0
  235. package/dist/types.js +1 -1
  236. package/dist/utility-learner.js +1 -1
  237. package/dist/utility-runtime.js +2 -2
  238. package/dist/verified-recall.js +3 -3
  239. package/dist/work/board.js +2 -2
  240. package/dist/work/storage.d.ts +2 -0
  241. package/dist/work/storage.js +1 -1
  242. package/package.json +1 -1
  243. package/src/access-http.ts +3 -0
  244. package/src/access-mcp.test.ts +51 -0
  245. package/src/access-mcp.ts +26 -5
  246. package/src/active-recall.test.ts +40 -0
  247. package/src/active-recall.ts +19 -2
  248. package/src/behavior-learner.ts +5 -3
  249. package/src/buffer-session.test.ts +58 -0
  250. package/src/buffer-surprise-trigger.test.ts +4 -18
  251. package/src/buffer.ts +39 -11
  252. package/src/calibration.ts +10 -4
  253. package/src/causal-consolidation.test.ts +47 -2
  254. package/src/causal-consolidation.ts +13 -9
  255. package/src/cli.ts +19 -4
  256. package/src/compounding/engine.ts +2 -0
  257. package/src/compounding/preference-consolidator.test.ts +292 -0
  258. package/src/compounding/preference-consolidator.ts +55 -19
  259. package/src/config.test.ts +213 -0
  260. package/src/config.ts +175 -4
  261. package/src/connectors/codex-materialize-runner.ts +7 -4
  262. package/src/consolidation-provenance-check.ts +24 -5
  263. package/src/conversation-index/indexer.test.ts +22 -0
  264. package/src/conversation-index/indexer.ts +7 -3
  265. package/src/cross-namespace-budget.test.ts +44 -21
  266. package/src/cross-namespace-budget.ts +2 -2
  267. package/src/enrichment/pipeline.ts +11 -16
  268. package/src/evals.ts +1 -1
  269. package/src/extraction-judge-chain.test.ts +55 -0
  270. package/src/extraction-judge.ts +7 -9
  271. package/src/extraction.ts +16 -5
  272. package/src/fallback-llm.test.ts +600 -1
  273. package/src/fallback-llm.ts +91 -22
  274. package/src/maintenance/memory-governance-cron.ts +39 -29
  275. package/src/mcp-memory-inspector-app.ts +54 -12
  276. package/src/message-parts/index.ts +6 -0
  277. package/src/message-parts/message-parts.test.ts +30 -0
  278. package/src/migrate/from-engram.ts +19 -5
  279. package/src/namespaces/search.test.ts +15 -2
  280. package/src/namespaces/search.ts +1 -1
  281. package/src/network/webdav.ts +61 -21
  282. package/src/operator-toolkit.ts +6 -2
  283. package/src/orchestrator.ts +173 -20
  284. package/src/qmd-client.test.ts +85 -0
  285. package/src/qmd-recall-cache.test.ts +16 -0
  286. package/src/qmd-recall-cache.ts +7 -0
  287. package/src/qmd.test.ts +54 -0
  288. package/src/qmd.ts +119 -19
  289. package/src/recall-planner-llm.test.ts +224 -0
  290. package/src/recall-planner-llm.ts +289 -0
  291. package/src/routing/store.ts +4 -8
  292. package/src/search/factory.ts +3 -0
  293. package/src/search/lancedb-backend.ts +15 -3
  294. package/src/search/meilisearch-backend.ts +70 -7
  295. package/src/search/noop-backend.ts +5 -1
  296. package/src/search/orama-backend.ts +15 -3
  297. package/src/search/port.ts +15 -0
  298. package/src/search/remote-backend.ts +5 -1
  299. package/src/session-observer-state.ts +1 -1
  300. package/src/summarizer.ts +3 -3
  301. package/src/temporal-index.test.ts +18 -0
  302. package/src/temporal-index.ts +45 -0
  303. package/src/training-export/cli-date-validation.test.ts +36 -0
  304. package/src/training-export/date-parse.ts +21 -2
  305. package/src/transfer/export-sqlite.ts +3 -0
  306. package/src/types.ts +35 -0
  307. package/src/utility-learner.ts +1 -0
  308. package/src/work/storage.ts +23 -0
  309. package/dist/chunk-5RPTH6AU.js.map +0 -1
  310. package/dist/chunk-AJA46VX5.js.map +0 -1
  311. package/dist/chunk-C4SQJZAF.js.map +0 -1
  312. package/dist/chunk-CHCA44C3.js.map +0 -1
  313. package/dist/chunk-CSKLPDN6.js.map +0 -1
  314. package/dist/chunk-DLJ4IR6M.js.map +0 -1
  315. package/dist/chunk-EAZGEEG2.js.map +0 -1
  316. package/dist/chunk-EVZFIAPG.js.map +0 -1
  317. package/dist/chunk-G3Z3QEF5.js.map +0 -1
  318. package/dist/chunk-GMAG2HS4.js.map +0 -1
  319. package/dist/chunk-HENLZHIT.js.map +0 -1
  320. package/dist/chunk-HINSGUA7.js.map +0 -1
  321. package/dist/chunk-HJNQQICM.js.map +0 -1
  322. package/dist/chunk-HPWVAEET.js.map +0 -1
  323. package/dist/chunk-IOTENEVL.js.map +0 -1
  324. package/dist/chunk-IP73YCZP.js.map +0 -1
  325. package/dist/chunk-JHMFYY7L.js.map +0 -1
  326. package/dist/chunk-JNANKJLN.js.map +0 -1
  327. package/dist/chunk-KGK2QKWL.js.map +0 -1
  328. package/dist/chunk-KM2A35EO.js.map +0 -1
  329. package/dist/chunk-KVEVLBKC.js.map +0 -1
  330. package/dist/chunk-L227SKTB.js.map +0 -1
  331. package/dist/chunk-LZ3VEOU5.js.map +0 -1
  332. package/dist/chunk-NOMEVTUD.js.map +0 -1
  333. package/dist/chunk-NZPF2SYV.js.map +0 -1
  334. package/dist/chunk-PCI747N2.js.map +0 -1
  335. package/dist/chunk-TH67Q46T.js.map +0 -1
  336. package/dist/chunk-UWY7GIVS.js.map +0 -1
  337. package/dist/chunk-VJXSUAO7.js.map +0 -1
  338. package/dist/chunk-XKIQZXUB.js.map +0 -1
  339. package/dist/chunk-XPSVGJYA.js.map +0 -1
  340. package/dist/chunk-XSWKORGM.js.map +0 -1
  341. package/dist/chunk-YCN4BVDK.js.map +0 -1
  342. package/dist/chunk-ZDTVJXIP.js.map +0 -1
  343. /package/dist/{capsule-crypto-7FJQINUR.js.map → capsule-crypto-YO5QJ6L3.js.map} +0 -0
  344. /package/dist/{chunk-AU7Q3LSC.js.map → chunk-2QSZNTDO.js.map} +0 -0
  345. /package/dist/{chunk-HSVJGWYS.js.map → chunk-2ROPI5OE.js.map} +0 -0
  346. /package/dist/{chunk-CF3ZF2YU.js.map → chunk-3QSU4NFF.js.map} +0 -0
  347. /package/dist/{chunk-OI27U2HT.js.map → chunk-5BTCT236.js.map} +0 -0
  348. /package/dist/{chunk-CO7ZO4TU.js.map → chunk-5VDJMYTF.js.map} +0 -0
  349. /package/dist/{chunk-YFS5OEKO.js.map → chunk-7MLB4NCL.js.map} +0 -0
  350. /package/dist/{chunk-2QANQKSQ.js.map → chunk-ADNZVFXG.js.map} +0 -0
  351. /package/dist/{chunk-557IAFPD.js.map → chunk-APRRL26Q.js.map} +0 -0
  352. /package/dist/{chunk-QDDHYAKV.js.map → chunk-AZDOWD2L.js.map} +0 -0
  353. /package/dist/{chunk-MLT75J5S.js.map → chunk-B6SU7YSE.js.map} +0 -0
  354. /package/dist/{chunk-FXKPZ3H6.js.map → chunk-BPSGLMQ4.js.map} +0 -0
  355. /package/dist/{chunk-2NLLXCJG.js.map → chunk-BXLOS5AJ.js.map} +0 -0
  356. /package/dist/{chunk-IK34DVAC.js.map → chunk-CIOMS6DI.js.map} +0 -0
  357. /package/dist/{chunk-7DZRO2DC.js.map → chunk-DEPRLVLK.js.map} +0 -0
  358. /package/dist/{chunk-DHGSZ3UD.js.map → chunk-DGNQRNLL.js.map} +0 -0
  359. /package/dist/{chunk-X7Y7WX73.js.map → chunk-DQEMWVMT.js.map} +0 -0
  360. /package/dist/{chunk-ETUPBUHB.js.map → chunk-GDASG7NC.js.map} +0 -0
  361. /package/dist/{chunk-4HP7HIE3.js.map → chunk-HP5FMB6L.js.map} +0 -0
  362. /package/dist/{chunk-DOX2CG6Y.js.map → chunk-IEUU7O4F.js.map} +0 -0
  363. /package/dist/{chunk-WSGF57U2.js.map → chunk-JQDZQ4TB.js.map} +0 -0
  364. /package/dist/{chunk-W7L6HXUC.js.map → chunk-LXOM6IQU.js.map} +0 -0
  365. /package/dist/{chunk-6JGNHWCI.js.map → chunk-OBIRVF36.js.map} +0 -0
  366. /package/dist/{chunk-GUPISBV2.js.map → chunk-PP2JH3GP.js.map} +0 -0
  367. /package/dist/{chunk-OXJBNGBK.js.map → chunk-PSUB67YB.js.map} +0 -0
  368. /package/dist/{chunk-KIB7SDIJ.js.map → chunk-Q6YIJGXJ.js.map} +0 -0
  369. /package/dist/{chunk-PPPZY2EU.js.map → chunk-QEMCQFDW.js.map} +0 -0
  370. /package/dist/{chunk-ZT3EGNLR.js.map → chunk-QPD426WT.js.map} +0 -0
  371. /package/dist/{chunk-RLV3PQGH.js.map → chunk-QVO4YOB7.js.map} +0 -0
  372. /package/dist/{chunk-KQAFEZQX.js.map → chunk-VDX2J7OX.js.map} +0 -0
  373. /package/dist/{chunk-IK7DCC5H.js.map → chunk-VMGLYN42.js.map} +0 -0
  374. /package/dist/{chunk-NSKYFGDL.js.map → chunk-X4QQB7O6.js.map} +0 -0
  375. /package/dist/{first-start-migration-GYJWIH36.js.map → first-start-migration-FF7YFGRP.js.map} +0 -0
  376. /package/dist/{tier-stats-SKML2OSF.js.map → tier-stats-3LYQ3VV5.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/access-http.ts"],"sourcesContent":["import { createServer, type IncomingMessage, type Server, type ServerResponse } from \"node:http\";\nimport { randomUUID, timingSafeEqual } from \"node:crypto\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { fileURLToPath, URL } from \"node:url\";\nimport { gunzipSync } from \"node:zlib\";\nimport { log } from \"./logger.js\";\nimport { EngramAccessInputError, type EngramAccessService } from \"./access-service.js\";\nimport { EngramMcpServer } from \"./access-mcp.js\";\nimport { validateRequest, type SchemaName, type SchemaTypeFor } from \"./access-schema.js\";\nimport {\n OFFLINE_SYNC_APPLY_MAX_BODY_BYTES,\n OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES,\n OFFLINE_SYNC_SNAPSHOT_BASE_MAX_BODY_BYTES,\n} from \"./offline-sync.js\";\nimport type { RecallDisclosure, RecallPlanMode } from \"./types.js\";\nimport { isRecallDisclosure } from \"./types.js\";\nimport { isTrustZoneName, type TrustZoneName, type TrustZoneRecordKind, type TrustZoneSourceClass } from \"./trust-zones.js\";\nimport { AdapterRegistry, type ResolvedIdentity } from \"./adapters/index.js\";\nimport type { CitationEntry } from \"./citations.js\";\nimport {\n subscribeGraphEvents,\n type GraphEvent,\n} from \"./graph-events.js\";\nimport { expandTildePath } from \"./utils/path.js\";\nimport { projectTagProjectId } from \"./coding/coding-namespace.js\";\n\nexport interface EngramAccessHttpServerOptions {\n service: EngramAccessService;\n host?: string;\n port?: number;\n authToken?: string;\n /** Additional valid tokens (for multi-connector auth). Checked alongside authToken. */\n authTokens?: string[];\n /** Dynamic token loader — called on each auth check so new/revoked tokens take effect without restart. */\n authTokensGetter?: () => string[];\n principal?: string;\n maxBodyBytes?: number;\n adminConsoleEnabled?: boolean;\n adminConsolePublicDir?: string;\n trustPrincipalHeader?: boolean;\n /** Enable adapter-based identity resolution from request headers */\n enableAdapters?: boolean;\n /** Custom adapter registry (defaults to built-in adapters) */\n adapterRegistry?: AdapterRegistry;\n /** Enable oai-mem-citation blocks in recall responses (issue #379). */\n citationsEnabled?: boolean;\n /** Auto-enable citations for Codex adapter connections (issue #379). */\n citationsAutoDetect?: boolean;\n}\n\nexport interface EngramAccessHttpServerStatus {\n running: boolean;\n host: string;\n port: number;\n maxBodyBytes: number;\n}\n\nfunction resolveDefaultAdminConsolePublicDir(): string {\n const thisDir = path.dirname(fileURLToPath(import.meta.url));\n const candidates = [\n // Standard: admin-console sibling to src/ (development layout)\n path.resolve(thisDir, \"../admin-console/public\"),\n // Bundled: admin-console inside dist/ alongside the bundle\n path.resolve(thisDir, \"./admin-console/public\"),\n // Package root: walk up from dist/ to the package root\n path.resolve(thisDir, \"../../admin-console/public\"),\n ];\n return candidates.find((candidate) => existsSync(candidate)) ?? candidates[0];\n}\n\nconst defaultAdminConsolePublicDir = resolveDefaultAdminConsolePublicDir();\nconst correlationIdStore = new AsyncLocalStorage<string>();\n\nconst WRITE_RATE_LIMIT_WINDOW_MS = 60_000;\nconst WRITE_RATE_LIMIT_MAX_REQUESTS = 30;\nconst TRUST_ZONE_RECORD_KINDS = [\"memory\", \"artifact\", \"state\", \"trajectory\", \"external\"] as const;\nconst TRUST_ZONE_SOURCE_CLASSES = [\"tool_output\", \"web_content\", \"subagent_trace\", \"system_memory\", \"user_input\", \"manual\"] as const;\n\nclass HttpError extends Error {\n readonly code: string;\n readonly details?: unknown;\n constructor(readonly status: number, message: string, code?: string, details?: unknown) {\n super(message);\n this.code = code ?? `http_${status}`;\n this.details = details;\n }\n}\n\nfunction hostToUrlAuthority(host: string): string {\n if (host.includes(\":\") && !host.startsWith(\"[\") && !host.endsWith(\"]\")) {\n return `[${host}]`;\n }\n return host;\n}\n\nfunction parseHttpServerPort(port: number | undefined): number {\n if (port === undefined) return 0;\n if (!Number.isInteger(port) || port < 0 || port > 65535) {\n throw new Error(\"access HTTP port must be an integer from 0 to 65535\");\n }\n return port;\n}\n\nfunction parseTrustZoneKindFilter(raw: string | null): TrustZoneRecordKind | undefined {\n if (raw === null) return undefined;\n if ((TRUST_ZONE_RECORD_KINDS as readonly string[]).includes(raw)) {\n return raw as TrustZoneRecordKind;\n }\n throw new HttpError(400, `kind must be one of ${TRUST_ZONE_RECORD_KINDS.join(\"|\")}`, \"invalid_kind_filter\");\n}\n\nfunction parseTrustZoneSourceClassFilter(raw: string | null): TrustZoneSourceClass | undefined {\n if (raw === null) return undefined;\n if ((TRUST_ZONE_SOURCE_CLASSES as readonly string[]).includes(raw)) {\n return raw as TrustZoneSourceClass;\n }\n throw new HttpError(400, `sourceClass must be one of ${TRUST_ZONE_SOURCE_CLASSES.join(\"|\")}`, \"invalid_source_class_filter\");\n}\n\nfunction parseTrustZoneFilter(raw: string | null): TrustZoneName | undefined {\n if (raw === null) return undefined;\n if (isTrustZoneName(raw)) {\n return raw;\n }\n throw new HttpError(400, \"zone must be one of quarantine|working|trusted\", \"invalid_zone_filter\");\n}\n\nfunction summarizeHttpRequest(req: IncomingMessage): string {\n const method = req.method ?? \"UNKNOWN\";\n try {\n const parsed = new URL(req.url ?? \"/\", \"http://localhost\");\n return `${method} ${parsed.pathname}`;\n } catch {\n return `${method} ${(req.url ?? \"/\").split(\"?\")[0]}`;\n }\n}\n\nfunction parseStrictIntegerQuery(\n raw: string | null,\n field: string,\n defaultValue: number,\n minValue: number,\n): number {\n if (raw === null) return defaultValue;\n if (!/^(?:0|[1-9]\\d*)$/.test(raw)) {\n throw new HttpError(400, `${field} must be an integer`, `invalid_${field}`);\n }\n const value = Number(raw);\n if (!Number.isInteger(value) || value < minValue) {\n throw new HttpError(400, `${field} must be an integer >= ${minValue}`, `invalid_${field}`);\n }\n return value;\n}\n\nfunction parseMemorySort(raw: string | null): \"updated_desc\" | \"updated_asc\" | \"created_desc\" | \"created_asc\" | undefined {\n if (raw === null) return undefined;\n if (\n raw === \"updated_desc\" ||\n raw === \"updated_asc\" ||\n raw === \"created_desc\" ||\n raw === \"created_asc\"\n ) {\n return raw;\n }\n throw new HttpError(400, \"sort must be one of updated_desc|updated_asc|created_desc|created_asc\", \"invalid_sort\");\n}\n\n/**\n * Decode a `:peerId` URL path segment, converting malformed percent-encoded\n * input (e.g., `%E0%A4%A`) into a 400 client error rather than letting\n * `URIError` bubble up as a 500 `internal_error`.\n */\nfunction decodePeerIdSegment(raw: string): string {\n try {\n return decodeURIComponent(raw);\n } catch {\n throw new EngramAccessInputError(\"peerId path segment is not valid percent-encoded input\");\n }\n}\n\nfunction codingContextFromProjectTag(projectTag: string): {\n projectId: string;\n branch: string | null;\n rootPath: string;\n defaultBranch: string | null;\n} {\n const projectId = projectTagProjectId(projectTag);\n return {\n projectId,\n branch: null,\n rootPath: projectId,\n defaultBranch: null,\n };\n}\n\nexport class EngramAccessHttpServer {\n private readonly service: EngramAccessService;\n private readonly host: string;\n private readonly requestedPort: number;\n private readonly authToken?: string;\n private readonly authTokens: string[];\n private readonly authTokensGetter?: () => string[];\n private readonly authenticatedPrincipal?: string;\n private readonly maxBodyBytes: number;\n private readonly adminConsoleEnabled: boolean;\n private readonly adminConsolePublicDir: string;\n private readonly trustPrincipalHeader: boolean;\n private readonly adapterRegistry: AdapterRegistry | null;\n private readonly writeRequestTimestamps: number[] = [];\n private readonly mcpServer: EngramMcpServer;\n private server: Server | null = null;\n private boundPort = 0;\n /** Active SSE response objects for /engram/v1/graph/events. */\n private readonly sseClients = new Set<ServerResponse>();\n /** Throttle batch: pending SSE event batches per client. */\n private readonly sseBatchTimers = new Map<ServerResponse, ReturnType<typeof setTimeout>>();\n private readonly ssePendingBatches = new Map<ServerResponse, GraphEvent[]>();\n /**\n * Per-client cleanup callbacks: clear heartbeat interval, flush timer,\n * unsubscribe from bus, and end the response. Stored here so `stop()`\n * can invoke them even when the client hasn't disconnected yet\n * (Cursor review thread `access-http.ts:232`).\n */\n private readonly sseCleanupFns = new Set<() => void>();\n\n constructor(options: EngramAccessHttpServerOptions) {\n this.service = options.service;\n this.host = options.host?.trim() || \"127.0.0.1\";\n this.requestedPort = parseHttpServerPort(options.port);\n this.authToken = options.authToken?.trim() || undefined;\n this.authTokens = (options.authTokens ?? []).map((t) => t.trim()).filter(Boolean);\n this.authTokensGetter = options.authTokensGetter;\n this.authenticatedPrincipal = options.principal?.trim() || undefined;\n this.maxBodyBytes = Number.isFinite(options.maxBodyBytes)\n ? Math.max(1, Math.floor(options.maxBodyBytes ?? 131072))\n : 131072;\n this.adminConsoleEnabled = options.adminConsoleEnabled !== false;\n this.adminConsolePublicDir = options.adminConsolePublicDir ?? defaultAdminConsolePublicDir;\n this.trustPrincipalHeader = options.trustPrincipalHeader === true;\n this.adapterRegistry = options.enableAdapters !== false\n ? (options.adapterRegistry ?? new AdapterRegistry())\n : null;\n this.mcpServer = new EngramMcpServer(this.service, {\n principal: options.principal,\n citationsEnabled: options.citationsEnabled,\n citationsAutoDetect: options.citationsAutoDetect,\n });\n }\n\n async start(): Promise<EngramAccessHttpServerStatus> {\n if (!this.authToken && this.authTokens.length === 0 && !this.authTokensGetter) {\n throw new Error(\"engram access HTTP requires authToken or authTokens\");\n }\n if (this.server) return this.status();\n\n const server = createServer((req, res) => {\n const correlationId = randomUUID();\n correlationIdStore.run(correlationId, () => {\n void this.handle(req, res, correlationId).catch((err) => {\n log.debug(`engram access HTTP request failed [${correlationId}]: ${err}`);\n if (err instanceof HttpError) {\n const payload: Record<string, unknown> = { error: err.message, code: err.code };\n if (err.details) payload.details = err.details;\n this.respondJson(res, err.status, payload);\n return;\n }\n if (err instanceof EngramAccessInputError) {\n this.respondJson(res, 400, { error: err.message, code: \"input_error\" });\n return;\n }\n if (res.headersSent) {\n res.destroy(err as Error);\n return;\n }\n log.error(\n `engram access HTTP internal error [${correlationId}] ${summarizeHttpRequest(req)}`,\n err,\n );\n this.respondJson(res, 500, { error: \"internal_error\", code: \"internal_error\" });\n });\n });\n });\n\n try {\n await new Promise<void>((resolve, reject) => {\n const onError = (err: Error) => {\n server.off(\"listening\", onListening);\n reject(err);\n };\n const onListening = () => {\n server.off(\"error\", onError);\n resolve();\n };\n server.once(\"error\", onError);\n server.once(\"listening\", onListening);\n server.listen(this.requestedPort, this.host);\n });\n } catch (err) {\n server.close();\n throw err;\n }\n\n this.server = server;\n const address = server.address();\n this.boundPort = typeof address === \"object\" && address ? address.port : this.requestedPort;\n return this.status();\n }\n\n async stop(): Promise<void> {\n if (!this.server) return;\n const server = this.server;\n this.server = null;\n this.boundPort = 0;\n // Invoke each SSE client's cleanup callback so heartbeat intervals,\n // batch timers, and graph-bus subscriptions are all released before the\n // HTTP server closes. Without this, long-running SSE connections leak\n // setInterval handles and EventEmitter listeners (Cursor review thread\n // `access-http.ts:232`).\n for (const cleanup of this.sseCleanupFns) {\n try { cleanup(); } catch { /* ignore */ }\n }\n this.sseCleanupFns.clear();\n // Belt-and-suspenders: clear any state not yet reached by cleanup fns.\n for (const [res, timer] of this.sseBatchTimers.entries()) {\n clearTimeout(timer);\n this.sseBatchTimers.delete(res);\n }\n this.ssePendingBatches.clear();\n for (const res of this.sseClients) {\n try { res.end(); } catch { /* ignore */ }\n }\n this.sseClients.clear();\n await new Promise<void>((resolve, reject) => {\n server.close((err) => (err ? reject(err) : resolve()));\n });\n }\n\n status(): EngramAccessHttpServerStatus {\n return {\n running: this.server !== null,\n host: this.host,\n port: this.boundPort,\n maxBodyBytes: this.maxBodyBytes,\n };\n }\n\n /**\n * Resolve the adapter identity for the incoming request.\n * Includes MCP clientInfo from the last initialize handshake if available.\n * Returns null if no adapter matches or adapters are disabled.\n */\n resolveAdapterIdentity(req: IncomingMessage): ResolvedIdentity | null {\n if (!this.adapterRegistry) return null;\n // Look up clientInfo for this specific MCP session to avoid cross-session leaks.\n // Non-MCP requests (no mcp-session-id header) get undefined clientInfo and\n // rely on HTTP headers for adapter matching.\n const sessionId = (() => {\n const raw = req.headers[\"mcp-session-id\"];\n return typeof raw === \"string\" ? raw.trim() : undefined;\n })();\n return this.adapterRegistry.resolve({\n headers: req.headers as Record<string, string | string[] | undefined>,\n clientInfo: this.mcpServer.getClientInfo(sessionId),\n });\n }\n\n /** Cache for per-request identity resolution (avoids double adapter resolution) */\n private identityCache = new WeakMap<IncomingMessage, { principal?: string; namespace?: string; sessionKey?: string }>();\n\n /** Resolve principal, namespace, and session key from request headers and adapter identity */\n private resolveRequestIdentity(req: IncomingMessage): { principal?: string; namespace?: string; sessionKey?: string } {\n const cached = this.identityCache.get(req);\n if (cached) return cached;\n let principal: string | undefined;\n let namespace: string | undefined;\n let sessionKey: string | undefined;\n\n // Explicit header override takes priority for principal\n if (this.trustPrincipalHeader) {\n const headerVal = req.headers[\"x-engram-principal\"];\n const raw = Array.isArray(headerVal) ? headerVal[0] : headerVal;\n if (typeof raw === \"string\") {\n const trimmed = raw.trim();\n if (trimmed.length > 0) {\n principal = trimmed;\n }\n }\n }\n\n if (!principal) {\n principal = this.authenticatedPrincipal;\n }\n\n // Try adapter-based identity resolution for namespace and, only when no\n // server principal is configured, an adapter-owned default principal.\n const adapterIdentity = this.resolveAdapterIdentity(req);\n if (adapterIdentity) {\n if (!principal) {\n principal = adapterIdentity.principal;\n }\n namespace = adapterIdentity.namespace;\n sessionKey = adapterIdentity.sessionKey;\n }\n\n const result = { principal, namespace, sessionKey };\n this.identityCache.set(req, result);\n return result;\n }\n\n private resolveRequestPrincipal(req: IncomingMessage): string | undefined {\n return this.resolveRequestIdentity(req).principal;\n }\n\n /** Resolve namespace: only use the explicit body value. Adapter-inferred namespace\n * is intentionally NOT used as a fallback for REST requests — omitting namespace\n * should default to the server's global namespace, not silently scope to an adapter. */\n private resolveNamespace(_req: IncomingMessage, bodyNamespace?: string): string | undefined {\n return bodyNamespace || undefined;\n }\n\n /**\n * Resolve the recall disclosure depth from the request (issue #677 PR\n * 2/4). Explicit body value wins; otherwise we accept a\n * `?disclosure=...` query parameter so curl/browser tooling can use the\n * three-tier surface without rewriting JSON. Invalid query values\n * throw `EngramAccessInputError` (CLAUDE.md rule 51 — no silent\n * fallback). An absent body field AND an absent query param yields\n * `undefined`, which the service maps to `DEFAULT_RECALL_DISCLOSURE`.\n */\n private resolveRecallDisclosure(\n bodyDisclosure: RecallDisclosure | undefined,\n parsed: URL,\n ): RecallDisclosure | undefined {\n if (bodyDisclosure !== undefined) {\n return bodyDisclosure;\n }\n const queryDisclosure = parsed.searchParams.get(\"disclosure\");\n if (queryDisclosure === null) {\n return undefined;\n }\n if (!isRecallDisclosure(queryDisclosure)) {\n throw new EngramAccessInputError(\n `disclosure must be one of: chunk, section, raw (got: ${queryDisclosure})`,\n );\n }\n return queryDisclosure;\n }\n\n private async handle(req: IncomingMessage, res: ServerResponse, correlationId: string): Promise<void> {\n const parsed = new URL(req.url ?? \"/\", `http://${hostToUrlAuthority(this.host)}`);\n const pathname = parsed.pathname;\n\n if (this.adminConsoleEnabled && await this.handleAdminConsole(req, res, pathname)) {\n return;\n }\n\n if (!this.isAuthorized(req, pathname)) {\n const body = JSON.stringify({ error: \"unauthorized\", code: \"unauthorized\" });\n res.writeHead(401, {\n \"content-type\": \"application/json; charset=utf-8\",\n \"www-authenticate\": \"Bearer\",\n \"x-request-id\": correlationId,\n });\n res.end(body);\n return;\n }\n\n if (req.method === \"POST\" && pathname === \"/mcp\") {\n await this.handleMcpRequest(req, res);\n return;\n }\n\n if (req.method === \"GET\" && pathname === \"/engram/v1/health\") {\n this.respondJson(res, 200, await this.service.health());\n return;\n }\n\n if (req.method === \"GET\" && pathname === \"/engram/v1/adapters\") {\n const identity = this.resolveAdapterIdentity(req);\n this.respondJson(res, 200, {\n adaptersEnabled: this.adapterRegistry !== null,\n registered: this.adapterRegistry?.list() ?? [],\n resolved: identity,\n });\n return;\n }\n\n if (req.method === \"POST\" && pathname === \"/engram/v1/recall\") {\n const body = await this.readValidatedBody(req, \"recall\");\n // Preserve the distinction between `codingContext: null` (explicit\n // clear) and `codingContext` missing from the JSON payload\n // (untouched). The previous `?? undefined` collapsed both into\n // undefined, so callers lost the ability to clear the session's\n // attached context through the recall endpoint.\n const codingContext =\n \"codingContext\" in body ? body.codingContext : undefined;\n // Disclosure resolution (issue #677 PR 2/4): accept the value from\n // the validated body OR the `?disclosure=` query parameter, with\n // the body taking precedence so an explicit JSON payload is never\n // silently overridden by a stale URL. CLAUDE.md rule 51: invalid\n // query-param values throw, never fall back silently.\n const disclosure = this.resolveRecallDisclosure(body.disclosure, parsed);\n // Issue #680 — historical recall pin (`asOf`). Body field wins\n // over `?as_of=` query param. Empty query is rejected only when\n // the body didn't supply a valid pin (codex P2 + cursor Medium).\n const asOfQueryRaw = parsed.searchParams.get(\"as_of\");\n const bodyHasAsOf =\n typeof body.asOf === \"string\" && body.asOf.length > 0;\n if (\n !bodyHasAsOf &&\n asOfQueryRaw !== null &&\n asOfQueryRaw.length === 0\n ) {\n throw new EngramAccessInputError(\n \"as_of must be a non-empty timestamp (got empty value)\",\n );\n }\n const asOf =\n body.asOf ??\n (asOfQueryRaw !== null && asOfQueryRaw.length > 0\n ? asOfQueryRaw\n : undefined);\n // Tag filter (issue #689). Body presence wins over query params\n // — explicit `tags: []` in body clears the filter even with\n // stale `?tag=` URLs.\n const bodyHasTagsField =\n body !== null &&\n typeof body === \"object\" &&\n \"tags\" in (body as Record<string, unknown>);\n const bodyTagsValue = bodyHasTagsField\n ? (body as { tags?: unknown }).tags\n : undefined;\n const bodyTags = Array.isArray(bodyTagsValue)\n ? (bodyTagsValue as string[])\n : undefined;\n const queryTags = parsed.searchParams.getAll(\"tag\");\n const tags = bodyHasTagsField\n ? bodyTags\n : queryTags.length > 0\n ? queryTags\n : undefined;\n const bodyTagMatch = (body as { tagMatch?: unknown }).tagMatch;\n let tagMatch: \"any\" | \"all\" | undefined;\n if (bodyTagMatch !== undefined) {\n if (bodyTagMatch === \"any\" || bodyTagMatch === \"all\") {\n tagMatch = bodyTagMatch;\n }\n } else {\n const queryTagMatch = parsed.searchParams.get(\"tag_match\");\n if (queryTagMatch !== null) {\n if (queryTagMatch !== \"any\" && queryTagMatch !== \"all\") {\n throw new EngramAccessInputError(\n `tag_match must be one of: any, all (got: ${queryTagMatch})`,\n );\n }\n tagMatch = queryTagMatch;\n }\n }\n // Issue #681 — `?include_low_confidence=true|false` mirrors the CLI\n // `--include-low-confidence` flag. Body field wins so a JSON payload can\n // explicitly clear a stale query parameter.\n const bodyIncludeLowConfidence =\n (body as { includeLowConfidence?: unknown }).includeLowConfidence;\n const queryIncludeLowConfidence = parsed.searchParams.get(\"include_low_confidence\");\n if (\n bodyIncludeLowConfidence === undefined &&\n queryIncludeLowConfidence !== null &&\n queryIncludeLowConfidence !== \"true\" &&\n queryIncludeLowConfidence !== \"false\"\n ) {\n throw new EngramAccessInputError(\n `include_low_confidence must be one of: true, false (got: ${queryIncludeLowConfidence})`,\n );\n }\n const includeLowConfidence =\n bodyIncludeLowConfidence === true ||\n (bodyIncludeLowConfidence === undefined &&\n queryIncludeLowConfidence === \"true\");\n const response = await this.service.recall({\n query: body.query ?? \"\",\n sessionKey: body.sessionKey,\n authenticatedPrincipal: this.resolveRequestPrincipal(req),\n idempotencyKey: body.idempotencyKey,\n namespace: this.resolveNamespace(req, body.namespace),\n topK: body.topK,\n mode: body.mode as RecallPlanMode | \"auto\" | undefined,\n includeDebug: body.includeDebug === true,\n // Forward the validated disclosure depth to the service layer\n // (issue #677). The zod schema accepts/rejects body values;\n // `resolveRecallDisclosure()` validates the query-param fallback.\n disclosure,\n codingContext,\n // Forward cwd/projectTag for auto git-context resolution (issue #569).\n cwd: body.cwd,\n projectTag: body.projectTag,\n ...(asOf !== undefined ? { asOf } : {}),\n ...(tags !== undefined ? { tags } : {}),\n ...(tagMatch !== undefined ? { tagMatch } : {}),\n ...(includeLowConfidence ? { includeLowConfidence: true } : {}),\n });\n this.respondJson(res, 200, response);\n return;\n }\n\n // Attach / clear coding-agent context for a session (issue #569 PR 5).\n // Mirrors `setCodingContext` on the access service. Connectors call this\n // at session start after resolving a git context for the cwd; `remnic\n // doctor` (PR 8) surfaces the attached context.\n if (req.method === \"POST\" && pathname === \"/engram/v1/coding-context\") {\n const body = await this.readValidatedBody(req, \"setCodingContext\");\n const codingContext =\n body.codingContext !== undefined\n ? body.codingContext\n : typeof body.projectTag === \"string\"\n ? codingContextFromProjectTag(body.projectTag)\n : (() => {\n throw new EngramAccessInputError(\"codingContext or projectTag is required\");\n })();\n this.service.setCodingContext({\n sessionKey: body.sessionKey,\n codingContext,\n });\n this.respondJson(res, 200, { ok: true });\n return;\n }\n\n if (\n req.method === \"POST\" &&\n (pathname === \"/engram/v1/capsules/export\" || pathname === \"/remnic/v1/capsules/export\")\n ) {\n const body = await this.readValidatedBody(req, \"capsuleExport\");\n this.ensureWriteRateLimitAvailable();\n const result = await this.service.capsuleExport({\n name: body.name,\n namespace: this.resolveNamespace(req, body.namespace),\n principal: this.resolveRequestPrincipal(req),\n since: body.since,\n includeKinds: body.includeKinds,\n peerIds: body.peerIds,\n includeTranscripts: body.includeTranscripts,\n encrypt: body.encrypt,\n });\n this.recordWriteRateLimitHit();\n this.respondJson(res, 200, result);\n return;\n }\n\n if (\n req.method === \"POST\" &&\n (pathname === \"/engram/v1/capsules/import\" || pathname === \"/remnic/v1/capsules/import\")\n ) {\n const body = await this.readValidatedBody(req, \"capsuleImport\");\n this.ensureWriteRateLimitAvailable();\n const result = await this.service.capsuleImport({\n archivePath: expandTildePath(body.archivePath),\n namespace: this.resolveNamespace(req, body.namespace),\n principal: this.resolveRequestPrincipal(req),\n mode: body.mode,\n passphrase: body.passphrase,\n });\n this.recordWriteRateLimitHit();\n this.respondJson(res, 200, result);\n return;\n }\n\n if (\n req.method === \"GET\" &&\n (pathname === \"/engram/v1/offline-sync/snapshot\" || pathname === \"/remnic/v1/offline-sync/snapshot\")\n ) {\n const includeTranscriptsRaw = parsed.searchParams.get(\"include_transcripts\");\n const includeContentRaw = parsed.searchParams.get(\"content\");\n if (\n includeTranscriptsRaw !== null &&\n includeTranscriptsRaw !== \"true\" &&\n includeTranscriptsRaw !== \"false\"\n ) {\n throw new EngramAccessInputError(\n `include_transcripts must be one of: true, false (got: ${includeTranscriptsRaw})`,\n );\n }\n if (\n includeContentRaw !== null &&\n includeContentRaw !== \"true\" &&\n includeContentRaw !== \"false\"\n ) {\n throw new EngramAccessInputError(\n `content must be one of: true, false (got: ${includeContentRaw})`,\n );\n }\n const namespaceParam = parsed.searchParams.get(\"namespace\");\n const result = await this.service.offlineSyncSnapshot({\n namespace: this.resolveNamespace(\n req,\n namespaceParam && namespaceParam.length > 0 ? namespaceParam : undefined,\n ),\n principal: this.resolveRequestPrincipal(req),\n includeTranscripts: includeTranscriptsRaw !== \"false\",\n includeContent: includeContentRaw !== \"false\",\n });\n this.respondJson(res, 200, result);\n return;\n }\n\n if (\n req.method === \"GET\" &&\n (pathname === \"/engram/v1/offline-sync/snapshot-stream\" ||\n pathname === \"/remnic/v1/offline-sync/snapshot-stream\")\n ) {\n const includeTranscriptsRaw = parsed.searchParams.get(\"include_transcripts\");\n const includeContentRaw = parsed.searchParams.get(\"content\");\n if (\n includeTranscriptsRaw !== null &&\n includeTranscriptsRaw !== \"true\" &&\n includeTranscriptsRaw !== \"false\"\n ) {\n throw new EngramAccessInputError(\n `include_transcripts must be one of: true, false (got: ${includeTranscriptsRaw})`,\n );\n }\n if (\n includeContentRaw !== null &&\n includeContentRaw !== \"false\"\n ) {\n throw new EngramAccessInputError(\"snapshot-stream content must be false\");\n }\n const namespaceParam = parsed.searchParams.get(\"namespace\");\n const result = await this.service.offlineSyncSnapshotStream({\n namespace: this.resolveNamespace(\n req,\n namespaceParam && namespaceParam.length > 0 ? namespaceParam : undefined,\n ),\n principal: this.resolveRequestPrincipal(req),\n includeTranscripts: includeTranscriptsRaw !== \"false\",\n includeContent: false,\n signal: this.createRequestAbortSignal(req, res),\n });\n await this.respondOfflineSnapshotStream(res, result);\n return;\n }\n\n if (\n req.method === \"POST\" &&\n (pathname === \"/engram/v1/offline-sync/snapshot\" || pathname === \"/remnic/v1/offline-sync/snapshot\")\n ) {\n const body = await this.readValidatedBody(\n req,\n \"offlineSyncSnapshot\",\n OFFLINE_SYNC_SNAPSHOT_BASE_MAX_BODY_BYTES,\n );\n const result = await this.service.offlineSyncSnapshot({\n namespace: this.resolveNamespace(req, body.namespace),\n principal: this.resolveRequestPrincipal(req),\n includeTranscripts: body.includeTranscripts,\n includeContent: body.includeContent,\n baseFiles: body.baseFiles,\n ...(body.baseCapturedAt ? { baseCapturedAt: new Date(body.baseCapturedAt) } : {}),\n signal: this.createRequestAbortSignal(req, res),\n });\n this.respondJson(res, 200, result);\n return;\n }\n\n if (\n req.method === \"POST\" &&\n (pathname === \"/engram/v1/offline-sync/files\" || pathname === \"/remnic/v1/offline-sync/files\")\n ) {\n const body = await this.readValidatedBody(req, \"offlineSyncFiles\");\n const result = await this.service.offlineSyncFiles({\n namespace: this.resolveNamespace(req, body.namespace),\n principal: this.resolveRequestPrincipal(req),\n includeTranscripts: body.includeTranscripts,\n paths: body.paths,\n });\n this.respondJson(res, 200, result);\n return;\n }\n\n if (\n req.method === \"POST\" &&\n (\n pathname === \"/engram/v1/offline-sync/file-content\" ||\n pathname === \"/remnic/v1/offline-sync/file-content\"\n )\n ) {\n const body = await this.readValidatedBody(req, \"offlineSyncFileContent\");\n const result = await this.service.offlineSyncFileContent({\n namespace: this.resolveNamespace(req, body.namespace),\n principal: this.resolveRequestPrincipal(req),\n includeTranscripts: body.includeTranscripts,\n path: body.path,\n offset: body.offset,\n length: body.length,\n });\n this.respondBinary(res, 200, result.content, {\n \"x-remnic-namespace\": encodeURIComponent(result.namespace),\n \"x-remnic-file-path\": encodeURIComponent(result.path),\n \"x-remnic-file-bytes\": String(result.bytes),\n \"x-remnic-file-mtime-ms\": String(result.mtimeMs),\n \"x-remnic-chunk-offset\": String(result.offset),\n \"x-remnic-chunk-bytes\": String(result.chunkBytes),\n ...(result.sha256 ? { \"x-remnic-file-sha256\": result.sha256 } : {}),\n });\n return;\n }\n\n if (\n req.method === \"POST\" &&\n (\n pathname === \"/engram/v1/offline-sync/apply-file-content\" ||\n pathname === \"/remnic/v1/offline-sync/apply-file-content\"\n )\n ) {\n const namespaceParam = parsed.searchParams.get(\"namespace\");\n const bytes = this.readRequiredIntegerHeader(req, \"x-remnic-file-bytes\");\n const offset = this.readOptionalIntegerHeader(req, \"x-remnic-chunk-offset\") ?? 0;\n const content = await this.readBinaryBody(req, OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES);\n const result = await this.service.offlineSyncApplyFileContent({\n namespace: this.resolveNamespace(\n req,\n namespaceParam && namespaceParam.length > 0 ? namespaceParam : undefined,\n ),\n principal: this.resolveRequestPrincipal(req),\n includeTranscripts: this.parseOptionalBooleanHeader(\n req,\n \"x-remnic-include-transcripts\",\n true,\n ),\n sourceId: this.readRequiredDecodedHeader(req, \"x-remnic-source-id\"),\n path: this.readRequiredDecodedHeader(req, \"x-remnic-file-path\"),\n sha256: this.readRequiredHeader(req, \"x-remnic-file-sha256\"),\n bytes,\n mtimeMs: this.readRequiredNumberHeader(req, \"x-remnic-file-mtime-ms\"),\n offset,\n baseSha256: this.readOptionalHeader(req, \"x-remnic-base-sha256\"),\n content,\n });\n this.respondJson(res, 200, result);\n return;\n }\n\n if (\n req.method === \"POST\" &&\n (pathname === \"/engram/v1/offline-sync/apply\" || pathname === \"/remnic/v1/offline-sync/apply\")\n ) {\n const body = await this.readValidatedBody(req, \"offlineSyncApply\", OFFLINE_SYNC_APPLY_MAX_BODY_BYTES);\n const result = await this.service.offlineSyncApply({\n namespace: this.resolveNamespace(req, body.namespace),\n principal: this.resolveRequestPrincipal(req),\n changeset: body.changeset,\n returnCurrentFiles: body.returnCurrentFiles,\n });\n this.respondJson(res, 200, result);\n return;\n }\n\n if (req.method === \"POST\" && pathname === \"/engram/v1/recall/explain\") {\n const body = await this.readValidatedBody(req, \"recallExplain\");\n const response = await this.service.recallExplain({\n sessionKey: body.sessionKey,\n namespace: this.resolveNamespace(req, body.namespace),\n authenticatedPrincipal: this.resolveRequestPrincipal(req),\n });\n this.respondJson(res, 200, response);\n return;\n }\n\n if (\n req.method === \"POST\" &&\n (pathname === \"/engram/v1/action-confidence\" || pathname === \"/remnic/v1/action-confidence\")\n ) {\n const body = await this.readValidatedBody(req, \"actionConfidence\");\n this.respondJson(res, 200, await this.service.actionConfidence(body));\n return;\n }\n\n // Tier-explain (issue #518): structured per-result annotation from\n // the direct-answer retrieval tier. Orthogonal to /recall/explain\n // above, which returns a graph-path explanation document.\n if (req.method === \"GET\" && pathname === \"/engram/v1/recall/tier-explain\") {\n const sessionParam = parsed.searchParams.get(\"session\");\n const sessionKey = sessionParam && sessionParam.length > 0 ? sessionParam : undefined;\n const namespaceParam = parsed.searchParams.get(\"namespace\");\n const namespace = this.resolveNamespace(\n req,\n namespaceParam && namespaceParam.length > 0 ? namespaceParam : undefined,\n );\n const payload = await this.service.recallTierExplain(\n sessionKey,\n namespace,\n this.resolveRequestPrincipal(req),\n );\n this.respondJson(res, 200, payload);\n return;\n }\n\n // Recall X-ray (issue #570 PR 4): unified per-result attribution\n // snapshot. Requires bearer auth (same as every other endpoint\n // here) and enforces namespace scope before the recall fires\n // (CLAUDE.md rule 42). Query comes from the `q` search param so\n // GET stays cacheable; `namespace` / `session` / `budget` are\n // optional.\n if (req.method === \"GET\" && pathname === \"/engram/v1/recall/xray\") {\n const queryParam = parsed.searchParams.get(\"q\");\n if (!queryParam || queryParam.trim().length === 0) {\n this.respondJson(res, 400, {\n error: \"missing_query\",\n code: \"missing_query\",\n message: \"q search parameter is required and must be non-empty\",\n });\n return;\n }\n const sessionParam = parsed.searchParams.get(\"session\");\n const sessionKey = sessionParam && sessionParam.length > 0\n ? sessionParam\n : undefined;\n const namespaceParam = parsed.searchParams.get(\"namespace\");\n const namespace = this.resolveNamespace(\n req,\n namespaceParam && namespaceParam.length > 0\n ? namespaceParam\n : undefined,\n );\n const budgetParam = parsed.searchParams.get(\"budget\");\n // Reject invalid `budget` with 400 rather than silently\n // defaulting (CLAUDE.md rules 14 + 51).\n let budget: number | undefined;\n if (budgetParam !== null && budgetParam !== \"\") {\n const parsedBudget = Number(budgetParam);\n if (\n !Number.isFinite(parsedBudget)\n || parsedBudget <= 0\n || !Number.isInteger(parsedBudget)\n ) {\n this.respondJson(res, 400, {\n error: \"invalid_budget\",\n code: \"invalid_budget\",\n message:\n \"budget expects a positive integer\",\n });\n return;\n }\n budget = parsedBudget;\n }\n // Disclosure depth (issue #677 PR 3/4 telemetry plumbing). When\n // present, must match the chunk|section|raw allow-list; invalid\n // values surface as a 400 (CLAUDE.md rule 51 — no silent\n // fallback) rather than silently disabling the per-disclosure\n // summary table.\n const disclosureParam = parsed.searchParams.get(\"disclosure\");\n let disclosure: RecallDisclosure | undefined;\n if (disclosureParam !== null && disclosureParam.length > 0) {\n if (!isRecallDisclosure(disclosureParam)) {\n this.respondJson(res, 400, {\n error: \"invalid_disclosure\",\n code: \"invalid_disclosure\",\n message:\n \"disclosure must be one of: chunk, section, raw\",\n });\n return;\n }\n disclosure = disclosureParam;\n }\n // Only translate validation errors (empty query, bad budget)\n // into 400s. Backend faults (timeouts, storage errors,\n // unexpected orchestrator failures) must bubble to the global\n // `handle()` error handler so they return 500 and get logged\n // properly. `service.recallXray` prefixes its validation\n // errors with \"recallXray:\" so we key off that prefix rather\n // than catching everything.\n let payload: Awaited<ReturnType<typeof this.service.recallXray>>;\n try {\n payload = await this.service.recallXray({\n query: queryParam,\n sessionKey,\n namespace,\n budget,\n authenticatedPrincipal: this.resolveRequestPrincipal(req),\n ...(disclosure !== undefined ? { disclosure } : {}),\n });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n if (message.startsWith(\"recallXray:\")) {\n this.respondJson(res, 400, {\n error: \"invalid_request\",\n code: \"invalid_request\",\n message,\n });\n return;\n }\n // Anything else is a server-side fault; rethrow so the\n // outer `handle()` catch returns 500 + logs the error.\n throw err;\n }\n this.respondJson(res, 200, payload);\n return;\n }\n\n if (req.method === \"POST\" && pathname === \"/engram/v1/observe\") {\n const body = await this.readValidatedBody(req, \"observe\");\n this.ensureWriteRateLimitAvailable();\n const response = await this.service.observe({\n sessionKey: body.sessionKey,\n messages: body.messages.map((message) => ({\n role: message.role,\n content: message.content,\n sourceFormat: message.sourceFormat ?? undefined,\n rawContent: message.rawContent ?? undefined,\n parts: message.parts ?? undefined,\n })),\n namespace: this.resolveNamespace(req, body.namespace),\n authenticatedPrincipal: this.resolveRequestPrincipal(req),\n skipExtraction: body.skipExtraction === true,\n // Forward cwd/projectTag for auto git-context resolution (issue #569).\n cwd: body.cwd,\n projectTag: body.projectTag,\n });\n this.recordWriteRateLimitHit();\n this.respondJson(res, 202, response);\n return;\n }\n\n if (req.method === \"POST\" && pathname === \"/engram/v1/lcm/search\") {\n const body = await this.readValidatedBody(req, \"lcmSearch\");\n const response = await this.service.lcmSearch({\n query: body.query,\n sessionKey: body.sessionKey,\n sessionPrefix: body.sessionPrefix,\n namespace: this.resolveNamespace(req, body.namespace),\n authenticatedPrincipal: this.resolveRequestPrincipal(req),\n limit: body.limit,\n });\n this.respondJson(res, 200, response);\n return;\n }\n\n if (\n req.method === \"POST\" &&\n (pathname === \"/engram/v1/lcm/compaction/flush\" || pathname === \"/remnic/v1/lcm/compaction/flush\")\n ) {\n const body = await this.readValidatedBody(req, \"lcmCompactionFlush\");\n this.ensureWriteRateLimitAvailable();\n const response = await this.service.lcmCompactionFlush({\n sessionKey: body.sessionKey,\n namespace: this.resolveNamespace(req, body.namespace),\n authenticatedPrincipal: this.resolveRequestPrincipal(req),\n });\n this.recordWriteRateLimitHit();\n this.respondJson(res, 200, response);\n return;\n }\n\n if (\n req.method === \"POST\" &&\n (pathname === \"/engram/v1/lcm/compaction/record\" || pathname === \"/remnic/v1/lcm/compaction/record\")\n ) {\n const body = await this.readValidatedBody(req, \"lcmCompactionRecord\");\n this.ensureWriteRateLimitAvailable();\n const response = await this.service.lcmCompactionRecord({\n sessionKey: body.sessionKey,\n namespace: this.resolveNamespace(req, body.namespace),\n tokensBefore: body.tokensBefore,\n tokensAfter: body.tokensAfter,\n authenticatedPrincipal: this.resolveRequestPrincipal(req),\n });\n this.recordWriteRateLimitHit();\n this.respondJson(res, 200, response);\n return;\n }\n\n if (req.method === \"GET\" && pathname === \"/engram/v1/lcm/status\") {\n this.respondJson(res, 200, await this.service.lcmStatus());\n return;\n }\n\n if (req.method === \"POST\" && pathname === \"/engram/v1/memories\") {\n const body = await this.readValidatedBody(req, \"memoryStore\");\n const request = {\n schemaVersion: body.schemaVersion,\n idempotencyKey: body.idempotencyKey,\n dryRun: body.dryRun === true,\n sessionKey: body.sessionKey,\n authenticatedPrincipal: this.resolveRequestPrincipal(req),\n content: body.content,\n category: body.category,\n confidence: body.confidence,\n namespace: this.resolveNamespace(req, body.namespace),\n tags: body.tags,\n entityRef: body.entityRef,\n ttl: body.ttl,\n sourceReason: body.sourceReason,\n };\n const idempotencyStatus = await this.service.peekMemoryStoreIdempotency(request);\n if (idempotencyStatus === \"miss\" && request.dryRun !== true) {\n this.ensureWriteRateLimitAvailable();\n }\n const response = await this.service.memoryStore(request);\n if (this.shouldCountWriteRateLimit(response as { dryRun?: boolean; idempotencyReplay?: boolean })) {\n this.recordWriteRateLimitHit();\n }\n this.respondJson(res, this.writeResponseStatus(response), response);\n return;\n }\n\n if (req.method === \"POST\" && pathname === \"/engram/v1/suggestions\") {\n const body = await this.readValidatedBody(req, \"suggestionSubmit\");\n const request = {\n schemaVersion: body.schemaVersion,\n idempotencyKey: body.idempotencyKey,\n dryRun: body.dryRun === true,\n sessionKey: body.sessionKey,\n authenticatedPrincipal: this.resolveRequestPrincipal(req),\n content: body.content,\n category: body.category,\n confidence: body.confidence,\n namespace: this.resolveNamespace(req, body.namespace),\n tags: body.tags,\n entityRef: body.entityRef,\n ttl: body.ttl,\n sourceReason: body.sourceReason,\n };\n const idempotencyStatus = await this.service.peekSuggestionSubmitIdempotency(request);\n if (idempotencyStatus === \"miss\" && request.dryRun !== true) {\n this.ensureWriteRateLimitAvailable();\n }\n const response = await this.service.suggestionSubmit(request);\n if (this.shouldCountWriteRateLimit(response as { dryRun?: boolean; idempotencyReplay?: boolean })) {\n this.recordWriteRateLimitHit();\n }\n this.respondJson(res, this.writeResponseStatus(response), response);\n return;\n }\n\n if (req.method === \"GET\" && pathname === \"/engram/v1/memories\") {\n const limit = parseStrictIntegerQuery(parsed.searchParams.get(\"limit\"), \"limit\", 50, 1);\n const offset = parseStrictIntegerQuery(parsed.searchParams.get(\"offset\"), \"offset\", 0, 0);\n const sort = parseMemorySort(parsed.searchParams.get(\"sort\"));\n const response = await this.service.memoryBrowse({\n query: parsed.searchParams.get(\"q\") ?? undefined,\n status: parsed.searchParams.get(\"status\") ?? undefined,\n category: parsed.searchParams.get(\"category\") ?? undefined,\n namespace: parsed.searchParams.get(\"namespace\") ?? undefined,\n authenticatedPrincipal: this.resolveRequestPrincipal(req),\n sort,\n limit,\n offset,\n });\n this.respondJson(res, 200, response);\n return;\n }\n\n const memoryMatch = pathname.match(/^\\/engram\\/v1\\/memories\\/([^/]+)$/);\n if (req.method === \"GET\" && memoryMatch) {\n const memoryId = decodeURIComponent(memoryMatch[1] ?? \"\");\n const namespace = parsed.searchParams.get(\"namespace\") ?? undefined;\n const response = await this.service.memoryGet(memoryId, namespace, this.resolveRequestPrincipal(req));\n this.respondJson(res, response.found ? 200 : 404, response);\n return;\n }\n\n const timelineMatch = pathname.match(/^\\/engram\\/v1\\/memories\\/([^/]+)\\/timeline$/);\n if (req.method === \"GET\" && timelineMatch) {\n const memoryId = decodeURIComponent(timelineMatch[1] ?? \"\");\n const namespace = parsed.searchParams.get(\"namespace\") ?? undefined;\n const limit = parseStrictIntegerQuery(parsed.searchParams.get(\"limit\"), \"limit\", 200, 1);\n const response = await this.service.memoryTimeline(memoryId, namespace, limit, this.resolveRequestPrincipal(req));\n this.respondJson(res, response.found ? 200 : 404, response);\n return;\n }\n\n if (req.method === \"GET\" && pathname === \"/engram/v1/entities\") {\n const limit = parseStrictIntegerQuery(parsed.searchParams.get(\"limit\"), \"limit\", 50, 1);\n const offset = parseStrictIntegerQuery(parsed.searchParams.get(\"offset\"), \"offset\", 0, 0);\n const response = await this.service.entityList({\n namespace: parsed.searchParams.get(\"namespace\") ?? undefined,\n query: parsed.searchParams.get(\"q\") ?? undefined,\n limit,\n offset,\n });\n this.respondJson(res, 200, response);\n return;\n }\n\n const entityMatch = pathname.match(/^\\/engram\\/v1\\/entities\\/([^/]+)$/);\n if (req.method === \"GET\" && entityMatch) {\n const entityName = decodeURIComponent(entityMatch[1] ?? \"\");\n const namespace = parsed.searchParams.get(\"namespace\") ?? undefined;\n const response = await this.service.entityGet(entityName, namespace);\n this.respondJson(res, response.found ? 200 : 404, response);\n return;\n }\n\n if (req.method === \"GET\" && pathname === \"/engram/v1/review-queue\") {\n const response = await this.service.reviewQueue(\n parsed.searchParams.get(\"runId\") ?? undefined,\n parsed.searchParams.get(\"namespace\") ?? undefined,\n this.resolveRequestPrincipal(req),\n );\n this.respondJson(res, 200, response);\n return;\n }\n\n if (req.method === \"GET\" && pathname === \"/engram/v1/maintenance\") {\n this.respondJson(res, 200, await this.service.maintenance(parsed.searchParams.get(\"namespace\") ?? undefined, this.resolveRequestPrincipal(req)));\n return;\n }\n\n if (req.method === \"GET\" && pathname === \"/engram/v1/quality\") {\n this.respondJson(res, 200, await this.service.quality(parsed.searchParams.get(\"namespace\") ?? undefined, this.resolveRequestPrincipal(req)));\n return;\n }\n\n if (req.method === \"GET\" && pathname === \"/engram/v1/trust-zones/status\") {\n this.respondJson(\n res,\n 200,\n await this.service.trustZoneStatus(parsed.searchParams.get(\"namespace\") ?? undefined, this.resolveRequestPrincipal(req)),\n );\n return;\n }\n\n // Procedural memory stats (issue #567 PR 5/5). Read-only; namespace is\n // scoped via the same resolver used by recall/trust-zones so cross-\n // tenant reads aren't possible (CLAUDE.md rule 42).\n if (req.method === \"GET\" && pathname === \"/engram/v1/procedural/stats\") {\n const namespaceParam = parsed.searchParams.get(\"namespace\");\n this.respondJson(\n res,\n 200,\n await this.service.procedureStats(\n {\n namespace: this.resolveNamespace(\n req,\n namespaceParam && namespaceParam.length > 0\n ? namespaceParam\n : undefined,\n ),\n },\n this.resolveRequestPrincipal(req),\n ),\n );\n return;\n }\n\n if (req.method === \"GET\" && pathname === \"/engram/v1/trust-zones/records\") {\n const limit = parseStrictIntegerQuery(parsed.searchParams.get(\"limit\"), \"limit\", 25, 1);\n const offset = parseStrictIntegerQuery(parsed.searchParams.get(\"offset\"), \"offset\", 0, 0);\n const response = await this.service.trustZoneBrowse({\n query: parsed.searchParams.get(\"q\") ?? undefined,\n zone: parseTrustZoneFilter(parsed.searchParams.get(\"zone\")),\n kind: parseTrustZoneKindFilter(parsed.searchParams.get(\"kind\")),\n sourceClass: parseTrustZoneSourceClassFilter(parsed.searchParams.get(\"sourceClass\")),\n namespace: parsed.searchParams.get(\"namespace\") ?? undefined,\n limit,\n offset,\n }, this.resolveRequestPrincipal(req));\n this.respondJson(res, 200, response);\n return;\n }\n\n if (req.method === \"POST\" && pathname === \"/engram/v1/review-disposition\") {\n const body = await this.readValidatedBody(req, \"reviewDisposition\");\n this.ensureWriteRateLimitAvailable();\n const response = await this.service.reviewDisposition({\n memoryId: body.memoryId,\n status: body.status,\n reasonCode: body.reasonCode,\n namespace: this.resolveNamespace(req, body.namespace),\n authenticatedPrincipal: this.resolveRequestPrincipal(req),\n });\n if (this.shouldCountWriteRateLimit(response as unknown as { dryRun?: boolean; idempotencyReplay?: boolean })) {\n this.recordWriteRateLimitHit();\n }\n this.respondJson(res, 200, response);\n return;\n }\n\n if (req.method === \"POST\" && pathname === \"/engram/v1/trust-zones/promote\") {\n const body = await this.readValidatedBody(req, \"trustZonePromote\");\n const dryRun = body.dryRun === true;\n if (!dryRun) {\n this.ensureWriteRateLimitAvailable();\n }\n const response = await this.service.trustZonePromote({\n recordId: body.recordId,\n targetZone: body.targetZone,\n promotionReason: body.promotionReason,\n recordedAt: body.recordedAt,\n summary: body.summary,\n dryRun,\n namespace: this.resolveNamespace(req, body.namespace),\n authenticatedPrincipal: this.resolveRequestPrincipal(req),\n });\n if (this.shouldCountWriteRateLimit(response as unknown as { dryRun?: boolean; idempotencyReplay?: boolean })) {\n this.recordWriteRateLimitHit();\n }\n this.respondJson(res, response.dryRun ? 200 : 201, response);\n return;\n }\n\n if (req.method === \"POST\" && pathname === \"/engram/v1/trust-zones/demo-seed\") {\n const body = await this.readValidatedBody(req, \"trustZoneDemoSeed\");\n const dryRun = body.dryRun === true;\n if (!dryRun) {\n this.ensureWriteRateLimitAvailable();\n }\n const response = await this.service.trustZoneDemoSeed({\n scenario: body.scenario,\n recordedAt: body.recordedAt,\n dryRun,\n namespace: this.resolveNamespace(req, body.namespace),\n authenticatedPrincipal: this.resolveRequestPrincipal(req),\n });\n if (this.shouldCountWriteRateLimit(response as unknown as { dryRun?: boolean; idempotencyReplay?: boolean })) {\n this.recordWriteRateLimitHit();\n }\n this.respondJson(res, response.dryRun ? 200 : 201, response);\n return;\n }\n\n // Citation usage tracking (issue #379)\n if (req.method === \"POST\" && pathname === \"/v1/citations/observed\") {\n const body = await this.readJsonBody(req);\n if (!body || typeof body !== \"object\" || Array.isArray(body)) {\n throw new HttpError(400, \"request body must be a JSON object\", \"invalid_body\");\n }\n const payload = body as Record<string, unknown>;\n const sessionId = typeof payload.sessionId === \"string\" ? payload.sessionId : undefined;\n const namespace = typeof payload.namespace === \"string\" ? payload.namespace : undefined;\n const citationsRaw = payload.citations;\n if (!citationsRaw || typeof citationsRaw !== \"object\" || Array.isArray(citationsRaw)) {\n throw new HttpError(400, \"citations must be a JSON object with entries and rolloutIds\", \"invalid_citations\");\n }\n const citObj = citationsRaw as Record<string, unknown>;\n const entries: CitationEntry[] = [];\n if (Array.isArray(citObj.entries)) {\n for (const raw of citObj.entries) {\n if (raw && typeof raw === \"object\" && !Array.isArray(raw)) {\n const e = raw as Record<string, unknown>;\n if (\n typeof e.path === \"string\" &&\n typeof e.lineStart === \"number\" &&\n typeof e.lineEnd === \"number\"\n ) {\n entries.push({\n path: e.path,\n lineStart: e.lineStart,\n lineEnd: e.lineEnd,\n note: typeof e.note === \"string\" ? e.note : \"\",\n });\n }\n }\n }\n }\n const rolloutIds: string[] = [];\n if (Array.isArray(citObj.rolloutIds)) {\n for (const id of citObj.rolloutIds) {\n if (typeof id === \"string\" && id.length > 0) {\n rolloutIds.push(id);\n }\n }\n }\n\n // Record usage: for each citation entry, try to increment usage on the\n // matching memory. The service exposes recordAccess for this purpose.\n // Pass authenticatedPrincipal so namespace ACL checks use the same\n // identity resolution as other write endpoints (Finding #1, issue #379).\n let matched = 0;\n let submitted = 0;\n if (typeof this.service.recordCitationUsage === \"function\") {\n const result = await this.service.recordCitationUsage({\n sessionId,\n namespace: this.resolveNamespace(req, namespace),\n authenticatedPrincipal: this.resolveRequestPrincipal(req),\n entries,\n rolloutIds,\n });\n submitted = result.submitted;\n matched = result.matched;\n }\n\n this.respondJson(res, 200, {\n ok: true,\n submitted,\n matched,\n entriesReceived: entries.length,\n rolloutIdsReceived: rolloutIds.length,\n });\n return;\n }\n\n // ── Contradiction Review (issue #520) ─────────────────────────────────────\n if (req.method === \"GET\" && pathname === \"/engram/v1/review/contradictions\") {\n const VALID_FILTERS = new Set([\"all\", \"unresolved\", \"contradicts\", \"independent\", \"duplicates\", \"needs-user\"]);\n const rawFilter = parsed.searchParams.get(\"filter\") ?? \"unresolved\";\n if (!VALID_FILTERS.has(rawFilter)) {\n this.respondJson(res, 400, { error: `Invalid filter '${rawFilter}'. Valid: ${[...VALID_FILTERS].join(\", \")}` });\n return;\n }\n const namespace = parsed.searchParams.get(\"namespace\") ?? undefined;\n const limit = parseStrictIntegerQuery(parsed.searchParams.get(\"limit\"), \"limit\", 50, 1);\n const {\n isDefaultReviewNamespace,\n listPairs,\n } = await import(\"./contradiction/contradiction-review.js\");\n const principal = this.resolveRequestPrincipal(req);\n const resolved = await this.service.getReadableStorageForNamespace(namespace, principal);\n const reviewNamespace = this.service.configRef.namespacesEnabled ? resolved.namespace : undefined;\n const includeUnscopedForNamespace = Boolean(\n reviewNamespace && isDefaultReviewNamespace(this.service.configRef.defaultNamespace, namespace, reviewNamespace),\n );\n const result = listPairs(this.service.memoryDir, {\n filter: rawFilter as \"all\" | \"unresolved\" | \"contradicts\" | \"independent\" | \"duplicates\" | \"needs-user\",\n namespace: reviewNamespace,\n includeUnscopedForNamespace,\n limit,\n });\n this.respondJson(res, 200, result);\n return;\n }\n\n if (req.method === \"GET\" && pathname.startsWith(\"/engram/v1/review/contradictions/\")) {\n const pairId = pathname.split(\"/\").pop() ?? \"\";\n const { readPair } = await import(\"./contradiction/contradiction-review.js\");\n const pair = readPair(this.service.memoryDir, pairId);\n if (!pair) {\n this.respondJson(res, 404, { error: \"pair_not_found\" });\n return;\n }\n try {\n await this.service.getReadableStorageForNamespace(pair.namespace, this.resolveRequestPrincipal(req));\n } catch {\n this.respondJson(res, 404, { error: \"pair_not_found\" });\n return;\n }\n this.respondJson(res, 200, pair);\n return;\n }\n\n if (req.method === \"POST\" && pathname === \"/engram/v1/review/resolve\") {\n const body = await this.readJsonBody(req) as Record<string, unknown>;\n const pairId = typeof body.pairId === \"string\" ? body.pairId : \"\";\n const verb = typeof body.verb === \"string\" ? body.verb : \"\";\n if (!pairId || !verb) {\n this.respondJson(res, 400, { error: \"pairId and verb are required\" });\n return;\n }\n const { isValidResolutionVerb, executeResolution } = await import(\"./contradiction/resolution.js\");\n if (!isValidResolutionVerb(verb)) {\n this.respondJson(res, 400, { error: `Invalid verb: ${verb}. Must be one of: keep-a, keep-b, merge, both-valid, needs-more-context` });\n return;\n }\n const principal = this.resolveRequestPrincipal(req);\n const result = await executeResolution(this.service.memoryDir, this.service.storageRef, pairId, verb, {\n mergedMemoryId: typeof body.mergedMemoryId === \"string\" ? body.mergedMemoryId : undefined,\n mergedContent: typeof body.mergedContent === \"string\" ? body.mergedContent : undefined,\n storageForNamespace: async (namespace) => {\n const resolved = await this.service.getWritableStorageForNamespace(namespace, principal);\n return resolved.storage;\n },\n });\n this.respondJson(res, 200, result);\n return;\n }\n\n // Graph snapshot (issue #691 PR 2/5) — read-only adjacency view used by\n // the admin-pane scaffold shipped in PR 1/5. All filters are query\n // params so the surface stays cacheable; invalid values yield 400 with\n // a descriptive body (CLAUDE.md rule 51 — never silently default).\n if (req.method === \"GET\" && pathname === \"/engram/v1/graph/snapshot\") {\n const limitRaw = parsed.searchParams.get(\"limit\");\n let limit: number | undefined;\n if (limitRaw !== null && limitRaw.length > 0) {\n const parsedLimit = Number(limitRaw);\n if (\n !Number.isFinite(parsedLimit)\n || !Number.isInteger(parsedLimit)\n || parsedLimit <= 0\n ) {\n this.respondJson(res, 400, {\n error: \"invalid_limit\",\n code: \"invalid_limit\",\n message: \"limit must be a positive integer\",\n });\n return;\n }\n limit = parsedLimit;\n }\n const sinceRaw = parsed.searchParams.get(\"since\");\n let since: string | undefined;\n if (sinceRaw !== null && sinceRaw.length > 0) {\n // Validate up-front so the access service can stay focused on the\n // pure snapshot logic (parser also runs there as a defense in\n // depth, but rejecting at the boundary preserves the\n // \"invalid_since\" error code instead of leaking a generic 500).\n if (!Number.isFinite(Date.parse(sinceRaw))) {\n this.respondJson(res, 400, {\n error: \"invalid_since\",\n code: \"invalid_since\",\n message: \"since must be a parseable ISO timestamp\",\n });\n return;\n }\n since = sinceRaw;\n }\n const focusNodeIdRaw = parsed.searchParams.get(\"focusNodeId\");\n const focusNodeId = focusNodeIdRaw && focusNodeIdRaw.length > 0\n ? focusNodeIdRaw\n : undefined;\n const categoriesRaw = parsed.searchParams.get(\"categories\");\n let categories: string[] | undefined;\n if (categoriesRaw !== null && categoriesRaw.length > 0) {\n categories = categoriesRaw\n .split(\",\")\n .map((value) => value.trim())\n .filter((value) => value.length > 0);\n if (categories.length === 0) {\n this.respondJson(res, 400, {\n error: \"invalid_categories\",\n code: \"invalid_categories\",\n message:\n \"categories must be a comma-separated list with at least one non-empty value\",\n });\n return;\n }\n }\n const namespaceParam = parsed.searchParams.get(\"namespace\");\n const namespace = this.resolveNamespace(\n req,\n namespaceParam && namespaceParam.length > 0 ? namespaceParam : undefined,\n );\n try {\n const snapshot = await this.service.graphSnapshot(\n {\n namespace,\n ...(limit !== undefined ? { limit } : {}),\n ...(since !== undefined ? { since } : {}),\n ...(focusNodeId !== undefined ? { focusNodeId } : {}),\n ...(categories !== undefined ? { categories } : {}),\n },\n this.resolveRequestPrincipal(req),\n );\n this.respondJson(res, 200, snapshot);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n if (message.startsWith(\"graphSnapshot:\")) {\n this.respondJson(res, 400, {\n error: \"invalid_request\",\n code: \"invalid_request\",\n message,\n });\n return;\n }\n throw err;\n }\n return;\n }\n\n if (req.method === \"POST\" && pathname === \"/engram/v1/contradiction-scan\") {\n const body = await this.readJsonBody(req) as Record<string, unknown>;\n const { runContradictionScan } = await import(\"./contradiction/contradiction-scan.js\");\n const principal = this.resolveRequestPrincipal(req);\n const result = await runContradictionScan({\n storage: this.service.storageRef,\n config: this.service.configRef,\n memoryDir: this.service.memoryDir,\n embeddingLookupFactory: this.service.embeddingLookupFactoryRef,\n storageForNamespace: (namespace) =>\n this.service.getWritableStorageForNamespace(namespace, principal),\n localLlm: this.service.localLlmRef,\n fallbackLlm: this.service.fallbackLlmRef,\n namespace: typeof body.namespace === \"string\" ? body.namespace : undefined,\n });\n this.respondJson(res, 200, result);\n return;\n }\n\n // ── Graph mutation event stream (issue #691 PR 5/5) ──────────────────────\n //\n // GET /engram/v1/graph/events\n //\n // Server-Sent Events stream that emits graph mutation events in real time.\n // Event types: node-added, node-updated, edge-added, edge-updated, edge-removed.\n //\n // Auth: same Bearer token scheme as every other endpoint (checked above).\n //\n // The SSE handler subscribes to the in-process graph event bus for the\n // resolved memory dir. Events are batched within a 200 ms window so a\n // burst of writes (e.g. extraction of a large turn) doesn't overwhelm\n // the admin UI canvas with individual re-renders.\n //\n // The client receives a `data: <json>\\n\\n` line per batch. Each batch\n // payload is { events: GraphEvent[] }.\n //\n // The stream sends a heartbeat `data: {\"type\":\"heartbeat\"}\\n\\n` every\n // 25 s so load balancers and proxies don't time out idle connections.\n if (req.method === \"GET\" && pathname === \"/engram/v1/graph/events\") {\n await this.handleGraphEventsSSE(req, res);\n return;\n }\n\n // ── Peer Registry endpoints (issue #679) ─────────────────────────────────\n // GET /engram/v1/console/state — operator console engine-state snapshot (issue #688 PR 2/3).\n // Read-only; namespace-aware via resolveRequestPrincipal so cross-tenant\n // reads are not possible (CLAUDE.md rule 42).\n if (req.method === \"GET\" && pathname === \"/engram/v1/console/state\") {\n const namespace = parsed.searchParams.get(\"namespace\") ?? undefined;\n const snapshot = await this.service.consoleState(namespace, this.resolveRequestPrincipal(req));\n this.respondJson(res, 200, snapshot);\n return;\n }\n\n // GET /engram/v1/peers — list all peers\n // GET /engram/v1/peers/:id — get one peer\n // PUT /engram/v1/peers/:id — upsert (create/update)\n // DELETE /engram/v1/peers/:id — delete identity only (idempotent)\n // DELETE /engram/v1/peers/:id?forget=true — destructive full purge (issue #679 completion)\n // GET /engram/v1/peers/:id/profile — get peer profile\n if (req.method === \"GET\" && pathname === \"/engram/v1/peers\") {\n const result = await this.service.peerList();\n this.respondJson(res, 200, result);\n return;\n }\n\n const peerProfileMatch = /^\\/engram\\/v1\\/peers\\/([^/]+)\\/profile$/.exec(pathname);\n if (peerProfileMatch) {\n if (req.method !== \"GET\") {\n this.respondJson(res, 405, { error: \"method_not_allowed\", code: \"method_not_allowed\" });\n return;\n }\n const peerId = decodePeerIdSegment(peerProfileMatch[1] ?? \"\");\n const result = await this.service.peerProfileGet(peerId);\n if (!result.found) {\n this.respondJson(res, 404, { error: \"peer_profile_not_found\", code: \"peer_profile_not_found\" });\n return;\n }\n this.respondJson(res, 200, result);\n return;\n }\n\n const peerIdMatch = /^\\/engram\\/v1\\/peers\\/([^/]+)$/.exec(pathname);\n if (peerIdMatch) {\n const peerId = decodePeerIdSegment(peerIdMatch[1] ?? \"\");\n\n if (req.method === \"GET\") {\n const result = await this.service.peerGet(peerId);\n if (!result.found) {\n this.respondJson(res, 404, { error: \"peer_not_found\", code: \"peer_not_found\" });\n return;\n }\n this.respondJson(res, 200, result);\n return;\n }\n\n if (req.method === \"PUT\") {\n const body = await this.readJsonBody(req) as Record<string, unknown>;\n // Reject malformed types up front rather than silently dropping them\n // to undefined and letting peerSet fall back to defaults\n // (CLAUDE.md rule 51: no silent defaults on bad input).\n if (\"kind\" in body && body.kind !== undefined && typeof body.kind !== \"string\") {\n throw new EngramAccessInputError(\"kind must be a string when provided\");\n }\n if (\n \"displayName\" in body &&\n body.displayName !== undefined &&\n typeof body.displayName !== \"string\"\n ) {\n throw new EngramAccessInputError(\"displayName must be a string when provided\");\n }\n if (\"notes\" in body && body.notes !== undefined && typeof body.notes !== \"string\") {\n throw new EngramAccessInputError(\"notes must be a string when provided\");\n }\n const result = await this.service.peerSet({\n id: peerId,\n kind: typeof body.kind === \"string\" ? body.kind : undefined,\n displayName: typeof body.displayName === \"string\" ? body.displayName : undefined,\n notes: typeof body.notes === \"string\" ? body.notes : undefined,\n });\n this.respondJson(res, result.created ? 201 : 200, result);\n return;\n }\n\n if (req.method === \"DELETE\") {\n // `?forget=true` triggers the destructive full-purge path (issue #679\n // completion). The caller must also pass `confirm=yes` in the request\n // body; absent confirmation yields 400. Plain DELETE (no ?forget) keeps\n // the existing soft-delete behaviour (identity.md only).\n const forgetParam = parsed.searchParams.get(\"forget\");\n if (forgetParam === \"true\") {\n const body = await this.readJsonBody(req) as Record<string, unknown>;\n const confirm = typeof body.confirm === \"string\" ? body.confirm : \"\";\n if (confirm !== \"yes\") {\n this.respondJson(res, 400, {\n error: \"confirm_required\",\n code: \"confirm_required\",\n message: \"DELETE ?forget=true requires { confirm: 'yes' } in the request body\",\n });\n return;\n }\n const result = await this.service.peerForget(peerId, { confirm: \"yes\" });\n this.respondJson(res, 200, result);\n return;\n }\n const result = await this.service.peerDelete(peerId);\n this.respondJson(res, 200, result);\n return;\n }\n\n this.respondJson(res, 405, { error: \"method_not_allowed\", code: \"method_not_allowed\" });\n return;\n }\n\n // ── Dreams telemetry (issue #678 PR 3+4) ──────────────────────────────────\n\n if (req.method === \"GET\" && pathname === \"/engram/v1/dreams/status\") {\n const { normalizeDreamsStatusWindowHours } = await import(\"./maintenance/dreams-ledger.js\");\n const windowHoursRaw = parsed.searchParams.get(\"windowHours\");\n let windowHours: number;\n try {\n windowHours = normalizeDreamsStatusWindowHours(\n windowHoursRaw !== null ? Number(windowHoursRaw) : undefined,\n );\n } catch {\n this.respondJson(res, 400, { error: \"windowHours must be a positive integer\" });\n return;\n }\n const namespaceParam = parsed.searchParams.get(\"namespace\");\n const namespace = namespaceParam && namespaceParam.length > 0 ? namespaceParam : undefined;\n const result = await this.service.dreamsStatus({\n windowHours,\n namespace,\n principal: this.resolveRequestPrincipal(req),\n });\n this.respondJson(res, 200, result);\n return;\n }\n\n if (req.method === \"POST\" && pathname === \"/engram/v1/dreams/run\") {\n const body = await this.readJsonBody(req) as Record<string, unknown>;\n const VALID_PHASES = [\"lightSleep\", \"rem\", \"deepSleep\"] as const;\n const phase = typeof body.phase === \"string\" ? body.phase : undefined;\n if (!phase || !(VALID_PHASES as readonly string[]).includes(phase)) {\n this.respondJson(res, 400, {\n error: `phase is required and must be one of: ${VALID_PHASES.join(\", \")}`,\n });\n return;\n }\n if (\n \"dryRun\" in body &&\n body.dryRun !== undefined &&\n typeof body.dryRun !== \"boolean\"\n ) {\n this.respondJson(res, 400, {\n error: \"dryRun must be a boolean when provided\",\n });\n return;\n }\n if (\n \"namespace\" in body &&\n body.namespace !== undefined &&\n typeof body.namespace !== \"string\"\n ) {\n this.respondJson(res, 400, {\n error: \"namespace must be a string when provided\",\n });\n return;\n }\n const dryRun = body.dryRun === true;\n const namespace =\n typeof body.namespace === \"string\" ? body.namespace : undefined;\n if (!dryRun) {\n this.ensureWriteRateLimitAvailable();\n }\n const result = await this.service.dreamsRun({\n phase: phase as import(\"./types.js\").DreamsPhase,\n dryRun,\n namespace,\n authenticatedPrincipal: this.resolveRequestPrincipal(req),\n });\n if (this.shouldCountWriteRateLimit(result as { dryRun?: boolean; idempotencyReplay?: boolean })) {\n this.recordWriteRateLimitHit();\n }\n this.respondJson(res, 200, result);\n return;\n }\n\n this.respondJson(res, 404, { error: \"not_found\", code: \"not_found\" });\n }\n\n private createRequestAbortSignal(req: IncomingMessage, res: ServerResponse): AbortSignal {\n const controller = new AbortController();\n const abort = () => {\n if (!controller.signal.aborted) controller.abort();\n };\n req.once(\"aborted\", abort);\n res.once(\"close\", () => {\n if (!res.writableEnded) abort();\n });\n return controller.signal;\n }\n\n /**\n * SSE handler for /engram/v1/graph/events.\n *\n * Lifecycle:\n * 1. Write SSE headers (Content-Type: text/event-stream).\n * 2. Register this response in `sseClients`.\n * 3. Resolve the namespace from the request and subscribe to THAT\n * namespace's graph event bus (Codex P1: in multi-namespace\n * deployments each namespace has its own bus keyed by its storage\n * dir — subscribing to the global root leaks events across tenants).\n * 4. On each event, add to a 200 ms batch; flush batch as a single SSE frame.\n * 5. Send heartbeat every 25 s.\n * 6. On client disconnect (req \"close\"), clean up timers and unsubscribe.\n * 7. Register the cleanup callback in `sseCleanupFns` so `stop()` can\n * release the heartbeat interval and bus subscription even when the\n * client never disconnects (Cursor review thread `access-http.ts:232`).\n */\n private async handleGraphEventsSSE(req: IncomingMessage, res: ServerResponse): Promise<void> {\n // Resolve namespace from the ?namespace= query parameter (same pattern\n // as graphSnapshot and other read endpoints). Falls back to the\n // default namespace when absent.\n const parsed = new URL(req.url ?? \"/\", `http://${hostToUrlAuthority(this.host)}`);\n const namespaceParam = parsed.searchParams.get(\"namespace\");\n const namespace = namespaceParam && namespaceParam.length > 0 ? namespaceParam : undefined;\n // Resolve to the per-namespace storage directory so the bus subscription\n // is scoped to the correct tenant (CLAUDE.md rule 42).\n // Pass the request principal so namespace ACL is enforced — without it,\n // resolveReadableNamespace throws when namespacesEnabled=true (Cursor\n // thread PRRT_kwDORJXyws59snoR / Codex thread PRRT_kwDORJXyws59soGJ).\n const principal = this.resolveRequestPrincipal(req);\n const memoryDir = await this.service.getMemoryDirForNamespace(namespace, principal);\n\n res.writeHead(200, {\n \"content-type\": \"text/event-stream; charset=utf-8\",\n \"cache-control\": \"no-cache, no-store, must-revalidate\",\n \"connection\": \"keep-alive\",\n \"x-accel-buffering\": \"no\", // prevent nginx buffering\n \"transfer-encoding\": \"chunked\",\n });\n\n // Send initial \"connected\" frame so the client knows the stream is live.\n const writeSSE = (payload: unknown): void => {\n try {\n res.write(`data: ${JSON.stringify(payload)}\\n\\n`);\n } catch {\n // client already gone — cleanup will fire via \"close\"\n }\n };\n\n writeSSE({ type: \"connected\" });\n\n this.sseClients.add(res);\n\n // --- 200 ms batch throttle -----------------------------------------------\n const flushBatch = (): void => {\n const batch = this.ssePendingBatches.get(res);\n if (!batch || batch.length === 0) return;\n this.ssePendingBatches.delete(res);\n this.sseBatchTimers.delete(res);\n writeSSE({ type: \"batch\", events: batch });\n };\n\n const unsubscribe = subscribeGraphEvents(memoryDir, (event: GraphEvent) => {\n let batch = this.ssePendingBatches.get(res);\n if (!batch) {\n batch = [];\n this.ssePendingBatches.set(res, batch);\n }\n batch.push(event);\n if (!this.sseBatchTimers.has(res)) {\n this.sseBatchTimers.set(res, setTimeout(flushBatch, 200));\n }\n });\n\n // --- 25 s heartbeat -------------------------------------------------------\n const heartbeatInterval = setInterval(() => {\n writeSSE({ type: \"heartbeat\" });\n }, 25_000);\n\n // --- Cleanup on client disconnect -----------------------------------------\n const cleanup = (): void => {\n clearInterval(heartbeatInterval);\n const timer = this.sseBatchTimers.get(res);\n if (timer !== undefined) {\n clearTimeout(timer);\n this.sseBatchTimers.delete(res);\n }\n this.ssePendingBatches.delete(res);\n unsubscribe();\n this.sseClients.delete(res);\n this.sseCleanupFns.delete(cleanup);\n try { res.end(); } catch { /* ignore */ }\n };\n\n // Register so stop() can invoke cleanup even when the client is still\n // connected (releases the heartbeat interval and bus subscription\n // before the HTTP server is torn down).\n this.sseCleanupFns.add(cleanup);\n\n req.once(\"close\", cleanup);\n req.once(\"error\", cleanup);\n }\n\n private async handleMcpRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n const body = await this.readJsonBody(req);\n const request = body as {\n jsonrpc?: string;\n id?: string | number | null;\n method?: string;\n params?: Record<string, unknown>;\n };\n\n // Enforce write rate limiting for MCP tool calls that mutate state,\n // matching the same protection applied to the REST write endpoints.\n // Pre-check ensures capacity; post-check skips counting dry runs and\n // idempotency replays, consistent with the REST handlers.\n const toolName = typeof request.params?.name === \"string\" ? request.params.name : \"\";\n const toolArgs = request.params?.arguments;\n const dreamsRunDryRun =\n (toolName === \"engram.dreams_run\" || toolName === \"remnic.dreams_run\") &&\n toolArgs !== null &&\n typeof toolArgs === \"object\" &&\n !Array.isArray(toolArgs) &&\n (toolArgs as { dryRun?: unknown }).dryRun === true;\n const memoryActionApplyDryRun =\n (toolName === \"engram.memory_action_apply\" || toolName === \"remnic.memory_action_apply\") &&\n toolArgs !== null &&\n typeof toolArgs === \"object\" &&\n !Array.isArray(toolArgs) &&\n (toolArgs as { dryRun?: unknown }).dryRun === true;\n const isMcpWrite =\n request.method === \"tools/call\" &&\n (\n toolName === \"engram.memory_store\" ||\n toolName === \"remnic.memory_store\" ||\n toolName === \"engram.suggestion_submit\" ||\n toolName === \"remnic.suggestion_submit\" ||\n toolName === \"engram.observe\" ||\n toolName === \"remnic.observe\" ||\n toolName === \"engram.lcm_compaction_flush\" ||\n toolName === \"remnic.lcm_compaction_flush\" ||\n toolName === \"engram.lcm_compaction_record\" ||\n toolName === \"remnic.lcm_compaction_record\" ||\n toolName === \"engram.capsule_export\" ||\n toolName === \"remnic.capsule_export\" ||\n toolName === \"engram.capsule_import\" ||\n toolName === \"remnic.capsule_import\" ||\n (\n !dreamsRunDryRun &&\n (toolName === \"engram.dreams_run\" || toolName === \"remnic.dreams_run\")\n ) ||\n (\n !memoryActionApplyDryRun &&\n (\n toolName === \"engram.memory_action_apply\" ||\n toolName === \"remnic.memory_action_apply\"\n )\n )\n );\n if (isMcpWrite) {\n this.ensureWriteRateLimitAvailable();\n }\n\n const sessionId = (() => {\n const raw = req.headers[\"mcp-session-id\"];\n return typeof raw === \"string\" ? raw.trim() : undefined;\n })();\n const mcpCorrelationId = correlationIdStore.getStore() ?? randomUUID();\n const requestIdentity = this.resolveRequestIdentity(req);\n const response = await this.mcpServer.handleRequest(request, {\n principalOverride: requestIdentity.principal,\n namespaceOverride: requestIdentity.namespace,\n sessionKeyOverride: requestIdentity.sessionKey,\n sessionId,\n correlationId: mcpCorrelationId,\n });\n\n if (isMcpWrite && response !== null) {\n const result = (response as Record<string, unknown>).result as Record<string, unknown> | undefined;\n const isError = result?.isError === true;\n const structured = result?.structuredContent as { dryRun?: boolean; idempotencyReplay?: boolean } | undefined;\n if (!isError && structured && this.shouldCountWriteRateLimit(structured)) {\n this.recordWriteRateLimitHit();\n }\n }\n if (response === null) {\n res.statusCode = 202;\n res.end();\n return;\n }\n // If this was an initialize response, pop the session ID keyed by\n // correlation ID (unique per HTTP request, not client-chosen JSON-RPC id).\n const assignedSessionId = this.mcpServer.popInitSessionId(mcpCorrelationId);\n if (assignedSessionId) {\n res.setHeader(\"mcp-session-id\", assignedSessionId);\n }\n this.respondJson(res, 200, response);\n }\n\n private respondJson(res: ServerResponse, status: number, payload: unknown): void {\n const body = JSON.stringify(payload, null, 2);\n res.statusCode = status;\n res.setHeader(\"content-type\", \"application/json; charset=utf-8\");\n res.setHeader(\"content-length\", String(Buffer.byteLength(body)));\n const cid = correlationIdStore.getStore();\n if (cid) {\n res.setHeader(\"x-request-id\", cid);\n }\n res.end(body);\n }\n\n private async respondOfflineSnapshotStream(\n res: ServerResponse,\n snapshot: Awaited<ReturnType<EngramAccessService[\"offlineSyncSnapshotStream\"]>>,\n ): Promise<void> {\n res.statusCode = 200;\n res.setHeader(\"content-type\", \"application/x-ndjson; charset=utf-8\");\n res.setHeader(\"cache-control\", \"no-store\");\n const cid = correlationIdStore.getStore();\n if (cid) {\n res.setHeader(\"x-request-id\", cid);\n }\n const waitForDrainOrClose = async (): Promise<boolean> => new Promise((resolve, reject) => {\n const cleanup = () => {\n res.off(\"drain\", onDrain);\n res.off(\"close\", onClose);\n res.off(\"error\", onError);\n };\n const onDrain = () => {\n cleanup();\n resolve(true);\n };\n const onClose = () => {\n cleanup();\n resolve(false);\n };\n const onError = (error: Error) => {\n cleanup();\n reject(error);\n };\n res.once(\"drain\", onDrain);\n res.once(\"close\", onClose);\n res.once(\"error\", onError);\n });\n const writeLine = async (payload: unknown): Promise<boolean> => {\n if (res.destroyed || res.writableEnded) return false;\n if (res.write(`${JSON.stringify(payload)}\\n`)) return true;\n if (res.destroyed || res.writableEnded) return false;\n return waitForDrainOrClose();\n };\n if (!await writeLine({\n type: \"snapshot\",\n namespace: snapshot.namespace,\n format: snapshot.format,\n schemaVersion: snapshot.schemaVersion,\n createdAt: snapshot.createdAt,\n sourceId: snapshot.sourceId,\n includeTranscripts: snapshot.includeTranscripts,\n })) return;\n for await (const file of snapshot.files) {\n if (!await writeLine({ type: \"file\", file })) return;\n }\n if (!res.destroyed && !res.writableEnded) {\n res.end();\n }\n }\n\n private respondBinary(\n res: ServerResponse,\n status: number,\n body: Buffer,\n headers: Record<string, string> = {},\n ): void {\n res.statusCode = status;\n res.setHeader(\"content-type\", \"application/octet-stream\");\n res.setHeader(\"content-length\", String(body.length));\n for (const [key, value] of Object.entries(headers)) {\n res.setHeader(key, value);\n }\n const cid = correlationIdStore.getStore();\n if (cid) {\n res.setHeader(\"x-request-id\", cid);\n }\n res.end(body);\n }\n\n private async handleAdminConsole(\n req: IncomingMessage,\n res: ServerResponse,\n pathname: string,\n ): Promise<boolean> {\n if (req.method !== \"GET\") return false;\n if (pathname === \"/remnic/ui\" || pathname === \"/engram/ui\") {\n res.statusCode = 301;\n res.setHeader(\"location\", pathname + \"/\");\n res.end();\n return true;\n }\n if (pathname === \"/remnic/ui/\" || pathname === \"/engram/ui/\") {\n await this.respondStatic(res, path.join(this.adminConsolePublicDir, \"index.html\"), \"text/html; charset=utf-8\");\n return true;\n }\n if (pathname === \"/remnic/ui/app.js\" || pathname === \"/engram/ui/app.js\") {\n await this.respondStatic(res, path.join(this.adminConsolePublicDir, \"app.js\"), \"application/javascript; charset=utf-8\");\n return true;\n }\n return false;\n }\n\n private async respondStatic(res: ServerResponse, filePath: string, contentType: string): Promise<void> {\n try {\n const body = await readFile(filePath, \"utf-8\");\n res.statusCode = 200;\n res.setHeader(\"content-type\", contentType);\n res.setHeader(\"content-length\", String(Buffer.byteLength(body)));\n res.end(body);\n } catch {\n this.respondJson(res, 404, { error: \"not_found\" });\n }\n }\n\n private async readJsonBody(\n req: IncomingMessage,\n maxBodyBytes = this.maxBodyBytes,\n ): Promise<Record<string, unknown>> {\n const encoding = (this.readOptionalHeader(req, \"content-encoding\") ?? \"identity\").toLowerCase();\n if (encoding !== \"identity\" && encoding !== \"gzip\") {\n throw new HttpError(415, \"unsupported_content_encoding\", \"unsupported_content_encoding\");\n }\n const chunks: Buffer[] = [];\n let total = 0;\n for await (const chunk of req) {\n const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);\n total += buffer.length;\n if (total > maxBodyBytes) {\n throw new HttpError(413, \"request_body_too_large\", \"request_body_too_large\");\n }\n chunks.push(buffer);\n }\n if (chunks.length === 0) return {};\n let body = Buffer.concat(chunks, total);\n if (encoding === \"gzip\") {\n try {\n body = gunzipSync(body, { maxOutputLength: maxBodyBytes });\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ERR_BUFFER_TOO_LARGE\") {\n throw new HttpError(413, \"request_body_too_large\", \"request_body_too_large\");\n }\n throw new HttpError(400, \"invalid_gzip_body\", \"invalid_gzip_body\");\n }\n if (body.byteLength > maxBodyBytes) {\n throw new HttpError(413, \"request_body_too_large\", \"request_body_too_large\");\n }\n }\n const raw = body.toString(\"utf-8\").trim();\n if (raw.length === 0) return {};\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw new HttpError(400, \"invalid_json\", \"invalid_json\");\n }\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n throw new HttpError(400, \"invalid_json_object\", \"invalid_json_object\");\n }\n return parsed as Record<string, unknown>;\n }\n\n private async readBinaryBody(req: IncomingMessage, maxBytes: number): Promise<Buffer> {\n const chunks: Buffer[] = [];\n let total = 0;\n for await (const chunk of req) {\n const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);\n total += buffer.length;\n if (total > maxBytes) {\n throw new HttpError(413, \"request_body_too_large\", \"request_body_too_large\");\n }\n chunks.push(buffer);\n }\n return Buffer.concat(chunks, total);\n }\n\n private readRequiredHeader(req: IncomingMessage, name: string): string {\n const value = this.readOptionalHeader(req, name);\n if (value === undefined || value.length === 0) {\n throw new EngramAccessInputError(`${name} header is required`);\n }\n return value;\n }\n\n private readOptionalHeader(req: IncomingMessage, name: string): string | undefined {\n const raw = req.headers[name.toLowerCase()];\n if (Array.isArray(raw)) return raw[0]?.trim() || undefined;\n return raw?.trim() || undefined;\n }\n\n private readRequiredDecodedHeader(req: IncomingMessage, name: string): string {\n const raw = this.readRequiredHeader(req, name);\n try {\n return decodeURIComponent(raw);\n } catch {\n throw new EngramAccessInputError(`${name} header is not valid percent-encoded input`);\n }\n }\n\n private readRequiredIntegerHeader(req: IncomingMessage, name: string): number {\n const raw = this.readRequiredHeader(req, name);\n const parsed = Number(raw);\n if (!Number.isInteger(parsed) || parsed < 0) {\n throw new EngramAccessInputError(`${name} header must be a non-negative integer`);\n }\n return parsed;\n }\n\n private readOptionalIntegerHeader(req: IncomingMessage, name: string): number | undefined {\n const raw = this.readOptionalHeader(req, name);\n if (raw === undefined) return undefined;\n const parsed = Number(raw);\n if (!Number.isInteger(parsed) || parsed < 0) {\n throw new EngramAccessInputError(`${name} header must be a non-negative integer`);\n }\n return parsed;\n }\n\n private readRequiredNumberHeader(req: IncomingMessage, name: string): number {\n const raw = this.readRequiredHeader(req, name);\n const parsed = Number(raw);\n if (!Number.isFinite(parsed) || parsed < 0) {\n throw new EngramAccessInputError(`${name} header must be a non-negative finite number`);\n }\n return parsed;\n }\n\n private parseOptionalBooleanHeader(\n req: IncomingMessage,\n name: string,\n defaultValue: boolean,\n ): boolean {\n const raw = this.readOptionalHeader(req, name);\n if (raw === undefined) return defaultValue;\n if (raw === \"true\") return true;\n if (raw === \"false\") return false;\n throw new EngramAccessInputError(`${name} header must be one of: true, false`);\n }\n\n private async readValidatedBody<S extends SchemaName>(\n req: IncomingMessage,\n schemaName: S,\n maxBodyBytes?: number,\n ): Promise<SchemaTypeFor<S>> {\n const raw = await this.readJsonBody(req, maxBodyBytes);\n const result = validateRequest(schemaName, raw);\n if (!result.success) {\n throw new HttpError(400, result.error.error, \"validation_error\", result.error.details);\n }\n return result.data as SchemaTypeFor<S>;\n }\n\n private isAuthorized(req: IncomingMessage, pathname?: string): boolean {\n if (!this.authToken && this.authTokens.length === 0 && !this.authTokensGetter) return false;\n // Primary path: Authorization: Bearer <token> header.\n const raw = req.headers.authorization;\n let candidate: string | null = null;\n if (raw) {\n const separator = raw.indexOf(\" \");\n if (separator > 0) {\n const scheme = raw.slice(0, separator).toLowerCase();\n if (scheme === \"bearer\") {\n candidate = raw.slice(separator + 1).trim();\n }\n }\n }\n // Fallback: ?token= query parameter — ONLY accepted for the SSE\n // endpoint (/engram/v1/graph/events). EventSource cannot set request\n // headers, so SSE clients must pass the token via the query string.\n // Allowing this fallback on every endpoint would let a CSRF attacker\n // embed a credentialed URL anywhere — restricting it to SSE limits the\n // attack surface (Codex P2 review thread `access-http.ts:1406`; Cursor\n // review thread `access-http.ts:1412`). Authorization header always\n // wins; timing-safe compare used below.\n if (!candidate && pathname === \"/engram/v1/graph/events\") {\n try {\n const parsed = new URL(req.url ?? \"/\", `http://${hostToUrlAuthority(this.host)}`);\n const queryToken = parsed.searchParams.get(\"token\");\n if (queryToken && queryToken.length > 0) {\n candidate = queryToken;\n }\n } catch {\n // Malformed URL — don't authenticate\n }\n }\n if (!candidate) return false;\n const token = candidate;\n // Check primary token\n if (this.authToken && this.timingSafeStringEqual(token, this.authToken)) return true;\n // Check static multi-connector tokens\n for (const valid of this.authTokens) {\n if (this.timingSafeStringEqual(token, valid)) return true;\n }\n // Check dynamic tokens (reloaded per request for generate/revoke without restart)\n if (this.authTokensGetter) {\n for (const valid of this.authTokensGetter()) {\n if (this.timingSafeStringEqual(token, valid)) return true;\n }\n }\n return false;\n }\n\n private timingSafeStringEqual(a: string, b: string): boolean {\n const left = this.encodeSecret(a);\n const right = this.encodeSecret(b);\n if (!left || !right) return false;\n return timingSafeEqual(left, right);\n }\n\n private encodeSecret(value: string): Buffer | null {\n const encoded = Buffer.from(value, \"utf-8\");\n if (encoded.length > 1024) return null;\n const out = Buffer.alloc(2 + 1024);\n out.writeUInt16BE(encoded.length, 0);\n encoded.copy(out, 2);\n return out;\n }\n\n private writeResponseStatus(response: { dryRun: boolean; status: string }): number {\n if (response.dryRun === true) return 200;\n if (response.status === \"stored\" || response.status === \"queued_for_review\") return 201;\n return 200;\n }\n\n private ensureWriteRateLimitAvailable(): void {\n const now = Date.now();\n while (\n this.writeRequestTimestamps.length > 0 &&\n now - (this.writeRequestTimestamps[0] ?? 0) > WRITE_RATE_LIMIT_WINDOW_MS\n ) {\n this.writeRequestTimestamps.shift();\n }\n if (this.writeRequestTimestamps.length >= WRITE_RATE_LIMIT_MAX_REQUESTS) {\n throw new HttpError(429, \"write_rate_limited\", \"write_rate_limited\");\n }\n }\n\n private recordWriteRateLimitHit(): void {\n this.writeRequestTimestamps.push(Date.now());\n }\n\n private shouldCountWriteRateLimit(response: { dryRun?: boolean; idempotencyReplay?: boolean }): boolean {\n return response.dryRun !== true && response.idempotencyReplay !== true;\n }\n}\n"],"mappings":"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","names":["result"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/training-export/date-parse.ts","../src/patterns-cli.ts"],"sourcesContent":["/**\n * Strict ISO 8601 date parsing for training-export CLI flags.\n *\n * Extracted from `cli.ts` so that both the canonical CLI (in\n * `@remnic/core`) and the thin front-end CLI (in `@remnic/cli`) can share\n * the same validator without duplicating the overflow/timezone rules.\n *\n * The parser rejects:\n * - Non-ISO strings (e.g. \"12/25/2026\", \"Dec 25 2026\")\n * - Calendar overflows (Feb 30, Feb 29 in non-leap years, Apr 31, etc.)\n * regardless of timezone suffix\n * - Out-of-range time components (hour >= 24, minute >= 60, second >= 60)\n *\n * Calendar overflow is validated structurally on the Y-M-D components, so\n * results are independent of the host's local timezone.\n */\n\n/**\n * Days in each month (1-indexed). February is 28 here; leap-year handling\n * is applied by `isCalendarDateValid` below.\n */\nconst DAYS_IN_MONTH = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];\n\nfunction isLeapYear(year: number): boolean {\n return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;\n}\n\n/**\n * True iff `year-month-day` is a valid Gregorian calendar date. Input\n * numbers must be integer-valued; month is 1-12, day is 1-31 nominally.\n */\nexport function isCalendarDateValid(\n year: number,\n month: number,\n day: number,\n): boolean {\n if (\n !Number.isInteger(year) ||\n !Number.isInteger(month) ||\n !Number.isInteger(day)\n ) {\n return false;\n }\n if (month < 1 || month > 12) return false;\n if (day < 1) return false;\n const maxDay = month === 2 && isLeapYear(year) ? 29 : DAYS_IN_MONTH[month];\n return day <= maxDay;\n}\n\n/**\n * Parse a strict ISO 8601 date string, rejecting malformed inputs, calendar\n * overflows, and out-of-range time components with a descriptive error.\n *\n * Accepted forms:\n * YYYY-MM-DD\n * YYYY-MM-DDTHH:mm:ss (naive / local time)\n * YYYY-MM-DDTHH:mm:ss.sssZ (UTC)\n * YYYY-MM-DDTHH:mm:ss+HH:MM (with timezone offset)\n * YYYY-MM-DDTHH:mm:ss.sss-HH:MM (with timezone offset)\n *\n * `flagName` is included in the error message so users can identify which\n * input failed (e.g. `--since` vs. `--until`).\n */\nexport function parseStrictCliDate(value: string, flagName: string): Date {\n // 1. Shape check: must begin YYYY-MM-DD and use ISO 8601 structure.\n // This rejects \"12/25/2026\", \"December 25, 2026\", RFC 2822, etc.\n const shape =\n /^(\\d{4})-(\\d{2})-(\\d{2})(?:T(\\d{2}):(\\d{2})(?::(\\d{2})(?:\\.(\\d{1,9}))?)?(Z|[+-]\\d{2}:\\d{2})?)?$/;\n const match = value.match(shape);\n if (!match) {\n throw new Error(\n `Invalid ${flagName} value \"${value}\": expected ISO 8601 format (YYYY-MM-DD or YYYY-MM-DDTHH:mm:ss[.sss][Z|±HH:MM]).`,\n );\n }\n\n const year = Number(match[1]);\n const month = Number(match[2]);\n const day = Number(match[3]);\n\n // 2. Structural calendar validation. This rejects Feb 31, Feb 29 in\n // non-leap years, Apr 31, etc. regardless of the timezone suffix, so\n // \"2026-02-31T00:00:00+05:30\" is rejected the same way as \"2026-02-31Z\".\n if (!isCalendarDateValid(year, month, day)) {\n throw new Error(\n `Invalid ${flagName} value \"${value}\": date components overflow (e.g. month has fewer days). Provide a valid calendar date.`,\n );\n }\n\n // 3. Optional time-component validation.\n // JavaScript's Date cannot represent a leap second: `:60` is silently\n // normalised to `:00` of the following minute, which would make a\n // \"strict\" validator return a different timestamp than the user\n // requested. Reject second == 60 outright so a strict parse cannot\n // round-trip to a different clock value.\n if (match[4] !== undefined) {\n const hour = Number(match[4]);\n const minute = Number(match[5]);\n const second = match[6] !== undefined ? Number(match[6]) : 0;\n if (hour > 23 || minute > 59 || second > 59) {\n throw new Error(\n `Invalid ${flagName} value \"${value}\": time components out of range.`,\n );\n }\n }\n\n // 4. Finally parse via Date for the actual timestamp value. At this point\n // we've already validated structure and calendar correctness, so any\n // remaining NaN (extremely unlikely) still fails closed.\n const d = new Date(value);\n if (!Number.isFinite(d.getTime())) {\n throw new Error(\n `Invalid ${flagName} value \"${value}\". Provide an ISO 8601 date string (YYYY-MM-DD or YYYY-MM-DDTHH:mm:ss).`,\n );\n }\n\n return d;\n}\n","/**\n * `remnic patterns` CLI helpers (issue #687 PR 4/4).\n *\n * Pure functions that:\n *\n * 1. Validate `--limit`, `--category`, `--since`, `--format` for\n * `remnic patterns list` and `--format` for\n * `remnic patterns explain <id>` (CLAUDE.md rules 14 + 51 — flags\n * throw listed-options errors instead of silently defaulting).\n *\n * 2. Filter the memory corpus to canonical memories produced by the\n * pattern-reinforcement maintenance job from issue #687 PR 2/4\n * (`reinforcement_count > 0`) and sort them by reinforcement\n * count, with `last_reinforced_at` (then `id`) as stable\n * tiebreakers (CLAUDE.md rule 19).\n *\n * 3. Reconstruct a single canonical's full picture: its\n * `derived_from` provenance chain (PR 2/4 stamps these), the\n * cluster members it absorbed (memories pointing at it via\n * `supersededBy`), and the canonical body so operators can read\n * it inline.\n *\n * 4. Render `text` (default) / `markdown` / `json` output for both\n * commands. The CLI handler in `cli.ts` stays thin and delegates\n * formatting here so HTTP / MCP surfaces (if added later) can\n * reuse the same renderers (CLAUDE.md rule 22 — never fork\n * formatting).\n */\n\nimport type { MemoryCategory, MemoryFile } from \"./types.js\";\nimport { DERIVED_FROM_MEMORY_ID_RE } from \"./consolidation-operator.js\";\nimport { parseStrictCliDate } from \"./training-export/date-parse.js\";\n\nexport const PATTERNS_OUTPUT_FORMATS = [\"text\", \"markdown\", \"json\"] as const;\nexport type PatternsOutputFormat = (typeof PATTERNS_OUTPUT_FORMATS)[number];\n\n// ───────────────────────────────────────────────────────────────────────────\n// Flag validation\n// ───────────────────────────────────────────────────────────────────────────\n\n/**\n * Validate `--format <fmt>`. Throws a listed-options error for any\n * value not in `PATTERNS_OUTPUT_FORMATS`. Returns `\"text\"` when the\n * value is `undefined` (no flag supplied).\n */\nexport function parsePatternsFormat(value: unknown): PatternsOutputFormat {\n if (value === undefined || value === null) return \"text\";\n if (\n typeof value !== \"string\" ||\n !(PATTERNS_OUTPUT_FORMATS as readonly string[]).includes(value)\n ) {\n throw new Error(\n `--format expects one of ${PATTERNS_OUTPUT_FORMATS.join(\", \")}; got ${JSON.stringify(value)}`,\n );\n }\n return value as PatternsOutputFormat;\n}\n\n/**\n * Validate `--limit <N>`. Must be a positive integer. Returns\n * `undefined` when the flag is absent (the caller falls back to a\n * default).\n */\nexport function parsePatternsLimit(value: unknown): number | undefined {\n if (value === undefined || value === null) return undefined;\n const parsed = typeof value === \"number\" ? value : Number(value);\n if (!Number.isFinite(parsed) || !Number.isInteger(parsed) || parsed <= 0) {\n throw new Error(\n `--limit expects a positive integer; got ${JSON.stringify(value)}`,\n );\n }\n return parsed;\n}\n\n/**\n * Validate `--category <list>`. Accepts a comma-separated list of\n * non-empty trimmed tokens. Returns the deduplicated list, or\n * `undefined` when no flag was supplied. CLAUDE.md rules 14 + 51:\n * `--category` with no value or with a value that resolves to zero\n * tokens is rejected.\n */\nexport function parsePatternsCategory(value: unknown): string[] | undefined {\n if (value === undefined || value === null) return undefined;\n if (typeof value !== \"string\") {\n throw new Error(\n `--category expects a comma-separated list of category names; got ${JSON.stringify(value)}`,\n );\n }\n const parts = value\n .split(\",\")\n .map((part) => part.trim())\n .filter((part) => part.length > 0);\n if (parts.length === 0) {\n throw new Error(\n `--category expects at least one non-empty category name; got ${JSON.stringify(value)}`,\n );\n }\n // Deduplicate while preserving first-seen order.\n const seen = new Set<string>();\n const unique: string[] = [];\n for (const part of parts) {\n if (!seen.has(part)) {\n seen.add(part);\n unique.push(part);\n }\n }\n return unique;\n}\n\n/**\n * Validate `--since <ISO>`. Delegates to `parseStrictCliDate` which\n * enforces a strict ISO 8601 shape and rejects calendar overflows and\n * non-ISO formats (e.g. \"12/25/2026\", \"Dec 25 2026\") that bare\n * `Date.parse()` would silently accept. Returns the canonical ISO\n * string (round-trip through `toISOString`) so downstream comparisons\n * use a consistent form.\n */\nexport function parsePatternsSince(value: unknown): string | undefined {\n if (value === undefined || value === null) return undefined;\n if (typeof value !== \"string\" || value.trim().length === 0) {\n throw new Error(\n `--since expects an ISO 8601 timestamp (e.g. 2026-04-01T00:00:00Z); got ${JSON.stringify(value)}`,\n );\n }\n // parseStrictCliDate throws with a descriptive message on invalid input.\n return parseStrictCliDate(value.trim(), \"--since\").toISOString();\n}\n\nexport interface ParsedPatternsListOptions {\n format: PatternsOutputFormat;\n limit?: number;\n categories?: string[];\n sinceIso?: string;\n}\n\nexport interface ParsedPatternsExplainOptions {\n format: PatternsOutputFormat;\n}\n\n/**\n * Validate the full option bag for `remnic patterns list`. Extracted\n * from the CLI handler so validation can be unit-tested without\n * booting an orchestrator (CLAUDE.md rules 14 + 51).\n */\nexport function parsePatternsListOptions(\n options: Record<string, unknown>,\n): ParsedPatternsListOptions {\n const format = parsePatternsFormat(options.format);\n const limit = parsePatternsLimit(options.limit);\n const categories = parsePatternsCategory(options.category);\n const sinceIso = parsePatternsSince(options.since);\n return {\n format,\n ...(limit !== undefined ? { limit } : {}),\n ...(categories !== undefined ? { categories } : {}),\n ...(sinceIso !== undefined ? { sinceIso } : {}),\n };\n}\n\n/**\n * Validate `remnic patterns explain` options + positional id. Throws\n * when `<memoryId>` is missing or empty.\n */\nexport function parsePatternsExplainOptions(\n rawId: unknown,\n options: Record<string, unknown>,\n): { id: string } & ParsedPatternsExplainOptions {\n if (typeof rawId !== \"string\" || rawId.trim().length === 0) {\n throw new Error(\"patterns explain: <memoryId> is required and must be non-empty\");\n }\n const format = parsePatternsFormat(options.format);\n return { id: rawId.trim(), format };\n}\n\n// ───────────────────────────────────────────────────────────────────────────\n// Core list / explain behavior\n// ───────────────────────────────────────────────────────────────────────────\n\nexport interface PatternListRow {\n id: string;\n category: MemoryCategory;\n reinforcementCount: number;\n lastReinforcedAt?: string;\n status: string;\n /** First non-empty content line, trimmed to ~120 chars for the table. */\n preview: string;\n /** Full path on disk (relative to memoryDir) for operators who want to inspect the file. */\n path: string;\n}\n\nconst DEFAULT_LIST_LIMIT = 50;\n\n/**\n * Filter, sort, and slice the memory corpus down to the rows the\n * `remnic patterns list` command should print.\n *\n * Rules (each one is exercised by `tests/cli/patterns.test.ts`):\n *\n * - Memories without `reinforcement_count` (or with a count <= 0) are\n * dropped — these are not pattern canonicals.\n * - When `categories` is supplied, only memories whose\n * `frontmatter.category` is in the list survive.\n * - When `sinceIso` is supplied, only memories whose\n * `last_reinforced_at` is `>= sinceIso` survive. Memories without\n * `last_reinforced_at` are dropped under `--since` (PR 2/4 always\n * stamps the timestamp alongside the count, so a missing timestamp\n * means a malformed file the operator should not see in this view).\n * - Sort by `reinforcement_count DESC`, then `last_reinforced_at\n * DESC`, then `id ASC` for a stable, deterministic order\n * (CLAUDE.md rule 19).\n * - Apply `limit` (default 50).\n */\nexport function collectPatternMemories(\n memories: readonly MemoryFile[],\n opts: ParsedPatternsListOptions,\n): PatternListRow[] {\n const sinceMs =\n opts.sinceIso !== undefined ? Date.parse(opts.sinceIso) : undefined;\n const categorySet =\n opts.categories !== undefined ? new Set(opts.categories) : undefined;\n\n const rows: PatternListRow[] = [];\n for (const memory of memories) {\n const fm = memory.frontmatter;\n const count = fm.reinforcement_count;\n if (typeof count !== \"number\" || !Number.isInteger(count) || count <= 0) {\n continue;\n }\n if (categorySet !== undefined && !categorySet.has(fm.category)) {\n continue;\n }\n if (sinceMs !== undefined) {\n if (typeof fm.last_reinforced_at !== \"string\") continue;\n const ts = Date.parse(fm.last_reinforced_at);\n if (!Number.isFinite(ts) || ts < sinceMs) continue;\n }\n rows.push({\n id: fm.id,\n category: fm.category,\n reinforcementCount: count,\n ...(fm.last_reinforced_at !== undefined\n ? { lastReinforcedAt: fm.last_reinforced_at }\n : {}),\n status: fm.status ?? \"active\",\n preview: extractPreview(memory.content),\n path: memory.path,\n });\n }\n\n rows.sort((a, b) => {\n if (b.reinforcementCount !== a.reinforcementCount) {\n return b.reinforcementCount - a.reinforcementCount;\n }\n // Guard NaN: malformed date strings make Date.parse return NaN, which\n // breaks the sort contract (NaN comparator return == non-deterministic\n // ordering). Treat invalid/missing timestamps as 0 (oldest possible).\n const aRaw = a.lastReinforcedAt ? Date.parse(a.lastReinforcedAt) : NaN;\n const bRaw = b.lastReinforcedAt ? Date.parse(b.lastReinforcedAt) : NaN;\n const aTs = Number.isFinite(aRaw) ? aRaw : 0;\n const bTs = Number.isFinite(bRaw) ? bRaw : 0;\n if (bTs !== aTs) return bTs - aTs;\n if (a.id < b.id) return -1;\n if (a.id > b.id) return 1;\n return 0;\n });\n\n const limit = opts.limit ?? DEFAULT_LIST_LIMIT;\n return rows.slice(0, limit);\n}\n\nexport interface PatternDerivedFromEntry {\n /** Raw `\"<path>:<version>\"` reference exactly as stored in `derived_from`. */\n ref: string;\n /** Source memory id, or the path component for older `path:version` references. */\n path: string;\n /** Page-version number component for older `path:version` references. */\n version: number | null;\n /** True when an older path-version reference had an invalid version component. */\n malformed?: boolean;\n}\n\nexport interface PatternClusterMember {\n id: string;\n status: string;\n supersededAt?: string;\n path: string;\n preview: string;\n}\n\nexport interface PatternExplainDetail {\n id: string;\n category: MemoryCategory;\n reinforcementCount: number;\n lastReinforcedAt?: string;\n status: string;\n derivedVia?: string;\n /** Full canonical body (frontmatter stripped). */\n canonicalContent: string;\n canonicalPath: string;\n /** Parsed `derived_from` chain — empty when PR 2/4 did not stamp it. */\n derivedFrom: PatternDerivedFromEntry[];\n /** Memories whose `supersededBy === <id>`, sorted by `supersededAt DESC` then `id ASC`. */\n clusterMembers: PatternClusterMember[];\n}\n\n/**\n * Build the structured detail object for a single canonical. Returns\n * `null` when the memory is not found or has never been touched by\n * pattern reinforcement (i.e., no `reinforcement_count`). The CLI\n * handler then prints a clean \"not a pattern\" error rather than\n * leaking an empty document.\n */\nexport function explainPatternMemory(\n memories: readonly MemoryFile[],\n id: string,\n): PatternExplainDetail | null {\n const canonical = memories.find((m) => m.frontmatter.id === id);\n if (!canonical) return null;\n const fm = canonical.frontmatter;\n const count = fm.reinforcement_count;\n if (typeof count !== \"number\" || !Number.isInteger(count) || count <= 0) {\n return null;\n }\n\n const derivedFrom: PatternDerivedFromEntry[] = (fm.derived_from ?? []).map(\n (ref) => {\n const lastColon = ref.lastIndexOf(\":\");\n const pathLikeRef = looksLikeDerivedFromPath(ref);\n if (lastColon >= 0) {\n const path = ref.slice(0, lastColon);\n const versionStr = ref.slice(lastColon + 1);\n if (\n looksLikeDerivedFromPath(path) &&\n /^\\d+$/.test(versionStr)\n ) {\n return { ref, path, version: Number(versionStr) };\n }\n if (!pathLikeRef && DERIVED_FROM_MEMORY_ID_RE.test(ref)) {\n return { ref, path: ref, version: null };\n }\n return { ref, path: ref, version: null, malformed: true };\n }\n if (DERIVED_FROM_MEMORY_ID_RE.test(ref)) {\n return {\n ref,\n path: ref,\n version: null,\n };\n }\n return { ref, path: ref, version: null, malformed: true };\n },\n );\n\n const members: PatternClusterMember[] = [];\n for (const m of memories) {\n if (m.frontmatter.supersededBy === id) {\n members.push({\n id: m.frontmatter.id,\n status: m.frontmatter.status ?? \"active\",\n ...(m.frontmatter.supersededAt !== undefined\n ? { supersededAt: m.frontmatter.supersededAt }\n : {}),\n path: m.path,\n preview: extractPreview(m.content),\n });\n }\n }\n members.sort((a, b) => {\n // Guard NaN: same rationale as collectPatternMemories sort — malformed\n // supersededAt strings must not produce a NaN return from the comparator.\n const aRaw = a.supersededAt ? Date.parse(a.supersededAt) : NaN;\n const bRaw = b.supersededAt ? Date.parse(b.supersededAt) : NaN;\n const aTs = Number.isFinite(aRaw) ? aRaw : 0;\n const bTs = Number.isFinite(bRaw) ? bRaw : 0;\n if (bTs !== aTs) return bTs - aTs;\n if (a.id < b.id) return -1;\n if (a.id > b.id) return 1;\n return 0;\n });\n\n return {\n id: fm.id,\n category: fm.category,\n reinforcementCount: count,\n ...(fm.last_reinforced_at !== undefined\n ? { lastReinforcedAt: fm.last_reinforced_at }\n : {}),\n status: fm.status ?? \"active\",\n ...(fm.derived_via !== undefined ? { derivedVia: fm.derived_via } : {}),\n canonicalContent: canonical.content.trim(),\n canonicalPath: canonical.path,\n derivedFrom,\n clusterMembers: members,\n };\n}\n\n// ───────────────────────────────────────────────────────────────────────────\n// Renderers\n// ───────────────────────────────────────────────────────────────────────────\n\nexport function renderPatternsList(\n rows: readonly PatternListRow[],\n format: PatternsOutputFormat,\n): string {\n if (format === \"json\") {\n return JSON.stringify({ rows }, null, 2);\n }\n if (rows.length === 0) {\n if (format === \"markdown\") {\n return \"# Pattern memories\\n\\n_No reinforced patterns found._\\n\";\n }\n return \"No reinforced patterns found.\";\n }\n if (format === \"markdown\") {\n const lines: string[] = [\"# Pattern memories\", \"\"];\n lines.push(\"| Count | ID | Category | Last reinforced | Preview |\");\n lines.push(\"| --- | --- | --- | --- | --- |\");\n for (const row of rows) {\n const last = row.lastReinforcedAt ?? \"—\";\n const preview = escapePipes(row.preview);\n lines.push(\n `| ${row.reinforcementCount} | \\`${row.id}\\` | ${row.category} | ${last} | ${preview} |`,\n );\n }\n return lines.join(\"\\n\") + \"\\n\";\n }\n // text\n const lines: string[] = [];\n lines.push(`Pattern memories (${rows.length}):`);\n lines.push(\"\");\n for (const row of rows) {\n const last = row.lastReinforcedAt ?? \"—\";\n lines.push(\n ` [${row.reinforcementCount}x] ${row.id} (${row.category}, last_reinforced=${last}, status=${row.status})`,\n );\n if (row.preview.length > 0) {\n lines.push(` ${row.preview}`);\n }\n lines.push(` path: ${row.path}`);\n }\n return lines.join(\"\\n\");\n}\n\nexport function renderPatternExplain(\n detail: PatternExplainDetail,\n format: PatternsOutputFormat,\n): string {\n if (format === \"json\") {\n return JSON.stringify(detail, null, 2);\n }\n const last = detail.lastReinforcedAt ?? \"—\";\n const derivedVia = detail.derivedVia ?? \"—\";\n if (format === \"markdown\") {\n const lines: string[] = [];\n lines.push(`# Pattern: \\`${detail.id}\\``);\n lines.push(\"\");\n lines.push(`- **Reinforcement count:** ${detail.reinforcementCount}`);\n lines.push(`- **Last reinforced:** ${last}`);\n lines.push(`- **Category:** ${detail.category}`);\n lines.push(`- **Status:** ${detail.status}`);\n lines.push(`- **Derived via:** ${derivedVia}`);\n lines.push(`- **Path:** \\`${detail.canonicalPath}\\``);\n lines.push(\"\");\n lines.push(\"## Canonical content\");\n lines.push(\"\");\n lines.push(\"```\");\n lines.push(detail.canonicalContent);\n lines.push(\"```\");\n lines.push(\"\");\n lines.push(`## Derived from (${detail.derivedFrom.length})`);\n lines.push(\"\");\n if (detail.derivedFrom.length === 0) {\n lines.push(\"_No derived_from entries recorded._\");\n } else {\n for (const entry of detail.derivedFrom) {\n const versionStr =\n entry.version !== null\n ? ` v${entry.version}`\n : entry.malformed\n ? \" (malformed)\"\n : \"\";\n lines.push(`- \\`${entry.path}\\`${versionStr}`);\n }\n }\n lines.push(\"\");\n lines.push(`## Cluster members (${detail.clusterMembers.length})`);\n lines.push(\"\");\n if (detail.clusterMembers.length === 0) {\n lines.push(\"_No superseded members reference this canonical._\");\n } else {\n for (const member of detail.clusterMembers) {\n const ts = member.supersededAt ?? \"—\";\n lines.push(`- \\`${member.id}\\` (status=${member.status}, supersededAt=${ts})`);\n if (member.preview.length > 0) {\n lines.push(` - ${escapePipes(member.preview)}`);\n }\n }\n }\n return lines.join(\"\\n\") + \"\\n\";\n }\n // text\n const lines: string[] = [];\n lines.push(`Pattern: ${detail.id}`);\n lines.push(` reinforcement_count: ${detail.reinforcementCount}`);\n lines.push(` last_reinforced_at: ${last}`);\n lines.push(` category: ${detail.category}`);\n lines.push(` status: ${detail.status}`);\n lines.push(` derived_via: ${derivedVia}`);\n lines.push(` path: ${detail.canonicalPath}`);\n lines.push(\"\");\n lines.push(\"Canonical content:\");\n for (const line of detail.canonicalContent.split(\"\\n\")) {\n lines.push(` ${line}`);\n }\n lines.push(\"\");\n lines.push(`Derived from (${detail.derivedFrom.length}):`);\n if (detail.derivedFrom.length === 0) {\n lines.push(\" (none)\");\n } else {\n for (const entry of detail.derivedFrom) {\n const versionStr =\n entry.version !== null\n ? ` v${entry.version}`\n : entry.malformed\n ? \" (malformed)\"\n : \"\";\n lines.push(` - ${entry.path}${versionStr}`);\n }\n }\n lines.push(\"\");\n lines.push(`Cluster members (${detail.clusterMembers.length}):`);\n if (detail.clusterMembers.length === 0) {\n lines.push(\" (none)\");\n } else {\n for (const member of detail.clusterMembers) {\n const ts = member.supersededAt ?? \"—\";\n lines.push(` - ${member.id} (status=${member.status}, supersededAt=${ts})`);\n if (member.preview.length > 0) {\n lines.push(` ${member.preview}`);\n }\n }\n }\n return lines.join(\"\\n\");\n}\n\n// ───────────────────────────────────────────────────────────────────────────\n// Internal helpers\n// ───────────────────────────────────────────────────────────────────────────\n\nfunction extractPreview(content: string): string {\n const trimmed = content.trim();\n if (trimmed.length === 0) return \"\";\n const firstLine = trimmed.split(\"\\n\").find((line) => line.trim().length > 0) ?? \"\";\n const collapsed = firstLine.trim().replace(/\\s+/g, \" \");\n if (collapsed.length <= 120) return collapsed;\n return collapsed.slice(0, 117) + \"...\";\n}\n\nfunction looksLikeDerivedFromPath(value: string): boolean {\n return value.includes(\"/\") || value.includes(\".\");\n}\n\n/**\n * Escape characters that would break a Markdown table cell:\n * - backslashes first (so the `\\|` escape below isn't double-escaped)\n * - then pipe characters\n *\n * CodeQL \"Incomplete string escaping or encoding\": backslash must be\n * escaped before pipe so that a literal `\\` in content isn't\n * misinterpreted as part of a `\\|` escape sequence.\n */\nfunction escapePipes(value: string): string {\n return value.replace(/\\\\/g, \"\\\\\\\\\").replace(/\\|/g, \"\\\\|\");\n}\n"],"mappings":"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","names":["lines"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/extraction-judge.ts"],"sourcesContent":["/**\n * Extraction Judge — LLM-as-judge fact-worthiness gate (issue #376).\n *\n * Evaluates extracted facts against a durability rubric before they are\n * persisted. Facts that are unlikely to be useful 30+ days from now or\n * across sessions are rejected (or shadow-logged depending on config).\n *\n * Design constraints:\n * - Corrections and principles are auto-approved (safety bypass).\n * - Critical-importance facts are auto-approved.\n * - Batches respect extractionJudgeBatchSize.\n * - Content-hash caching avoids redundant LLM calls.\n * - Performance budget: <= 1.5s per batch.\n */\n\nimport { createHash } from \"node:crypto\";\nimport { log } from \"./logger.js\";\nimport type { PluginConfig, ImportanceLevel } from \"./types.js\";\nimport type { LocalLlmClient } from \"./local-llm.js\";\nimport type { FallbackLlmClient } from \"./fallback-llm.js\";\nimport { extractJsonCandidates } from \"./json-extract.js\";\nimport { normalizeProcedureSteps } from \"./procedural/procedure-types.js\";\n\n// ---------------------------------------------------------------------------\n// Public interfaces\n// ---------------------------------------------------------------------------\n\nexport interface JudgeCandidate {\n text: string;\n category: string;\n confidence: number;\n tags?: string[];\n /** Local importance level, set by caller before judging. */\n importanceLevel?: ImportanceLevel;\n}\n\n/**\n * Verdict kinds (issue #562, PR 1).\n *\n * - `\"accept\"`: fact is durable, persist it.\n * - `\"reject\"`: fact is not durable, drop it.\n * - `\"defer\"`: fact is ambiguous; push it back into the buffer for another\n * pass with fresh context. Inspired by MemReader (arxiv 2604.07877).\n *\n * PR 1 only introduces the type. No emit path produces `\"defer\"` yet — the\n * defer-capable prompt, buffer re-routing, telemetry, and GRPO data\n * collection are landing in PRs 2, 3, and 4 respectively.\n */\nexport type JudgeVerdictKind = \"accept\" | \"reject\" | \"defer\";\n\n/**\n * Judge verdict shape.\n *\n * Back-compat note: `kind` is optional. Verdicts serialized before PR 1\n * (both in-memory cache entries and any persisted caches) only carry\n * `{ durable, reason }`. Downstream consumers must either read `durable`\n * directly, or use {@link getVerdictKind} / {@link isDurableVerdict} which\n * gracefully fall back to the boolean when `kind` is missing, and ignore\n * unknown future `kind` values rather than crashing.\n */\nexport interface JudgeVerdict {\n /**\n * True iff the fact should be persisted. For `\"defer\"` verdicts this is\n * `false` — a deferred fact is not (yet) persisted, so callers that only\n * look at `durable` will treat defer as \"skip this turn\", which matches\n * the pre-PR-1 fail-closed behavior for non-accepted verdicts.\n */\n durable: boolean;\n reason: string;\n /**\n * Optional explicit verdict kind. Added in PR 1 of issue #562. Legacy\n * verdicts (including cache entries produced before this field existed)\n * do not set `kind`; use {@link getVerdictKind} to read this safely.\n */\n kind?: JudgeVerdictKind;\n}\n\n/**\n * Resolve a verdict's effective kind.\n *\n * - If `kind` is explicitly set to one of the known values, return it.\n * - If `kind` is absent, infer from `durable` (back-compat with pre-PR-1\n * cache entries and emit paths that have not been updated yet).\n * - If `kind` is set to an unrecognised value (forward-compat, e.g. a\n * future cache entry loaded by an older build), fall back to `durable`\n * so we never crash on unknown strings.\n */\nexport function getVerdictKind(verdict: JudgeVerdict): JudgeVerdictKind {\n const raw = verdict.kind;\n if (raw === \"accept\" || raw === \"reject\" || raw === \"defer\") {\n return raw;\n }\n return verdict.durable ? \"accept\" : \"reject\";\n}\n\n/**\n * Type guard: returns `true` only for verdicts that should be persisted.\n * Treats both `\"reject\"` and `\"defer\"` as \"not durable\" — defer means the\n * caller should re-evaluate later, not write now.\n */\nexport function isDurableVerdict(verdict: JudgeVerdict): boolean {\n return getVerdictKind(verdict) === \"accept\";\n}\n\n/**\n * Validate a cache entry loaded from persistence / another process.\n *\n * Strict: accepts legacy `{ durable, reason }` entries and new entries\n * whose `kind` is one of the three known `JudgeVerdictKind` values.\n * Rejects structurally wrong types and unknown `kind` strings so the\n * type-guard narrowing is sound — callers that receive\n * `value is JudgeVerdict` can safely treat `kind` as the declared\n * union.\n *\n * Forward-compat is handled by {@link normalizeCachedVerdict}, which\n * drops unknown `kind` strings before validation so a newer build's\n * cache entry still loads instead of being rejected.\n */\nexport function isValidCachedVerdict(value: unknown): value is JudgeVerdict {\n if (typeof value !== \"object\" || value === null) return false;\n const v = value as Record<string, unknown>;\n if (typeof v.durable !== \"boolean\") return false;\n if (typeof v.reason !== \"string\") return false;\n if (v.kind !== undefined) {\n if (v.kind !== \"accept\" && v.kind !== \"reject\" && v.kind !== \"defer\") {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Forward-compatible cache-entry loader.\n *\n * Drops unknown `kind` strings to `undefined` (so `getVerdictKind` can\n * fall back to `durable`), then validates structurally. Non-string\n * `kind` values are still treated as structural violations and rejected.\n * Returns the sanitised verdict, or `null` when the entry is structurally\n * unusable.\n */\nexport function normalizeCachedVerdict(value: unknown): JudgeVerdict | null {\n if (typeof value !== \"object\" || value === null) return null;\n const v = value as Record<string, unknown>;\n if (typeof v.durable !== \"boolean\") return null;\n if (typeof v.reason !== \"string\") return null;\n let kind: JudgeVerdictKind | undefined;\n if (v.kind !== undefined) {\n if (typeof v.kind !== \"string\") return null;\n if (v.kind === \"accept\" || v.kind === \"reject\" || v.kind === \"defer\") {\n kind = v.kind;\n }\n // Unknown string `kind`: dropped to undefined for forward-compat.\n }\n const out: JudgeVerdict = { durable: v.durable, reason: v.reason };\n if (kind !== undefined) out.kind = kind;\n return out;\n}\n\nexport interface JudgeBatchResult {\n verdicts: Map<number, JudgeVerdict>;\n /** Number of verdicts served from cache. */\n cached: number;\n /** Number of verdicts produced by an LLM call. */\n judged: number;\n /** Total wall-clock time in milliseconds. */\n elapsed: number;\n /**\n * Number of verdicts in this batch that resolved to `\"defer\"` (issue #562,\n * PR 2). Callers can use this to decide whether to retain buffer turns for\n * the next extraction pass.\n */\n deferred: number;\n /**\n * Number of defers that were forcibly converted to `\"reject\"` because the\n * same candidate text had already been deferred at least\n * `extractionJudgeMaxDeferrals` times. Rolled out of `deferred` — a\n * candidate counted here is *not* also in `deferred`.\n */\n deferredCappedToReject: number;\n}\n\n/**\n * Per-verdict observation emitted by `judgeFactDurability` when an\n * `onVerdict` callback is supplied (issue #562, PR 3). Used to wire the\n * observation ledger / telemetry stream without coupling the judge module\n * directly to filesystem I/O. One event is emitted for every resolved\n * verdict, including auto-approved and cache-hit paths.\n */\nexport interface JudgeVerdictObservation {\n verdict: JudgeVerdict;\n /** The original `JudgeCandidate` passed in (same reference). */\n candidate: JudgeCandidate;\n /** SHA-256 of `text\\0category`, same key the cache/deferCounter use. */\n contentHash: string;\n /** Verdict resolution path. Useful for debugging + dashboards. */\n source: \"auto-approve\" | \"cache\" | \"llm\" | \"llm-cap-rejected\" | \"fail-open\";\n /**\n * How many times this candidate had already been deferred before this\n * verdict resolved. 0 when the candidate had never been deferred.\n */\n priorDeferrals: number;\n /**\n * Milliseconds from batch start to now. Shared across verdicts emitted in\n * the same batch.\n */\n elapsedMs: number;\n}\n\n// ---------------------------------------------------------------------------\n// Prompt (embedded; mirrors prompts/extraction_judge.prompt.md)\n// ---------------------------------------------------------------------------\n\nconst JUDGE_SYSTEM_PROMPT = `You are a memory curator evaluating whether extracted facts are **durable** — worth storing for long-term recall across sessions.\n\nA fact is **durable** if it will still be useful 30+ days from now and is relevant across multiple sessions, not just the current task.\n\nReturn one of three verdicts per candidate:\n\nACCEPT — the fact is durable, persist it:\n- Personal preferences, identities, or relationships\n- Decisions with rationale that affect future work\n- Corrections to previously held beliefs\n- Principles, rules, or constraints the user wants respected\n- Stable facts about projects, tools, or workflows\n- Commitments, deadlines, or obligations\n\nREJECT — the fact is not durable, drop it:\n- Transient task details (\"currently debugging line 42\")\n- Ephemeral state (\"the build is running now\")\n- Routine operations (\"ran npm install\")\n- Conversational filler or acknowledgements\n- Information that will be stale within hours\n- Step-by-step instructions for a one-time task\n\nDEFER — the fact MIGHT be durable but needs more context to decide. The candidate will be re-evaluated on a later extraction pass with fresh context; if it cannot be resolved within a small number of re-evaluations it will be rejected.\n- Ambiguous referents (\"he said they'd follow up on it\")\n- Partial or in-progress statements that might become durable once completed\n- Future-tense commitments whose subject or timeline is unclear\n- Facts whose durability hinges on context not present in the candidate text\n\nDo NOT use defer as a soft reject. Reject facts you are confident are transient. Only defer when another turn of context would genuinely change the verdict.\n\nReturn a JSON array of objects with these fields:\n- index: number (the candidate index)\n- kind: string — one of \"accept\", \"reject\", \"defer\"\n- reason: string (brief explanation, under 80 characters)\n\nYou may also include durable (boolean) for backwards compatibility: true for accept, false for reject or defer. If kind is omitted, durable determines the verdict.\n\nRules:\n1. Return exactly one verdict per input candidate, matched by index.\n2. When in doubt between accept and reject, lean toward accept — false negatives (losing a useful fact) are worse than false positives (keeping a marginal one).\n3. Use defer only when another turn of context would genuinely change the verdict.\n4. Output valid JSON only. No markdown fences, no commentary.\n\nExample output:\n[{\"index\": 0, \"kind\": \"accept\", \"durable\": true, \"reason\": \"Stable personal preference\"}, {\"index\": 1, \"kind\": \"reject\", \"durable\": false, \"reason\": \"Ephemeral build status\"}, {\"index\": 2, \"kind\": \"defer\", \"durable\": false, \"reason\": \"Ambiguous pronoun\"}]`;\n\n// ---------------------------------------------------------------------------\n// Content-hash cache (in-memory, per-process fallback)\n// ---------------------------------------------------------------------------\n\n/** Maximum entries before evicting the oldest half. */\nconst VERDICT_CACHE_MAX_SIZE = 10_000;\n\n/** Module-level fallback cache, used when callers do not pass their own. */\nconst defaultVerdictCache = new Map<string, JudgeVerdict>();\n\n/**\n * Per-content-hash deferral counter (issue #562, PR 2).\n *\n * When the judge emits a `\"defer\"` verdict for a candidate whose content\n * has already been deferred `extractionJudgeMaxDeferrals` times, the verdict\n * is forcibly converted to `\"reject\"` so a pathological LLM response cannot\n * produce an infinite defer loop.\n *\n * Module-level with a size cap so stale test state cannot leak between runs\n * in the unlikely case a caller does not clear it between processes.\n */\nconst defaultDeferCounts = new Map<string, number>();\nconst DEFER_COUNT_MAX_SIZE = 20_000;\n\nfunction cacheKey(text: string, category: string): string {\n return createHash(\"sha256\").update(`${text}\\0${category}`).digest(\"hex\");\n}\n\n/**\n * Resolve the effective defer cap from config, defaulting to 2 when the\n * config value is missing or non-positive. Matches the PR 2 spec.\n */\nfunction resolveDeferCap(config: PluginConfig): number {\n const raw = (config as { extractionJudgeMaxDeferrals?: number })\n .extractionJudgeMaxDeferrals;\n if (typeof raw === \"number\" && Number.isFinite(raw) && raw >= 1) {\n return Math.floor(raw);\n }\n return 2;\n}\n\n/**\n * Enforce the max-size invariant on a verdict cache. When the cache exceeds\n * VERDICT_CACHE_MAX_SIZE, the oldest half of entries are deleted (Map\n * iteration order is insertion order).\n */\nfunction enforceMaxCacheSize(cache: Map<string, JudgeVerdict>): void {\n if (cache.size <= VERDICT_CACHE_MAX_SIZE) return;\n const deleteCount = Math.floor(cache.size / 2);\n let deleted = 0;\n for (const key of cache.keys()) {\n if (deleted >= deleteCount) break;\n cache.delete(key);\n deleted++;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Categories that bypass the judge (safety / correctness)\n// ---------------------------------------------------------------------------\n\nconst AUTO_APPROVE_CATEGORIES = new Set([\"correction\", \"principle\"]);\n\n/** Explicit trigger phrasing — procedures must match to persist (issue #519). */\nconst PROCEDURE_TRIGGER_RE =\n /(when you|whenever|before you|before running|always\\s|first\\b.*\\bthen|to deploy|to ship|run these steps|follow these steps|how (i|we)\\s|recipe for|workflow|each time you)/i;\n\n/**\n * Deterministic gate for extracted `procedure` memories: ≥2 steps with non-empty\n * intents and explicit trigger wording in title and/or steps.\n */\nexport function validateProcedureExtraction(input: {\n content: string;\n procedureSteps?: unknown;\n}): JudgeVerdict {\n const steps = normalizeProcedureSteps(input.procedureSteps);\n if (steps.length < 2) {\n return { durable: false, reason: \"Procedure requires at least two steps with intents\" };\n }\n const combined = [input.content, ...steps.map((s) => s.intent)].join(\" \").toLowerCase();\n if (!PROCEDURE_TRIGGER_RE.test(combined)) {\n return { durable: false, reason: \"Procedure missing explicit trigger phrasing\" };\n }\n return { durable: true, reason: \"Procedure structure validated\" };\n}\n\n// ---------------------------------------------------------------------------\n// Core judge function\n// ---------------------------------------------------------------------------\n\n/**\n * Evaluate a batch of candidate facts for durability.\n *\n * Auto-approves corrections, principles, and critical-importance facts.\n * Remaining candidates are batched (up to extractionJudgeBatchSize),\n * checked against an in-memory content-hash cache, and sent to the LLM\n * for verdict.\n */\nexport async function judgeFactDurability(\n candidates: JudgeCandidate[],\n config: PluginConfig,\n localLlm: LocalLlmClient | null,\n fallbackLlm: FallbackLlmClient | null,\n cache?: Map<string, JudgeVerdict>,\n deferCounts?: Map<string, number>,\n onVerdict?: (observation: JudgeVerdictObservation) => void,\n): Promise<JudgeBatchResult> {\n const startMs = Date.now();\n const verdicts = new Map<number, JudgeVerdict>();\n let cached = 0;\n let judged = 0;\n let deferred = 0;\n let deferredCappedToReject = 0;\n\n // Use caller-provided cache for per-orchestrator scoping, or fall back\n // to the module-level default cache.\n const verdictCache = cache ?? defaultVerdictCache;\n const deferCountMap = deferCounts ?? defaultDeferCounts;\n const deferCap = resolveDeferCap(config);\n\n // Lazy emit (Codex P2): when `onVerdict` is undefined (default path —\n // telemetry off), payload construction is skipped entirely. Callers\n // pass a factory instead of a pre-built observation so the `sha256`\n // `contentHash` and surrounding object allocation only run when a\n // subscriber is present. For large batches with telemetry off this\n // removes per-verdict overhead that would otherwise fire on every\n // auto-approved / cache / fail-open path.\n const emit = (build: () => JudgeVerdictObservation): void => {\n if (!onVerdict) return;\n let observation: JudgeVerdictObservation;\n try {\n observation = build();\n } catch (err) {\n log.debug(\n `extraction-judge: onVerdict builder threw (non-fatal): ${err instanceof Error ? err.message : String(err)}`,\n );\n return;\n }\n try {\n onVerdict(observation);\n } catch (err) {\n // Fail-open: telemetry errors must never block extraction.\n log.debug(\n `extraction-judge: onVerdict callback threw (non-fatal): ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n };\n\n if (candidates.length === 0) {\n return {\n verdicts,\n cached,\n judged,\n elapsed: 0,\n deferred,\n deferredCappedToReject,\n };\n }\n\n // Indices that need LLM judgment\n const pendingIndices: number[] = [];\n\n for (let i = 0; i < candidates.length; i++) {\n const c = candidates[i];\n\n // Auto-approve safety categories\n if (AUTO_APPROVE_CATEGORIES.has(c.category)) {\n const v: JudgeVerdict = {\n durable: true,\n reason: `Auto-approved: ${c.category} category bypasses judge`,\n };\n verdicts.set(i, v);\n emit(() => ({\n verdict: v,\n candidate: c,\n contentHash: cacheKey(c.text, c.category),\n source: \"auto-approve\",\n priorDeferrals: 0,\n elapsedMs: Date.now() - startMs,\n }));\n continue;\n }\n\n // Auto-approve critical importance\n if (c.importanceLevel === \"critical\") {\n const v: JudgeVerdict = {\n durable: true,\n reason: \"Auto-approved: critical importance\",\n };\n verdicts.set(i, v);\n emit(() => ({\n verdict: v,\n candidate: c,\n contentHash: cacheKey(c.text, c.category),\n source: \"auto-approve\",\n priorDeferrals: 0,\n elapsedMs: Date.now() - startMs,\n }));\n continue;\n }\n\n // Check cache\n const key = cacheKey(c.text, c.category);\n const cachedVerdict = verdictCache.get(key);\n if (cachedVerdict) {\n verdicts.set(i, cachedVerdict);\n cached++;\n emit(() => ({\n verdict: cachedVerdict,\n candidate: c,\n contentHash: key,\n source: \"cache\",\n priorDeferrals: deferCountMap.get(key) ?? 0,\n elapsedMs: Date.now() - startMs,\n }));\n continue;\n }\n\n pendingIndices.push(i);\n }\n\n // If all resolved without LLM, return early\n if (pendingIndices.length === 0) {\n return {\n verdicts,\n cached,\n judged,\n elapsed: Date.now() - startMs,\n deferred,\n deferredCappedToReject,\n };\n }\n\n // Batch the pending candidates up to batchSize\n const batchSize = config.extractionJudgeBatchSize;\n for (let batchStart = 0; batchStart < pendingIndices.length; batchStart += batchSize) {\n const batchIndices = pendingIndices.slice(batchStart, batchStart + batchSize);\n const batchPayload = batchIndices.map((idx) => ({\n index: idx,\n text: candidates[idx].text,\n category: candidates[idx].category,\n confidence: candidates[idx].confidence,\n }));\n\n const userPrompt = JSON.stringify(batchPayload);\n\n try {\n const llmResponse = await callJudgeLlm(\n userPrompt,\n config,\n localLlm,\n fallbackLlm,\n );\n\n if (llmResponse) {\n const parsed = parseJudgeResponse(llmResponse, batchIndices);\n // Per-batch defer-increment dedupe (codex P2): a single extraction\n // pass must not advance the cap more than once for identical\n // candidate content, even if the same text appears multiple times\n // in the same LLM response. Duplicate hits share the first\n // increment's `priorDeferrals` snapshot.\n const deferredThisBatch = new Set<string>();\n for (const [idx, rawVerdict] of parsed.entries()) {\n const c = candidates[idx];\n const key = cacheKey(c.text, c.category);\n let verdict = rawVerdict;\n let source: JudgeVerdictObservation[\"source\"] = \"llm\";\n const priorDefers = deferCountMap.get(key) ?? 0;\n\n // Defer cap (issue #562, PR 2). A candidate that has already been\n // deferred `deferCap` times is forcibly rejected so a pathological\n // LLM response cannot produce an infinite defer loop.\n if (getVerdictKind(verdict) === \"defer\") {\n if (priorDefers >= deferCap) {\n verdict = {\n durable: false,\n reason: `Defer cap reached (${deferCap} prior defers); rejecting`,\n kind: \"reject\",\n };\n source = \"llm-cap-rejected\";\n // Only clear + count the cap conversion once per batch for\n // this key — duplicates in the same response all resolve to\n // reject but should not inflate the cap-rejection counter.\n if (!deferredThisBatch.has(key)) {\n deferCountMap.delete(key);\n deferredCappedToReject++;\n deferredThisBatch.add(key);\n }\n } else if (!deferredThisBatch.has(key)) {\n deferCountMap.set(key, priorDefers + 1);\n deferred++;\n deferredThisBatch.add(key);\n // Bound the per-process defer-counter map.\n if (deferCountMap.size > DEFER_COUNT_MAX_SIZE) {\n const drop = Math.floor(deferCountMap.size / 2);\n let dropped = 0;\n for (const k of deferCountMap.keys()) {\n if (dropped >= drop) break;\n deferCountMap.delete(k);\n dropped++;\n }\n }\n }\n // else: duplicate defer for a key already counted this batch —\n // no additional counter increment, verdict still marked defer.\n } else {\n // On accept/reject, clear any outstanding defer counter so a\n // future reappearance of the same text starts fresh.\n deferCountMap.delete(key);\n }\n\n verdicts.set(idx, verdict);\n judged++;\n // Cache non-defer verdicts. Defer is intentionally NOT cached:\n // caching it would short-circuit the re-evaluation pass that is\n // the entire point of the defer verdict.\n if (getVerdictKind(verdict) !== \"defer\") {\n verdictCache.set(key, verdict);\n }\n emit(() => ({\n verdict,\n candidate: c,\n contentHash: key,\n source,\n priorDeferrals: priorDefers,\n elapsedMs: Date.now() - startMs,\n }));\n }\n // Evict oldest entries if cache exceeds max size\n enforceMaxCacheSize(verdictCache);\n }\n } catch (err) {\n // Fail-open: if the LLM call fails, approve all candidates in this batch\n log.warn(\n `extraction-judge: LLM call failed, approving batch (fail-open): ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n\n // Fill in any missing verdicts from this batch (fail-open: approve).\n // Clear defer counts so a transient outage doesn't leave stale state\n // that causes later defers to hit the cap early.\n for (const idx of batchIndices) {\n if (!verdicts.has(idx)) {\n const c = candidates[idx];\n const hash = cacheKey(c.text, c.category);\n // Capture the prior deferral count BEFORE clearing so the\n // telemetry event reflects the true state rather than always 0.\n const priorDefers = deferCountMap.get(hash) ?? 0;\n deferCountMap.delete(hash);\n const v: JudgeVerdict = {\n durable: true,\n reason: \"Approved by default (judge unavailable or parse error)\",\n };\n verdicts.set(idx, v);\n emit(() => {\n return {\n verdict: v,\n candidate: c,\n contentHash: hash,\n source: \"fail-open\",\n priorDeferrals: priorDefers,\n elapsedMs: Date.now() - startMs,\n };\n });\n }\n }\n }\n\n return {\n verdicts,\n cached,\n judged,\n elapsed: Date.now() - startMs,\n deferred,\n deferredCappedToReject,\n };\n}\n\n// ---------------------------------------------------------------------------\n// LLM call helpers\n// ---------------------------------------------------------------------------\n\nasync function callJudgeLlm(\n userPrompt: string,\n config: PluginConfig,\n localLlm: LocalLlmClient | null,\n fallbackLlm: FallbackLlmClient | null,\n): Promise<string | null> {\n const messages: Array<{ role: \"system\" | \"user\"; content: string }> = [\n { role: \"system\", content: JUDGE_SYSTEM_PROMPT },\n { role: \"user\", content: userPrompt },\n ];\n\n const modelOverride = config.extractionJudgeModel || undefined;\n\n // When modelSource is \"gateway\", skip localLlm and go directly to fallback\n // (the gateway-routed backend). This respects the operator's explicit\n // routing preference.\n const skipLocal = config.modelSource === \"gateway\";\n\n // Resolve the gateway agent ID so the fallback LLM routes through the\n // correct agent persona's model chain — identical to the pattern used\n // by ExtractionEngine.withGatewayAgent().\n const agentId =\n config.modelSource === \"gateway\"\n ? (config.gatewayAgentId || undefined)\n : undefined;\n\n // Try local LLM first (unless modelSource says gateway)\n if (localLlm && !skipLocal) {\n try {\n const result = await (localLlm as any).chatCompletion(messages, {\n temperature: 0.1,\n maxTokens: 2048,\n responseFormat: { type: \"json_object\" },\n timeoutMs: 1500,\n operation: \"extraction-judge\",\n ...(modelOverride ? { model: modelOverride } : {}),\n });\n if (result?.content) {\n return result.content;\n }\n } catch (err) {\n log.debug(\n `extraction-judge: local LLM failed, trying fallback: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n // Try fallback LLM\n if (fallbackLlm) {\n try {\n const result = await fallbackLlm.chatCompletion(\n messages as Array<{ role: \"system\" | \"user\" | \"assistant\"; content: string }>,\n {\n temperature: 0.1,\n maxTokens: 2048,\n timeoutMs: 1500,\n ...(modelOverride ? { model: modelOverride } : {}),\n ...(agentId ? { agentId } : {}),\n },\n );\n if (result?.content) {\n return result.content;\n }\n } catch (err) {\n log.debug(\n `extraction-judge: fallback LLM failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Response parsing\n// ---------------------------------------------------------------------------\n\nfunction parseJudgeResponse(\n raw: string,\n expectedIndices: number[],\n): Map<number, JudgeVerdict> {\n const result = new Map<number, JudgeVerdict>();\n const expectedSet = new Set(expectedIndices);\n\n try {\n // Try direct parse first, then fall back to JSON extraction\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n const candidates = extractJsonCandidates(raw);\n if (candidates.length > 0) {\n parsed = JSON.parse(candidates[0]);\n }\n }\n\n if (!Array.isArray(parsed)) {\n // Might be wrapped in an object with a key\n if (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) {\n const values = Object.values(parsed as Record<string, unknown>);\n for (const v of values) {\n if (Array.isArray(v)) {\n parsed = v;\n break;\n }\n }\n }\n if (!Array.isArray(parsed)) {\n log.debug(\"extraction-judge: response is not an array, cannot parse\");\n return result;\n }\n }\n\n for (const item of parsed) {\n if (\n typeof item !== \"object\" ||\n item === null ||\n typeof (item as any).index !== \"number\"\n ) {\n continue;\n }\n const idx = (item as any).index as number;\n if (!expectedSet.has(idx)) continue;\n\n // Parse kind first — it's the primary signal in PR 2 and above.\n // Fall back to durable for pre-PR-2 model responses that only return\n // the boolean.\n let kind: JudgeVerdictKind | undefined;\n const rawKind = (item as any).kind;\n const rawAction = (item as any).action;\n if (rawKind === \"accept\" || rawKind === \"reject\" || rawKind === \"defer\") {\n kind = rawKind;\n } else if (\n rawAction === \"accept\" ||\n rawAction === \"reject\" ||\n rawAction === \"defer\"\n ) {\n // Tolerate `action` as an alias — MemReader uses that word in the\n // paper and models may echo it.\n kind = rawAction;\n }\n\n const hasDurable = typeof (item as any).durable === \"boolean\";\n const durableFromModel = hasDurable\n ? ((item as any).durable as boolean)\n : undefined;\n\n // Resolve the durable flag from kind when present; otherwise trust\n // the model's boolean; otherwise fail-open to durable=true.\n let durable: boolean;\n if (kind === \"accept\") {\n durable = true;\n } else if (kind === \"reject\" || kind === \"defer\") {\n durable = false;\n } else if (durableFromModel !== undefined) {\n durable = durableFromModel;\n } else {\n durable = true; // fail-open\n }\n\n const reason =\n typeof (item as any).reason === \"string\"\n ? ((item as any).reason as string).slice(0, 120)\n : \"No reason provided\";\n\n const verdict: JudgeVerdict = { durable, reason };\n if (kind !== undefined) verdict.kind = kind;\n result.set(idx, verdict);\n }\n } catch (err) {\n log.debug(\n `extraction-judge: failed to parse response: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Cache management (exposed for testing)\n// ---------------------------------------------------------------------------\n\n/** Clear the in-memory default verdict cache. Primarily for tests. */\nexport function clearVerdictCache(): void {\n defaultVerdictCache.clear();\n defaultDeferCounts.clear();\n}\n\n/** Return the current default verdict cache size. Primarily for tests. */\nexport function verdictCacheSize(): number {\n return defaultVerdictCache.size;\n}\n\n/** Create a new per-instance verdict cache. Orchestrators should hold one. */\nexport function createVerdictCache(): Map<string, JudgeVerdict> {\n return new Map();\n}\n\n/**\n * Create a new per-instance defer-counter map. Orchestrators should hold one\n * alongside their verdict cache so defer counts survive across extraction\n * passes within a single orchestrator but do not leak across orchestrators.\n */\nexport function createDeferCountMap(): Map<string, number> {\n return new Map();\n}\n"],"mappings":"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","names":[]}