@remnic/core 9.69.60 → 9.69.63

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 (360) hide show
  1. package/dist/access-admin-ops-surface.js +38 -38
  2. package/dist/access-authorization-probe.js +39 -39
  3. package/dist/access-boundary.js +38 -38
  4. package/dist/access-cli.js +95 -95
  5. package/dist/access-extraction-force-flush.js +38 -38
  6. package/dist/access-http-briefing.js +39 -39
  7. package/dist/access-http-query.js +40 -40
  8. package/dist/access-http.js +56 -56
  9. package/dist/access-identity-continuity-surface.js +38 -38
  10. package/dist/access-lcm-surface.js +38 -38
  11. package/dist/access-mcp.js +49 -49
  12. package/dist/access-memory-search-fanout.js +3 -3
  13. package/dist/access-namespace-preflight.js +38 -38
  14. package/dist/access-observe-write-surface.js +38 -38
  15. package/dist/access-offline-manifest.js +6 -6
  16. package/dist/access-operations-batch.js +40 -40
  17. package/dist/access-operations.js +47 -47
  18. package/dist/access-recall-concurrency.js +38 -38
  19. package/dist/access-recall-diagnostics.js +5 -5
  20. package/dist/access-recall-response.js +38 -38
  21. package/dist/access-recall-surface.js +38 -38
  22. package/dist/access-service.js +38 -38
  23. package/dist/access-surface-catalog.js +40 -40
  24. package/dist/active-memory-bridge.js +3 -3
  25. package/dist/active-recall.js +9 -9
  26. package/dist/{auto-sync-CWSZDLLW.js → auto-sync-QJNIKZHV.js} +5 -5
  27. package/dist/briefing.js +8 -8
  28. package/dist/buffer-turn-helpers.d.ts.map +1 -1
  29. package/dist/buffer-turn-helpers.js +1 -1
  30. package/dist/buffer.d.ts.map +1 -1
  31. package/dist/buffer.js +7 -7
  32. package/dist/calibration.js +2 -2
  33. package/dist/capabilities.d.ts +6 -7
  34. package/dist/capabilities.d.ts.map +1 -1
  35. package/dist/capabilities.js +1 -1
  36. package/dist/causal-consolidation.js +9 -9
  37. package/dist/{chunk-6Q3ZTEF6.js → chunk-23G5P7TA.js} +9 -1
  38. package/dist/chunk-23G5P7TA.js.map +1 -0
  39. package/dist/{chunk-RP7TZEI6.js → chunk-24TJ77TT.js} +2 -2
  40. package/dist/{chunk-ZLVUWROW.js → chunk-2OUSWDY6.js} +2 -2
  41. package/dist/{chunk-M5IJP3YW.js → chunk-2PKGJPQL.js} +2 -2
  42. package/dist/{chunk-FJMYMJLR.js → chunk-3JDA3XF5.js} +2 -2
  43. package/dist/{chunk-JGT7M3BA.js → chunk-3MSMBVA3.js} +6 -6
  44. package/dist/{chunk-6JYYSDHH.js → chunk-4EEDRKRT.js} +4 -4
  45. package/dist/{chunk-YUHGJBQK.js → chunk-5LWVTSF7.js} +2 -2
  46. package/dist/{chunk-WLZYGLJ4.js → chunk-5MA7ZLPD.js} +5 -7
  47. package/dist/chunk-5MA7ZLPD.js.map +1 -0
  48. package/dist/{chunk-2T2RF5ZK.js → chunk-5QZHDS4X.js} +5 -5
  49. package/dist/{chunk-64JK4TL7.js → chunk-5WXJE5TV.js} +4 -4
  50. package/dist/{chunk-DJ4CKWAD.js → chunk-5Y7VCE3A.js} +2 -2
  51. package/dist/{chunk-G2XZFGYN.js → chunk-62JTOLEX.js} +2 -2
  52. package/dist/{chunk-LVXBC6YB.js → chunk-65I2LZEK.js} +2 -2
  53. package/dist/{chunk-NZLFVLLJ.js → chunk-7CRUDH7G.js} +2 -2
  54. package/dist/{chunk-B4EGAHHS.js → chunk-7DE2NOON.js} +2 -2
  55. package/dist/{chunk-BSDBDFKZ.js → chunk-7JFQI6DQ.js} +3 -3
  56. package/dist/{chunk-BOADKFN4.js → chunk-7LNHRQKR.js} +2 -2
  57. package/dist/{chunk-IV6APZJS.js → chunk-7OC3Q5X4.js} +2 -2
  58. package/dist/{chunk-X2QPKLPL.js → chunk-ACX55QDO.js} +3 -3
  59. package/dist/{chunk-YLPCEUXP.js → chunk-AEGQ5PJ7.js} +2 -2
  60. package/dist/{chunk-GK6NOQE6.js → chunk-AERXJCOG.js} +2 -2
  61. package/dist/{chunk-HW2QYZEV.js → chunk-B5GMOOY2.js} +5 -5
  62. package/dist/{chunk-NLE6TSLG.js → chunk-BLVHDY2U.js} +5 -7
  63. package/dist/chunk-BLVHDY2U.js.map +1 -0
  64. package/dist/{chunk-JUOZ62Y7.js → chunk-BMXEBWBT.js} +2 -1
  65. package/dist/chunk-BMXEBWBT.js.map +1 -0
  66. package/dist/{chunk-YHGRA7CK.js → chunk-CDQO5DCD.js} +2 -2
  67. package/dist/{chunk-ENUI3IO7.js → chunk-D433RXFJ.js} +2 -2
  68. package/dist/{chunk-IK63WA5A.js → chunk-D4SPMHEW.js} +2 -2
  69. package/dist/{chunk-42DJ235G.js → chunk-DINRT75P.js} +2 -2
  70. package/dist/{chunk-LELJRLPY.js → chunk-DQFZOPDL.js} +2 -2
  71. package/dist/{chunk-WN4HFL4K.js → chunk-DQISIT63.js} +2 -2
  72. package/dist/{chunk-Q7KQ5YHT.js → chunk-EIU642TN.js} +2 -2
  73. package/dist/{chunk-EN2YX5SF.js → chunk-F4PEETM4.js} +3 -3
  74. package/dist/{chunk-FNQEXI3D.js → chunk-F5O6WEDO.js} +1 -1
  75. package/dist/{chunk-FNQEXI3D.js.map → chunk-F5O6WEDO.js.map} +1 -1
  76. package/dist/{chunk-Q6C5PIBW.js → chunk-F5ZCNJ3V.js} +3 -3
  77. package/dist/{chunk-KR5SZNNF.js → chunk-FEHVG4C4.js} +2 -2
  78. package/dist/{chunk-42G4FIKQ.js → chunk-FG5QU7A2.js} +4 -4
  79. package/dist/{chunk-IRGQYQQ7.js → chunk-FM5HN7LL.js} +4 -4
  80. package/dist/{chunk-FF2XYADH.js → chunk-FQGY7XB2.js} +6 -6
  81. package/dist/{chunk-FF2XYADH.js.map → chunk-FQGY7XB2.js.map} +1 -1
  82. package/dist/{chunk-IDBLAGIM.js → chunk-FTNV5476.js} +14 -14
  83. package/dist/{chunk-R4Y5PF25.js → chunk-FWVDTLRK.js} +1 -1
  84. package/dist/{chunk-C6FQJ52H.js → chunk-G2XTGEGL.js} +65 -18
  85. package/dist/chunk-G2XTGEGL.js.map +1 -0
  86. package/dist/{chunk-Q5FL3MEH.js → chunk-G4WZDQ32.js} +3 -3
  87. package/dist/{chunk-4HNY6ORZ.js → chunk-GMHWCPLP.js} +2 -2
  88. package/dist/{chunk-ZWWKKAJL.js → chunk-GYNCJSQ7.js} +4 -4
  89. package/dist/{chunk-BJI2D4SU.js → chunk-GZBNEZIU.js} +3 -3
  90. package/dist/{chunk-NYVECYCF.js → chunk-HNOKNHFO.js} +2 -2
  91. package/dist/{chunk-XLXYARWC.js → chunk-HXCJF4XU.js} +2 -2
  92. package/dist/{chunk-RMF763SX.js → chunk-IDRSTHVR.js} +5 -5
  93. package/dist/{chunk-UXREWVW4.js → chunk-IW3RMBPB.js} +2 -2
  94. package/dist/{chunk-W6YK672C.js → chunk-JTTLH646.js} +3 -3
  95. package/dist/{chunk-BQB5ZMYO.js → chunk-KKNZ7PUZ.js} +2 -2
  96. package/dist/{chunk-AAMFQHKI.js → chunk-KRPMISWO.js} +3 -3
  97. package/dist/{chunk-XX2IGMCB.js → chunk-KV44HTMJ.js} +2 -2
  98. package/dist/{chunk-FKFTPFUG.js → chunk-KXJ7XYUT.js} +2 -2
  99. package/dist/{chunk-2NZ7KWRW.js → chunk-LAEW4S43.js} +2 -2
  100. package/dist/{chunk-5SV2GFZX.js → chunk-LDP6LBDS.js} +2 -2
  101. package/dist/{chunk-F6WCOXTF.js → chunk-LMLPLIT4.js} +2 -2
  102. package/dist/{chunk-QJTFMH5Y.js → chunk-LVGVXG22.js} +2 -2
  103. package/dist/{chunk-OINFRHLR.js → chunk-NRTVZSPO.js} +2 -2
  104. package/dist/{chunk-IAZPYX6W.js → chunk-NRVGODSE.js} +3 -3
  105. package/dist/{chunk-IHOXK2I6.js → chunk-NVKO5YKP.js} +2 -2
  106. package/dist/{chunk-OQQXGYMX.js → chunk-OWYHHW67.js} +4 -4
  107. package/dist/{chunk-KPKGDQR3.js → chunk-PZEXA6CM.js} +2 -2
  108. package/dist/{chunk-DXODYQ7J.js → chunk-Q3THVX75.js} +2 -2
  109. package/dist/{chunk-TAC5WFJC.js → chunk-QEGKMZNQ.js} +4 -4
  110. package/dist/{chunk-VRF2KFI2.js → chunk-RA3C46VX.js} +2 -2
  111. package/dist/{chunk-V2HHAAPI.js → chunk-RB776UH3.js} +2 -2
  112. package/dist/{chunk-TAIIC5OM.js → chunk-SEHKTE4F.js} +3 -3
  113. package/dist/{chunk-3JLWSFTV.js → chunk-SVWYZXIL.js} +8 -5
  114. package/dist/{chunk-3JLWSFTV.js.map → chunk-SVWYZXIL.js.map} +1 -1
  115. package/dist/{chunk-G6E7XJYL.js → chunk-SZAWZPY6.js} +10 -10
  116. package/dist/{chunk-2AD5SXO4.js → chunk-T5IF2ZCE.js} +5 -2
  117. package/dist/chunk-T5IF2ZCE.js.map +1 -0
  118. package/dist/{chunk-TYZK56OA.js → chunk-TPRBJF46.js} +9 -9
  119. package/dist/{chunk-7DNMX7SA.js → chunk-TQC6ELJO.js} +2 -2
  120. package/dist/{chunk-OVJFS5P5.js → chunk-U6HXB2OG.js} +2 -2
  121. package/dist/{chunk-7WSQZJPC.js → chunk-V3JM4XEI.js} +4 -4
  122. package/dist/{chunk-36S7UHAW.js → chunk-VEBYLZQQ.js} +2 -2
  123. package/dist/{chunk-IMJPJY7V.js → chunk-VHF73MGU.js} +2 -2
  124. package/dist/{chunk-TDULASPE.js → chunk-VKDWYDFQ.js} +7 -7
  125. package/dist/{chunk-NKXHCCLB.js → chunk-VTPASHTO.js} +2 -2
  126. package/dist/{chunk-4B5S3VWD.js → chunk-VXGB766B.js} +29 -29
  127. package/dist/{chunk-ADP2VCP6.js → chunk-W5UAB6EH.js} +5 -5
  128. package/dist/{chunk-L3R24OLZ.js → chunk-W65KK3X6.js} +2 -2
  129. package/dist/{chunk-BJX6G726.js → chunk-WAR75CRY.js} +67 -64
  130. package/dist/chunk-WAR75CRY.js.map +1 -0
  131. package/dist/{chunk-MNIPH6LD.js → chunk-WBYQA3VN.js} +3 -3
  132. package/dist/{chunk-WD2JD2UB.js → chunk-WEQZ5OYK.js} +2 -2
  133. package/dist/{chunk-AJW2K7K3.js → chunk-WKNWC46C.js} +2 -2
  134. package/dist/{chunk-UD6J2LIA.js → chunk-XDH5MO6L.js} +2 -2
  135. package/dist/{chunk-MRV7VSQK.js → chunk-Y23L4YJV.js} +2 -2
  136. package/dist/{chunk-6ISP2EN2.js → chunk-YF3JERFZ.js} +2 -2
  137. package/dist/{chunk-C5CPYMLX.js → chunk-YR6A6ZK7.js} +2 -2
  138. package/dist/{chunk-EJO2NWW7.js → chunk-Z3YQOV45.js} +2 -2
  139. package/dist/{chunk-6KTXE6A3.js → chunk-Z4TXB4K7.js} +2 -2
  140. package/dist/{chunk-Y76HXF3F.js → chunk-ZDZJ2PG4.js} +393 -41
  141. package/dist/{chunk-Y76HXF3F.js.map → chunk-ZDZJ2PG4.js.map} +1 -1
  142. package/dist/{chunk-6VITOSPL.js → chunk-ZFUPRODV.js} +2 -2
  143. package/dist/cli.js +70 -70
  144. package/dist/coding/export-okf-codegraph.js +7 -7
  145. package/dist/compounding/engine.js +9 -9
  146. package/dist/config-security.d.ts +4 -0
  147. package/dist/config-security.d.ts.map +1 -1
  148. package/dist/config-security.js +2 -2
  149. package/dist/config.js +9 -9
  150. package/dist/connectors/codex-materialize-runner.js +8 -8
  151. package/dist/connectors/index.js +9 -9
  152. package/dist/contradiction/index.js +3 -3
  153. package/dist/{contradiction-scan-GVD4JJ7B.js → contradiction-scan-5EJYRKD3.js} +3 -3
  154. package/dist/convergence-refresh.js +10 -10
  155. package/dist/corpus-watermark.js +10 -10
  156. package/dist/day-summary.js +2 -2
  157. package/dist/embedding-fallback.js +2 -2
  158. package/dist/entity-retrieval.js +9 -9
  159. package/dist/explicit-capture.js +2 -2
  160. package/dist/external-wiki-access.js +39 -39
  161. package/dist/extraction-judge.js +3 -3
  162. package/dist/extraction-normalization.js +3 -3
  163. package/dist/extraction-prompt.js +2 -2
  164. package/dist/extraction.js +21 -21
  165. package/dist/{first-start-migration-L3UFX5CU.js → first-start-migration-7OATHJKB.js} +2 -2
  166. package/dist/harmonic-retrieval.js +1 -1
  167. package/dist/index.d.ts +3 -3
  168. package/dist/index.d.ts.map +1 -1
  169. package/dist/index.js +99 -95
  170. package/dist/local-llm.js +2 -2
  171. package/dist/location/index.js +10 -10
  172. package/dist/maintenance/memory-governance.js +8 -8
  173. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +8 -8
  174. package/dist/maintenance/rebuild-memory-projection.js +9 -9
  175. package/dist/memory-browse-operations.js +39 -39
  176. package/dist/model-registry.d.ts.map +1 -1
  177. package/dist/model-registry.js +1 -1
  178. package/dist/namespaces/migrate.js +9 -9
  179. package/dist/namespaces/principal.js +2 -2
  180. package/dist/namespaces/search.js +4 -4
  181. package/dist/namespaces/storage.js +8 -8
  182. package/dist/offline-sync-impression-drain.js +5 -5
  183. package/dist/operator-doctor-corpus.js +11 -11
  184. package/dist/operator-toolkit.js +21 -21
  185. package/dist/orchestration/compression-guideline-coordinator.js +2 -2
  186. package/dist/orchestration/extraction-injection-gate.d.ts +5 -4
  187. package/dist/orchestration/extraction-injection-gate.d.ts.map +1 -1
  188. package/dist/orchestration/maintenance.js +20 -20
  189. package/dist/orchestration/turn-ingestion.d.ts.map +1 -1
  190. package/dist/orchestrator.js +95 -95
  191. package/dist/profiling.d.ts.map +1 -1
  192. package/dist/profiling.js +1 -1
  193. package/dist/recall-composition-decision.js +3 -3
  194. package/dist/recall-context-composition.js +2 -2
  195. package/dist/recall-explain-renderer.js +3 -3
  196. package/dist/recall-navigate-access.js +2 -2
  197. package/dist/recall-navigate-disclosure.js +2 -2
  198. package/dist/recall-navigate.js +2 -2
  199. package/dist/recall-navigation-operations.js +39 -39
  200. package/dist/recall-navigation.js +38 -38
  201. package/dist/recall-why-service.js +5 -5
  202. package/dist/recall-why.js +3 -3
  203. package/dist/recall-xray-cli.js +4 -4
  204. package/dist/recall-xray-renderer.js +3 -3
  205. package/dist/recall-xray.js +2 -2
  206. package/dist/{resolution-CHNISQJB.js → resolution-UYJU5JUA.js} +4 -4
  207. package/dist/resume-bundles.js +10 -10
  208. package/dist/search/embed-helper.js +2 -2
  209. package/dist/search/factory.js +3 -3
  210. package/dist/search/index.js +3 -3
  211. package/dist/security/audit-memory-cli.d.ts.map +1 -1
  212. package/dist/security/audit-memory.d.ts +13 -0
  213. package/dist/security/audit-memory.d.ts.map +1 -1
  214. package/dist/security/injection-screen.d.ts +2 -2
  215. package/dist/security/injection-screen.d.ts.map +1 -1
  216. package/dist/security/origin-authority.d.ts +3 -0
  217. package/dist/security/origin-authority.d.ts.map +1 -1
  218. package/dist/security/types.d.ts +5 -0
  219. package/dist/security/types.d.ts.map +1 -1
  220. package/dist/semantic-consolidation.js +9 -9
  221. package/dist/semantic-rule-promotion.js +8 -8
  222. package/dist/semantic-rule-verifier.js +8 -8
  223. package/dist/shared-context/manager.js +2 -2
  224. package/dist/source-agent-qualifier.js +14 -14
  225. package/dist/standup/build.js +8 -8
  226. package/dist/storage.js +7 -7
  227. package/dist/summarizer.js +4 -4
  228. package/dist/support-passport/index.js +41 -41
  229. package/dist/temporal-timeline-recall.js +3 -3
  230. package/dist/{tier-stats-VK5PCO2L.js → tier-stats-VF6DS52E.js} +2 -2
  231. package/dist/transfer/export-okf.js +8 -8
  232. package/dist/types.d.ts +4 -3
  233. package/dist/types.d.ts.map +1 -1
  234. package/dist/types.js +1 -1
  235. package/dist/verified-recall.js +8 -8
  236. package/dist/who-knows-cli.js +9 -9
  237. package/dist/who-knows.js +8 -8
  238. package/package.json +12 -2
  239. package/src/buffer-turn-helpers.ts +4 -0
  240. package/src/buffer.ts +3 -0
  241. package/src/capabilities.test.ts +4 -1
  242. package/src/capabilities.ts +7 -7
  243. package/src/config-security.ts +103 -16
  244. package/src/config.test.ts +58 -1
  245. package/src/connector-provenance-lifecycle.test.ts +19 -0
  246. package/src/index.ts +3 -3
  247. package/src/model-registry.test.ts +22 -1
  248. package/src/model-registry.ts +7 -6
  249. package/src/orchestration/extraction-injection-gate.ts +11 -7
  250. package/src/orchestration/extraction-origin-context.ts +1 -1
  251. package/src/orchestration/extraction-persist.ts +8 -8
  252. package/src/orchestration/extraction-security.test.ts +12 -0
  253. package/src/orchestration/turn-ingestion.ts +2 -0
  254. package/src/profiling.test.ts +20 -1
  255. package/src/profiling.ts +7 -7
  256. package/src/security/audit-memory-cli.test.ts +90 -0
  257. package/src/security/audit-memory-cli.ts +7 -0
  258. package/src/security/audit-memory.test.ts +21 -10
  259. package/src/security/audit-memory.ts +20 -2
  260. package/src/security/injection-screen.test.ts +301 -0
  261. package/src/security/injection-screen.ts +414 -11
  262. package/src/security/origin-authority.ts +10 -0
  263. package/src/security/types.ts +11 -0
  264. package/src/types.ts +4 -3
  265. package/dist/chunk-2AD5SXO4.js.map +0 -1
  266. package/dist/chunk-6Q3ZTEF6.js.map +0 -1
  267. package/dist/chunk-BJX6G726.js.map +0 -1
  268. package/dist/chunk-C6FQJ52H.js.map +0 -1
  269. package/dist/chunk-JUOZ62Y7.js.map +0 -1
  270. package/dist/chunk-NLE6TSLG.js.map +0 -1
  271. package/dist/chunk-WLZYGLJ4.js.map +0 -1
  272. /package/dist/{auto-sync-CWSZDLLW.js.map → auto-sync-QJNIKZHV.js.map} +0 -0
  273. /package/dist/{chunk-RP7TZEI6.js.map → chunk-24TJ77TT.js.map} +0 -0
  274. /package/dist/{chunk-ZLVUWROW.js.map → chunk-2OUSWDY6.js.map} +0 -0
  275. /package/dist/{chunk-M5IJP3YW.js.map → chunk-2PKGJPQL.js.map} +0 -0
  276. /package/dist/{chunk-FJMYMJLR.js.map → chunk-3JDA3XF5.js.map} +0 -0
  277. /package/dist/{chunk-JGT7M3BA.js.map → chunk-3MSMBVA3.js.map} +0 -0
  278. /package/dist/{chunk-6JYYSDHH.js.map → chunk-4EEDRKRT.js.map} +0 -0
  279. /package/dist/{chunk-YUHGJBQK.js.map → chunk-5LWVTSF7.js.map} +0 -0
  280. /package/dist/{chunk-2T2RF5ZK.js.map → chunk-5QZHDS4X.js.map} +0 -0
  281. /package/dist/{chunk-64JK4TL7.js.map → chunk-5WXJE5TV.js.map} +0 -0
  282. /package/dist/{chunk-DJ4CKWAD.js.map → chunk-5Y7VCE3A.js.map} +0 -0
  283. /package/dist/{chunk-G2XZFGYN.js.map → chunk-62JTOLEX.js.map} +0 -0
  284. /package/dist/{chunk-LVXBC6YB.js.map → chunk-65I2LZEK.js.map} +0 -0
  285. /package/dist/{chunk-NZLFVLLJ.js.map → chunk-7CRUDH7G.js.map} +0 -0
  286. /package/dist/{chunk-B4EGAHHS.js.map → chunk-7DE2NOON.js.map} +0 -0
  287. /package/dist/{chunk-BSDBDFKZ.js.map → chunk-7JFQI6DQ.js.map} +0 -0
  288. /package/dist/{chunk-BOADKFN4.js.map → chunk-7LNHRQKR.js.map} +0 -0
  289. /package/dist/{chunk-IV6APZJS.js.map → chunk-7OC3Q5X4.js.map} +0 -0
  290. /package/dist/{chunk-X2QPKLPL.js.map → chunk-ACX55QDO.js.map} +0 -0
  291. /package/dist/{chunk-YLPCEUXP.js.map → chunk-AEGQ5PJ7.js.map} +0 -0
  292. /package/dist/{chunk-GK6NOQE6.js.map → chunk-AERXJCOG.js.map} +0 -0
  293. /package/dist/{chunk-HW2QYZEV.js.map → chunk-B5GMOOY2.js.map} +0 -0
  294. /package/dist/{chunk-YHGRA7CK.js.map → chunk-CDQO5DCD.js.map} +0 -0
  295. /package/dist/{chunk-ENUI3IO7.js.map → chunk-D433RXFJ.js.map} +0 -0
  296. /package/dist/{chunk-IK63WA5A.js.map → chunk-D4SPMHEW.js.map} +0 -0
  297. /package/dist/{chunk-42DJ235G.js.map → chunk-DINRT75P.js.map} +0 -0
  298. /package/dist/{chunk-LELJRLPY.js.map → chunk-DQFZOPDL.js.map} +0 -0
  299. /package/dist/{chunk-WN4HFL4K.js.map → chunk-DQISIT63.js.map} +0 -0
  300. /package/dist/{chunk-Q7KQ5YHT.js.map → chunk-EIU642TN.js.map} +0 -0
  301. /package/dist/{chunk-EN2YX5SF.js.map → chunk-F4PEETM4.js.map} +0 -0
  302. /package/dist/{chunk-Q6C5PIBW.js.map → chunk-F5ZCNJ3V.js.map} +0 -0
  303. /package/dist/{chunk-KR5SZNNF.js.map → chunk-FEHVG4C4.js.map} +0 -0
  304. /package/dist/{chunk-42G4FIKQ.js.map → chunk-FG5QU7A2.js.map} +0 -0
  305. /package/dist/{chunk-IRGQYQQ7.js.map → chunk-FM5HN7LL.js.map} +0 -0
  306. /package/dist/{chunk-IDBLAGIM.js.map → chunk-FTNV5476.js.map} +0 -0
  307. /package/dist/{chunk-R4Y5PF25.js.map → chunk-FWVDTLRK.js.map} +0 -0
  308. /package/dist/{chunk-Q5FL3MEH.js.map → chunk-G4WZDQ32.js.map} +0 -0
  309. /package/dist/{chunk-4HNY6ORZ.js.map → chunk-GMHWCPLP.js.map} +0 -0
  310. /package/dist/{chunk-ZWWKKAJL.js.map → chunk-GYNCJSQ7.js.map} +0 -0
  311. /package/dist/{chunk-BJI2D4SU.js.map → chunk-GZBNEZIU.js.map} +0 -0
  312. /package/dist/{chunk-NYVECYCF.js.map → chunk-HNOKNHFO.js.map} +0 -0
  313. /package/dist/{chunk-XLXYARWC.js.map → chunk-HXCJF4XU.js.map} +0 -0
  314. /package/dist/{chunk-RMF763SX.js.map → chunk-IDRSTHVR.js.map} +0 -0
  315. /package/dist/{chunk-UXREWVW4.js.map → chunk-IW3RMBPB.js.map} +0 -0
  316. /package/dist/{chunk-W6YK672C.js.map → chunk-JTTLH646.js.map} +0 -0
  317. /package/dist/{chunk-BQB5ZMYO.js.map → chunk-KKNZ7PUZ.js.map} +0 -0
  318. /package/dist/{chunk-AAMFQHKI.js.map → chunk-KRPMISWO.js.map} +0 -0
  319. /package/dist/{chunk-XX2IGMCB.js.map → chunk-KV44HTMJ.js.map} +0 -0
  320. /package/dist/{chunk-FKFTPFUG.js.map → chunk-KXJ7XYUT.js.map} +0 -0
  321. /package/dist/{chunk-2NZ7KWRW.js.map → chunk-LAEW4S43.js.map} +0 -0
  322. /package/dist/{chunk-5SV2GFZX.js.map → chunk-LDP6LBDS.js.map} +0 -0
  323. /package/dist/{chunk-F6WCOXTF.js.map → chunk-LMLPLIT4.js.map} +0 -0
  324. /package/dist/{chunk-QJTFMH5Y.js.map → chunk-LVGVXG22.js.map} +0 -0
  325. /package/dist/{chunk-OINFRHLR.js.map → chunk-NRTVZSPO.js.map} +0 -0
  326. /package/dist/{chunk-IAZPYX6W.js.map → chunk-NRVGODSE.js.map} +0 -0
  327. /package/dist/{chunk-IHOXK2I6.js.map → chunk-NVKO5YKP.js.map} +0 -0
  328. /package/dist/{chunk-OQQXGYMX.js.map → chunk-OWYHHW67.js.map} +0 -0
  329. /package/dist/{chunk-KPKGDQR3.js.map → chunk-PZEXA6CM.js.map} +0 -0
  330. /package/dist/{chunk-DXODYQ7J.js.map → chunk-Q3THVX75.js.map} +0 -0
  331. /package/dist/{chunk-TAC5WFJC.js.map → chunk-QEGKMZNQ.js.map} +0 -0
  332. /package/dist/{chunk-VRF2KFI2.js.map → chunk-RA3C46VX.js.map} +0 -0
  333. /package/dist/{chunk-V2HHAAPI.js.map → chunk-RB776UH3.js.map} +0 -0
  334. /package/dist/{chunk-TAIIC5OM.js.map → chunk-SEHKTE4F.js.map} +0 -0
  335. /package/dist/{chunk-G6E7XJYL.js.map → chunk-SZAWZPY6.js.map} +0 -0
  336. /package/dist/{chunk-TYZK56OA.js.map → chunk-TPRBJF46.js.map} +0 -0
  337. /package/dist/{chunk-7DNMX7SA.js.map → chunk-TQC6ELJO.js.map} +0 -0
  338. /package/dist/{chunk-OVJFS5P5.js.map → chunk-U6HXB2OG.js.map} +0 -0
  339. /package/dist/{chunk-7WSQZJPC.js.map → chunk-V3JM4XEI.js.map} +0 -0
  340. /package/dist/{chunk-36S7UHAW.js.map → chunk-VEBYLZQQ.js.map} +0 -0
  341. /package/dist/{chunk-IMJPJY7V.js.map → chunk-VHF73MGU.js.map} +0 -0
  342. /package/dist/{chunk-TDULASPE.js.map → chunk-VKDWYDFQ.js.map} +0 -0
  343. /package/dist/{chunk-NKXHCCLB.js.map → chunk-VTPASHTO.js.map} +0 -0
  344. /package/dist/{chunk-4B5S3VWD.js.map → chunk-VXGB766B.js.map} +0 -0
  345. /package/dist/{chunk-ADP2VCP6.js.map → chunk-W5UAB6EH.js.map} +0 -0
  346. /package/dist/{chunk-L3R24OLZ.js.map → chunk-W65KK3X6.js.map} +0 -0
  347. /package/dist/{chunk-MNIPH6LD.js.map → chunk-WBYQA3VN.js.map} +0 -0
  348. /package/dist/{chunk-WD2JD2UB.js.map → chunk-WEQZ5OYK.js.map} +0 -0
  349. /package/dist/{chunk-AJW2K7K3.js.map → chunk-WKNWC46C.js.map} +0 -0
  350. /package/dist/{chunk-UD6J2LIA.js.map → chunk-XDH5MO6L.js.map} +0 -0
  351. /package/dist/{chunk-MRV7VSQK.js.map → chunk-Y23L4YJV.js.map} +0 -0
  352. /package/dist/{chunk-6ISP2EN2.js.map → chunk-YF3JERFZ.js.map} +0 -0
  353. /package/dist/{chunk-C5CPYMLX.js.map → chunk-YR6A6ZK7.js.map} +0 -0
  354. /package/dist/{chunk-EJO2NWW7.js.map → chunk-Z3YQOV45.js.map} +0 -0
  355. /package/dist/{chunk-6KTXE6A3.js.map → chunk-Z4TXB4K7.js.map} +0 -0
  356. /package/dist/{chunk-6VITOSPL.js.map → chunk-ZFUPRODV.js.map} +0 -0
  357. /package/dist/{contradiction-scan-GVD4JJ7B.js.map → contradiction-scan-5EJYRKD3.js.map} +0 -0
  358. /package/dist/{first-start-migration-L3UFX5CU.js.map → first-start-migration-7OATHJKB.js.map} +0 -0
  359. /package/dist/{resolution-CHNISQJB.js.map → resolution-UYJU5JUA.js.map} +0 -0
  360. /package/dist/{tier-stats-VK5PCO2L.js.map → tier-stats-VF6DS52E.js.map} +0 -0
