@remnic/core 10.0.38 → 10.0.40

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 (444) hide show
  1. package/dist/access-admin-ops-surface.js +73 -73
  2. package/dist/access-audit.js +2 -2
  3. package/dist/access-authorization-probe.js +74 -74
  4. package/dist/access-boundary.js +73 -73
  5. package/dist/access-citation-namespace.js +2 -2
  6. package/dist/access-cli.js +162 -161
  7. package/dist/access-cli.js.map +1 -1
  8. package/dist/access-extraction-force-flush.js +73 -73
  9. package/dist/access-http-briefing.js +74 -74
  10. package/dist/access-http-query.js +75 -75
  11. package/dist/access-http.js +98 -98
  12. package/dist/access-identity-continuity-surface.js +73 -73
  13. package/dist/access-lcm-surface.js +73 -73
  14. package/dist/access-mcp.js +87 -87
  15. package/dist/access-namespace-preflight.js +73 -73
  16. package/dist/access-observe-write-category.js +15 -15
  17. package/dist/access-observe-write-surface.js +73 -73
  18. package/dist/access-offline-manifest.js +12 -12
  19. package/dist/access-operations-batch.js +77 -77
  20. package/dist/access-operations.js +84 -84
  21. package/dist/access-recall-concurrency.js +73 -73
  22. package/dist/access-recall-diagnostics.js +2 -2
  23. package/dist/access-recall-response.js +73 -73
  24. package/dist/access-recall-surface.js +73 -73
  25. package/dist/access-schema.js +10 -10
  26. package/dist/access-service.d.ts +2 -2
  27. package/dist/access-service.d.ts.map +1 -1
  28. package/dist/access-service.js +73 -73
  29. package/dist/access-surface-catalog.js +75 -75
  30. package/dist/active-recall.js +29 -29
  31. package/dist/adapters/index.js +4 -4
  32. package/dist/adapters/registry.js +2 -2
  33. package/dist/{auto-sync-432USQDH.js → auto-sync-BNCBMU6H.js} +7 -7
  34. package/dist/briefing.js +19 -19
  35. package/dist/buffer-types.d.ts +59 -0
  36. package/dist/buffer-types.d.ts.map +1 -0
  37. package/dist/buffer-types.js +1 -0
  38. package/dist/buffer.d.ts +14 -22
  39. package/dist/buffer.d.ts.map +1 -1
  40. package/dist/buffer.js +11 -11
  41. package/dist/calibration.js +2 -2
  42. package/dist/{capsule-crypto-7FJQINUR.js → capsule-crypto-GWVG7LGC.js} +2 -2
  43. package/dist/causal-behavior.js +2 -2
  44. package/dist/causal-chain.js +2 -2
  45. package/dist/causal-consolidation.js +22 -22
  46. package/dist/causal-retrieval.js +2 -2
  47. package/dist/causal-trajectory-graph.js +2 -2
  48. package/dist/causal-trajectory.js +1 -1
  49. package/dist/{chunk-MKE5DP3S.js → chunk-23ZMQONL.js} +2 -2
  50. package/dist/{chunk-3K5IEJTK.js → chunk-2AV2U2SZ.js} +3 -3
  51. package/dist/{chunk-HJ3UTGIW.js → chunk-2JNBPOZ2.js} +3 -3
  52. package/dist/{chunk-5ANUG4JZ.js → chunk-2T6KEOUL.js} +2 -2
  53. package/dist/{chunk-EEOYF3IB.js → chunk-3RJDYZJE.js} +2 -2
  54. package/dist/{chunk-P5CUEB2Q.js → chunk-4QLKVZH6.js} +8 -8
  55. package/dist/{chunk-XTBEXZFN.js → chunk-5SF7JOJB.js} +4 -4
  56. package/dist/{chunk-53BLBDV6.js → chunk-5TRU6QQC.js} +2 -2
  57. package/dist/{chunk-DKHX2FHI.js → chunk-64WHWIPL.js} +2 -2
  58. package/dist/{chunk-TVIGN3XZ.js → chunk-6FRFVIKC.js} +10 -10
  59. package/dist/{chunk-JIA435P3.js → chunk-6ITNEPJO.js} +2 -2
  60. package/dist/{chunk-WEK3OUGO.js → chunk-6X3J4NLZ.js} +10 -5
  61. package/dist/chunk-6X3J4NLZ.js.map +1 -0
  62. package/dist/{chunk-FGEY2AGV.js → chunk-7BCYAJKP.js} +2 -2
  63. package/dist/{chunk-PSQ2P2T3.js → chunk-7XZ7TOLQ.js} +3 -3
  64. package/dist/{chunk-6JEEY42N.js → chunk-AER3HD3B.js} +2 -2
  65. package/dist/{chunk-POGPI5GR.js → chunk-AY6LO7GD.js} +2 -2
  66. package/dist/{chunk-HXFIILGF.js → chunk-BFPF5N3H.js} +4 -4
  67. package/dist/{chunk-WCBLPKG3.js → chunk-BIYVUPC6.js} +172 -143
  68. package/dist/chunk-BIYVUPC6.js.map +1 -0
  69. package/dist/{chunk-KQAFEZQX.js → chunk-BUKK5SWA.js} +2 -2
  70. package/dist/{chunk-LHBOFROT.js → chunk-CHNZPOWX.js} +4 -3
  71. package/dist/{chunk-LHBOFROT.js.map → chunk-CHNZPOWX.js.map} +1 -1
  72. package/dist/{chunk-6F5BGIAF.js → chunk-CNAL35D5.js} +3 -3
  73. package/dist/{chunk-YC2C67F7.js → chunk-CRXGQRNA.js} +3 -3
  74. package/dist/{chunk-WRDFYSUC.js → chunk-CZVNOTLR.js} +2 -2
  75. package/dist/{chunk-VPO53QMG.js → chunk-D6DOLQYK.js} +2 -2
  76. package/dist/{chunk-RGKXF4W3.js → chunk-E5IEI2MR.js} +2 -2
  77. package/dist/{chunk-Z2T5BPOZ.js → chunk-EIYJK7OD.js} +2 -2
  78. package/dist/{chunk-FRAL3EU4.js → chunk-EKPRLTAE.js} +2 -2
  79. package/dist/{chunk-MCPSMWUC.js → chunk-EPEDMEHO.js} +10 -10
  80. package/dist/{chunk-MCPSMWUC.js.map → chunk-EPEDMEHO.js.map} +1 -1
  81. package/dist/{chunk-TYGLV6ZG.js → chunk-EYGOM6AI.js} +2 -2
  82. package/dist/{chunk-TYGLV6ZG.js.map → chunk-EYGOM6AI.js.map} +1 -1
  83. package/dist/{chunk-I75BWXRZ.js → chunk-F2RDRE7M.js} +2 -2
  84. package/dist/{chunk-2AKIVSHP.js → chunk-FAKRTS3Y.js} +2 -2
  85. package/dist/{chunk-MZWHIAOL.js → chunk-FC3ZFEXF.js} +2 -2
  86. package/dist/{chunk-3PLAL2KP.js → chunk-FJ264QBP.js} +17 -9
  87. package/dist/chunk-FJ264QBP.js.map +1 -0
  88. package/dist/{chunk-7VFNGQ4V.js → chunk-FLDXEJFX.js} +2 -2
  89. package/dist/{chunk-TYLNWE4D.js → chunk-FNEYSTB6.js} +2 -2
  90. package/dist/{chunk-XHX67LX6.js → chunk-FPHU6KVI.js} +2 -2
  91. package/dist/{chunk-JH4FCVWJ.js → chunk-G6OFEGUR.js} +2 -2
  92. package/dist/{chunk-WCIDCJOQ.js → chunk-GAUS4XGN.js} +3 -3
  93. package/dist/{chunk-SZPPCEYT.js → chunk-GDOI4U4D.js} +2 -2
  94. package/dist/{chunk-63YPKHAU.js → chunk-GLB6VV3J.js} +2 -2
  95. package/dist/{chunk-3XVBGGF3.js → chunk-GRN4BVPM.js} +2 -2
  96. package/dist/{chunk-ZAP7BKTZ.js → chunk-GZMHBRIR.js} +6 -6
  97. package/dist/{chunk-645WOU5I.js → chunk-H7BZBSP6.js} +4 -4
  98. package/dist/{chunk-TXP7Q7T5.js → chunk-HN35OH2C.js} +2 -2
  99. package/dist/{chunk-SWZOAQUM.js → chunk-HSNV4CSW.js} +57 -57
  100. package/dist/{chunk-GFYFKXWZ.js → chunk-HUDPXTXW.js} +2 -2
  101. package/dist/{chunk-C2KOW2UQ.js → chunk-I7CWAJHX.js} +2 -2
  102. package/dist/{chunk-L2JQSG5M.js → chunk-I7TR2OCU.js} +2 -2
  103. package/dist/{chunk-5DCS4C4S.js → chunk-ICTJOOWZ.js} +4 -4
  104. package/dist/{chunk-NH6GZEQN.js → chunk-IF6EG22P.js} +10 -10
  105. package/dist/chunk-IF6EG22P.js.map +1 -0
  106. package/dist/{chunk-STM4T335.js → chunk-IJH6METJ.js} +2 -2
  107. package/dist/{chunk-6SYS5YX3.js → chunk-IJJWM2ZA.js} +2 -2
  108. package/dist/{chunk-3AODCBKX.js → chunk-IWDFHVPJ.js} +6 -6
  109. package/dist/{chunk-XHVO3CGX.js → chunk-JGS55BAS.js} +53 -2
  110. package/dist/chunk-JGS55BAS.js.map +1 -0
  111. package/dist/{chunk-L7PGPH4E.js → chunk-JJSMSS45.js} +2 -2
  112. package/dist/{chunk-74AY3S7U.js → chunk-JNLYHJG7.js} +4 -4
  113. package/dist/{chunk-OLH4XCLU.js → chunk-JXQTECMU.js} +2 -2
  114. package/dist/{chunk-6QOL4G76.js → chunk-KQXRVELF.js} +2 -2
  115. package/dist/{chunk-PJRKLB4Z.js → chunk-L5PM7B3I.js} +16 -2
  116. package/dist/{chunk-PJRKLB4Z.js.map → chunk-L5PM7B3I.js.map} +1 -1
  117. package/dist/{chunk-VGRM43X6.js → chunk-LB6HIXQC.js} +2 -2
  118. package/dist/{chunk-N7DVBHU3.js → chunk-LR7RW4T6.js} +3 -3
  119. package/dist/{chunk-AYBAC2N4.js → chunk-LWIU5BMA.js} +3 -3
  120. package/dist/{chunk-FZVZYU5C.js → chunk-LXN737FX.js} +2 -2
  121. package/dist/{chunk-7ZRRJ6RG.js → chunk-MGYZENUY.js} +2 -2
  122. package/dist/{chunk-YQ6SLFNZ.js → chunk-MPJDQC4G.js} +3 -3
  123. package/dist/{chunk-7HXZOWTR.js → chunk-N3PUGD7E.js} +2 -2
  124. package/dist/{chunk-EGNONTVT.js → chunk-NBEM5QEH.js} +6 -6
  125. package/dist/{chunk-QO5KDQGG.js → chunk-NFJWB27H.js} +20 -18
  126. package/dist/chunk-NFJWB27H.js.map +1 -0
  127. package/dist/{chunk-JF3MEIHO.js → chunk-O67H7OXJ.js} +4 -4
  128. package/dist/{chunk-OLHN4ZNT.js → chunk-ONIVKGNC.js} +3 -3
  129. package/dist/{chunk-2NLLXCJG.js → chunk-OWHERGF2.js} +2 -2
  130. package/dist/{chunk-I73ZSORJ.js → chunk-OXSTKCYK.js} +4 -4
  131. package/dist/{chunk-UFM3PJDT.js → chunk-PARM6OYL.js} +1 -1
  132. package/dist/chunk-PARM6OYL.js.map +1 -0
  133. package/dist/{chunk-VSSQIBVU.js → chunk-PJXSBXEC.js} +2 -2
  134. package/dist/{chunk-4B37KNMP.js → chunk-PW63SXFM.js} +2 -2
  135. package/dist/{chunk-TPKB7T6Z.js → chunk-Q6UZREJK.js} +2 -2
  136. package/dist/{chunk-X247CYL6.js → chunk-Q77SLBWT.js} +4 -4
  137. package/dist/{chunk-TAEJ2MRR.js → chunk-QFD7OANX.js} +62 -62
  138. package/dist/chunk-QFD7OANX.js.map +1 -0
  139. package/dist/{chunk-5K23NQRI.js → chunk-QGNZ5QPV.js} +2 -2
  140. package/dist/{chunk-UJDTXWMT.js → chunk-QIMGULGN.js} +2 -2
  141. package/dist/{chunk-E24RUQEN.js → chunk-QNIYL5SK.js} +2 -2
  142. package/dist/{chunk-KOY25HUB.js → chunk-QYAXMXOB.js} +2 -2
  143. package/dist/{chunk-J7G656MY.js → chunk-R42VUN5V.js} +4 -4
  144. package/dist/{chunk-LOMSBYNS.js → chunk-RPHCSMTQ.js} +309 -106
  145. package/dist/chunk-RPHCSMTQ.js.map +1 -0
  146. package/dist/{chunk-AYXRK264.js → chunk-RROFIAYI.js} +9 -9
  147. package/dist/{chunk-YYGZ4EIY.js → chunk-RUAIO5UA.js} +2 -2
  148. package/dist/{chunk-E5PVMB3I.js → chunk-SDXBR5QO.js} +2 -2
  149. package/dist/{chunk-OKKBOTRA.js → chunk-SLVR3U4E.js} +2 -2
  150. package/dist/{chunk-CUWOSRCS.js → chunk-SUKPM6DV.js} +2 -2
  151. package/dist/{chunk-TDCR6PQL.js → chunk-TWRPWJJT.js} +2 -2
  152. package/dist/{chunk-6DTIYAAN.js → chunk-UGV256H3.js} +2 -2
  153. package/dist/{chunk-DG4H56SK.js → chunk-UIK3U36O.js} +2 -2
  154. package/dist/{chunk-KOAVX2IT.js → chunk-UKIIAEJF.js} +2 -2
  155. package/dist/{chunk-XLEP7SS3.js → chunk-UMSH4I3E.js} +2 -2
  156. package/dist/{chunk-X7Y7WX73.js → chunk-UVYI6VIX.js} +1 -1
  157. package/dist/chunk-VA3GNAWQ.js +58 -0
  158. package/dist/chunk-VA3GNAWQ.js.map +1 -0
  159. package/dist/{chunk-4P4VLPGB.js → chunk-VECRSYQG.js} +1 -1
  160. package/dist/{chunk-GGI6FLO6.js → chunk-VHBGJAYC.js} +2 -2
  161. package/dist/{chunk-NMKETOAX.js → chunk-VSHWPOUB.js} +2 -2
  162. package/dist/{chunk-VC3X7XP3.js → chunk-VTZSIG6O.js} +2 -2
  163. package/dist/{chunk-UBN5AOLT.js → chunk-W5EO4USJ.js} +2 -2
  164. package/dist/{chunk-Y7427SL7.js → chunk-WCGJK4NQ.js} +4 -4
  165. package/dist/{chunk-4IZ6AC2U.js → chunk-WJMAWDAU.js} +2 -2
  166. package/dist/{chunk-JH2ALMPR.js → chunk-WR5POHQ3.js} +2 -2
  167. package/dist/{chunk-EHIKY2IA.js → chunk-WU5WTCH5.js} +2 -2
  168. package/dist/{chunk-QKXPOLQD.js → chunk-WUBGMV3G.js} +6 -6
  169. package/dist/{chunk-FKTMWDN2.js → chunk-WUL6LDJ4.js} +2 -2
  170. package/dist/{chunk-5UPOKIFP.js → chunk-XBHUMPIQ.js} +12 -12
  171. package/dist/{chunk-Y5ZHZKZD.js → chunk-XJ77IOAD.js} +2 -2
  172. package/dist/{chunk-U7HJBODU.js → chunk-XKTHJHSQ.js} +5 -5
  173. package/dist/{chunk-FQFMLOAC.js → chunk-XLUMO5H2.js} +20 -20
  174. package/dist/chunk-XLUMO5H2.js.map +1 -0
  175. package/dist/{chunk-JFI3ATK4.js → chunk-XMYWYJM2.js} +2 -2
  176. package/dist/{chunk-64S6X4IU.js → chunk-XTN54NML.js} +4 -4
  177. package/dist/{chunk-CVMAOPAH.js → chunk-XXBCUIYQ.js} +10 -10
  178. package/dist/{chunk-QOUKZ2N3.js → chunk-XXW3P3RX.js} +2 -2
  179. package/dist/{chunk-RWRHGE75.js → chunk-Y473XFTD.js} +2 -2
  180. package/dist/{chunk-VGFNTY3Y.js → chunk-YFXRLRKP.js} +2 -2
  181. package/dist/{chunk-DAOMWGO2.js → chunk-ZX5N5D6M.js} +4 -4
  182. package/dist/cli.js +121 -121
  183. package/dist/coding/export-okf-codegraph.js +20 -20
  184. package/dist/coding/pre-action-gate.js +2 -2
  185. package/dist/compounding/engine.js +21 -21
  186. package/dist/config.d.ts.map +1 -1
  187. package/dist/config.js +29 -29
  188. package/dist/connectors/codex-materialize-runner.js +19 -19
  189. package/dist/connectors/index.js +19 -19
  190. package/dist/contradiction/index.js +5 -5
  191. package/dist/convergence-refresh.js +21 -21
  192. package/dist/corpus-watermark.js +21 -21
  193. package/dist/deep-recall-http-glue.js +11 -11
  194. package/dist/deep-recall.js +2 -2
  195. package/dist/entity-retrieval.js +20 -20
  196. package/dist/event-order-recall.js +2 -2
  197. package/dist/explicit-capture.js +6 -6
  198. package/dist/external-wiki-access.js +74 -74
  199. package/dist/extraction-error-classification.d.ts +15 -0
  200. package/dist/extraction-error-classification.d.ts.map +1 -1
  201. package/dist/extraction-error-classification.js +7 -3
  202. package/dist/extraction-window-drain.d.ts +48 -0
  203. package/dist/extraction-window-drain.d.ts.map +1 -0
  204. package/dist/extraction-window-drain.js +14 -0
  205. package/dist/extraction.js +28 -28
  206. package/dist/{graph-edge-decay-2BZTY2IM.js → graph-edge-decay-3HVLMT6U.js} +5 -5
  207. package/dist/graph-edge-decay-3HVLMT6U.js.map +1 -0
  208. package/dist/graph-jsonl.js +3 -3
  209. package/dist/graph-snapshot.js +3 -3
  210. package/dist/graph.js +4 -4
  211. package/dist/harmonic-retrieval.js +20 -20
  212. package/dist/harmonic-source-lookup.js +2 -2
  213. package/dist/index.js +209 -208
  214. package/dist/lcm/engine.js +2 -2
  215. package/dist/lcm/index.js +7 -7
  216. package/dist/local-llm.js +2 -2
  217. package/dist/location/index.js +22 -22
  218. package/dist/maintenance/memory-governance.js +19 -19
  219. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +19 -19
  220. package/dist/maintenance/rebuild-memory-projection-runner.js +21 -21
  221. package/dist/maintenance/rebuild-memory-projection.js +20 -20
  222. package/dist/memory-browse-operations.js +74 -74
  223. package/dist/memory-browse.js +6 -6
  224. package/dist/memory-subject.js +3 -3
  225. package/dist/namespaces/migrate.js +20 -20
  226. package/dist/namespaces/search.d.ts +1 -0
  227. package/dist/namespaces/search.d.ts.map +1 -1
  228. package/dist/namespaces/search.js +11 -9
  229. package/dist/namespaces/storage.js +19 -19
  230. package/dist/offline-sync-changeset-generations.js +3 -3
  231. package/dist/offline-sync-embedding-generation.js +2 -2
  232. package/dist/offline-sync-file-io.js +2 -2
  233. package/dist/offline-sync-impression-drain.js +3 -3
  234. package/dist/offline-sync-snapshot-stream.js +8 -8
  235. package/dist/offline-sync-upload-staging.js +3 -3
  236. package/dist/offline-sync.js +9 -9
  237. package/dist/operator-doctor-corpus.js +22 -22
  238. package/dist/operator-toolkit.js +40 -40
  239. package/dist/orchestration/extraction-drain.d.ts +90 -0
  240. package/dist/orchestration/extraction-drain.d.ts.map +1 -0
  241. package/dist/orchestration/extraction-run-helpers.d.ts +3 -0
  242. package/dist/orchestration/extraction-run-helpers.d.ts.map +1 -1
  243. package/dist/orchestration/extraction-run.d.ts +4 -1
  244. package/dist/orchestration/extraction-run.d.ts.map +1 -1
  245. package/dist/orchestration/maintenance.js +33 -33
  246. package/dist/orchestration/qmd-result-resolver.d.ts +5 -0
  247. package/dist/orchestration/qmd-result-resolver.d.ts.map +1 -1
  248. package/dist/orchestration/recall-search-pipeline.d.ts.map +1 -1
  249. package/dist/orchestration/turn-ingestion.d.ts +3 -0
  250. package/dist/orchestration/turn-ingestion.d.ts.map +1 -1
  251. package/dist/orchestrator.d.ts +8 -0
  252. package/dist/orchestrator.d.ts.map +1 -1
  253. package/dist/orchestrator.js +162 -161
  254. package/dist/qmd.js +5 -5
  255. package/dist/recall-explain-renderer.js +3 -3
  256. package/dist/recall-navigate-access.js +2 -2
  257. package/dist/recall-navigate-disclosure.js +2 -2
  258. package/dist/recall-navigate.js +2 -2
  259. package/dist/recall-navigation-operations.js +74 -74
  260. package/dist/recall-navigation.js +73 -73
  261. package/dist/recall-state-view-admission.js +6 -6
  262. package/dist/recall-why-service.js +6 -6
  263. package/dist/recall-xray-cli.js +4 -4
  264. package/dist/recall-xray-renderer.js +3 -3
  265. package/dist/recall-xray.js +2 -2
  266. package/dist/reconcile/manifest.js +3 -3
  267. package/dist/{resolution-4ZEQPXUZ.js → resolution-NNYG37YB.js} +6 -6
  268. package/dist/resolution-NNYG37YB.js.map +1 -0
  269. package/dist/resume-bundles.js +30 -30
  270. package/dist/retrieval-agents.js +2 -2
  271. package/dist/salvage-envelope.js +5 -5
  272. package/dist/search/factory.js +6 -6
  273. package/dist/search/index.js +10 -10
  274. package/dist/secure-store/index.js +2 -2
  275. package/dist/semantic-consolidation.js +20 -20
  276. package/dist/semantic-rule-promotion.js +19 -19
  277. package/dist/semantic-rule-verifier.js +19 -19
  278. package/dist/source-agent-qualifier.js +23 -23
  279. package/dist/standup/build.js +19 -19
  280. package/dist/storage/dropped-extraction-chunk.d.ts +8 -0
  281. package/dist/storage/dropped-extraction-chunk.d.ts.map +1 -0
  282. package/dist/storage.d.ts +1 -0
  283. package/dist/storage.d.ts.map +1 -1
  284. package/dist/storage.js +18 -18
  285. package/dist/subject-config.js +4 -4
  286. package/dist/summarizer.js +3 -3
  287. package/dist/support-passport/index.js +76 -76
  288. package/dist/transfer/backup.js +2 -2
  289. package/dist/transfer/capsule-export.js +2 -2
  290. package/dist/transfer/capsule-import.js +2 -2
  291. package/dist/transfer/export-okf.js +20 -20
  292. package/dist/types.d.ts +7 -0
  293. package/dist/types.d.ts.map +1 -1
  294. package/dist/types.js +1 -1
  295. package/dist/verified-recall.js +19 -19
  296. package/dist/who-knows-cli.js +20 -20
  297. package/dist/who-knows.js +19 -19
  298. package/dist/write-envelope.js +4 -4
  299. package/package.json +2 -2
  300. package/src/access-entity-principal.test.ts +190 -0
  301. package/src/access-http.ts +2 -2
  302. package/src/access-operations-batch.ts +2 -2
  303. package/src/access-service.ts +7 -6
  304. package/src/buffer-drop-extraction-chunk.test.ts +196 -0
  305. package/src/buffer-types.ts +65 -0
  306. package/src/buffer.ts +60 -62
  307. package/src/chat/chat-executor.ts +1 -1
  308. package/src/config.ts +8 -0
  309. package/src/extraction-error-classification.ts +23 -0
  310. package/src/extraction-local-failure-class.test.ts +55 -0
  311. package/src/extraction-window-drain.test.ts +123 -0
  312. package/src/extraction-window-drain.ts +110 -0
  313. package/src/extraction.ts +9 -9
  314. package/src/namespaces/search.ts +1 -1
  315. package/src/orchestration/extraction-drain.ts +261 -0
  316. package/src/orchestration/extraction-run-helpers.ts +8 -0
  317. package/src/orchestration/extraction-run.test.ts +83 -2
  318. package/src/orchestration/extraction-run.ts +5 -4
  319. package/src/orchestration/qmd-result-resolver.ts +26 -1
  320. package/src/orchestration/recall-search-pipeline.ts +11 -12
  321. package/src/orchestration/turn-ingestion.ts +9 -5
  322. package/src/orchestrator.ts +21 -0
  323. package/src/secure-store/secure-fs.ts +3 -1
  324. package/src/storage/dropped-extraction-chunk.ts +27 -0
  325. package/src/storage-dropped-chunk-filenames.test.ts +30 -0
  326. package/src/storage.ts +6 -7
  327. package/src/types.ts +7 -0
  328. package/dist/chunk-3PLAL2KP.js.map +0 -1
  329. package/dist/chunk-FQFMLOAC.js.map +0 -1
  330. package/dist/chunk-LOMSBYNS.js.map +0 -1
  331. package/dist/chunk-NH6GZEQN.js.map +0 -1
  332. package/dist/chunk-QO5KDQGG.js.map +0 -1
  333. package/dist/chunk-TAEJ2MRR.js.map +0 -1
  334. package/dist/chunk-UFM3PJDT.js.map +0 -1
  335. package/dist/chunk-WCBLPKG3.js.map +0 -1
  336. package/dist/chunk-WEK3OUGO.js.map +0 -1
  337. package/dist/chunk-XHVO3CGX.js.map +0 -1
  338. /package/dist/{auto-sync-432USQDH.js.map → auto-sync-BNCBMU6H.js.map} +0 -0
  339. /package/dist/{capsule-crypto-7FJQINUR.js.map → buffer-types.js.map} +0 -0
  340. /package/dist/{graph-edge-decay-2BZTY2IM.js.map → capsule-crypto-GWVG7LGC.js.map} +0 -0
  341. /package/dist/{chunk-MKE5DP3S.js.map → chunk-23ZMQONL.js.map} +0 -0
  342. /package/dist/{chunk-3K5IEJTK.js.map → chunk-2AV2U2SZ.js.map} +0 -0
  343. /package/dist/{chunk-HJ3UTGIW.js.map → chunk-2JNBPOZ2.js.map} +0 -0
  344. /package/dist/{chunk-5ANUG4JZ.js.map → chunk-2T6KEOUL.js.map} +0 -0
  345. /package/dist/{chunk-EEOYF3IB.js.map → chunk-3RJDYZJE.js.map} +0 -0
  346. /package/dist/{chunk-P5CUEB2Q.js.map → chunk-4QLKVZH6.js.map} +0 -0
  347. /package/dist/{chunk-XTBEXZFN.js.map → chunk-5SF7JOJB.js.map} +0 -0
  348. /package/dist/{chunk-53BLBDV6.js.map → chunk-5TRU6QQC.js.map} +0 -0
  349. /package/dist/{chunk-DKHX2FHI.js.map → chunk-64WHWIPL.js.map} +0 -0
  350. /package/dist/{chunk-TVIGN3XZ.js.map → chunk-6FRFVIKC.js.map} +0 -0
  351. /package/dist/{chunk-JIA435P3.js.map → chunk-6ITNEPJO.js.map} +0 -0
  352. /package/dist/{chunk-FGEY2AGV.js.map → chunk-7BCYAJKP.js.map} +0 -0
  353. /package/dist/{chunk-PSQ2P2T3.js.map → chunk-7XZ7TOLQ.js.map} +0 -0
  354. /package/dist/{chunk-6JEEY42N.js.map → chunk-AER3HD3B.js.map} +0 -0
  355. /package/dist/{chunk-POGPI5GR.js.map → chunk-AY6LO7GD.js.map} +0 -0
  356. /package/dist/{chunk-HXFIILGF.js.map → chunk-BFPF5N3H.js.map} +0 -0
  357. /package/dist/{chunk-KQAFEZQX.js.map → chunk-BUKK5SWA.js.map} +0 -0
  358. /package/dist/{chunk-6F5BGIAF.js.map → chunk-CNAL35D5.js.map} +0 -0
  359. /package/dist/{chunk-YC2C67F7.js.map → chunk-CRXGQRNA.js.map} +0 -0
  360. /package/dist/{chunk-WRDFYSUC.js.map → chunk-CZVNOTLR.js.map} +0 -0
  361. /package/dist/{chunk-VPO53QMG.js.map → chunk-D6DOLQYK.js.map} +0 -0
  362. /package/dist/{chunk-RGKXF4W3.js.map → chunk-E5IEI2MR.js.map} +0 -0
  363. /package/dist/{chunk-Z2T5BPOZ.js.map → chunk-EIYJK7OD.js.map} +0 -0
  364. /package/dist/{chunk-FRAL3EU4.js.map → chunk-EKPRLTAE.js.map} +0 -0
  365. /package/dist/{chunk-I75BWXRZ.js.map → chunk-F2RDRE7M.js.map} +0 -0
  366. /package/dist/{chunk-2AKIVSHP.js.map → chunk-FAKRTS3Y.js.map} +0 -0
  367. /package/dist/{chunk-MZWHIAOL.js.map → chunk-FC3ZFEXF.js.map} +0 -0
  368. /package/dist/{chunk-7VFNGQ4V.js.map → chunk-FLDXEJFX.js.map} +0 -0
  369. /package/dist/{chunk-TYLNWE4D.js.map → chunk-FNEYSTB6.js.map} +0 -0
  370. /package/dist/{chunk-XHX67LX6.js.map → chunk-FPHU6KVI.js.map} +0 -0
  371. /package/dist/{chunk-JH4FCVWJ.js.map → chunk-G6OFEGUR.js.map} +0 -0
  372. /package/dist/{chunk-WCIDCJOQ.js.map → chunk-GAUS4XGN.js.map} +0 -0
  373. /package/dist/{chunk-SZPPCEYT.js.map → chunk-GDOI4U4D.js.map} +0 -0
  374. /package/dist/{chunk-63YPKHAU.js.map → chunk-GLB6VV3J.js.map} +0 -0
  375. /package/dist/{chunk-3XVBGGF3.js.map → chunk-GRN4BVPM.js.map} +0 -0
  376. /package/dist/{chunk-ZAP7BKTZ.js.map → chunk-GZMHBRIR.js.map} +0 -0
  377. /package/dist/{chunk-645WOU5I.js.map → chunk-H7BZBSP6.js.map} +0 -0
  378. /package/dist/{chunk-TXP7Q7T5.js.map → chunk-HN35OH2C.js.map} +0 -0
  379. /package/dist/{chunk-SWZOAQUM.js.map → chunk-HSNV4CSW.js.map} +0 -0
  380. /package/dist/{chunk-GFYFKXWZ.js.map → chunk-HUDPXTXW.js.map} +0 -0
  381. /package/dist/{chunk-C2KOW2UQ.js.map → chunk-I7CWAJHX.js.map} +0 -0
  382. /package/dist/{chunk-L2JQSG5M.js.map → chunk-I7TR2OCU.js.map} +0 -0
  383. /package/dist/{chunk-5DCS4C4S.js.map → chunk-ICTJOOWZ.js.map} +0 -0
  384. /package/dist/{chunk-STM4T335.js.map → chunk-IJH6METJ.js.map} +0 -0
  385. /package/dist/{chunk-6SYS5YX3.js.map → chunk-IJJWM2ZA.js.map} +0 -0
  386. /package/dist/{chunk-3AODCBKX.js.map → chunk-IWDFHVPJ.js.map} +0 -0
  387. /package/dist/{chunk-L7PGPH4E.js.map → chunk-JJSMSS45.js.map} +0 -0
  388. /package/dist/{chunk-74AY3S7U.js.map → chunk-JNLYHJG7.js.map} +0 -0
  389. /package/dist/{chunk-OLH4XCLU.js.map → chunk-JXQTECMU.js.map} +0 -0
  390. /package/dist/{chunk-6QOL4G76.js.map → chunk-KQXRVELF.js.map} +0 -0
  391. /package/dist/{chunk-VGRM43X6.js.map → chunk-LB6HIXQC.js.map} +0 -0
  392. /package/dist/{chunk-N7DVBHU3.js.map → chunk-LR7RW4T6.js.map} +0 -0
  393. /package/dist/{chunk-AYBAC2N4.js.map → chunk-LWIU5BMA.js.map} +0 -0
  394. /package/dist/{chunk-FZVZYU5C.js.map → chunk-LXN737FX.js.map} +0 -0
  395. /package/dist/{chunk-7ZRRJ6RG.js.map → chunk-MGYZENUY.js.map} +0 -0
  396. /package/dist/{chunk-YQ6SLFNZ.js.map → chunk-MPJDQC4G.js.map} +0 -0
  397. /package/dist/{chunk-7HXZOWTR.js.map → chunk-N3PUGD7E.js.map} +0 -0
  398. /package/dist/{chunk-EGNONTVT.js.map → chunk-NBEM5QEH.js.map} +0 -0
  399. /package/dist/{chunk-JF3MEIHO.js.map → chunk-O67H7OXJ.js.map} +0 -0
  400. /package/dist/{chunk-OLHN4ZNT.js.map → chunk-ONIVKGNC.js.map} +0 -0
  401. /package/dist/{chunk-2NLLXCJG.js.map → chunk-OWHERGF2.js.map} +0 -0
  402. /package/dist/{chunk-I73ZSORJ.js.map → chunk-OXSTKCYK.js.map} +0 -0
  403. /package/dist/{chunk-VSSQIBVU.js.map → chunk-PJXSBXEC.js.map} +0 -0
  404. /package/dist/{chunk-4B37KNMP.js.map → chunk-PW63SXFM.js.map} +0 -0
  405. /package/dist/{chunk-TPKB7T6Z.js.map → chunk-Q6UZREJK.js.map} +0 -0
  406. /package/dist/{chunk-X247CYL6.js.map → chunk-Q77SLBWT.js.map} +0 -0
  407. /package/dist/{chunk-5K23NQRI.js.map → chunk-QGNZ5QPV.js.map} +0 -0
  408. /package/dist/{chunk-UJDTXWMT.js.map → chunk-QIMGULGN.js.map} +0 -0
  409. /package/dist/{chunk-E24RUQEN.js.map → chunk-QNIYL5SK.js.map} +0 -0
  410. /package/dist/{chunk-KOY25HUB.js.map → chunk-QYAXMXOB.js.map} +0 -0
  411. /package/dist/{chunk-J7G656MY.js.map → chunk-R42VUN5V.js.map} +0 -0
  412. /package/dist/{chunk-AYXRK264.js.map → chunk-RROFIAYI.js.map} +0 -0
  413. /package/dist/{chunk-YYGZ4EIY.js.map → chunk-RUAIO5UA.js.map} +0 -0
  414. /package/dist/{chunk-E5PVMB3I.js.map → chunk-SDXBR5QO.js.map} +0 -0
  415. /package/dist/{chunk-OKKBOTRA.js.map → chunk-SLVR3U4E.js.map} +0 -0
  416. /package/dist/{chunk-CUWOSRCS.js.map → chunk-SUKPM6DV.js.map} +0 -0
  417. /package/dist/{chunk-TDCR6PQL.js.map → chunk-TWRPWJJT.js.map} +0 -0
  418. /package/dist/{chunk-6DTIYAAN.js.map → chunk-UGV256H3.js.map} +0 -0
  419. /package/dist/{chunk-DG4H56SK.js.map → chunk-UIK3U36O.js.map} +0 -0
  420. /package/dist/{chunk-KOAVX2IT.js.map → chunk-UKIIAEJF.js.map} +0 -0
  421. /package/dist/{chunk-XLEP7SS3.js.map → chunk-UMSH4I3E.js.map} +0 -0
  422. /package/dist/{chunk-X7Y7WX73.js.map → chunk-UVYI6VIX.js.map} +0 -0
  423. /package/dist/{chunk-4P4VLPGB.js.map → chunk-VECRSYQG.js.map} +0 -0
  424. /package/dist/{chunk-GGI6FLO6.js.map → chunk-VHBGJAYC.js.map} +0 -0
  425. /package/dist/{chunk-NMKETOAX.js.map → chunk-VSHWPOUB.js.map} +0 -0
  426. /package/dist/{chunk-VC3X7XP3.js.map → chunk-VTZSIG6O.js.map} +0 -0
  427. /package/dist/{chunk-UBN5AOLT.js.map → chunk-W5EO4USJ.js.map} +0 -0
  428. /package/dist/{chunk-Y7427SL7.js.map → chunk-WCGJK4NQ.js.map} +0 -0
  429. /package/dist/{chunk-4IZ6AC2U.js.map → chunk-WJMAWDAU.js.map} +0 -0
  430. /package/dist/{chunk-JH2ALMPR.js.map → chunk-WR5POHQ3.js.map} +0 -0
  431. /package/dist/{chunk-EHIKY2IA.js.map → chunk-WU5WTCH5.js.map} +0 -0
  432. /package/dist/{chunk-QKXPOLQD.js.map → chunk-WUBGMV3G.js.map} +0 -0
  433. /package/dist/{chunk-FKTMWDN2.js.map → chunk-WUL6LDJ4.js.map} +0 -0
  434. /package/dist/{chunk-5UPOKIFP.js.map → chunk-XBHUMPIQ.js.map} +0 -0
  435. /package/dist/{chunk-Y5ZHZKZD.js.map → chunk-XJ77IOAD.js.map} +0 -0
  436. /package/dist/{chunk-U7HJBODU.js.map → chunk-XKTHJHSQ.js.map} +0 -0
  437. /package/dist/{chunk-JFI3ATK4.js.map → chunk-XMYWYJM2.js.map} +0 -0
  438. /package/dist/{chunk-64S6X4IU.js.map → chunk-XTN54NML.js.map} +0 -0
  439. /package/dist/{chunk-CVMAOPAH.js.map → chunk-XXBCUIYQ.js.map} +0 -0
  440. /package/dist/{chunk-QOUKZ2N3.js.map → chunk-XXW3P3RX.js.map} +0 -0
  441. /package/dist/{chunk-RWRHGE75.js.map → chunk-Y473XFTD.js.map} +0 -0
  442. /package/dist/{chunk-VGFNTY3Y.js.map → chunk-YFXRLRKP.js.map} +0 -0
  443. /package/dist/{chunk-DAOMWGO2.js.map → chunk-ZX5N5D6M.js.map} +0 -0
  444. /package/dist/{resolution-4ZEQPXUZ.js.map → extraction-window-drain.js.map} +0 -0
