@remnic/core 9.3.701 → 9.3.702

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 (301) hide show
  1. package/dist/access-boundary.d.ts +7 -7
  2. package/dist/access-boundary.js +15 -12
  3. package/dist/access-cli.js +36 -33
  4. package/dist/access-cli.js.map +1 -1
  5. package/dist/access-http.d.ts +7 -7
  6. package/dist/access-http.js +18 -15
  7. package/dist/access-mcp.d.ts +7 -7
  8. package/dist/access-mcp.js +17 -14
  9. package/dist/access-operations.d.ts +7 -7
  10. package/dist/access-operations.js +16 -13
  11. package/dist/{access-service-CGVWK6lZ.d.ts → access-service-COCzhgEL.d.ts} +397 -19
  12. package/dist/access-service.d.ts +6 -6
  13. package/dist/access-service.js +14 -11
  14. package/dist/access-surface-catalog.d.ts +7 -7
  15. package/dist/action-confidence.d.ts +1 -1
  16. package/dist/active-memory-bridge.d.ts +1 -1
  17. package/dist/active-memory-bridge.js +2 -2
  18. package/dist/active-recall.d.ts +1 -1
  19. package/dist/active-recall.js +7 -6
  20. package/dist/active-recall.js.map +1 -1
  21. package/dist/behavior-learner.d.ts +1 -1
  22. package/dist/behavior-signals.d.ts +1 -1
  23. package/dist/bootstrap.d.ts +5 -5
  24. package/dist/briefing.d.ts +1 -1
  25. package/dist/briefing.js +6 -5
  26. package/dist/buffer-surprise-report.d.ts +1 -1
  27. package/dist/buffer.d.ts +1 -1
  28. package/dist/calibration.d.ts +1 -1
  29. package/dist/capabilities.d.ts +1 -1
  30. package/dist/{catalog-DBIghceA.d.ts → catalog-DxCzhjE6.d.ts} +2 -2
  31. package/dist/causal-behavior.d.ts +1 -1
  32. package/dist/causal-consolidation.d.ts +1 -1
  33. package/dist/causal-consolidation.js +7 -6
  34. package/dist/causal-consolidation.js.map +1 -1
  35. package/dist/{chunk-YXLT4EMM.js → chunk-4463LUIE.js} +12 -2
  36. package/dist/chunk-4463LUIE.js.map +1 -0
  37. package/dist/{chunk-R5DB26G6.js → chunk-4SBW47WK.js} +9 -23
  38. package/dist/chunk-4SBW47WK.js.map +1 -0
  39. package/dist/{chunk-KF4TXW7Z.js → chunk-5VXVXJH6.js} +149 -6
  40. package/dist/{chunk-KF4TXW7Z.js.map → chunk-5VXVXJH6.js.map} +1 -1
  41. package/dist/{chunk-ODTWHSY2.js → chunk-64XXOQRW.js} +2 -2
  42. package/dist/{chunk-ZT7B64BE.js → chunk-6TAETM63.js} +2 -2
  43. package/dist/{chunk-HF4N43Q7.js → chunk-6VVP6NK7.js} +2 -2
  44. package/dist/{chunk-FN2SM5SN.js → chunk-ABCGDW3A.js} +75 -12
  45. package/dist/chunk-ABCGDW3A.js.map +1 -0
  46. package/dist/{chunk-7TAQEPLE.js → chunk-AMNLZ6SF.js} +2 -2
  47. package/dist/{chunk-KS7WQ4BZ.js → chunk-CZJ6QSKG.js} +3 -3
  48. package/dist/{chunk-27LQPUMZ.js → chunk-EOOVJK2U.js} +3 -3
  49. package/dist/{chunk-QP37KL5H.js → chunk-EYJD6KIO.js} +2 -2
  50. package/dist/{chunk-WFEZUGU5.js → chunk-EZR35XHX.js} +2 -2
  51. package/dist/{chunk-UU6MVCJ6.js → chunk-FIOYURII.js} +32 -25
  52. package/dist/chunk-FIOYURII.js.map +1 -0
  53. package/dist/{chunk-JO3E5VGS.js → chunk-FVI5B7DE.js} +2 -2
  54. package/dist/{chunk-SFMRLXIV.js → chunk-GFIARMA7.js} +15 -7
  55. package/dist/chunk-GFIARMA7.js.map +1 -0
  56. package/dist/{chunk-PONNZ54D.js → chunk-GY3SKOS4.js} +4 -4
  57. package/dist/{chunk-U33LWTQQ.js → chunk-HV57RHMD.js} +4 -4
  58. package/dist/{chunk-IKNQAGBV.js → chunk-IX3UQT4H.js} +1 -1
  59. package/dist/{chunk-IKNQAGBV.js.map → chunk-IX3UQT4H.js.map} +1 -1
  60. package/dist/{chunk-IYOPIG3E.js → chunk-IX72AAMZ.js} +2 -2
  61. package/dist/{chunk-JKOKX3PS.js → chunk-JMA4RYRN.js} +2 -2
  62. package/dist/{chunk-DEDQXIDL.js → chunk-JTKFZMZ7.js} +2 -2
  63. package/dist/{chunk-OLOYQZFB.js → chunk-KC6TCAWV.js} +5 -5
  64. package/dist/{chunk-ROZJACKP.js → chunk-KKK7YTYN.js} +4 -1
  65. package/dist/chunk-KKK7YTYN.js.map +1 -0
  66. package/dist/{chunk-EC2AYKRX.js → chunk-L6W77GWW.js} +10 -24
  67. package/dist/chunk-L6W77GWW.js.map +1 -0
  68. package/dist/{chunk-ED35D32I.js → chunk-LQ4J7ELC.js} +2 -2
  69. package/dist/chunk-LUPVCGYK.js +63 -0
  70. package/dist/chunk-LUPVCGYK.js.map +1 -0
  71. package/dist/{chunk-TFVVONWD.js → chunk-MBUM2Y3L.js} +2 -2
  72. package/dist/{chunk-T5QAZIBO.js → chunk-MOXFPLD6.js} +3 -3
  73. package/dist/{chunk-XTIRCSIH.js → chunk-MXEWQKM7.js} +2 -2
  74. package/dist/{chunk-ZYNMX6IU.js → chunk-NUIJEGVD.js} +6 -6
  75. package/dist/{chunk-FUCJAZ25.js → chunk-OXEAMU42.js} +529 -9
  76. package/dist/chunk-OXEAMU42.js.map +1 -0
  77. package/dist/{chunk-YO4MBK3I.js → chunk-QGJAGC2J.js} +2 -2
  78. package/dist/{chunk-ISLJ5WIM.js → chunk-QIMFOCSH.js} +2 -2
  79. package/dist/{chunk-IJEZMWKA.js → chunk-SFOAQQDJ.js} +3 -3
  80. package/dist/{chunk-HRUULBBV.js → chunk-SHRRWOVY.js} +81 -4
  81. package/dist/chunk-SHRRWOVY.js.map +1 -0
  82. package/dist/{chunk-NINRTFSV.js → chunk-SINGJCUR.js} +5 -5
  83. package/dist/{chunk-ZPQVJEVQ.js → chunk-SK2CR6MW.js} +146 -2
  84. package/dist/chunk-SK2CR6MW.js.map +1 -0
  85. package/dist/{chunk-6W2D6FGG.js → chunk-TGAHHCB6.js} +2 -2
  86. package/dist/{chunk-D75JXBV4.js → chunk-WN4GHSDH.js} +2 -2
  87. package/dist/{chunk-K4DWSPMW.js → chunk-WRGPE6AW.js} +2 -2
  88. package/dist/{chunk-4HIAWLA2.js → chunk-XGMCUY5P.js} +60 -114
  89. package/dist/chunk-XGMCUY5P.js.map +1 -0
  90. package/dist/{chunk-SDPDU2PM.js → chunk-YTMDF6S7.js} +2 -2
  91. package/dist/{chunk-MNU5G4TK.js → chunk-Z7XEIAV4.js} +2 -2
  92. package/dist/{chunk-HXHKLVAS.js → chunk-ZCEI242W.js} +23 -23
  93. package/dist/{cli-D3XeenwN.d.ts → cli-BM4xQPp4.d.ts} +3 -3
  94. package/dist/cli.d.ts +7 -7
  95. package/dist/cli.js +33 -32
  96. package/dist/compounding/engine.d.ts +1 -1
  97. package/dist/compounding/engine.js +6 -5
  98. package/dist/compounding/preference-consolidator.d.ts +1 -1
  99. package/dist/compression-optimizer.d.ts +1 -1
  100. package/dist/config.d.ts +1 -1
  101. package/dist/config.js +4 -2
  102. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  103. package/dist/connectors/codex-materialize-runner.js +6 -5
  104. package/dist/connectors/codex-materialize.d.ts +1 -1
  105. package/dist/connectors/index.d.ts +1 -1
  106. package/dist/connectors/index.js +7 -6
  107. package/dist/consolidation-provenance-check.d.ts +1 -1
  108. package/dist/consolidation-undo.d.ts +1 -1
  109. package/dist/contradiction/index.d.ts +2 -2
  110. package/dist/conversation-index/backend.d.ts +1 -1
  111. package/dist/conversation-index/chunker.d.ts +1 -1
  112. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  113. package/dist/conversation-index/indexer.d.ts +1 -1
  114. package/dist/conversation-index/search.d.ts +1 -1
  115. package/dist/day-summary.d.ts +1 -1
  116. package/dist/delinearize.d.ts +1 -1
  117. package/dist/direct-answer-wiring.d.ts +1 -1
  118. package/dist/direct-answer.d.ts +1 -1
  119. package/dist/embedding-fallback.d.ts +1 -1
  120. package/dist/enrichment/index.d.ts +1 -1
  121. package/dist/entity-retrieval.d.ts +1 -1
  122. package/dist/entity-retrieval.js +6 -5
  123. package/dist/entity-schema.d.ts +1 -1
  124. package/dist/event-order-recall.js +2 -1
  125. package/dist/explicit-capture.d.ts +5 -5
  126. package/dist/explicit-capture.js +2 -2
  127. package/dist/explicit-cue-recall.js +2 -1
  128. package/dist/extraction-faithfulness.d.ts +1 -1
  129. package/dist/extraction-judge-telemetry.d.ts +1 -1
  130. package/dist/extraction-judge-training.d.ts +1 -1
  131. package/dist/extraction-judge.d.ts +1 -1
  132. package/dist/extraction.d.ts +14 -1
  133. package/dist/extraction.js +5 -3
  134. package/dist/fallback-llm.d.ts +1 -1
  135. package/dist/identity-continuity.d.ts +1 -1
  136. package/dist/importance.d.ts +1 -1
  137. package/dist/index.d.ts +123 -123
  138. package/dist/index.js +53 -52
  139. package/dist/index.js.map +1 -1
  140. package/dist/intent.d.ts +1 -1
  141. package/dist/lcm/engine.d.ts +1 -1
  142. package/dist/lcm/index.d.ts +1 -1
  143. package/dist/lcm/tools.d.ts +1 -1
  144. package/dist/lifecycle.d.ts +1 -1
  145. package/dist/live-connectors-runner.d.ts +1 -1
  146. package/dist/local-llm.d.ts +1 -1
  147. package/dist/maintenance/memory-governance.d.ts +1 -1
  148. package/dist/maintenance/memory-governance.js +6 -5
  149. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +6 -5
  150. package/dist/maintenance/rebuild-memory-projection.js +7 -6
  151. package/dist/mcp-memory-inspector-app.d.ts +7 -7
  152. package/dist/memory-action-policy.d.ts +1 -1
  153. package/dist/memory-cache.d.ts +1 -1
  154. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  155. package/dist/memory-projection-store.d.ts +1 -1
  156. package/dist/memory-provenance.d.ts +1 -1
  157. package/dist/memory-worth-outcomes.d.ts +1 -1
  158. package/dist/models-json.d.ts +1 -1
  159. package/dist/namespaces/migrate.d.ts +2 -2
  160. package/dist/namespaces/migrate.js +7 -6
  161. package/dist/namespaces/principal.d.ts +1 -1
  162. package/dist/namespaces/search.d.ts +1 -1
  163. package/dist/namespaces/storage.d.ts +2 -2
  164. package/dist/namespaces/storage.js +6 -5
  165. package/dist/native-knowledge.d.ts +1 -1
  166. package/dist/operator-toolkit.d.ts +1 -1
  167. package/dist/operator-toolkit.js +12 -11
  168. package/dist/orchestration/maintenance.d.ts +2 -2
  169. package/dist/orchestration/maintenance.js +8 -7
  170. package/dist/{orchestrator-BzMCZlKn.d.ts → orchestrator-C9CDWAm6.d.ts} +4 -4
  171. package/dist/orchestrator.d.ts +5 -5
  172. package/dist/orchestrator.js +29 -27
  173. package/dist/patterns-cli.d.ts +1 -1
  174. package/dist/policy-runtime.d.ts +1 -1
  175. package/dist/provenance.d.ts +36 -2
  176. package/dist/provenance.js +5 -1
  177. package/dist/qmd-recall-cache.d.ts +1 -1
  178. package/dist/qmd.d.ts +1 -1
  179. package/dist/recall-disclosure-escalation.d.ts +1 -1
  180. package/dist/recall-explain-renderer.d.ts +1 -1
  181. package/dist/recall-explain-renderer.js +3 -3
  182. package/dist/recall-pipeline-stages.d.ts +15 -0
  183. package/dist/recall-pipeline-stages.js +3 -56
  184. package/dist/recall-pipeline-stages.js.map +1 -1
  185. package/dist/recall-planner-llm.d.ts +1 -1
  186. package/dist/recall-state.d.ts +1 -1
  187. package/dist/recall-tag-filter.d.ts +1 -1
  188. package/dist/recall-xray-cli.d.ts +1 -1
  189. package/dist/recall-xray-cli.js +4 -4
  190. package/dist/recall-xray-renderer.d.ts +1 -1
  191. package/dist/recall-xray-renderer.js +3 -3
  192. package/dist/recall-xray.d.ts +1 -1
  193. package/dist/recall-xray.js +2 -2
  194. package/dist/resolve-auth-token.d.ts +1 -1
  195. package/dist/response-guidance-recall.js +2 -1
  196. package/dist/resume-bundles.js +7 -5
  197. package/dist/retrieval-agents.d.ts +1 -1
  198. package/dist/retrieval-tiers.d.ts +1 -1
  199. package/dist/routing/engine.d.ts +1 -1
  200. package/dist/routing/store.d.ts +1 -1
  201. package/dist/schemas.d.ts +19 -0
  202. package/dist/schemas.js +1 -1
  203. package/dist/search/embed-helper.d.ts +1 -1
  204. package/dist/search/factory.d.ts +1 -1
  205. package/dist/search/index.d.ts +1 -1
  206. package/dist/search/lancedb-backend.d.ts +1 -1
  207. package/dist/search/meilisearch-backend.d.ts +1 -1
  208. package/dist/search/noop-backend.d.ts +1 -1
  209. package/dist/search/orama-backend.d.ts +1 -1
  210. package/dist/search/port.d.ts +1 -1
  211. package/dist/search/remote-backend.d.ts +1 -1
  212. package/dist/{semantic-DJR8_DMQ.d.ts → semantic-SLAa_prH.d.ts} +1 -1
  213. package/dist/{semantic-consolidation-BtUfv-AL.d.ts → semantic-consolidation-DgFXyALl.d.ts} +1 -1
  214. package/dist/semantic-consolidation.d.ts +2 -2
  215. package/dist/semantic-consolidation.js +7 -6
  216. package/dist/semantic-rule-promotion.js +6 -5
  217. package/dist/semantic-rule-verifier.d.ts +1 -1
  218. package/dist/semantic-rule-verifier.js +6 -5
  219. package/dist/session-observer-bands.d.ts +1 -1
  220. package/dist/session-observer-state.d.ts +1 -1
  221. package/dist/shared-context/manager.d.ts +1 -1
  222. package/dist/signal.d.ts +1 -1
  223. package/dist/storage.d.ts +13 -1
  224. package/dist/storage.js +5 -4
  225. package/dist/summarizer.d.ts +1 -1
  226. package/dist/summary-snapshot.d.ts +1 -1
  227. package/dist/targeted-fact-recall.js +2 -1
  228. package/dist/temporal-supersession.d.ts +1 -1
  229. package/dist/temporal-validity.d.ts +1 -1
  230. package/dist/threading.d.ts +1 -1
  231. package/dist/tier-migration.d.ts +1 -1
  232. package/dist/tier-routing.d.ts +1 -1
  233. package/dist/topics.d.ts +1 -1
  234. package/dist/transcript.d.ts +1 -1
  235. package/dist/transcript.js +2 -2
  236. package/dist/{types-PuiPZ9iE.d.ts → types-MWKPZnM0.d.ts} +25 -1
  237. package/dist/types.d.ts +1 -1
  238. package/dist/types.js +1 -1
  239. package/dist/utility-runtime.d.ts +1 -1
  240. package/dist/verified-recall.js +6 -5
  241. package/package.json +2 -2
  242. package/src/access-http.ts +162 -0
  243. package/src/access-service.ts +215 -0
  244. package/src/admin/admin-surfaces.test.ts +458 -0
  245. package/src/admin/admin-surfaces.ts +819 -0
  246. package/src/event-order-recall.test.ts +53 -0
  247. package/src/event-order-recall.ts +61 -37
  248. package/src/explicit-cue-recall.ts +21 -1
  249. package/src/extraction.ts +91 -6
  250. package/src/orchestrator.ts +46 -5
  251. package/src/provenance-extraction.test.ts +838 -0
  252. package/src/provenance.ts +413 -0
  253. package/src/recall-pipeline-parity.test.ts +288 -0
  254. package/src/recall-pipeline-stages.test.ts +43 -0
  255. package/src/recall-pipeline-stages.ts +22 -0
  256. package/src/response-guidance-recall.ts +32 -36
  257. package/src/schemas.ts +7 -0
  258. package/src/storage.ts +23 -0
  259. package/src/targeted-fact-recall.ts +25 -32
  260. package/src/types.ts +24 -0
  261. package/dist/chunk-4HIAWLA2.js.map +0 -1
  262. package/dist/chunk-EC2AYKRX.js.map +0 -1
  263. package/dist/chunk-FN2SM5SN.js.map +0 -1
  264. package/dist/chunk-FUCJAZ25.js.map +0 -1
  265. package/dist/chunk-HRUULBBV.js.map +0 -1
  266. package/dist/chunk-R5DB26G6.js.map +0 -1
  267. package/dist/chunk-ROZJACKP.js.map +0 -1
  268. package/dist/chunk-SFMRLXIV.js.map +0 -1
  269. package/dist/chunk-UU6MVCJ6.js.map +0 -1
  270. package/dist/chunk-YXLT4EMM.js.map +0 -1
  271. package/dist/chunk-ZPQVJEVQ.js.map +0 -1
  272. /package/dist/{chunk-ODTWHSY2.js.map → chunk-64XXOQRW.js.map} +0 -0
  273. /package/dist/{chunk-ZT7B64BE.js.map → chunk-6TAETM63.js.map} +0 -0
  274. /package/dist/{chunk-HF4N43Q7.js.map → chunk-6VVP6NK7.js.map} +0 -0
  275. /package/dist/{chunk-7TAQEPLE.js.map → chunk-AMNLZ6SF.js.map} +0 -0
  276. /package/dist/{chunk-KS7WQ4BZ.js.map → chunk-CZJ6QSKG.js.map} +0 -0
  277. /package/dist/{chunk-27LQPUMZ.js.map → chunk-EOOVJK2U.js.map} +0 -0
  278. /package/dist/{chunk-QP37KL5H.js.map → chunk-EYJD6KIO.js.map} +0 -0
  279. /package/dist/{chunk-WFEZUGU5.js.map → chunk-EZR35XHX.js.map} +0 -0
  280. /package/dist/{chunk-JO3E5VGS.js.map → chunk-FVI5B7DE.js.map} +0 -0
  281. /package/dist/{chunk-PONNZ54D.js.map → chunk-GY3SKOS4.js.map} +0 -0
  282. /package/dist/{chunk-U33LWTQQ.js.map → chunk-HV57RHMD.js.map} +0 -0
  283. /package/dist/{chunk-IYOPIG3E.js.map → chunk-IX72AAMZ.js.map} +0 -0
  284. /package/dist/{chunk-JKOKX3PS.js.map → chunk-JMA4RYRN.js.map} +0 -0
  285. /package/dist/{chunk-DEDQXIDL.js.map → chunk-JTKFZMZ7.js.map} +0 -0
  286. /package/dist/{chunk-OLOYQZFB.js.map → chunk-KC6TCAWV.js.map} +0 -0
  287. /package/dist/{chunk-ED35D32I.js.map → chunk-LQ4J7ELC.js.map} +0 -0
  288. /package/dist/{chunk-TFVVONWD.js.map → chunk-MBUM2Y3L.js.map} +0 -0
  289. /package/dist/{chunk-T5QAZIBO.js.map → chunk-MOXFPLD6.js.map} +0 -0
  290. /package/dist/{chunk-XTIRCSIH.js.map → chunk-MXEWQKM7.js.map} +0 -0
  291. /package/dist/{chunk-ZYNMX6IU.js.map → chunk-NUIJEGVD.js.map} +0 -0
  292. /package/dist/{chunk-YO4MBK3I.js.map → chunk-QGJAGC2J.js.map} +0 -0
  293. /package/dist/{chunk-ISLJ5WIM.js.map → chunk-QIMFOCSH.js.map} +0 -0
  294. /package/dist/{chunk-IJEZMWKA.js.map → chunk-SFOAQQDJ.js.map} +0 -0
  295. /package/dist/{chunk-NINRTFSV.js.map → chunk-SINGJCUR.js.map} +0 -0
  296. /package/dist/{chunk-6W2D6FGG.js.map → chunk-TGAHHCB6.js.map} +0 -0
  297. /package/dist/{chunk-D75JXBV4.js.map → chunk-WN4GHSDH.js.map} +0 -0
  298. /package/dist/{chunk-K4DWSPMW.js.map → chunk-WRGPE6AW.js.map} +0 -0
  299. /package/dist/{chunk-SDPDU2PM.js.map → chunk-YTMDF6S7.js.map} +0 -0
  300. /package/dist/{chunk-MNU5G4TK.js.map → chunk-Z7XEIAV4.js.map} +0 -0
  301. /package/dist/{chunk-HXHKLVAS.js.map → chunk-ZCEI242W.js.map} +0 -0