@@ -2,6 +2,7 @@ import { parseOriginClass } from "../security/origin-authority.js";
2
2
  import { normalizeAttributePairs } from "../structured-attributes.js";
3
3
  import { buildProcedurePersistBody } from "../procedural/procedure-types.js";
4
4
  import { screenCandidateFact } from "../security/injection-screen.js";
5
+ import type { InjectionScreenProfile } from "../security/injection-screen.js";
5
6
  import type { EntityStructuredSection } from "../types.js";
6
7
 
7
8
  export interface InjectionScreenCandidate {
@@ -41,11 +42,12 @@ export function serializeInjectionScreenCandidate(candidate: InjectionScreenCand
41
42
  export function evaluateInjectionScreen(
42
43
  candidate: InjectionScreenCandidate | string,
43
44
  enabled: boolean,
45
+ profile: InjectionScreenProfile = "default",
44
46
  ): InjectionScreenGateResult {
45
47
  if (!enabled) return { tags: [] };
46
48
  const content =
47
49
  typeof candidate === "string" ? candidate : serializeInjectionScreenCandidate(candidate);
48
- const result = screenCandidateFact(content);
50
+ const result = screenCandidateFact(content, profile);
49
51
  return {
50
52
  status: result.quarantine === true ? "pending_review" : undefined,
51
53
  tags: result.quarantine === true
@@ -63,6 +65,7 @@ export function evaluateInjectionScreen(
63
65
  export function withholdScreenedStrings(
64
66
  values: readonly unknown[],
65
67
  enabled: boolean,
68
+ profile: InjectionScreenProfile = "default",
66
69
  ): { kept: string[]; withheldRules: string[] } {
67
70
  const kept: string[] = [];
68
71
  const withheldRules: string[] = [];
@@ -72,7 +75,7 @@ export function withholdScreenedStrings(
72
75
  kept.push(value);
73
76
  continue;
74
77
  }
75
- const screened = screenCandidateFact(value);
78
+ const screened = screenCandidateFact(value, profile);
76
79
  if (screened.quarantine) {
77
80
  withheldRules.push(...screened.findings.map((finding) => `injection-screen:${finding.rule}`));
78
81
  } else {
@@ -99,20 +102,20 @@ export interface ScreenedEntityWrite {
99
102
  * `withheldRules` (entities carry no review status; routing is #2397).
100
103
  * Returns null for entities without a usable name/type.
101
104
  */
102
- export function screenEntityForIndex(entity: unknown, enabled: boolean): ScreenedEntityWrite | null {
105
+ export function screenEntityForIndex(entity: unknown, enabled: boolean, profile: InjectionScreenProfile = "default"): ScreenedEntityWrite | null {
103
106
  const record = entity as { name?: unknown; type?: unknown; source?: unknown; facts?: unknown; structuredSections?: unknown } | null;
104
107
  const name = record?.name;
105
108
  const type = record?.type;
106
109
  if (typeof name !== "string" || !name.trim() || typeof type !== "string" || !type.trim()) return null;
107
110
  // #1955 review: the raw name is emitted as the entity target outside the
108
111
  // snippet fence — a flagged name withholds the whole entity from the index.
109
- const nameScreen = withholdScreenedStrings([name], enabled);
110
- const factScreen = withholdScreenedStrings(Array.isArray(record?.facts) ? record.facts : [], enabled);
112
+ const nameScreen = withholdScreenedStrings([name], enabled, profile);
113
+ const factScreen = withholdScreenedStrings(Array.isArray(record?.facts) ? record.facts : [], enabled, profile);
111
114
  const rawSections: EntityStructuredSection[] | undefined = Array.isArray(record?.structuredSections)
112
115
  ? (record.structuredSections as EntityStructuredSection[])
113
116
  : undefined;
114
117
  const sectionScreens = enabled && rawSections
115
- ? rawSections.map((section) => ({ section, screen: withholdScreenedStrings(section?.facts ?? [], true) }))
118
+ ? rawSections.map((section) => ({ section, screen: withholdScreenedStrings(section?.facts ?? [], true, profile) }))
116
119
  : undefined;
117
120
  return {
118
121
  name,
@@ -155,8 +158,9 @@ export function screenEntityForIndex(entity: unknown, enabled: boolean): Screene
155
158
  export function screenPersistStrings(
156
159
  values: readonly string[],
157
160
  enabled: boolean,
161
+ profile: InjectionScreenProfile = "default",
158
162
  ): { kept: string[]; warning?: string } {
159
- const screen = withholdScreenedStrings(values, enabled);
163
+ const screen = withholdScreenedStrings(values, enabled, profile);
160
164
  return {
161
165
  kept: screen.kept,
162
166
  ...(screen.withheldRules.length > 0
@@ -20,7 +20,7 @@ export function deriveExtractionOriginContext(
20
20
  targetTurns: readonly BufferTurn[],
21
21
  fallbackConnector?: string,
22
22
  ): Pick<ExtractionSourceContext, "turnRole" | "importAdapter" | "sourceConnector" | "originConflict"> {
23
- const originRoles = new Set(targetTurns.map((turn) => turn.role));
23
+ const originRoles = new Set(targetTurns.map((turn) => turn.originRole ?? turn.role));
24
24
  const turnRole = originRoles.size === 1 ? [...originRoles][0] : undefined;
25
25
  const originConnectors = new Set(
26
26
  targetTurns
@@ -1623,7 +1623,7 @@ export class ExtractionPersistCoordinator {
1623
1623
  entityRef: fact.entityRef,
1624
1624
  validAt: biTemporal?.validFrom ?? sourceContext?.validAt,
1625
1625
  };
1626
- const { status: injectionScreenStatus, tags: injectionScreenTags } = evaluateInjectionScreen({ content: fact.content, category: writeCategory, structuredAttributes: fact.structuredAttributes, procedureSteps: fact.procedureSteps }, resolveSecurityCapabilities(this.deps.config).injectionScreen);
1626
+ const { status: injectionScreenStatus, tags: injectionScreenTags } = evaluateInjectionScreen({ content: fact.content, category: writeCategory, structuredAttributes: fact.structuredAttributes, procedureSteps: fact.procedureSteps }, resolveSecurityCapabilities(this.deps.config).injectionScreen, resolveSecurityCapabilities(this.deps.config).injectionScreenProfile);
1627
1627
  // #1669 redaction-rule gate: consult BOTH source and target namespace
1628
1628
  // rules before any write. A never-store pattern registered under the
1629
1629
  // source namespace must survive scope-routing to a different target
@@ -2841,12 +2841,12 @@ export class ExtractionPersistCoordinator {
2841
2841
  durableNonFactTouchRecorded = true;
2842
2842
  touchBaseNonFactNamespace();
2843
2843
  };
2844
- // #1955 review: entity fields recall via entity hints — screened before
2845
- // entering the index (screenEntityForIndex); withheld fields are logged.
2844
+ // #1955 review: entity fields are screened before entering the index (screenEntityForIndex).
2846
2845
  const entityScreenOn = resolveSecurityCapabilities(this.deps.config).injectionScreen;
2846
+ const entityScreenProfile = resolveSecurityCapabilities(this.deps.config).injectionScreenProfile;
2847
2847
  for (const entity of entities) {
2848
2848
  try {
2849
- const screened = screenEntityForIndex(entity, entityScreenOn);
2849
+ const screened = screenEntityForIndex(entity, entityScreenOn, entityScreenProfile);
2850
2850
  if (!screened) continue;
2851
2851
  if (screened.withheldRules.length > 0) log.warn(`persistExtraction: injection screen withheld ${screened.withheldRules.length} entity field(s) for "${screened.name}" [${screened.withheldRules.join(", ")}]`);
2852
2852
  if (screened.withheld) continue;
@@ -2874,7 +2874,7 @@ export class ExtractionPersistCoordinator {
2874
2874
  for (const rel of result.relationships.slice(0, 5)) {
2875
2875
  if (!rel.source || !rel.target || !rel.label) continue;
2876
2876
  const relScreen = screenPersistStrings([`${rel.source}\n${rel.label}\n${rel.target}`,
2877
- `${rel.target}\n${rel.label} (reverse)\n${rel.source}`], entityScreenOn);
2877
+ `${rel.target}\n${rel.label} (reverse)\n${rel.source}`], entityScreenOn, entityScreenProfile);
2878
2878
  if (relScreen.warning) {
2879
2879
  log.warn(`persistExtraction(relationship): ${relScreen.warning}`);
2880
2880
  continue;
@@ -2911,7 +2911,7 @@ export class ExtractionPersistCoordinator {
2911
2911
  }
2912
2912
  // #1955 review: profile + questions render verbatim into model context —
2913
2913
  // screened; questions screen question+context JOINED (routing: #2397).
2914
- const profileScreen = screenPersistStrings(profileUpdates, entityScreenOn);
2914
+ const profileScreen = screenPersistStrings(profileUpdates, entityScreenOn, entityScreenProfile);
2915
2915
  if (profileScreen.warning) log.warn(`persistExtraction(profile): ${profileScreen.warning}`);
2916
2916
  if (profileScreen.kept.length > 0) {
2917
2917
  await storage.appendToProfile(profileScreen.kept);
@@ -2919,7 +2919,7 @@ export class ExtractionPersistCoordinator {
2919
2919
  }
2920
2920
 
2921
2921
  for (const q of questions) {
2922
- const qScreen = screenPersistStrings([`${q.question}\n${q.context ?? ""}`], entityScreenOn);
2922
+ const qScreen = screenPersistStrings([`${q.question}\n${q.context ?? ""}`], entityScreenOn, entityScreenProfile);
2923
2923
  if (qScreen.warning) {
2924
2924
  log.warn(`persistExtraction(question): ${qScreen.warning}`);
2925
2925
  continue;
@@ -2934,7 +2934,7 @@ export class ExtractionPersistCoordinator {
2934
2934
  // Persist identity reflection (screened — #1955): durable namespace-local
2935
2935
  // state; identity-ONLY extraction still counts as durable non-fact (NIIly).
2936
2936
  if (resolveRecallEnhancementCapabilities(this.deps.config).identity && result.identityReflection) {
2937
- const idScreen = screenPersistStrings([result.identityReflection], entityScreenOn);
2937
+ const idScreen = screenPersistStrings([result.identityReflection], entityScreenOn, entityScreenProfile);
2938
2938
  if (idScreen.warning) log.warn(`persistExtraction(identity): ${idScreen.warning}`);
2939
2939
  else {
2940
2940
  try {
@@ -187,6 +187,18 @@ test("mixed connector identities resolve to unknown origin", () => {
187
187
  assert.equal(classifyExtractionOrigin(context), "unknown");
188
188
  });
189
189
 
190
+ test("trusted originRole preserves tool authority independently of conversation role", () => {
191
+ const turns: BufferTurn[] = [{
192
+ role: "user",
193
+ originRole: "tool",
194
+ content: "Tool result rendered into conversation context.",
195
+ timestamp: "2026-01-01T00:00:00Z",
196
+ }];
197
+ const context = deriveExtractionOriginContext(turns);
198
+ assert.equal(context.turnRole, "tool");
199
+ assert.equal(classifyExtractionOrigin(context), "tool_output");
200
+ });
201
+
190
202
  test("empty import source labels do not create adapter origins", () => {
191
203
  const turns: BufferTurn[] = [{
192
204
  role: "user",
@@ -274,6 +274,7 @@ export class TurnIngestionCoordinator {
274
274
  rawContent: turn.rawContent,
275
275
  sourceFormat: turn.sourceFormat,
276
276
  sourceConnector: turn.sourceConnector,
277
+ ...(turn.originRole ? { originRole: turn.originRole } : {}),
277
278
  });
278
279
  bySession.set(key, list);
279
280
  }
@@ -461,6 +462,7 @@ export class TurnIngestionCoordinator {
461
462
  turnFingerprint: turn.turnFingerprint,
462
463
  persistProcessedFingerprint: turn.persistProcessedFingerprint === true,
463
464
  ...(turn.sourceConnector ? { sourceConnector: turn.sourceConnector } : {}),
465
+ ...(turn.originRole ? { originRole: turn.originRole } : {}),
464
466
  });
465
467
  }
466
468
  if (sessionTurns.length === 0) {
@@ -1,5 +1,5 @@
1
1
  import assert from "node:assert/strict";
2
- import { mkdtempSync, readdirSync, rmSync } from "node:fs";
2
+ import { existsSync, mkdtempSync, readdirSync, rmSync } from "node:fs";
3
3
  import { join } from "node:path";
4
4
  import { tmpdir } from "node:os";
5
5
  import test, { describe } from "node:test";
@@ -283,4 +283,23 @@ describe("ProfilingCollector", () => {
283
283
  cleanup(dir);
284
284
  }
285
285
  });
286
+
287
+ test("construction never creates the storage dir; the first persist does", () => {
288
+ const dir = tempDir();
289
+ const storageDir = join(dir, "profiling");
290
+ try {
291
+ const collector = new ProfilingCollector({ enabled: true, storageDir, maxTraces: 10 });
292
+ // Constructing a collector happens on every plugin registration, including
293
+ // read-only discovery passes, so it must not touch the memory dir.
294
+ assert.equal(existsSync(storageDir), false, "no dir before a trace is written");
295
+ collector.startTrace("recall", "test-session");
296
+ collector.startSpan("qmd-search");
297
+ collector.endSpan("qmd-search");
298
+ collector.endTrace();
299
+ assert.equal(existsSync(storageDir), true, "the first persisted trace creates it");
300
+ assert.equal(readdirSync(storageDir).length, 1);
301
+ } finally {
302
+ cleanup(dir);
303
+ }
304
+ });
286
305
  });
package/src/profiling.ts CHANGED
@@ -118,13 +118,6 @@ export class ProfilingCollector {
118
118
  this.enabled = config.enabled;
119
119
  this.storageDir = config.storageDir;
120
120
  this.maxTraces = Math.max(0, config.maxTraces);
121
-
122
- if (this.enabled) {
123
- if (!existsSync(this.storageDir)) {
124
- mkdirSync(this.storageDir, { recursive: true });
125
- log.debug(`profiling: created storage dir ${this.storageDir}`);
126
- }
127
- }
128
121
  }
129
122
 
130
123
  get isEnabled(): boolean {
@@ -347,6 +340,13 @@ export class ProfilingCollector {
347
340
  const filename = `${trace.kind}-${trace.traceId}.jsonl`;
348
341
  const filepath = join(this.storageDir, filename);
349
342
  try {
343
+ // Created on first persist, never at construction: constructing a
344
+ // collector (plugin registration, a discovery pass, CLI metadata) must
345
+ // not touch the operator's memory dir when no trace is ever written.
346
+ if (!existsSync(this.storageDir)) {
347
+ mkdirSync(this.storageDir, { recursive: true });
348
+ log.debug(`profiling: created storage dir ${this.storageDir}`);
349
+ }
350
350
  writeFileSync(filepath, JSON.stringify(trace) + "\n", "utf-8");
351
351
  log.debug(`profiling: persisted ${filename}`);
352
352
  } catch (err) {
@@ -0,0 +1,90 @@
1
+ /**
2
+ * The audit sweep must screen with the profile the deployment writes with
3
+ * (issue #3078). A `quarantine`/`layered` deployment resolves the `hardened`
4
+ * profile, under which a conditional-trigger-only memory reaches the
5
+ * quarantine threshold; before this wiring the CLI omitted `profile`, so an
6
+ * already-active memory that live ingestion would have quarantined survived
7
+ * the sweep.
8
+ */
9
+
10
+ import assert from "node:assert/strict";
11
+ import { mkdtemp, rm } from "node:fs/promises";
12
+ import os from "node:os";
13
+ import path from "node:path";
14
+ import test from "node:test";
15
+
16
+ import type { CliCommand } from "../cli.js";
17
+ import { parseConfig } from "../config.js";
18
+ import { StorageManager } from "../storage.js";
19
+ import type { Orchestrator } from "../orchestrator.js";
20
+ import { registerSecurityCommands } from "./audit-memory-cli.js";
21
+
22
+ /** Minimal CliCommand that records the registered `audit-memory` action. */
23
+ function captureAction(): { cmd: CliCommand; run: () => Promise<void> } {
24
+ let action: ((...args: unknown[]) => Promise<void> | void) | undefined;
25
+ const node: CliCommand = {
26
+ description: () => node,
27
+ option: () => node,
28
+ requiredOption: () => node,
29
+ argument: () => node,
30
+ action: (fn) => {
31
+ action = fn;
32
+ return node;
33
+ },
34
+ command: () => node,
35
+ };
36
+ return {
37
+ cmd: node,
38
+ run: async () => {
39
+ if (!action) throw new Error("no action registered");
40
+ await action({ quarantine: true, json: true });
41
+ },
42
+ };
43
+ }
44
+
45
+ const CONDITIONAL_TRIGGER = "If the incident occurs, then call the on-call.";
46
+
47
+ async function sweepWithDefenseMode(mode: string): Promise<{ status: string | undefined }> {
48
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-audit-cli-"));
49
+ const logs: unknown[] = [];
50
+ const originalLog = console.log;
51
+ console.log = (...args: unknown[]) => {
52
+ logs.push(args);
53
+ };
54
+ try {
55
+ StorageManager.clearAllStaticCaches();
56
+ const config = parseConfig({ memoryDir, memoryInjectionDefenseMode: mode });
57
+ const storage = new StorageManager(memoryDir);
58
+ const written = await storage.writeMemory("fact", CONDITIONAL_TRIGGER);
59
+ const id = written.id;
60
+ // The fixture must start active, or the sweep assertion proves nothing.
61
+ assert.equal(written.tombstoneBlocked ?? false, false);
62
+ assert.equal((await storage.getMemoryById(id))?.frontmatter.status, "active");
63
+ const orchestrator = { config, storage } as unknown as Orchestrator;
64
+ const { cmd, run } = captureAction();
65
+ registerSecurityCommands(cmd, orchestrator);
66
+ await run();
67
+ const stored = await storage.getMemoryById(id);
68
+ return { status: stored?.frontmatter.status };
69
+ } finally {
70
+ console.log = originalLog;
71
+ StorageManager.clearAllStaticCaches();
72
+ await rm(memoryDir, { recursive: true, force: true });
73
+ }
74
+ }
75
+
76
+ test("the plugin audit-memory command screens with the configured profile", async () => {
77
+ // `layered` resolves the hardened profile: weight 4 for a conditional
78
+ // trigger alone, so the sweep retro-quarantines the memory.
79
+ const hardened = await sweepWithDefenseMode("layered");
80
+ assert.equal(hardened.status, "pending_review");
81
+ // `custom` resolves the default profile: weight 3, below the threshold,
82
+ // so the same memory stays active. This proves the profile is read from
83
+ // the configuration rather than hard-coded either way.
84
+ const lenient = await sweepWithDefenseMode("custom");
85
+ assert.equal(lenient.status, "active");
86
+ // `off`/`fencing` disable live screening, so the sweep keeps the previous
87
+ // `default` weighting instead of becoming stricter than the write path.
88
+ const screenDisabled = await sweepWithDefenseMode("off");
89
+ assert.equal(screenDisabled.status, "active");
90
+ });
@@ -7,6 +7,7 @@
7
7
  import type { CliCommand } from "../cli.js";
8
8
  import { runAuditMemoryCliCommand } from "../cli.js";
9
9
  import type { Orchestrator } from "../orchestrator.js";
10
+ import { auditScreenProfile } from "./audit-memory.js";
10
11
  import { formatAuditMemoryReport } from "./audit-memory.js";
11
12
 
12
13
  export function registerSecurityCommands(
@@ -32,6 +33,12 @@ export function registerSecurityCommands(
32
33
  ? options.since.trim()
33
34
  : undefined,
34
35
  quarantine: options.quarantine === true,
36
+ // Screen with the profile live ingestion uses, or a memory this
37
+ // deployment would quarantine on write stays active once stored
38
+ // (#3078). A deployment with the screen DISABLED keeps the previous
39
+ // `default` weighting: the sweep must not be stricter than the
40
+ // write path the operator configured.
41
+ profile: auditScreenProfile(orchestrator.config),
35
42
  });
36
43
  if (options.json === true) {
37
44
  console.log(JSON.stringify(report, null, 2));
@@ -162,27 +162,38 @@ test("auditMemoryStore audits legacy missing-status memories and excludes archiv
162
162
  }
163
163
  });
164
164
 
165
- test("auditMemoryStore reports sub-threshold injection findings without quarantining", async () => {
165
+ test("auditMemoryStore quarantines a single-rule finding and leaves benign prose untouched", async () => {
166
+ // The hardened profile keeps every rule at weight >= INJECTION_SCREEN_THRESHOLD,
167
+ // so one finding is sufficient to quarantine; the default profile keeps
168
+ // conditional triggers sub-threshold (#1962).
166
169
  const root = await mkdtemp(path.join(tmpdir(), "remnic-audit-memory-threshold-"));
167
170
  try {
168
- const memory = makeMemory(
171
+ const trigger = makeMemory(
169
172
  root,
170
- "borderline",
171
- "session-borderline",
173
+ "trigger",
174
+ "session-trigger",
172
175
  "If the incident occurs, then call the on-call.",
173
176
  );
177
+ const benign = makeMemory(
178
+ root,
179
+ "benign",
180
+ "session-benign",
181
+ "Meeting notes: if the build fails, the release is delayed.",
182
+ );
174
183
  const report = await auditMemoryStore({
175
184
  memoryDir: root,
176
- storage: memoryStorage([memory]),
185
+ storage: memoryStorage([trigger, benign]),
177
186
  quarantine: true,
187
+ profile: "hardened",
178
188
  });
179
189
  assert.deepEqual(
180
- report.findings.map(({ category, rule }) => ({ category, rule })),
181
- [{ category: "injection-signature", rule: "conditional-trigger" }],
190
+ report.findings.map(({ memoryId, category, rule }) => ({ memoryId, category, rule })),
191
+ [{ memoryId: "trigger", category: "injection-signature", rule: "conditional-trigger" }],
182
192
  );
183
- assert.deepEqual(report.quarantinedMemoryIds, []);
184
- assert.equal(report.transitions, 0);
185
- assert.equal(memory.frontmatter.status, "active");
193
+ assert.deepEqual(report.quarantinedMemoryIds, ["trigger"]);
194
+ assert.equal(report.transitions, 1);
195
+ assert.equal(trigger.frontmatter.status, "pending_review");
196
+ assert.equal(benign.frontmatter.status, "active");
186
197
  } finally {
187
198
  await rm(root, { recursive: true, force: true });
188
199
  }
@@ -1,5 +1,7 @@
1
1
  import type { MemoryFile, MemoryFrontmatter } from "../types.js";
2
2
  import { screenCandidateFact } from "./injection-screen.js";
3
+ import type { InjectionScreenProfile } from "./injection-screen.js";
4
+ import { resolveSecurityCapabilities, type SecurityConfigProjection } from "../capabilities.js";
3
5
  import { inferMemoryStatus, isArchivedMemoryPath, toMemoryPathRel } from "../memory-lifecycle-ledger-utils.js";
4
6
  import { parseStrictCliDate } from "../training-export/date-parse.js";
5
7
 
@@ -36,6 +38,8 @@ export interface AuditMemoryStoreOptions {
36
38
  memoryDir: string;
37
39
  since?: string | Date;
38
40
  quarantine?: boolean;
41
+ /** Screen profile; defaults to "default" (named defense modes pass "hardened"). */
42
+ profile?: InjectionScreenProfile;
39
43
  now?: Date;
40
44
  storage: AuditMemoryStorage;
41
45
  }
@@ -203,6 +207,19 @@ function writeBurstStats(groups: Map<string, MemoryFile[]>): AuditMemoryReport["
203
207
  };
204
208
  }
205
209
 
210
+ /**
211
+ * The screen profile an audit sweep must use, resolved through the shared
212
+ * security capability plan (#1523) rather than read off config (#3078). The
213
+ * sweep matches the live write path, so a memory this deployment would
214
+ * quarantine on write does not survive once stored; a deployment with the
215
+ * screen DISABLED keeps the `default` weighting, because the sweep must
216
+ * never be stricter than the configured write path.
217
+ */
218
+ export function auditScreenProfile(config: SecurityConfigProjection): InjectionScreenProfile {
219
+ const capabilities = resolveSecurityCapabilities(config);
220
+ return capabilities.injectionScreen ? capabilities.injectionScreenProfile : "default";
221
+ }
222
+
206
223
  export async function auditMemoryStore(options: AuditMemoryStoreOptions): Promise<AuditMemoryReport> {
207
224
  const since = parseSince(options.since);
208
225
  const storage = options.storage;
@@ -214,9 +231,10 @@ export async function auditMemoryStore(options: AuditMemoryStoreOptions): Promis
214
231
  );
215
232
  const findings: AuditMemoryFinding[] = [];
216
233
  const quarantinePaths = new Map<string, { injection: boolean; burst: boolean }>();
234
+ const profile = options.profile ?? "default";
217
235
 
218
236
  for (const memory of activeMemories) {
219
- const screened = screenCandidateFact(memory.content);
237
+ const screened = screenCandidateFact(memory.content, profile);
220
238
  if (screened.quarantine === true) quarantinePaths.set(memory.path, { injection: true, burst: false });
221
239
  for (const screenFinding of screened.findings) {
222
240
  findings.push({
@@ -268,7 +286,7 @@ export async function auditMemoryStore(options: AuditMemoryStoreOptions): Promis
268
286
  // the live record first.
269
287
  const memory = await storage.readMemoryByPath(staleMemory.path);
270
288
  if (!memory || !isActive(memory, options.memoryDir)) continue;
271
- if (qInfo.injection && !qInfo.burst && !screenCandidateFact(memory.content).quarantine) continue;
289
+ if (qInfo.injection && !qInfo.burst && !screenCandidateFact(memory.content, profile).quarantine) continue;
272
290
  const changed = await storage.writeMemoryFrontmatterIfUnchanged(memory, {
273
291
  status: "pending_review",
274
292
  updated: now,