@@ -12,10 +12,10 @@ import {
12
12
  isMemoryCategory,
13
13
  isSealedMemoryEnvelope,
14
14
  sealedWriteToLegacyArgs
15
- } from "./chunk-TDCR6PQL.js";
15
+ } from "./chunk-TWRPWJJT.js";
16
16
  import "./chunk-BT7NVCML.js";
17
- import "./chunk-E5PVMB3I.js";
18
- import "./chunk-UBN5AOLT.js";
17
+ import "./chunk-SDXBR5QO.js";
18
+ import "./chunk-W5EO4USJ.js";
19
19
  import "./chunk-5FVVY2EB.js";
20
20
  import "./chunk-JDSVLVCG.js";
21
21
  import "./chunk-5GKPFL3S.js";
@@ -24,7 +24,7 @@ import "./chunk-EBRG7ZIK.js";
24
24
  import "./chunk-P7FMDTKL.js";
25
25
  import "./chunk-X4OZMANG.js";
26
26
  import "./chunk-R2MBW2S4.js";
27
- import "./chunk-TYGLV6ZG.js";
27
+ import "./chunk-EYGOM6AI.js";
28
28
  import "./chunk-A6XUJE5D.js";
29
29
  import "./chunk-C7HJ3NEI.js";
30
30
  import "./chunk-VS2IYZRU.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remnic/core",