@@ -0,0 +1,458 @@
1
+ /**
2
+ * Tests for the admin console surfaces (issue #1502).
3
+ *
4
+ * Each surface is exercised against the SAME core APIs the runtime uses so
5
+ * the acceptance criteria ("scope inspector returns the same plan as runtime
6
+ * resolver"; "promotion requires reason and enforces authorization"; etc.)
7
+ * hold by construction rather than by mock.
8
+ */
9
+ import assert from "node:assert/strict";
10
+ import { mkdtemp, mkdir, rm, writeFile } from "node:fs/promises";
11
+ import os from "node:os";
12
+ import path from "node:path";
13
+ import test from "node:test";
14
+
15
+ import { NamespaceCatalog } from "../namespaces/catalog.js";
16
+ import { parseConfig } from "../config.js";
17
+ import {
18
+ AdminPromotionError,
19
+ auditTranscripts,
20
+ gatherMaintenanceHealth,
21
+ inspectScope,
22
+ listAdminNamespaces,
23
+ promoteMemory,
24
+ REDACTED,
25
+ redactSensitive,
26
+ type PromotionStorageProvider,
27
+ } from "./admin-surfaces.js";
28
+
29
+ // ---------------------------------------------------------------------------
30
+ // Helpers
31
+ // ---------------------------------------------------------------------------
32
+
33
+ /** Minimal namespace-enabled config for admin-surface tests. */
34
+ function makeConfig(overrides: Record<string, unknown> = {}) {
35
+ return parseConfig({
36
+ namespacesEnabled: true,
37
+ defaultNamespace: "default",
38
+ sharedNamespace: "shared",
39
+ ...overrides,
40
+ });
41
+ }
42
+
43
+ async function makeTempDir(): Promise<string> {
44
+ return mkdtemp(path.join(os.tmpdir(), "remnic-admin-test-"));
45
+ }
46
+
47
+ // ---------------------------------------------------------------------------
48
+ // redactSensitive
49
+ // ---------------------------------------------------------------------------
50
+
51
+ test("redactSensitive redacts bearer-token-shaped values and sensitive keys", () => {
52
+ const redacted = redactSensitive({
53
+ namespace: "default",
54
+ // The KEY name triggers redaction (contains "token"); value is an inert fixture.
55
+ authToken: "test-auth-token-fixture",
56
+ nested: {
57
+ // The KEY name triggers redaction (matches "bearer"); value is inert.
58
+ bearer: "test-bearer-fixture",
59
+ safe: "keep me",
60
+ // The KEY name triggers redaction (matches "password"); value is inert.
61
+ password: "test-password-fixture",
62
+ },
63
+ // A value matching BEARER_VALUE_RE under a non-sensitive key exercises the
64
+ // value-based branch independently. "bearer-test" is obviously not a real
65
+ // credential — it just matches the prefix regex.
66
+ description: "bearer-test-fixture",
67
+ // A ≥40-char opaque string under a non-sensitive key exercises the long-
68
+ // opaque branch. All-a's has zero entropy so it won't trip secret scanners.
69
+ opaqueField: "a".repeat(46),
70
+ array: ["bearer-test-array-value", "normal value"],
71
+ identityToken: "ns-test-routing-token", // routing token — NOT redacted (exempt key)
72
+ });
73
+ assert.equal(redacted.namespace, "default");
74
+ assert.equal((redacted as Record<string, unknown>).authToken, REDACTED);
75
+ assert.equal(
76
+ ((redacted as Record<string, unknown>).nested as Record<string, unknown>).bearer,
77
+ REDACTED,
78
+ );
79
+ assert.equal(
80
+ ((redacted as Record<string, unknown>).nested as Record<string, unknown>).safe,
81
+ "keep me",
82
+ );
83
+ assert.equal(
84
+ ((redacted as Record<string, unknown>).nested as Record<string, unknown>).password,
85
+ REDACTED,
86
+ );
87
+ // Value-based branch: "bearer-test-fixture" matches BEARER_VALUE_RE even under
88
+ // a non-sensitive key.
89
+ assert.equal((redacted as Record<string, unknown>).description, REDACTED);
90
+ // Long-opaque branch: 46-char alphanumeric string under a non-sensitive key.
91
+ assert.equal((redacted as Record<string, unknown>).opaqueField, REDACTED);
92
+ // The 16-hex identity token must survive (it's a routing token, not a credential).
93
+ assert.equal((redacted as Record<string, unknown>).identityToken, "ns-test-routing-token");
94
+ });
95
+
96
+ test("redactSensitive leaves primitives untouched", () => {
97
+ assert.equal(redactSensitive("plain"), "plain");
98
+ assert.equal(redactSensitive(42), 42);
99
+ assert.equal(redactSensitive(true), true);
100
+ assert.equal(redactSensitive(null), null);
101
+ });
102
+
103
+ // ---------------------------------------------------------------------------
104
+ // inspectScope — single-user (namespaces disabled)
105
+ // ---------------------------------------------------------------------------
106
+
107
+ test("inspectScope returns a self-layer plan in single-user mode", () => {
108
+ const config = parseConfig({ namespacesEnabled: false });
109
+ const inspection = inspectScope({ config, sessionKey: "agent:bot:discord:channel:1" });
110
+ assert.equal(inspection.principal, "default");
111
+ assert.equal(inspection.scopeProfileId, null);
112
+ assert.equal(inspection.codingOverlay, null);
113
+ assert.ok(inspection.readNamespaces.length >= 1);
114
+ assert.equal(inspection.writeNamespace, config.defaultNamespace);
115
+ const selfLayer = inspection.layers.find((layer) => layer.id === "self");
116
+ assert.ok(selfLayer, "a self layer must be present in single-user mode");
117
+ assert.equal(selfLayer?.namespace, config.defaultNamespace);
118
+ });
119
+
120
+ // ---------------------------------------------------------------------------
121
+ // inspectScope — namespace-aware: principal derived from session key
122
+ // ---------------------------------------------------------------------------
123
+
124
+ test("inspectScope resolves a principal-scoped write namespace when namespaces are enabled", () => {
125
+ const config = makeConfig({
126
+ principalFromSessionKeyMode: "prefix",
127
+ principalFromSessionKeyRules: [{ match: "alice:", principal: "alice" }],
128
+ namespacePolicies: [{ name: "alice", readPrincipals: ["alice"], writePrincipals: ["alice"] }],
129
+ });
130
+ const inspection = inspectScope({ config, sessionKey: "alice:bot:discord:1" });
131
+ assert.equal(inspection.principal, "alice");
132
+ assert.equal(inspection.writeNamespace, "alice");
133
+ assert.ok(
134
+ inspection.readNamespaces.includes("alice"),
135
+ "read namespaces must include the principal self namespace",
136
+ );
137
+ // The plan field MUST be present so the "same plan as runtime resolver"
138
+ // acceptance test holds — the dashboard displays this verbatim.
139
+ assert.ok(inspection.plan, "plan must be present");
140
+ assert.equal(inspection.plan.baseNamespace, inspection.writeNamespace);
141
+ });
142
+
143
+ test("inspectScope surfaces a warning when namespaces are enabled but no principal resolves", () => {
144
+ const config = makeConfig();
145
+ const inspection = inspectScope({ config, sessionKey: undefined });
146
+ assert.ok(
147
+ inspection.warnings.some((w) => w.includes("no principal resolved")),
148
+ "expected a no-principal warning",
149
+ );
150
+ });
151
+
152
+ test("inspectScope flags an ignored namespace override that is not readable", () => {
153
+ const config = makeConfig({
154
+ namespacePolicies: [
155
+ { name: "protected", readPrincipals: ["bob"], writePrincipals: ["bob"] },
156
+ ],
157
+ });
158
+ const inspection = inspectScope({
159
+ config,
160
+ sessionKey: "alice:bot:x:1",
161
+ namespace: "protected",
162
+ });
163
+ // The override is not readable by alice → warning + plan falls through.
164
+ assert.equal(inspection.namespaceOverride, undefined);
165
+ assert.ok(
166
+ inspection.warnings.some((w) => w.includes("not readable")),
167
+ "expected an ignored-override warning",
168
+ );
169
+ });
170
+
171
+ // ---------------------------------------------------------------------------
172
+ // listAdminNamespaces
173
+ // ---------------------------------------------------------------------------
174
+
175
+ test("listAdminNamespaces returns disabled payload when the catalog is off", async () => {
176
+ const config = parseConfig({ namespacesEnabled: false });
177
+ const catalog = new NamespaceCatalog(config);
178
+ const result = await listAdminNamespaces({ catalog });
179
+ assert.equal(result.enabled, false);
180
+ assert.equal(result.entries.length, 0);
181
+ });
182
+
183
+ test("listAdminNamespaces lists configured + discovered namespaces and marks stale entries", async () => {
184
+ const memoryDir = await makeTempDir();
185
+ try {
186
+ const config = makeConfig({ memoryDir });
187
+ const catalog = new NamespaceCatalog(config);
188
+ await catalog.registerConfiguredNamespaces();
189
+ const result = await listAdminNamespaces({ catalog, staleThresholdDays: 0 });
190
+ assert.equal(result.enabled, true);
191
+ // default + shared should both be present.
192
+ const names = result.entries.map((entry) => entry.namespace);
193
+ assert.ok(names.includes("default"), "default namespace must be listed");
194
+ assert.ok(names.includes("shared"), "shared namespace must be listed");
195
+ // staleThresholdDays: 0 → every entry written > 0 days ago is stale.
196
+ // freshly-registered namespaces have no lastWriteAt, so they are stale.
197
+ assert.ok(result.entries.every((entry) => entry.stale), "fresh entries should be stale");
198
+ } finally {
199
+ await rm(memoryDir, { recursive: true, force: true });
200
+ }
201
+ });
202
+
203
+ test("listAdminNamespaces filters by principal", async () => {
204
+ const memoryDir = await makeTempDir();
205
+ try {
206
+ const config = makeConfig({
207
+ memoryDir,
208
+ namespacePolicies: [
209
+ { name: "alice", readPrincipals: ["alice"], writePrincipals: ["alice"] },
210
+ { name: "bob", readPrincipals: ["bob"], writePrincipals: ["bob"] },
211
+ ],
212
+ });
213
+ const catalog = new NamespaceCatalog(config);
214
+ await catalog.registerConfiguredNamespaces();
215
+ const result = await listAdminNamespaces({ catalog, filter: { principal: "alice" } });
216
+ assert.ok(result.entries.every((entry) => entry.principal === "alice"));
217
+ } finally {
218
+ await rm(memoryDir, { recursive: true, force: true });
219
+ }
220
+ });
221
+
222
+ // ---------------------------------------------------------------------------
223
+ // gatherMaintenanceHealth
224
+ // ---------------------------------------------------------------------------
225
+
226
+ test("gatherMaintenanceHealth reports degraded mode when QMD probe fails", async () => {
227
+ const memoryDir = await makeTempDir();
228
+ try {
229
+ const config = makeConfig({ memoryDir });
230
+ const catalog = new NamespaceCatalog(config);
231
+ await catalog.registerConfiguredNamespaces();
232
+ const report = await gatherMaintenanceHealth({
233
+ catalog,
234
+ qmdHealthProvider: async () => {
235
+ throw new Error("qmd unreachable");
236
+ },
237
+ });
238
+ assert.equal(report.enabled, true);
239
+ assert.equal(report.degradedMode, true);
240
+ assert.ok(
241
+ report.perNamespace.some((entry) => entry.qmdDegraded && entry.qmdError === "QMD health probe failed"),
242
+ "the failing namespace must be flagged degraded with a sanitized error message",
243
+ );
244
+ } finally {
245
+ await rm(memoryDir, { recursive: true, force: true });
246
+ }
247
+ });
248
+
249
+ test("gatherMaintenanceHealth reports healthy when QMD probe returns available", async () => {
250
+ const memoryDir = await makeTempDir();
251
+ try {
252
+ const config = makeConfig({ memoryDir });
253
+ const catalog = new NamespaceCatalog(config);
254
+ await catalog.registerConfiguredNamespaces();
255
+ const report = await gatherMaintenanceHealth({
256
+ catalog,
257
+ qmdHealthProvider: async (namespace) => ({
258
+ namespace,
259
+ collection: `col-${namespace}`,
260
+ available: true,
261
+ collectionState: "present",
262
+ debugStatus: "ok",
263
+ installedVersion: "1.0.0",
264
+ supportedVersion: "1.0.0",
265
+ supported: true,
266
+ upgradeAvailable: false,
267
+ daemonMode: false,
268
+ }),
269
+ });
270
+ assert.equal(report.degradedMode, false);
271
+ assert.ok(report.perNamespace.every((entry) => !entry.qmdDegraded));
272
+ } finally {
273
+ await rm(memoryDir, { recursive: true, force: true });
274
+ }
275
+ });
276
+
277
+ // ---------------------------------------------------------------------------
278
+ // auditTranscripts
279
+ // ---------------------------------------------------------------------------
280
+
281
+ test("auditTranscripts detects mixed other/default data and stays dry-run", async () => {
282
+ const memoryDir = await makeTempDir();
283
+ try {
284
+ // Seed a shared other/default file holding two distinct sessions.
285
+ const transcriptsDir = path.join(memoryDir, "transcripts", "other", "default");
286
+ await mkdir(transcriptsDir, { recursive: true });
287
+ const today = new Date().toISOString().slice(0, 10);
288
+ await writeFile(
289
+ path.join(transcriptsDir, `${today}.jsonl`),
290
+ [
291
+ JSON.stringify({ sessionKey: "pi-geek:abc", entry: "hello from abc", role: "user" }),
292
+ JSON.stringify({ sessionKey: "pi-geek:def", entry: "hello from def", role: "user" }),
293
+ ].join("\n") + "\n",
294
+ );
295
+ const report = await auditTranscripts(memoryDir);
296
+ assert.equal(report.dryRun, true);
297
+ assert.equal(report.mixedOtherDefault, true);
298
+ assert.equal(report.distinctSessions, 2);
299
+ assert.equal(report.movedEntries, 2);
300
+ assert.ok(report.summary.includes("2 distinct sessions"));
301
+ } finally {
302
+ await rm(memoryDir, { recursive: true, force: true });
303
+ }
304
+ });
305
+
306
+ test("auditTranscripts reports clean when no legacy data exists", async () => {
307
+ const memoryDir = await makeTempDir();
308
+ try {
309
+ const report = await auditTranscripts(memoryDir);
310
+ assert.equal(report.mixedOtherDefault, false);
311
+ assert.equal(report.distinctSessions, 0);
312
+ assert.equal(report.movedEntries, 0);
313
+ assert.ok(report.summary.includes("nothing to migrate"));
314
+ } finally {
315
+ await rm(memoryDir, { recursive: true, force: true });
316
+ }
317
+ });
318
+
319
+ // ---------------------------------------------------------------------------
320
+ // promoteMemory — reason + authorization enforcement
321
+ // ---------------------------------------------------------------------------
322
+
323
+ /** In-memory storage provider for promotion tests. */
324
+ function makeMemoryStorageProvider(): PromotionStorageProvider & {
325
+ written: Array<{ namespace: string; memoryId: string; tags: string[]; lineage: string[] }>;
326
+ } {
327
+ const written: Array<{ namespace: string; memoryId: string; tags: string[]; lineage: string[] }> = [];
328
+ let counter = 0;
329
+ return {
330
+ written,
331
+ readMemory: async () => ({
332
+ category: "fact" as const,
333
+ content: "the sky is blue",
334
+ frontmatter: { confidence: 0.9, tags: ["test"] } as never,
335
+ }),
336
+ writePromotedMemory: async (namespace, memory) => {
337
+ counter += 1;
338
+ const memoryId = `promoted-${counter}`;
339
+ written.push({
340
+ namespace,
341
+ memoryId,
342
+ tags: memory.tags,
343
+ lineage: memory.lineage ?? [],
344
+ });
345
+ return memoryId;
346
+ },
347
+ };
348
+ }
349
+
350
+ test("promoteMemory rejects an empty reason", async () => {
351
+ const config = makeConfig();
352
+ const storage = makeMemoryStorageProvider();
353
+ await assert.rejects(
354
+ () =>
355
+ promoteMemory({
356
+ config,
357
+ sourceMemoryId: "mem-1",
358
+ sourceNamespace: "default",
359
+ targets: [{ kind: "explicit", namespace: "shared" }],
360
+ reason: " ",
361
+ actor: "operator",
362
+ storage,
363
+ }),
364
+ (err: unknown) => err instanceof AdminPromotionError && err.code === "reason_required",
365
+ );
366
+ });
367
+
368
+ test("promoteMemory rejects when no targets are supplied", async () => {
369
+ const config = makeConfig();
370
+ const storage = makeMemoryStorageProvider();
371
+ await assert.rejects(
372
+ () =>
373
+ promoteMemory({
374
+ config,
375
+ sourceMemoryId: "mem-1",
376
+ sourceNamespace: "default",
377
+ targets: [],
378
+ reason: "ok reason",
379
+ actor: "operator",
380
+ storage,
381
+ }),
382
+ (err: unknown) => err instanceof AdminPromotionError && err.code === "targets_required",
383
+ );
384
+ });
385
+
386
+ test("promoteMemory writes into an explicit writable target namespace and records audit lineage", async () => {
387
+ const config = makeConfig({
388
+ namespacePolicies: [
389
+ { name: "shared", readPrincipals: ["alice"], writePrincipals: ["alice"] },
390
+ ],
391
+ });
392
+ const storage = makeMemoryStorageProvider();
393
+ const result = await promoteMemory({
394
+ config,
395
+ sourceMemoryId: "mem-1",
396
+ sourceNamespace: "default",
397
+ principal: "alice",
398
+ targets: [{ kind: "explicit", namespace: "shared" }],
399
+ reason: "promote for team visibility",
400
+ actor: "alice",
401
+ storage,
402
+ });
403
+ assert.equal(result.ok, true);
404
+ assert.equal(result.targets.length, 1);
405
+ assert.equal(result.targets[0]?.promoted, true);
406
+ assert.equal(result.targets[0]?.namespace, "shared");
407
+ assert.equal(result.audit.reason, "promote for team visibility");
408
+ assert.equal(result.audit.targets.length, 1);
409
+ assert.equal(result.audit.targets[0]?.promoted, true);
410
+ assert.equal(storage.written.length, 1);
411
+ assert.equal(storage.written[0]?.namespace, "shared");
412
+ assert.ok(storage.written[0]?.tags.includes("admin-promotion-explicit"));
413
+ assert.deepEqual(storage.written[0]?.lineage, ["mem-1"]);
414
+ });
415
+
416
+ test("promoteMemory refuses an explicit target the principal cannot write", async () => {
417
+ const config = makeConfig({
418
+ namespacePolicies: [
419
+ { name: "protected", readPrincipals: ["bob"], writePrincipals: ["bob"] },
420
+ ],
421
+ });
422
+ const storage = makeMemoryStorageProvider();
423
+ const result = await promoteMemory({
424
+ config,
425
+ sourceMemoryId: "mem-1",
426
+ sourceNamespace: "default",
427
+ principal: "alice",
428
+ targets: [{ kind: "explicit", namespace: "protected" }],
429
+ reason: "attempt unauthorized promotion",
430
+ actor: "alice",
431
+ storage,
432
+ });
433
+ assert.equal(result.ok, false);
434
+ assert.equal(result.targets[0]?.authorized, false);
435
+ assert.equal(result.targets[0]?.promoted, false);
436
+ assert.equal(storage.written.length, 0);
437
+ });
438
+
439
+ test("promoteMemory throws source_not_found when the source memory is absent", async () => {
440
+ const config = makeConfig();
441
+ const storage: PromotionStorageProvider = {
442
+ readMemory: async () => null,
443
+ writePromotedMemory: async () => "unused",
444
+ };
445
+ await assert.rejects(
446
+ () =>
447
+ promoteMemory({
448
+ config,
449
+ sourceMemoryId: "missing",
450
+ sourceNamespace: "default",
451
+ targets: [{ kind: "explicit", namespace: "shared" }],
452
+ reason: "ok",
453
+ actor: "alice",
454
+ storage,
455
+ }),
456
+ (err: unknown) => err instanceof AdminPromotionError && err.code === "source_not_found",
457
+ );
458
+ });