3
- "version": "10.0.38",
3
+ "version": "10.0.40",
4
4
  "description": "Framework-agnostic Remnic memory engine — orchestrator, storage, extraction, search, trust zones",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -3347,7 +3347,7 @@
3347
3347
  "core"
3348
3348
  ],
3349
3349
  "peerDependencies": {
3350
- "@remnic/coding-graph": "^10.0.38"
3350
+ "@remnic/coding-graph": "^10.0.40"
3351
3351
  },
3352
3352
  "peerDependenciesMeta": {
3353
3353
  "@remnic/coding-graph": {
@@ -0,0 +1,190 @@
1
+ import assert from "node:assert/strict";
2
+ import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ import test, { type TestContext } from "node:test";
6
+ import { EngramAccessHttpServer } from "./access-http.js";
7
+ import { getOperation } from "./access-boundary.js";
8
+ import { EngramAccessService } from "./access-service.js";
9
+ import { createChatExecutor } from "./chat/chat-executor.js";
10
+ import { parseConfig } from "./config.js";
11
+ import { NamespaceStorageRouter } from "./namespaces/storage.js";
12
+ import type { Orchestrator } from "./orchestrator.js";
13
+
14
+ interface EntityHttpBody {
15
+ error?: string;
16
+ found?: boolean;
17
+ namespace?: string;
18
+ entities?: Array<{ name?: string }>;
19
+ entity?: { name?: string };
20
+ }
21
+
22
+ interface McpToolBody {
23
+ result: { isError: boolean; content: Array<{ text: string }>; structuredContent: { entity: { name: string } } };
24
+ }
25
+
26
+ async function readMcp(response: Response): Promise<McpToolBody> {
27
+ // SAFETY: /mcp answers tools/call with the JSON-RPC result shape named above; each test asserts the fields it reads.
28
+ return (await response.json()) as McpToolBody;
29
+ }
30
+
31
+ async function readBody(response: Response): Promise<EntityHttpBody> {
32
+ // SAFETY: the access server answers these routes with the JSON shape named above; each test asserts the fields it reads.
33
+ return (await response.json()) as EntityHttpBody;
34
+ }
35
+
36
+ /** Entity reads need only config and real storage routing from the orchestrator. */
37
+ async function createFixture(t: TestContext, namespacesEnabled = true) {
38
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-entity-acl-"));
39
+ t.after(() => rm(memoryDir, { recursive: true, force: true }));
40
+ const config = parseConfig({
41
+ memoryDir,
42
+ namespacesEnabled,
43
+ defaultNamespace: "default",
44
+ sharedNamespace: "shared",
45
+ namespacePolicies: [
46
+ { name: "default", readPrincipals: ["owner"], writePrincipals: ["owner"] },
47
+ { name: "restricted", readPrincipals: ["owner", "reader"], writePrincipals: ["owner"] },
48
+ ],
49
+ });
50
+ const router = new NamespaceStorageRouter(config);
51
+ for (const namespace of namespacesEnabled ? ["default", "restricted"] : ["default"]) {
52
+ const storage = await router.storageFor(namespace);
53
+ const entitiesDir = path.join(storage.dir, "entities");
54
+ await mkdir(entitiesDir, { recursive: true });
55
+ await writeFile(path.join(entitiesDir, "project-widget.md"), [
56
+ `# Widget-${namespace}`,
57
+ "",
58
+ "**Type:** project",
59
+ "",
60
+ "## Summary",
61
+ "",
62
+ `Synthetic entity in ${namespace}.`,
63
+ "",
64
+ ].join("\n"));
65
+ }
66
+ const dependencies: Pick<Orchestrator, "config" | "getStorage"> = {
67
+ config,
68
+ getStorage: (namespace) => router.storageFor(namespace ?? config.defaultNamespace),
69
+ };
70
+ // SAFETY: the entity read paths touch only `config` and `getStorage` (the Pick above); the rest of the Orchestrator is unused here.
71
+ return new EngramAccessService(dependencies as Orchestrator);
72
+ }
73
+
74
+ test("entity service enforces read ACLs and requires a principal before list/get", async (t) => {
75
+ const service = await createFixture(t);
76
+ await assert.rejects(() => service.entityList({ namespace: "restricted" }, "intruder"), /not readable/);
77
+ await assert.rejects(() => service.entityGet("project-widget", "restricted", "intruder"), /not readable/);
78
+ await assert.rejects(() => service.entityList({ namespace: "restricted" }), /authentication required/);
79
+ await assert.rejects(() => service.entityGet("project-widget", "restricted"), /authentication required/);
80
+ await assert.rejects(() => service.entityList({}, "reader"), /not readable/);
81
+ await assert.rejects(() => service.entityGet("project-widget", undefined, "reader"), /not readable/);
82
+
83
+ const list = await service.entityList({ namespace: " restricted ", query: "widget", limit: 1 }, "reader");
84
+ assert.equal(list.namespace, "restricted");
85
+ assert.equal(list.total, 1);
86
+ assert.equal(list.entities[0]?.name, "Widget-restricted");
87
+ const entity = await service.entityGet("project-widget", " restricted ", "reader");
88
+ assert.equal(entity.namespace, "restricted");
89
+ assert.equal(entity.entity?.name, "Widget-restricted");
90
+ assert.deepEqual(await service.entityGet("missing", "restricted", "reader"), {
91
+ found: false, namespace: "restricted",
92
+ });
93
+ });
94
+
95
+ test("entity service retains principal-free reads when namespaces are disabled", async (t) => {
96
+ const service = await createFixture(t, false);
97
+ assert.equal((await service.entityList()).entities[0]?.name, "Widget-default");
98
+ assert.equal((await service.entityGet("project-widget")).entity?.name, "Widget-default");
99
+ });
100
+
101
+ test("entity_list registry dispatch preserves the trusted principal", async (t) => {
102
+ const service = await createFixture(t);
103
+ const operation = getOperation("entity_list");
104
+ assert.ok(operation);
105
+ await assert.rejects(
106
+ () => operation.run({ principal: "owner" }, { service, authenticatedPrincipal: "reader" }),
107
+ /not readable/,
108
+ );
109
+ const output = await operation.run({}, { service, authenticatedPrincipal: "owner" });
110
+ const result = JSON.parse(JSON.stringify(output)).result;
111
+ assert.equal(result.namespace, "default");
112
+ assert.equal(result.entities[0]?.name, "Widget-default");
113
+ });
114
+
115
+ test("HTTP and MCP entity reads bind ACLs to the transport principal across aliases", async (t) => {
116
+ const service = await createFixture(t);
117
+ const token = "synthetic-entity-token";
118
+ const server = new EngramAccessHttpServer({
119
+ service,
120
+ host: "127.0.0.1",
121
+ port: 0,
122
+ principal: "reader",
123
+ enableAdapters: false,
124
+ trustPrincipalHeader: false,
125
+ authTokenEntriesGetter: () => [{
126
+ token,
127
+ capabilities: { version: 1, ops: ["entity_get", "entity_list"], namespaces: ["default", "restricted"] },
128
+ }],
129
+ });
130
+ const started = await server.start();
131
+ t.after(() => server.stop());
132
+ const base = `http://${started.host}:${started.port}`;
133
+ const headers = {
134
+ authorization: `Bearer ${token}`,
135
+ "content-type": "application/json",
136
+ "x-engram-principal": "owner",
137
+ };
138
+ for (const prefix of ["engram", "remnic"]) {
139
+ // The entity HTTP routes are served under /engram/v1 only; the /remnic prefix is an alias for the MCP tool names below.
140
+ for (const suffix of prefix === "engram" ? ["entities", "entities/project-widget"] : []) {
141
+ const denied = await fetch(`${base}/${prefix}/v1/${suffix}?namespace=default&principal=owner`, { headers });
142
+ assert.equal(denied.status, 400);
143
+ assert.match((await readBody(denied)).error ?? "", /not readable/);
144
+ const allowed = await fetch(`${base}/${prefix}/v1/${suffix}?namespace=restricted`, { headers });
145
+ assert.equal(allowed.status, 200);
146
+ const body = await readBody(allowed);
147
+ assert.equal(body.namespace, "restricted");
148
+ assert.equal(suffix === "entities" ? body.entities?.[0]?.name : body.entity?.name, "Widget-restricted");
149
+ }
150
+ if (prefix === "engram") {
151
+ const missing = await fetch(`${base}/${prefix}/v1/entities/missing?namespace=restricted`, { headers });
152
+ assert.equal(missing.status, 404);
153
+ assert.equal((await readBody(missing)).found, false);
154
+ }
155
+
156
+ for (const namespace of ["default", "restricted"]) {
157
+ const response = await fetch(`${base}/mcp`, {
158
+ method: "POST",
159
+ headers,
160
+ body: JSON.stringify({
161
+ jsonrpc: "2.0",
162
+ id: `${prefix}-${namespace}`,
163
+ method: "tools/call",
164
+ params: {
165
+ name: `${prefix}.entity_get`,
166
+ arguments: {
167
+ name: "project-widget", namespace, principal: "owner", authenticatedPrincipal: "owner",
168
+ },
169
+ },
170
+ }),
171
+ });
172
+ assert.equal(response.status, 200);
173
+ const body = await readMcp(response);
174
+ assert.equal(body.result.isError, namespace === "default");
175
+ if (namespace === "default") {
176
+ assert.match(body.result.content[0].text, /not readable/);
177
+ } else {
178
+ assert.equal(body.result.structuredContent.entity.name, "Widget-restricted");
179
+ }
180
+ }
181
+ }
182
+ });
183
+
184
+ test("chat entity reads preserve the bound principal instead of losing identity", async (t) => {
185
+ const service = await createFixture(t);
186
+ const allowed = createChatExecutor({ service, namespace: "restricted", principal: "reader" });
187
+ assert.equal(JSON.parse(await allowed.entityGet("project-widget")).entity.name, "Widget-restricted");
188
+ const denied = createChatExecutor({ service, namespace: "default", principal: "reader" });
189
+ await assert.rejects(() => denied.entityGet("project-widget"), /not readable/);
190
+ });
@@ -2168,7 +2168,7 @@ export class EngramAccessHttpServer extends ReviewDeckAccessHttpBase {
2168
2168
  query: parsed.searchParams.get("q") ?? undefined,
2169
2169
  limit,
2170
2170
  offset,
2171
- });
2171
+ }, this.resolveRequestPrincipal(req));
2172
2172
  this.respondJson(res, 200, response);
2173
2173
  return;
2174
2174
  }
@@ -2178,7 +2178,7 @@ export class EngramAccessHttpServer extends ReviewDeckAccessHttpBase {
2178
2178
  this.enforceTokenOp("entity_get"); // boundary dispatch (issue #1525)
2179
2179
  const entityName = decodeURIComponent(entityMatch[1] ?? "");
2180
2180
  const namespace = this.resolveNamespace(req, parsed.searchParams.get("namespace") ?? undefined);
2181
- const response = await this.service.entityGet(entityName, namespace);
2181
+ const response = await this.service.entityGet(entityName, namespace, this.resolveRequestPrincipal(req));
2182
2182
  this.respondJson(res, response.found ? 200 : 404, response);
2183
2183
  return;
2184
2184
  }
@@ -279,7 +279,7 @@ defineOperation({
279
279
  };
280
280
  },
281
281
  });
282
- defineOperation({ name: "entity_get", description: "Get entity.", schema: strictSchema({ name: S.str, namespace: S.str }), handler: async (input, ctx) => ({ result: await ctx.service.entityGet(optStr(input.name) ?? "", optStr(input.namespace)) }) });
282
+ defineOperation({ name: "entity_get", description: "Get entity.", schema: strictSchema({ name: S.str, namespace: S.str }), handler: async (input, ctx) => ({ result: await ctx.service.entityGet(optStr(input.name) ?? "", optStr(input.namespace), ctx.authenticatedPrincipal) }) });
283
283
  defineOperation({ name: "review_queue_list", description: "List review queue.", schema: strictSchema({ runId: S.str, namespace: S.str }), handler: async (input, ctx) => ({ result: await ctx.service.reviewQueue(optStr(input.runId) ?? "", optStr(input.namespace), ctx.authenticatedPrincipal) }) });
284
284
  // Issue #2482: observe validates through the canonical observeRequestSchema
285
285
  // (same as HTTP/MCP wire validation). Nullable wire fields (parts /
@@ -472,7 +472,7 @@ defineOperation({
472
472
  return { result: getRecallTimingStatus(ctx.service.configRef) };
473
473
  },
474
474
  });
475
- defineOperation({ name: "entity_list", description: "List entities.", schema: strictSchema({}), handler: async (_i, ctx) => ({ result: await ctx.service.entityList() }) });
475
+ defineOperation({ name: "entity_list", description: "List entities.", schema: strictSchema({}), handler: async (_i, ctx) => ({ result: await ctx.service.entityList({}, ctx.authenticatedPrincipal) }) });
476
476
  defineOperation({ name: "maintenance_status", description: "Maintenance status.", schema: strictSchema({}), handler: async (_i, ctx) => ({ result: await ctx.service.maintenance() }) });
477
477
  defineOperation({ name: "quality_status", description: "Quality status.", schema: strictSchema({}), handler: async (_i, ctx) => ({ result: await ctx.service.quality() }) });
478
478
  defineOperation({ name: "trust_zones_status", description: "Trust-zone status.", schema: strictSchema({}), handler: async (_i, ctx) => ({ result: await ctx.service.trustZoneStatus() }) });
@@ -3506,10 +3506,11 @@ export class EngramAccessService extends SupportPassportAccessServiceBase {
3506
3506
  query?: string;
3507
3507
  limit?: number;
3508
3508
  offset?: number;
3509
- } = {}
3509
+ } = {},
3510
+ principal?: string
3510
3511
  ): Promise<EngramAccessEntityListResponse> {
3511
- const storage = await this.orchestrator.getStorage(options.namespace);
3512
- const resolvedNamespace = options.namespace?.trim() || this.orchestrator.config.defaultNamespace;
3512
+ const resolvedNamespace = this.resolveReadableNamespace(options.namespace, principal);
3513
+ const storage = await this.orchestrator.getStorage(resolvedNamespace);
3513
3514
  const { limit, offset } = normalizePagination(options.limit, options.offset);
3514
3515
  const query = options.query?.trim().toLowerCase() ?? "";
3515
3516
 
@@ -3553,9 +3554,9 @@ export class EngramAccessService extends SupportPassportAccessServiceBase {
3553
3554
  };
3554
3555
  }
3555
3556
 
3556
- async entityGet(name: string, namespace?: string): Promise<EngramAccessEntityResponse> {
3557
- const storage = await this.orchestrator.getStorage(namespace);
3558
- const resolvedNamespace = namespace?.trim() || this.orchestrator.config.defaultNamespace;
3557
+ async entityGet(name: string, namespace?: string, principal?: string): Promise<EngramAccessEntityResponse> {
3558
+ const resolvedNamespace = this.resolveReadableNamespace(namespace, principal);
3559
+ const storage = await this.orchestrator.getStorage(resolvedNamespace);
3559
3560
  const raw = await storage.readEntity(name);
3560
3561
  if (!raw) return { found: false, namespace: resolvedNamespace };
3561
3562
  return {
@@ -0,0 +1,196 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { mkdtemp, rm } from "node:fs/promises";
4
+ import os from "node:os";
5
+ import path from "node:path";
6
+ import { SmartBuffer } from "./buffer.js";
7
+ import { parseConfig } from "./config.js";
8
+ import { StorageManager } from "./storage.js";
9
+ import type { BufferTurn } from "./types.js";
10
+ import { ExtractionDrain } from "./orchestration/extraction-drain.js";
11
+ import type { ExtractionRunResult } from "./orchestration/extraction-run.js";
12
+
13
+ function makeTurn(sessionKey: string, content: string): BufferTurn {
14
+ return {
15
+ role: "user",
16
+ content,
17
+ timestamp: "2026-10-29T12:00:00.000Z",
18
+ sessionKey,
19
+ };
20
+ }
21
+
22
+ /** A real buffer on real storage; `restart()` is what a process restart would load from disk. */
23
+ async function withBuffer(run: (buffer: SmartBuffer, restart: () => Promise<SmartBuffer>) => Promise<void>): Promise<void> {
24
+ const root = await mkdtemp(path.join(os.tmpdir(), "remnic-drop-chunk-"));
25
+ try {
26
+ const buffer = new SmartBuffer(parseConfig({}), new StorageManager(root));
27
+ await run(buffer, async () => {
28
+ const reloaded = new SmartBuffer(parseConfig({}), new StorageManager(root));
29
+ await reloaded.load();
30
+ return reloaded;
31
+ });
32
+ } finally {
33
+ await rm(root, { recursive: true, force: true });
34
+ }
35
+ }
36
+
37
+ test("dropExtractionChunk removes the matched prefix and the drop survives a restart", async () => {
38
+ await withBuffer(async (buffer, restart) => {
39
+ const turns = [makeTurn("s1", "turn one"), makeTurn("s1", "turn two"), makeTurn("s1", "turn three")];
40
+ for (const turn of turns) await buffer.addTurn("s1", turn);
41
+ await buffer.flushPendingSave();
42
+
43
+ const dropped = await buffer.dropExtractionChunk("s1", turns.slice(0, 2));
44
+
45
+ assert.equal(dropped, 2);
46
+ assert.deepEqual(buffer.getTurns("s1").map((turn) => turn.content), ["turn three"]);
47
+ assert.deepEqual((await restart()).getTurns("s1").map((turn) => turn.content), ["turn three"], "what a restart loads");
48
+ // A drop is not an extraction: the extraction bookkeeping stays untouched.
49
+ assert.equal(buffer.getExtractionCount("s1"), 0);
50
+ });
51
+ });
52
+
53
+ test("dropExtractionChunk returns zero without dropping when turns no longer match", async () => {
54
+ await withBuffer(async (buffer, restart) => {
55
+ await buffer.addTurn("s1", makeTurn("s1", "kept turn"));
56
+ await buffer.flushPendingSave();
57
+
58
+ const dropped = await buffer.dropExtractionChunk("s1", [makeTurn("s1", "already extracted elsewhere")]);
59
+
60
+ assert.equal(dropped, 0);
61
+ assert.equal(buffer.getTurns("s1").length, 1);
62
+ assert.equal((await restart()).getTurns("s1").length, 1, "the kept turn is still there after a restart");
63
+ });
64
+ });
65
+
66
+ test("dropExtractionChunk drops the whole matched window and a restart finds the buffer empty", async () => {
67
+ await withBuffer(async (buffer, restart) => {
68
+ const turns = [makeTurn("s1", "only turn")];
69
+ await buffer.addTurn("s1", turns[0]!);
70
+ await buffer.flushPendingSave();
71
+
72
+ const dropped = await buffer.dropExtractionChunk("s1", turns);
73
+
74
+ assert.equal(dropped, 1);
75
+ assert.equal(buffer.getTurns("s1").length, 0);
76
+ assert.equal((await restart()).getTurns("s1").length, 0);
77
+ });
78
+ });
79
+
80
+ const FAILED: ExtractionRunResult = { status: "skipped", reason: "empty_extraction_result", retainedBuffer: true, failureClass: "parse_empty", persistedCount: 0, durableOutputCount: 0 };
81
+ const DONE: ExtractionRunResult = { status: "completed", persistedCount: 1, durableOutputCount: 1 };
82
+
83
+ /** w7K's probe on #3266: a pinned capture sits before a native group drained with clearMatchingTurns. */
84
+ async function drainBehindPinnedCapture(buffer: SmartBuffer, results: ExtractionRunResult[], dropAfter: number): Promise<ExtractionRunResult> {
85
+ const pinned: BufferTurn = { ...makeTurn("s1", "pinned capture"), acceptedCapture: true };
86
+ const native = [makeTurn("s1", "a".repeat(60)), makeTurn("s1", "b".repeat(60))];
87
+ for (const turn of [pinned, ...native]) await buffer.addTurn("s1", turn);
88
+ await buffer.flushPendingSave();
89
+ const drain = new ExtractionDrain({
90
+ config: { extractionMinUserTurns: 1, extractionMinChars: 0, extractionMaxTurnChars: 100_000, extractionChunkDropAfterFailures: dropAfter },
91
+ extractionWindowBudgetChars: () => 100,
92
+ runExtraction: async (turns, options) => {
93
+ const result = results.shift() ?? DONE;
94
+ // A successful run clears its chunk the way the coordinator does for a native group: by identity.
95
+ if (result.status === "completed") await buffer.clearAfterExtraction("s1", turns, options?.clearMatchingTurns === true ? { allowNonPrefix: true } : undefined);
96
+ return result;
97
+ },
98
+ getStorage: async () => ({ saveDroppedExtractionChunk: async () => "/recovery/copy.json" }),
99
+ buffer,
100
+ extractionQueueCoordinator: { beginPreemptable: () => {} },
101
+ });
102
+ return await drain.run(native, {
103
+ bufferKey: "s1",
104
+ clearBufferAfterExtraction: true,
105
+ clearMatchingTurns: true,
106
+ skipUserTurnThreshold: false,
107
+ failOnExtractionFailure: false,
108
+ forceExtractionAttempt: false,
109
+ });
110
+ }
111
+
112
+ test("a dropped chunk behind a pinned capture is removed by identity, like a successful clear (w7K)", async () => {
113
+ await withBuffer(async (buffer, restart) => {
114
+ const result = await drainBehindPinnedCapture(buffer, [FAILED, DONE], 1);
115
+
116
+ assert.equal(result.status, "completed");
117
+ assert.deepEqual(buffer.getTurns("s1").map((turn) => turn.content), ["pinned capture"], "the failed turn is gone, the pinned capture stays");
118
+ assert.deepEqual((await restart()).getTurns("s1").map((turn) => turn.content), ["pinned capture"], "and a restart agrees");
119
+ });
120
+ });
121
+
122
+ test("a failed chunk made only of deferred-retained turns can be dropped, and a restart agrees (Codex P2)", async () => {
123
+ await withBuffer(async (buffer, restart) => {
124
+ const retained = [makeTurn("s1", "retained one"), makeTurn("s1", "retained two")];
125
+ const live = makeTurn("s1", "live turn");
126
+ await buffer.retainDeferredTurns("s1", retained);
127
+ await buffer.addTurn("s1", live);
128
+ await buffer.flushPendingSave();
129
+
130
+ // The window a trigger snapshot sees is the retained turns followed by the live ones; the first chunk is retained-only.
131
+ const dropped = await buffer.dropExtractionChunk("s1", retained);
132
+
133
+ assert.equal(dropped, 2);
134
+ assert.deepEqual(buffer.getRetainedDeferredTurns("s1"), []);
135
+ assert.deepEqual(buffer.getTurns("s1").map((turn) => turn.content), ["live turn"]);
136
+ const reloaded = await restart();
137
+ assert.deepEqual(reloaded.getRetainedDeferredTurns("s1"), [], "retained turns stay dropped after a restart");
138
+ assert.deepEqual(reloaded.getTurns("s1").map((turn) => turn.content), ["live turn"]);
139
+ });
140
+ });
141
+
142
+ test("a chunk that spans retained and live turns drops both", async () => {
143
+ await withBuffer(async (buffer, restart) => {
144
+ const retained = [makeTurn("s1", "retained one")];
145
+ const live = [makeTurn("s1", "live one"), makeTurn("s1", "live two")];
146
+ await buffer.retainDeferredTurns("s1", retained);
147
+ for (const turn of live) await buffer.addTurn("s1", turn);
148
+ await buffer.flushPendingSave();
149
+
150
+ const dropped = await buffer.dropExtractionChunk("s1", [...retained, live[0]!]);
151
+
152
+ assert.equal(dropped, 2);
153
+ assert.deepEqual((await restart()).getTurns("s1").map((turn) => turn.content), ["live two"]);
154
+ });
155
+ });
156
+
157
+ test("deferred retention across chunks of one window stays within one retention window (Codex P2)", async () => {
158
+ await withBuffer(async (buffer, restart) => {
159
+ const window = Array.from({ length: 30 }, (_, i) => makeTurn("s1", `turn ${i}`));
160
+ for (const turn of window) await buffer.addTurn("s1", turn);
161
+ // Three chunks of ten, each deferring all of its turns; every run names the whole window as the processed snapshot.
162
+ for (let chunk = 0; chunk < 3; chunk++) {
163
+ await buffer.retainDeferredTurns("s1", window.slice(chunk * 10, chunk * 10 + 10), 10, window);
164
+ }
165
+ assert.equal(buffer.getRetainedDeferredTurns("s1").length, 10, "the latest chunk's retention replaces the earlier ones");
166
+ assert.equal((await restart()).getRetainedDeferredTurns("s1").length, 10);
167
+ });
168
+ });
169
+
170
+ test("a chunk holding only some retained turns drops those and keeps the rest of the retention slot (Phosphene)", async () => {
171
+ await withBuffer(async (buffer, restart) => {
172
+ const retained = [makeTurn("s1", "retained one"), makeTurn("s1", "retained two"), makeTurn("s1", "retained three")];
173
+ await buffer.retainDeferredTurns("s1", retained);
174
+ await buffer.addTurn("s1", makeTurn("s1", "live turn"));
175
+ await buffer.flushPendingSave();
176
+
177
+ const dropped = await buffer.dropExtractionChunk("s1", retained.slice(0, 2));
178
+
179
+ assert.equal(dropped, 2);
180
+ assert.deepEqual(buffer.getRetainedDeferredTurns("s1").map((turn) => turn.content), ["retained three"]);
181
+ const reloaded = await restart();
182
+ assert.deepEqual(reloaded.getRetainedDeferredTurns("s1").map((turn) => turn.content), ["retained three"]);
183
+ assert.deepEqual(reloaded.getTurns("s1").map((turn) => turn.content), ["retained three", "live turn"]);
184
+ });
185
+ });
186
+
187
+ test("retention for an early chunk leaves the retained turns of a later, unprocessed chunk alone (Codex P2)", async () => {
188
+ await withBuffer(async (buffer, restart) => {
189
+ const retained = [makeTurn("s1", "early retained"), makeTurn("s1", "late retained")];
190
+ await buffer.retainDeferredTurns("s1", retained);
191
+ // Chunk 0 holds the first retained turn; nothing was deferred in it, so it clears the slot for the turns it processed.
192
+ await buffer.retainDeferredTurns("s1", [], 0, retained.slice(0, 1));
193
+ assert.deepEqual(buffer.getRetainedDeferredTurns("s1").map((turn) => turn.content), ["late retained"]);
194
+ assert.deepEqual((await restart()).getRetainedDeferredTurns("s1").map((turn) => turn.content), ["late retained"]);
195
+ });
196
+ });
@@ -0,0 +1,65 @@
1
+ /** Types split out of buffer.ts (structural ratchet, issue #1995). */
2
+
3
+ import type { BufferTurn } from "./types.js";
4
+
5
+ /**
6
+ * Optional surprise probe injected into `SmartBuffer`.
7
+ *
8
+ * Computes a D-MEM-style novelty score in `[0, 1]` for an incoming turn.
9
+ * The buffer treats the probe as purely additive: if it is not provided, if
10
+ * the feature flag is off, or if the probe throws/times out, the buffer
11
+ * falls back to the existing signal/turn-count/time triggers unchanged.
12
+ *
13
+ * Callers are responsible for sampling recent memories and passing them
14
+ * through the embedding pipeline — the buffer does not want to know about
15
+ * storage, embeddings, or QMD.
16
+ *
17
+ * @param bufferKey Identifier for the active buffer (session/thread).
18
+ * @param turn The incoming turn whose novelty is being scored.
19
+ * @param recentTurns Turns already buffered for this key (most recent first
20
+ * is NOT guaranteed — treat as unordered corpus).
21
+ * @returns A surprise score in `[0, 1]`, or `null` if no score could be
22
+ * produced (e.g. empty corpus, probe declined to embed).
23
+ */
24
+ export interface BufferSurpriseProbe {
25
+ scoreTurn(
26
+ bufferKey: string,
27
+ turn: BufferTurn,
28
+ recentTurns: readonly BufferTurn[],
29
+ ): Promise<number | null>;
30
+ }
31
+
32
+ /**
33
+ * Minimal data carried on the serialized telemetry write chain
34
+ * (issue #563 PR 3).
35
+ *
36
+ * We intentionally do NOT capture the full `BufferTurn` here: under
37
+ * slow filesystem latency the chain can back up, and retaining
38
+ * `turn.content` for every pending append causes memory pressure on
39
+ * large conversations. Only the fields the ledger row actually needs
40
+ * cross the chain boundary.
41
+ */
42
+ export interface SurpriseTelemetryQueueEntry {
43
+ bufferKey: string;
44
+ turnRole: "user" | "assistant";
45
+ sessionKey: string | null;
46
+ surpriseScore: number;
47
+ triggered: boolean;
48
+ turnCountInWindow: number;
49
+ /**
50
+ * ISO timestamp captured at the moment the turn was scored, NOT when
51
+ * the ledger append eventually runs. Backpressure on the serialized
52
+ * write chain could otherwise shift event timestamps away from the
53
+ * real decision moment and distort the distribution report (p90
54
+ * inflated, current-threshold row misidentified).
55
+ */
56
+ timestamp: string;
57
+ /**
58
+ * Threshold value in force when `triggered` was computed. Must be
59
+ * snapshot here rather than read from `config` at emit time — a
60
+ * concurrent config change between queue and write would otherwise
61
+ * record `triggered=true` against a newer threshold the operator
62
+ * never set, distorting precision/recall interpretation.
63
+ */
64
+ threshold: number;
65
+ }