@remnic/core 9.69.9 → 9.69.11

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 (577) hide show
  1. package/dist/access-admin-ops-surface.d.ts +15 -13
  2. package/dist/access-admin-ops-surface.js +41 -28
  3. package/dist/access-authorization-probe.d.ts +13 -11
  4. package/dist/access-authorization-probe.js +42 -29
  5. package/dist/access-boundary.d.ts +13 -11
  6. package/dist/access-boundary.js +41 -28
  7. package/dist/access-cli.js +101 -89
  8. package/dist/access-cli.js.map +1 -1
  9. package/dist/access-coding-context-resolution.d.ts +2 -1
  10. package/dist/access-extraction-force-flush.d.ts +13 -11
  11. package/dist/access-extraction-force-flush.js +41 -28
  12. package/dist/access-health-types.d.ts +2 -1
  13. package/dist/access-http-lcm-compaction.d.ts +13 -11
  14. package/dist/access-http-lifecycle-flush.d.ts +13 -11
  15. package/dist/access-http-offline-stream.d.ts +13 -11
  16. package/dist/access-http-query.d.ts +3 -2
  17. package/dist/access-http-query.js +43 -30
  18. package/dist/access-http.d.ts +14 -12
  19. package/dist/access-http.js +62 -47
  20. package/dist/access-identity-continuity-surface.d.ts +10 -9
  21. package/dist/access-identity-continuity-surface.js +41 -28
  22. package/dist/access-lcm-surface.d.ts +13 -11
  23. package/dist/access-lcm-surface.js +41 -28
  24. package/dist/access-mcp-output-schemas.js +1 -1
  25. package/dist/access-mcp.d.ts +13 -11
  26. package/dist/access-mcp.js +53 -39
  27. package/dist/access-memory-search-fanout.d.ts +3 -2
  28. package/dist/{access-namespace-preflight-S8fhQcCo.d.ts → access-namespace-preflight-Cy0yPsaE.d.ts} +1 -1
  29. package/dist/access-namespace-preflight.d.ts +4 -3
  30. package/dist/access-namespace-preflight.js +41 -28
  31. package/dist/access-observe-write-surface.d.ts +15 -13
  32. package/dist/access-observe-write-surface.js +41 -28
  33. package/dist/access-offline-manifest.d.ts +10 -9
  34. package/dist/access-offline-manifest.js +3 -3
  35. package/dist/access-operations-batch.js +44 -31
  36. package/dist/access-operations.d.ts +19 -17
  37. package/dist/access-operations.js +49 -36
  38. package/dist/access-recall-concurrency.d.ts +13 -11
  39. package/dist/access-recall-concurrency.js +41 -28
  40. package/dist/access-recall-response.d.ts +13 -11
  41. package/dist/access-recall-response.js +41 -28
  42. package/dist/access-recall-surface.d.ts +13 -11
  43. package/dist/access-recall-surface.js +41 -28
  44. package/dist/access-schema.d.ts +107 -90
  45. package/dist/access-schema.js +5 -3
  46. package/dist/{access-service-LbwWl05g.d.ts → access-service-Cqfk3dD1.d.ts} +89 -72
  47. package/dist/access-service-helpers.d.ts +13 -11
  48. package/dist/access-service.d.ts +13 -11
  49. package/dist/access-service.js +41 -28
  50. package/dist/access-surface-catalog.d.ts +13 -11
  51. package/dist/access-surface-catalog.js +45 -30
  52. package/dist/access-surface-catalog.js.map +1 -1
  53. package/dist/access-wearables-meetings-surface.d.ts +4 -3
  54. package/dist/action-confidence.d.ts +2 -1
  55. package/dist/active-memory-bridge.d.ts +2 -1
  56. package/dist/active-recall.d.ts +2 -1
  57. package/dist/active-recall.js +6 -5
  58. package/dist/active-recall.js.map +1 -1
  59. package/dist/adapters/index.js +4 -4
  60. package/dist/adapters/registry.js +2 -2
  61. package/dist/ambient-provenance.d.ts +2 -1
  62. package/dist/artifact-search.d.ts +2 -1
  63. package/dist/behavior-learner.d.ts +2 -1
  64. package/dist/behavior-signals.d.ts +2 -1
  65. package/dist/bootstrap.d.ts +10 -9
  66. package/dist/briefing-window.d.ts +3 -2
  67. package/dist/briefing.d.ts +3 -2
  68. package/dist/briefing.js +8 -8
  69. package/dist/buffer-surprise-report.d.ts +2 -1
  70. package/dist/buffer-turn-helpers.d.ts +2 -1
  71. package/dist/buffer.d.ts +3 -2
  72. package/dist/bulk-import/index.d.ts +4 -3
  73. package/dist/calibration.d.ts +2 -1
  74. package/dist/capabilities.d.ts +2 -1
  75. package/dist/{catalog-BmBXTtOs.d.ts → catalog-9X8WpZNO.d.ts} +1 -1
  76. package/dist/causal-behavior.d.ts +2 -1
  77. package/dist/causal-behavior.js +2 -2
  78. package/dist/causal-chain.js +2 -2
  79. package/dist/causal-consolidation.d.ts +2 -1
  80. package/dist/causal-consolidation.js +11 -11
  81. package/dist/causal-retrieval.js +2 -2
  82. package/dist/causal-trajectory-graph.d.ts +2 -1
  83. package/dist/causal-trajectory-graph.js +2 -2
  84. package/dist/causal-trajectory.js +1 -1
  85. package/dist/{chunk-DKZR56A3.js → chunk-227WJVPY.js} +2 -2
  86. package/dist/{chunk-RXS4SQ5S.js → chunk-2EHDPHMD.js} +2 -2
  87. package/dist/{chunk-ZPN6SSWA.js → chunk-2XJDAEAM.js} +2 -2
  88. package/dist/{chunk-J3JEW5CT.js → chunk-3GCK6ONU.js} +2 -2
  89. package/dist/{chunk-44HBCMOA.js → chunk-3ITTF7YH.js} +51 -51
  90. package/dist/{chunk-754GA2UE.js → chunk-3YKOFCKP.js} +11 -6
  91. package/dist/chunk-3YKOFCKP.js.map +1 -0
  92. package/dist/{chunk-GD7D7WP2.js → chunk-4UVDLNHQ.js} +2 -2
  93. package/dist/{chunk-IGUWU5BD.js → chunk-4WIKMOE3.js} +44 -22
  94. package/dist/chunk-4WIKMOE3.js.map +1 -0
  95. package/dist/{chunk-LVYO2HZJ.js → chunk-5HO3QBAD.js} +11 -6
  96. package/dist/chunk-5HO3QBAD.js.map +1 -0
  97. package/dist/{chunk-3QWF54M4.js → chunk-5P2KNFJZ.js} +149 -25
  98. package/dist/chunk-5P2KNFJZ.js.map +1 -0
  99. package/dist/{chunk-YVMTXBJJ.js → chunk-5YQ7RFSO.js} +2 -2
  100. package/dist/{chunk-4PJYD2L3.js → chunk-6TOWUN2R.js} +3 -3
  101. package/dist/{chunk-HINMCD7V.js → chunk-7NCUHD5U.js} +2 -2
  102. package/dist/{chunk-QHYSECIG.js → chunk-7ZMU4XQT.js} +2 -2
  103. package/dist/{chunk-GISV63M2.js → chunk-APZXA4WI.js} +2 -2
  104. package/dist/{chunk-2QSZNTDO.js → chunk-AU7Q3LSC.js} +4 -4
  105. package/dist/{chunk-G4MCAHMF.js → chunk-B75VCEX5.js} +5 -5
  106. package/dist/{chunk-DJZWNKFO.js → chunk-BE4Y6GK6.js} +2 -2
  107. package/dist/{chunk-E5WTGEWX.js → chunk-BEXFNGQ3.js} +3 -3
  108. package/dist/{chunk-SO73GYOZ.js → chunk-BFDOBESV.js} +2 -2
  109. package/dist/{chunk-OLT3YTDH.js → chunk-BIJAWZYW.js} +4 -4
  110. package/dist/{chunk-X5TGZAP2.js → chunk-BO4PWIJY.js} +3 -3
  111. package/dist/{chunk-JMAG7WZ7.js → chunk-BX6GW4KC.js} +2 -2
  112. package/dist/chunk-C5C7IJ4Q.js +27 -0
  113. package/dist/chunk-C5C7IJ4Q.js.map +1 -0
  114. package/dist/chunk-CC37E3QM.js +198 -0
  115. package/dist/chunk-CC37E3QM.js.map +1 -0
  116. package/dist/{chunk-X5PIDJ3L.js → chunk-DA4ZMCBU.js} +3 -3
  117. package/dist/{chunk-PEOFTEUC.js → chunk-DH3V7RCQ.js} +21 -13
  118. package/dist/chunk-DH3V7RCQ.js.map +1 -0
  119. package/dist/chunk-DXFG2VGN.js +50 -0
  120. package/dist/chunk-DXFG2VGN.js.map +1 -0
  121. package/dist/{chunk-4OFKZAJG.js → chunk-EAARGPWI.js} +2 -1
  122. package/dist/chunk-EAARGPWI.js.map +1 -0
  123. package/dist/{chunk-H6RSANGQ.js → chunk-ETZ7KKOS.js} +2 -2
  124. package/dist/{chunk-K4E3Y3ZX.js → chunk-G7VEQEMG.js} +2 -1
  125. package/dist/chunk-G7VEQEMG.js.map +1 -0
  126. package/dist/{chunk-SXQZMC7R.js → chunk-GR4C3FHT.js} +2 -2
  127. package/dist/{chunk-S6AHHQ6C.js → chunk-H5IIBGDM.js} +2 -2
  128. package/dist/{chunk-GFGQOZGG.js → chunk-HFRGCNFY.js} +10 -10
  129. package/dist/chunk-HRATODNO.js +28 -0
  130. package/dist/chunk-HRATODNO.js.map +1 -0
  131. package/dist/{chunk-MAG6M3B6.js → chunk-HTOWFFAI.js} +2 -2
  132. package/dist/chunk-HUSTM6PU.js +27 -0
  133. package/dist/chunk-HUSTM6PU.js.map +1 -0
  134. package/dist/{chunk-KAVQ5GYY.js → chunk-I4QAH4SY.js} +3 -3
  135. package/dist/{chunk-2MW3UQNX.js → chunk-I6DUKBUI.js} +2 -2
  136. package/dist/{chunk-VI637ILW.js → chunk-IN673LEP.js} +48 -15
  137. package/dist/chunk-IN673LEP.js.map +1 -0
  138. package/dist/{chunk-YHCBJULX.js → chunk-JGXMA6HL.js} +2 -2
  139. package/dist/{chunk-TA7UZZMW.js → chunk-JHTF22NQ.js} +2 -2
  140. package/dist/{chunk-ANN5VMHT.js → chunk-LDOQE34V.js} +2 -2
  141. package/dist/{chunk-MEW53VQJ.js → chunk-LDWIPYJ6.js} +7 -7
  142. package/dist/{chunk-227UFSEQ.js → chunk-LEPOP46W.js} +4 -4
  143. package/dist/{chunk-H3HOC6UT.js → chunk-LF6SHWVV.js} +2 -2
  144. package/dist/{chunk-QGUFN25Q.js → chunk-LJAP4KSW.js} +2 -2
  145. package/dist/{chunk-JAU4MRKB.js → chunk-LJNLLNEM.js} +2 -2
  146. package/dist/{chunk-6C57JBJ3.js → chunk-LUDXSSTW.js} +2 -2
  147. package/dist/{chunk-YJPFTF57.js → chunk-LWBSEYW3.js} +6 -6
  148. package/dist/chunk-M6RORUO5.js +59 -0
  149. package/dist/chunk-M6RORUO5.js.map +1 -0
  150. package/dist/{chunk-PRK4WTPU.js → chunk-M7DGN6JZ.js} +3 -3
  151. package/dist/{chunk-EN75MUTO.js → chunk-MNH2GM4O.js} +5 -5
  152. package/dist/{chunk-LK4TOYPU.js → chunk-NF3NMAG7.js} +2 -2
  153. package/dist/{chunk-M5UJJUON.js → chunk-NHLEFBE2.js} +10 -2
  154. package/dist/chunk-NHLEFBE2.js.map +1 -0
  155. package/dist/chunk-NN5CQTAJ.js +42 -0
  156. package/dist/chunk-NN5CQTAJ.js.map +1 -0
  157. package/dist/{chunk-VGTXHTWU.js → chunk-OASGWNYL.js} +2 -2
  158. package/dist/chunk-OEDW4ER7.js +62 -0
  159. package/dist/chunk-OEDW4ER7.js.map +1 -0
  160. package/dist/{chunk-C2JCVZWX.js → chunk-OLBZ2WGG.js} +2 -2
  161. package/dist/{chunk-Z3SQEEB6.js → chunk-OUKBMQ2O.js} +2 -2
  162. package/dist/{chunk-XXW32OL7.js → chunk-OYV6RKPM.js} +1 -1
  163. package/dist/chunk-OYV6RKPM.js.map +1 -0
  164. package/dist/{chunk-2Z3DG5CQ.js → chunk-P6GKRT2H.js} +1 -1
  165. package/dist/{chunk-A3WMMQAH.js → chunk-P7LVYPIX.js} +3 -3
  166. package/dist/{chunk-26JWBSWD.js → chunk-PGCZLHRB.js} +11 -3
  167. package/dist/chunk-PGCZLHRB.js.map +1 -0
  168. package/dist/{chunk-Y3WMJAZ3.js → chunk-QRDSXR3V.js} +2 -2
  169. package/dist/{chunk-NDE7CH6C.js → chunk-QUVWFZOU.js} +2 -2
  170. package/dist/{chunk-M5GBTETG.js → chunk-R7FXPG4T.js} +2 -2
  171. package/dist/chunk-RF2SMMPP.js +37 -0
  172. package/dist/chunk-RF2SMMPP.js.map +1 -0
  173. package/dist/{chunk-X66BHMAU.js → chunk-RJ57OOCD.js} +2 -2
  174. package/dist/chunk-S5G2LAL7.js +354 -0
  175. package/dist/chunk-S5G2LAL7.js.map +1 -0
  176. package/dist/{chunk-VOPOPTZ7.js → chunk-TRLCMLX7.js} +2 -2
  177. package/dist/{chunk-KZMFU7YL.js → chunk-V3HUBF7T.js} +2 -2
  178. package/dist/{chunk-KLL5SPER.js → chunk-VHAKBUBD.js} +2 -2
  179. package/dist/{chunk-WF2WCZCR.js → chunk-VYD63IFH.js} +3 -3
  180. package/dist/chunk-VZIAVM72.js +49 -0
  181. package/dist/chunk-VZIAVM72.js.map +1 -0
  182. package/dist/chunk-WTWQA7BB.js +28 -0
  183. package/dist/chunk-WTWQA7BB.js.map +1 -0
  184. package/dist/{chunk-J55NAXDH.js → chunk-X4FIZAVQ.js} +82 -40
  185. package/dist/chunk-X4FIZAVQ.js.map +1 -0
  186. package/dist/{chunk-3FXXFLVK.js → chunk-XFPHV65N.js} +2 -2
  187. package/dist/{chunk-JCUG7AXZ.js → chunk-XJJYSX6F.js} +4 -4
  188. package/dist/{chunk-NAZROP6I.js → chunk-XMIAU4CO.js} +2 -2
  189. package/dist/{chunk-LHGIBXVX.js → chunk-XQGFIAG7.js} +2 -2
  190. package/dist/{chunk-5TBO7CDR.js → chunk-YSSAGB2O.js} +4 -23
  191. package/dist/chunk-YSSAGB2O.js.map +1 -0
  192. package/dist/{chunk-IWO4HEOL.js → chunk-YWN3GYI2.js} +2 -2
  193. package/dist/{chunk-IIO4C3YL.js → chunk-Z33VUMKY.js} +3 -3
  194. package/dist/{cli-Bvy4jdBu.d.ts → cli-Dk-lM_tI.d.ts} +5 -5
  195. package/dist/cli.d.ts +15 -13
  196. package/dist/cli.js +80 -68
  197. package/dist/coding/export-okf-codegraph.d.ts +2 -1
  198. package/dist/coding/export-okf-codegraph.js +8 -8
  199. package/dist/coding/pre-action-gate.d.ts +2 -1
  200. package/dist/coding/pre-action-gate.js +2 -2
  201. package/dist/compounding/engine.d.ts +3 -2
  202. package/dist/compounding/engine.js +10 -9
  203. package/dist/compounding/preference-consolidator.d.ts +2 -1
  204. package/dist/compression-optimizer.d.ts +2 -1
  205. package/dist/config.d.ts +2 -1
  206. package/dist/config.js +6 -5
  207. package/dist/connectors/codex-materialize-runner.d.ts +2 -1
  208. package/dist/connectors/codex-materialize-runner.js +8 -8
  209. package/dist/connectors/codex-materialize.d.ts +2 -1
  210. package/dist/connectors/index.d.ts +2 -1
  211. package/dist/connectors/index.js +10 -9
  212. package/dist/consolidation-provenance-check.d.ts +3 -2
  213. package/dist/consolidation-undo.d.ts +3 -2
  214. package/dist/contradiction/index.d.ts +4 -3
  215. package/dist/converge-config.d.ts +2 -1
  216. package/dist/convergence-refresh.d.ts +3 -2
  217. package/dist/convergence-refresh.js +10 -10
  218. package/dist/conversation-index/backend.d.ts +2 -1
  219. package/dist/conversation-index/backend.js +2 -2
  220. package/dist/conversation-index/chunker.d.ts +2 -1
  221. package/dist/conversation-index/faiss-adapter.d.ts +2 -1
  222. package/dist/conversation-index/indexer.d.ts +2 -1
  223. package/dist/conversation-index/search.d.ts +2 -1
  224. package/dist/corpus-watermark.d.ts +2 -1
  225. package/dist/corpus-watermark.js +10 -10
  226. package/dist/cross-lingual-recall.d.ts +2 -1
  227. package/dist/day-summary.d.ts +2 -1
  228. package/dist/deep-recall-config.d.ts +32 -0
  229. package/dist/deep-recall-config.js +12 -0
  230. package/dist/deep-recall-http-glue.d.ts +170 -0
  231. package/dist/deep-recall-http-glue.js +31 -0
  232. package/dist/deep-recall-http-glue.js.map +1 -0
  233. package/dist/deep-recall-mcp-tools.d.ts +144 -0
  234. package/dist/deep-recall-mcp-tools.js +8 -0
  235. package/dist/deep-recall-mcp-tools.js.map +1 -0
  236. package/dist/deep-recall-policy-llm.d.ts +37 -0
  237. package/dist/deep-recall-policy-llm.js +19 -0
  238. package/dist/deep-recall-policy-llm.js.map +1 -0
  239. package/dist/deep-recall-renderer.d.ts +16 -0
  240. package/dist/deep-recall-renderer.js +8 -0
  241. package/dist/deep-recall-renderer.js.map +1 -0
  242. package/dist/deep-recall-seeds.d.ts +83 -0
  243. package/dist/deep-recall-seeds.js +8 -0
  244. package/dist/deep-recall-seeds.js.map +1 -0
  245. package/dist/deep-recall.d.ts +97 -0
  246. package/dist/deep-recall.js +13 -0
  247. package/dist/deep-recall.js.map +1 -0
  248. package/dist/delinearize.d.ts +2 -1
  249. package/dist/dependency-propagation-config.d.ts +2 -1
  250. package/dist/{dependency-propagation-delivery-BC3bCEet.d.ts → dependency-propagation-delivery-BZGUecZf.d.ts} +1 -1
  251. package/dist/direct-answer-wiring.d.ts +2 -1
  252. package/dist/direct-answer.d.ts +2 -1
  253. package/dist/embedding-fallback.d.ts +2 -1
  254. package/dist/enrichment/index.d.ts +2 -1
  255. package/dist/entity-origin-fields.d.ts +2 -1
  256. package/dist/entity-retrieval.d.ts +3 -2
  257. package/dist/entity-retrieval.js +8 -8
  258. package/dist/entity-schema.d.ts +2 -1
  259. package/dist/episodic-context.d.ts +2 -1
  260. package/dist/eval-trajectory-contracts.d.ts +2 -1
  261. package/dist/eval-trajectory-store.d.ts +2 -1
  262. package/dist/eval-trajectory.d.ts +2 -1
  263. package/dist/explicit-capture.d.ts +10 -9
  264. package/dist/external-wiki-access.d.ts +13 -11
  265. package/dist/external-wiki-access.js +42 -29
  266. package/dist/external-wiki-collection-registration.d.ts +2 -1
  267. package/dist/external-wiki-collection.d.ts +2 -1
  268. package/dist/external-wiki-mcp-tools.d.ts +13 -11
  269. package/dist/extraction-error-classification.d.ts +2 -1
  270. package/dist/extraction-faithfulness.d.ts +2 -1
  271. package/dist/extraction-judge-telemetry.d.ts +2 -1
  272. package/dist/extraction-judge-training.d.ts +2 -1
  273. package/dist/extraction-judge.d.ts +2 -1
  274. package/dist/extraction-liveness.d.ts +2 -1
  275. package/dist/extraction-normalization.d.ts +2 -1
  276. package/dist/extraction-prompt.d.ts +2 -1
  277. package/dist/extraction-source-grounding-rules.d.ts +2 -1
  278. package/dist/extraction-source-grounding.d.ts +2 -1
  279. package/dist/extraction.d.ts +2 -1
  280. package/dist/extraction.js +14 -13
  281. package/dist/fallback-llm.d.ts +2 -1
  282. package/dist/graph-dashboard-diff.d.ts +2 -1
  283. package/dist/graph-dashboard-key.d.ts +2 -1
  284. package/dist/graph-dashboard-parser.d.ts +2 -1
  285. package/dist/{graph-edge-decay-DGTBFALQ.js → graph-edge-decay-FXGELBFA.js} +4 -4
  286. package/dist/graph-edge-decay-FXGELBFA.js.map +1 -0
  287. package/dist/graph-edge-reinforcement.d.ts +2 -1
  288. package/dist/graph-path-reconstruction.d.ts +2 -1
  289. package/dist/graph-path-scoring.d.ts +2 -1
  290. package/dist/graph-snapshot.d.ts +2 -1
  291. package/dist/graph-snapshot.js +3 -3
  292. package/dist/graph.d.ts +2 -1
  293. package/dist/graph.js +2 -2
  294. package/dist/harmonic-construction.js +3 -3
  295. package/dist/harmonic-retrieval.d.ts +38 -2
  296. package/dist/harmonic-retrieval.js +12 -3
  297. package/dist/importance.d.ts +2 -1
  298. package/dist/importers/index.d.ts +2 -1
  299. package/dist/in-flight-reads.d.ts +2 -1
  300. package/dist/{index-D4hS9uxK.d.ts → index-B4iTvT-w.d.ts} +2 -2
  301. package/dist/index.d.ts +701 -699
  302. package/dist/index.js +118 -106
  303. package/dist/intent.d.ts +2 -1
  304. package/dist/lcm/engine.d.ts +2 -1
  305. package/dist/lcm/index.d.ts +2 -1
  306. package/dist/lcm/tools.d.ts +2 -1
  307. package/dist/lifecycle.d.ts +2 -1
  308. package/dist/live-connectors-runner.d.ts +2 -1
  309. package/dist/local-llm.d.ts +2 -1
  310. package/dist/local-model-endpoint.d.ts +2 -1
  311. package/dist/location/index.d.ts +4 -3
  312. package/dist/location/index.js +10 -10
  313. package/dist/maintenance/memory-governance.d.ts +2 -1
  314. package/dist/maintenance/memory-governance.js +8 -8
  315. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +3 -2
  316. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +8 -8
  317. package/dist/maintenance/rebuild-memory-projection.d.ts +3 -2
  318. package/dist/maintenance/rebuild-memory-projection.js +9 -9
  319. package/dist/{maintenance-BRcc3Hx8.d.ts → maintenance-BBpNqEeJ.d.ts} +3 -3
  320. package/dist/mcp-memory-inspector-app.d.ts +13 -11
  321. package/dist/mcp-read-only-tools.js +1 -1
  322. package/dist/memory-action-policy.d.ts +2 -1
  323. package/dist/memory-cache.d.ts +2 -1
  324. package/dist/memory-controller.d.ts +2 -1
  325. package/dist/memory-lifecycle-ledger-utils.d.ts +2 -1
  326. package/dist/memory-projection-store.d.ts +2 -1
  327. package/dist/memory-provenance.d.ts +2 -1
  328. package/dist/memory-snapshot.d.ts +2 -1
  329. package/dist/memory-subject-cli.d.ts +13 -11
  330. package/dist/memory-subject.d.ts +13 -11
  331. package/dist/memory-worth-outcomes.d.ts +3 -2
  332. package/dist/models-json.d.ts +2 -1
  333. package/dist/namespaces/migrate.d.ts +4 -3
  334. package/dist/namespaces/migrate.js +9 -9
  335. package/dist/namespaces/principal.d.ts +2 -1
  336. package/dist/namespaces/search.d.ts +2 -1
  337. package/dist/namespaces/search.js +4 -4
  338. package/dist/namespaces/storage.d.ts +4 -3
  339. package/dist/namespaces/storage.js +8 -8
  340. package/dist/native-knowledge.d.ts +2 -1
  341. package/dist/offline-sync-impression-drain.d.ts +2 -1
  342. package/dist/offline-sync.js +2 -2
  343. package/dist/operator-doctor-corpus.d.ts +2 -1
  344. package/dist/operator-doctor-corpus.js +11 -11
  345. package/dist/operator-doctor-replica.d.ts +2 -1
  346. package/dist/operator-toolkit.d.ts +4 -3
  347. package/dist/operator-toolkit.js +24 -23
  348. package/dist/orchestration/compression-guideline-coordinator.d.ts +3 -2
  349. package/dist/orchestration/maintenance.d.ts +5 -4
  350. package/dist/orchestration/maintenance.js +16 -16
  351. package/dist/{orchestrator-Btq9lzAN.d.ts → orchestrator-DglY1H0w.d.ts} +8 -8
  352. package/dist/orchestrator.d.ts +10 -9
  353. package/dist/orchestrator.js +101 -89
  354. package/dist/patterns-cli.d.ts +2 -1
  355. package/dist/{pipeline-CZoNdFb5.d.ts → pipeline-C7qRsy6g.d.ts} +1 -1
  356. package/dist/policy-runtime.d.ts +2 -1
  357. package/dist/proactive-contention.d.ts +2 -1
  358. package/dist/provenance.d.ts +2 -1
  359. package/dist/{public-http-2MyshWxl.d.ts → public-http-CPpCsi35.d.ts} +1 -1
  360. package/dist/{qmd-VIjSCKIE.d.ts → qmd-YRLTa3AE.d.ts} +1 -1
  361. package/dist/qmd-preflight.d.ts +3 -2
  362. package/dist/qmd-recall-cache.d.ts +2 -1
  363. package/dist/qmd.d.ts +3 -2
  364. package/dist/recall-concurrency-config.d.ts +2 -1
  365. package/dist/recall-deep-expand-select.js +4 -44
  366. package/dist/recall-deep-expand-select.js.map +1 -1
  367. package/dist/recall-deep-frontier.js +4 -23
  368. package/dist/recall-deep-frontier.js.map +1 -1
  369. package/dist/recall-deep-rewrite.js +4 -23
  370. package/dist/recall-deep-rewrite.js.map +1 -1
  371. package/dist/recall-disclosure-escalation.d.ts +2 -1
  372. package/dist/recall-explain-renderer.d.ts +2 -1
  373. package/dist/recall-explain-renderer.js +3 -3
  374. package/dist/recall-memory-map.d.ts +2 -1
  375. package/dist/recall-navigate-access.d.ts +2 -1
  376. package/dist/recall-navigate-access.js +2 -2
  377. package/dist/recall-navigate-disclosure.d.ts +2 -1
  378. package/dist/recall-navigate-disclosure.js +1 -1
  379. package/dist/recall-navigate.d.ts +2 -1
  380. package/dist/recall-navigate.js +2 -2
  381. package/dist/recall-planner-llm.d.ts +2 -1
  382. package/dist/recall-state.d.ts +2 -1
  383. package/dist/recall-tag-filter.d.ts +2 -1
  384. package/dist/recall-timings.d.ts +2 -1
  385. package/dist/recall-xray-cli.d.ts +2 -1
  386. package/dist/recall-xray-cli.js +4 -4
  387. package/dist/recall-xray-renderer.d.ts +2 -1
  388. package/dist/recall-xray-renderer.js +3 -3
  389. package/dist/recall-xray.d.ts +2 -1
  390. package/dist/recall-xray.js +2 -2
  391. package/dist/reconcile/cursor.d.ts +2 -1
  392. package/dist/reconcile/manifest.d.ts +2 -1
  393. package/dist/reconcile/plan.d.ts +2 -1
  394. package/dist/replay/normalizers/chatgpt.d.ts +2 -1
  395. package/dist/replay/normalizers/claude.d.ts +2 -1
  396. package/dist/replay/normalizers/openclaw.d.ts +2 -1
  397. package/dist/replay/normalizers/shared.d.ts +2 -1
  398. package/dist/replay/runner.d.ts +2 -1
  399. package/dist/replay/types.d.ts +2 -1
  400. package/dist/replica-divergence.d.ts +2 -1
  401. package/dist/replica-peers-config.d.ts +2 -1
  402. package/dist/resolve-auth-token.d.ts +2 -1
  403. package/dist/resume-bundles.js +7 -6
  404. package/dist/retrieval-agents.d.ts +3 -2
  405. package/dist/retrieval-tiers.d.ts +2 -1
  406. package/dist/routing/engine.d.ts +2 -1
  407. package/dist/routing/store.d.ts +2 -1
  408. package/dist/runtime/http-transport.d.ts +4 -0
  409. package/dist/runtime/http-transport.js +10 -0
  410. package/dist/runtime/http-transport.js.map +1 -0
  411. package/dist/salvage-envelope.d.ts +2 -1
  412. package/dist/schemas.d.ts +176 -176
  413. package/dist/{scope-profiles-DqbxQXIS.d.ts → scope-profiles-BVvqVzJX.d.ts} +1 -1
  414. package/dist/search/embed-helper.d.ts +2 -1
  415. package/dist/search/factory.d.ts +2 -1
  416. package/dist/search/factory.js +3 -3
  417. package/dist/search/index.d.ts +2 -1
  418. package/dist/search/index.js +3 -3
  419. package/dist/search/lancedb-backend.d.ts +2 -1
  420. package/dist/search/meilisearch-backend.d.ts +2 -1
  421. package/dist/search/noop-backend.d.ts +2 -1
  422. package/dist/search/orama-backend.d.ts +2 -1
  423. package/dist/search/port.d.ts +2 -1
  424. package/dist/search/remote-backend.d.ts +2 -1
  425. package/dist/{semantic-consolidation-DW3rEUoW.d.ts → semantic-consolidation-BzCI6Kuu.d.ts} +1 -1
  426. package/dist/semantic-consolidation.d.ts +3 -2
  427. package/dist/semantic-consolidation.js +9 -9
  428. package/dist/semantic-rule-promotion.js +8 -8
  429. package/dist/semantic-rule-verifier.d.ts +2 -1
  430. package/dist/semantic-rule-verifier.js +8 -8
  431. package/dist/{service-B2vJU_Bx.d.ts → service-DQ3Gscy5.d.ts} +2 -2
  432. package/dist/session-observer-bands.d.ts +2 -1
  433. package/dist/session-observer-state.d.ts +2 -1
  434. package/dist/shared-context/manager.d.ts +43 -7
  435. package/dist/shared-context/manager.js +2 -1
  436. package/dist/signal.d.ts +2 -1
  437. package/dist/source-agent-qualifier.d.ts +2 -1
  438. package/dist/source-agent-qualifier.js +12 -11
  439. package/dist/standup/build.js +8 -8
  440. package/dist/{storage-6fn7BPmb.d.ts → storage-DmTbQdD0.d.ts} +1 -1
  441. package/dist/storage.d.ts +3 -2
  442. package/dist/storage.js +7 -7
  443. package/dist/subject-config.d.ts +2 -1
  444. package/dist/summarizer.d.ts +2 -1
  445. package/dist/summary-snapshot.d.ts +2 -1
  446. package/dist/support-passport/index.d.ts +16 -14
  447. package/dist/support-passport/index.js +44 -31
  448. package/dist/temporal-supersession.d.ts +3 -2
  449. package/dist/temporal-timeline-recall.d.ts +2 -1
  450. package/dist/temporal-validity.d.ts +2 -1
  451. package/dist/threading.d.ts +2 -1
  452. package/dist/tier-migration.d.ts +3 -2
  453. package/dist/tier-routing.d.ts +2 -1
  454. package/dist/topics.d.ts +2 -1
  455. package/dist/transcript.d.ts +2 -1
  456. package/dist/transfer/export-okf.d.ts +2 -1
  457. package/dist/transfer/export-okf.js +9 -9
  458. package/dist/transfer/types.d.ts +78 -78
  459. package/dist/trust-score-stage.d.ts +2 -1
  460. package/dist/trust-score.d.ts +2 -1
  461. package/dist/{types-eM7QIcX2.d.ts → types-CLRTESSD.d.ts} +3 -1
  462. package/dist/types.d.ts +2 -1
  463. package/dist/types.js +1 -1
  464. package/dist/utility-runtime.d.ts +2 -1
  465. package/dist/verified-recall.js +8 -8
  466. package/dist/who-knows-cli.d.ts +13 -11
  467. package/dist/who-knows-cli.js +9 -9
  468. package/dist/who-knows.d.ts +13 -11
  469. package/dist/who-knows.js +8 -8
  470. package/dist/write-envelope.d.ts +2 -1
  471. package/package.json +12 -2
  472. package/src/access-boundary.ts +1 -0
  473. package/src/access-http.ts +5 -5
  474. package/src/access-mcp-output-schemas.ts +1 -0
  475. package/src/access-mcp.ts +3 -3
  476. package/src/access-operations-batch.ts +3 -1
  477. package/src/access-schema.ts +12 -0
  478. package/src/access-service.ts +162 -5
  479. package/src/access-surface-catalog.ts +2 -0
  480. package/src/cli/deep-recall-commands.ts +60 -0
  481. package/src/cli.ts +2 -2
  482. package/src/config.test.ts +19 -0
  483. package/src/config.ts +7 -0
  484. package/src/deep-recall-config.ts +83 -0
  485. package/src/deep-recall-http-glue.ts +75 -0
  486. package/src/deep-recall-mcp-tools.ts +33 -0
  487. package/src/deep-recall-policy-llm.ts +65 -0
  488. package/src/deep-recall-renderer.ts +41 -0
  489. package/src/deep-recall-seeds.ts +134 -0
  490. package/src/deep-recall-surface.test.ts +902 -0
  491. package/src/deep-recall.test.ts +348 -0
  492. package/src/deep-recall.ts +572 -0
  493. package/src/harmonic-retrieval.ts +78 -25
  494. package/src/mcp-read-only-tools.ts +1 -0
  495. package/src/shared-context/envelope-at.test.ts +23 -0
  496. package/src/shared-context/envelope-at.ts +12 -6
  497. package/src/shared-context/envelope-io.ts +184 -0
  498. package/src/shared-context/envelope-wiring.test.ts +193 -0
  499. package/src/shared-context/governance.ts +28 -9
  500. package/src/shared-context/iso-instant.ts +43 -0
  501. package/src/shared-context/manager.ts +74 -15
  502. package/src/shared-context/provenance.ts +3 -26
  503. package/src/shared-context/write-origin.test.ts +145 -0
  504. package/src/types.ts +3 -1
  505. package/dist/chunk-26JWBSWD.js.map +0 -1
  506. package/dist/chunk-3QWF54M4.js.map +0 -1
  507. package/dist/chunk-4OFKZAJG.js.map +0 -1
  508. package/dist/chunk-5TBO7CDR.js.map +0 -1
  509. package/dist/chunk-754GA2UE.js.map +0 -1
  510. package/dist/chunk-IGUWU5BD.js.map +0 -1
  511. package/dist/chunk-J55NAXDH.js.map +0 -1
  512. package/dist/chunk-K4E3Y3ZX.js.map +0 -1
  513. package/dist/chunk-LVYO2HZJ.js.map +0 -1
  514. package/dist/chunk-M5UJJUON.js.map +0 -1
  515. package/dist/chunk-PEOFTEUC.js.map +0 -1
  516. package/dist/chunk-VI637ILW.js.map +0 -1
  517. package/dist/chunk-XXW32OL7.js.map +0 -1
  518. /package/dist/{chunk-DKZR56A3.js.map → chunk-227WJVPY.js.map} +0 -0
  519. /package/dist/{chunk-RXS4SQ5S.js.map → chunk-2EHDPHMD.js.map} +0 -0
  520. /package/dist/{chunk-ZPN6SSWA.js.map → chunk-2XJDAEAM.js.map} +0 -0
  521. /package/dist/{chunk-J3JEW5CT.js.map → chunk-3GCK6ONU.js.map} +0 -0
  522. /package/dist/{chunk-44HBCMOA.js.map → chunk-3ITTF7YH.js.map} +0 -0
  523. /package/dist/{chunk-GD7D7WP2.js.map → chunk-4UVDLNHQ.js.map} +0 -0
  524. /package/dist/{chunk-YVMTXBJJ.js.map → chunk-5YQ7RFSO.js.map} +0 -0
  525. /package/dist/{chunk-4PJYD2L3.js.map → chunk-6TOWUN2R.js.map} +0 -0
  526. /package/dist/{chunk-HINMCD7V.js.map → chunk-7NCUHD5U.js.map} +0 -0
  527. /package/dist/{chunk-QHYSECIG.js.map → chunk-7ZMU4XQT.js.map} +0 -0
  528. /package/dist/{chunk-GISV63M2.js.map → chunk-APZXA4WI.js.map} +0 -0
  529. /package/dist/{chunk-2QSZNTDO.js.map → chunk-AU7Q3LSC.js.map} +0 -0
  530. /package/dist/{chunk-G4MCAHMF.js.map → chunk-B75VCEX5.js.map} +0 -0
  531. /package/dist/{chunk-DJZWNKFO.js.map → chunk-BE4Y6GK6.js.map} +0 -0
  532. /package/dist/{chunk-E5WTGEWX.js.map → chunk-BEXFNGQ3.js.map} +0 -0
  533. /package/dist/{chunk-SO73GYOZ.js.map → chunk-BFDOBESV.js.map} +0 -0
  534. /package/dist/{chunk-OLT3YTDH.js.map → chunk-BIJAWZYW.js.map} +0 -0
  535. /package/dist/{chunk-X5TGZAP2.js.map → chunk-BO4PWIJY.js.map} +0 -0
  536. /package/dist/{chunk-JMAG7WZ7.js.map → chunk-BX6GW4KC.js.map} +0 -0
  537. /package/dist/{chunk-X5PIDJ3L.js.map → chunk-DA4ZMCBU.js.map} +0 -0
  538. /package/dist/{chunk-H6RSANGQ.js.map → chunk-ETZ7KKOS.js.map} +0 -0
  539. /package/dist/{chunk-SXQZMC7R.js.map → chunk-GR4C3FHT.js.map} +0 -0
  540. /package/dist/{chunk-S6AHHQ6C.js.map → chunk-H5IIBGDM.js.map} +0 -0
  541. /package/dist/{chunk-GFGQOZGG.js.map → chunk-HFRGCNFY.js.map} +0 -0
  542. /package/dist/{chunk-MAG6M3B6.js.map → chunk-HTOWFFAI.js.map} +0 -0
  543. /package/dist/{chunk-KAVQ5GYY.js.map → chunk-I4QAH4SY.js.map} +0 -0
  544. /package/dist/{chunk-2MW3UQNX.js.map → chunk-I6DUKBUI.js.map} +0 -0
  545. /package/dist/{chunk-YHCBJULX.js.map → chunk-JGXMA6HL.js.map} +0 -0
  546. /package/dist/{chunk-TA7UZZMW.js.map → chunk-JHTF22NQ.js.map} +0 -0
  547. /package/dist/{chunk-ANN5VMHT.js.map → chunk-LDOQE34V.js.map} +0 -0
  548. /package/dist/{chunk-MEW53VQJ.js.map → chunk-LDWIPYJ6.js.map} +0 -0
  549. /package/dist/{chunk-227UFSEQ.js.map → chunk-LEPOP46W.js.map} +0 -0
  550. /package/dist/{chunk-H3HOC6UT.js.map → chunk-LF6SHWVV.js.map} +0 -0
  551. /package/dist/{chunk-QGUFN25Q.js.map → chunk-LJAP4KSW.js.map} +0 -0
  552. /package/dist/{chunk-JAU4MRKB.js.map → chunk-LJNLLNEM.js.map} +0 -0
  553. /package/dist/{chunk-6C57JBJ3.js.map → chunk-LUDXSSTW.js.map} +0 -0
  554. /package/dist/{chunk-YJPFTF57.js.map → chunk-LWBSEYW3.js.map} +0 -0
  555. /package/dist/{chunk-PRK4WTPU.js.map → chunk-M7DGN6JZ.js.map} +0 -0
  556. /package/dist/{chunk-EN75MUTO.js.map → chunk-MNH2GM4O.js.map} +0 -0
  557. /package/dist/{chunk-LK4TOYPU.js.map → chunk-NF3NMAG7.js.map} +0 -0
  558. /package/dist/{chunk-VGTXHTWU.js.map → chunk-OASGWNYL.js.map} +0 -0
  559. /package/dist/{chunk-C2JCVZWX.js.map → chunk-OLBZ2WGG.js.map} +0 -0
  560. /package/dist/{chunk-Z3SQEEB6.js.map → chunk-OUKBMQ2O.js.map} +0 -0
  561. /package/dist/{chunk-2Z3DG5CQ.js.map → chunk-P6GKRT2H.js.map} +0 -0
  562. /package/dist/{chunk-A3WMMQAH.js.map → chunk-P7LVYPIX.js.map} +0 -0
  563. /package/dist/{chunk-Y3WMJAZ3.js.map → chunk-QRDSXR3V.js.map} +0 -0
  564. /package/dist/{chunk-NDE7CH6C.js.map → chunk-QUVWFZOU.js.map} +0 -0
  565. /package/dist/{chunk-M5GBTETG.js.map → chunk-R7FXPG4T.js.map} +0 -0
  566. /package/dist/{chunk-X66BHMAU.js.map → chunk-RJ57OOCD.js.map} +0 -0
  567. /package/dist/{chunk-VOPOPTZ7.js.map → chunk-TRLCMLX7.js.map} +0 -0
  568. /package/dist/{chunk-KZMFU7YL.js.map → chunk-V3HUBF7T.js.map} +0 -0
  569. /package/dist/{chunk-KLL5SPER.js.map → chunk-VHAKBUBD.js.map} +0 -0
  570. /package/dist/{chunk-WF2WCZCR.js.map → chunk-VYD63IFH.js.map} +0 -0
  571. /package/dist/{chunk-3FXXFLVK.js.map → chunk-XFPHV65N.js.map} +0 -0
  572. /package/dist/{chunk-JCUG7AXZ.js.map → chunk-XJJYSX6F.js.map} +0 -0
  573. /package/dist/{chunk-NAZROP6I.js.map → chunk-XMIAU4CO.js.map} +0 -0
  574. /package/dist/{chunk-LHGIBXVX.js.map → chunk-XQGFIAG7.js.map} +0 -0
  575. /package/dist/{chunk-IWO4HEOL.js.map → chunk-YWN3GYI2.js.map} +0 -0
  576. /package/dist/{chunk-IIO4C3YL.js.map → chunk-Z33VUMKY.js.map} +0 -0
  577. /package/dist/{graph-edge-decay-DGTBFALQ.js.map → deep-recall-config.js.map} +0 -0
@@ -14,6 +14,7 @@ import { countRecallTokenOverlap, normalizeRecallTokens } from "./recall-tokeniz
14
14
  import { stripAttributesSuffix } from "./structured-attributes.js";
15
15
  import { isValidityExpiredNow } from "./temporal-validity.js";
16
16
  import { isRecord } from "./store-contract.js";
17
+ import { isSupportPassportPrivateMemory } from "./support-passport/card-projection.js";
17
18
  import type { MemoryFile } from "./types.js";
18
19
 
19
20
  type SourceMemoryMap = Map<string, MemoryFile>;
@@ -73,6 +74,11 @@ function projectSourceBackedNode(
73
74
  const memory = sourceMemories.get(memoryId);
74
75
  return (
75
76
  memory !== undefined &&
77
+ // #2332: a private support-passport record leaves the eligible set the
78
+ // same way a rejected one does — a node title or anchor attribution
79
+ // rebuilt from it would leak governed metadata into the deep-recall
80
+ // frontier (and every other graph reader) before any content check runs.
81
+ !isSupportPassportPrivateMemory(memory) &&
76
82
  inferMemoryStatus(memory.frontmatter, toMemoryPathRel(memoryDir, memory.path)) === "active" &&
77
83
  (temporalExpiredInInjection || !isValidityExpiredNow(memory.frontmatter, nowMs))
78
84
  );
@@ -232,7 +238,7 @@ function scoreAnchor(
232
238
  return { score, matchedFields };
233
239
  }
234
240
 
235
- async function readAbstractionNodes(options: {
241
+ export async function readAbstractionNodes(options: {
236
242
  memoryDir: string;
237
243
  abstractionNodeStoreDir?: string;
238
244
  }): Promise<AbstractionNode[]> {
@@ -249,7 +255,7 @@ async function readAbstractionNodes(options: {
249
255
  return nodes;
250
256
  }
251
257
 
252
- async function readCueAnchors(options: {
258
+ export async function readCueAnchors(options: {
253
259
  memoryDir: string;
254
260
  abstractionNodeStoreDir?: string;
255
261
  }): Promise<CueAnchor[]> {
@@ -267,27 +273,46 @@ async function readCueAnchors(options: {
267
273
  return anchors;
268
274
  }
269
275
 
270
- export async function searchHarmonicRetrieval(options: {
276
+ export interface ProjectedHarmonicGraph {
277
+ nodes: AbstractionNode[];
278
+ anchors: CueAnchor[];
279
+ }
280
+
281
+ /**
282
+ * Read nodes + anchors and project BOTH against the namespace's current active
283
+ * memories. This is the single projection every graph reader shares: a raw
284
+ * `readAbstractionNodes` / `readCueAnchors` pair still carries the stored title,
285
+ * summary, tags, and anchor attribution of a memory that was later rejected,
286
+ * quarantined, or otherwise moved out of the active set, so a second reader
287
+ * that skipped the projection could leak governed metadata even when the
288
+ * memory itself is excluded from the final results.
289
+ *
290
+ * - A node whose every source memory left the active set is dropped.
291
+ * - A surviving node's title/summary/tags/entityRefs are rebuilt from its
292
+ * active sources only.
293
+ * - An anchor keeps a node reference only while its attribution runs through
294
+ * one of that node's surviving active sources, and is dropped once no
295
+ * reference survives.
296
+ */
297
+ export async function readProjectedHarmonicGraph(options: {
271
298
  memoryDir: string;
272
299
  abstractionNodeStoreDir?: string;
273
- query: string;
274
- maxResults: number;
275
- sessionKey?: string;
276
300
  anchorsEnabled: boolean;
277
301
  abortSignal?: AbortSignal;
278
302
  temporalExpiredInInjection?: boolean;
279
- }): Promise<HarmonicRetrievalResult[]> {
303
+ nowMs?: number;
304
+ }): Promise<ProjectedHarmonicGraph> {
280
305
  throwIfAborted(options.abortSignal, "harmonic retrieval aborted");
281
- const queryTokens = new Set(normalizeRecallTokens(options.query, ["what", "which"]));
282
- if (queryTokens.size === 0 || options.maxResults <= 0) return [];
283
-
284
306
  const nodes = await readAbstractionNodes(options);
285
- const sourceBackedNodes = nodes.filter((node) => (node.sourceMemoryIds?.length ?? 0) > 0);
286
- const sourceMemories: SourceMemoryMap =
287
- sourceBackedNodes.length > 0 ? await readSourceMemories(options) : new Map<string, MemoryFile>();
307
+ const sourceBacked = nodes.some((node) => (node.sourceMemoryIds?.length ?? 0) > 0);
308
+ const sourceMemories: SourceMemoryMap = sourceBacked
309
+ ? await readSourceMemories(options)
310
+ : new Map<string, MemoryFile>();
311
+ const nowMs = options.nowMs ?? Date.now();
312
+ // A node whose full stored source set survived projection keeps legacy
313
+ // anchor attribution (an anchor written before per-node source ids existed).
288
314
  const legacyCompatibleNodeRefs = new Set<string>();
289
- const nowMs = Date.now();
290
- const eligibleNodes = nodes.flatMap((node) => {
315
+ const projectedNodes = nodes.flatMap((node) => {
291
316
  const projected = projectSourceBackedNode(
292
317
  node,
293
318
  sourceMemories,
@@ -304,6 +329,40 @@ export async function searchHarmonicRetrieval(options: {
304
329
  }
305
330
  return projected ? [projected] : [];
306
331
  });
332
+ if (!options.anchorsEnabled) return { nodes: projectedNodes, anchors: [] };
333
+ throwIfAborted(options.abortSignal, "harmonic retrieval aborted");
334
+ const nodeIndex = new Map(projectedNodes.map((node) => [node.nodeId, node]));
335
+ const anchors = (await readCueAnchors(options)).flatMap((anchor) => {
336
+ throwIfAborted(options.abortSignal, "harmonic retrieval aborted");
337
+ const nodeRefs = anchor.nodeRefs.filter((nodeRef) => {
338
+ const node = nodeIndex.get(nodeRef);
339
+ return (
340
+ node !== undefined &&
341
+ anchorMatchesProjectedNode(anchor, nodeRef, node, legacyCompatibleNodeRefs.has(nodeRef))
342
+ );
343
+ });
344
+ return nodeRefs.length > 0 ? [{ ...anchor, nodeRefs }] : [];
345
+ });
346
+ return { nodes: projectedNodes, anchors };
347
+ }
348
+
349
+ export async function searchHarmonicRetrieval(options: {
350
+ memoryDir: string;
351
+ abstractionNodeStoreDir?: string;
352
+ query: string;
353
+ maxResults: number;
354
+ sessionKey?: string;
355
+ anchorsEnabled: boolean;
356
+ abortSignal?: AbortSignal;
357
+ temporalExpiredInInjection?: boolean;
358
+ }): Promise<HarmonicRetrievalResult[]> {
359
+ throwIfAborted(options.abortSignal, "harmonic retrieval aborted");
360
+ const queryTokens = new Set(normalizeRecallTokens(options.query, ["what", "which"]));
361
+ if (queryTokens.size === 0 || options.maxResults <= 0) return [];
362
+
363
+ // One projection for every graph reader: nodes and anchors both arrive
364
+ // already narrowed to the namespace's current active memories.
365
+ const { nodes: eligibleNodes, anchors } = await readProjectedHarmonicGraph(options);
307
366
  const candidates = new Map<string, HarmonicCandidate>();
308
367
 
309
368
  for (const node of eligibleNodes) {
@@ -321,19 +380,13 @@ export async function searchHarmonicRetrieval(options: {
321
380
 
322
381
  if (options.anchorsEnabled) {
323
382
  throwIfAborted(options.abortSignal, "harmonic retrieval aborted");
324
- const anchors = await readCueAnchors(options);
325
383
  const nodeIndex = new Map(eligibleNodes.map((node) => [node.nodeId, node]));
326
384
  for (const anchor of anchors) {
327
385
  throwIfAborted(options.abortSignal, "harmonic retrieval aborted");
328
- const eligibleNodeRefs = anchor.nodeRefs.filter((nodeRef) => {
329
- const node = nodeIndex.get(nodeRef);
330
- return (
331
- node !== undefined &&
332
- anchorMatchesProjectedNode(anchor, nodeRef, node, legacyCompatibleNodeRefs.has(nodeRef))
333
- );
334
- });
335
- const eligibleNodeTags = new Set(eligibleNodeRefs.flatMap((nodeRef) => nodeIndex.get(nodeRef)?.tags ?? []));
336
- const eligibleAnchorTags = anchor.tags?.filter((tag) => eligibleNodeTags.has(tag)) ?? [];
386
+ // `nodeRefs` are the projection's surviving references already.
387
+ const eligibleNodeRefs = anchor.nodeRefs;
388
+ const eligibleNodeTags = new Set(eligibleNodeRefs.flatMap((nodeRef) => nodeIndex.get(nodeRef)?.tags ?? []));
389
+ const eligibleAnchorTags = anchor.tags?.filter((tag) => eligibleNodeTags.has(tag)) ?? [];
337
390
  const { score, matchedFields } = scoreAnchor(anchor, queryTokens, eligibleAnchorTags);
338
391
  if (score <= 0) continue;
339
392
  for (const nodeRef of eligibleNodeRefs) {
@@ -27,6 +27,7 @@ export const MCP_READ_ONLY_TOOL_SUFFIXES: Readonly<Record<string, true>> = {
27
27
  location_day: true,
28
28
  meetings_list: true,
29
29
  meetings_get: true,
30
+ deep_recall: true,
30
31
  standup: true,
31
32
  action_confidence: true,
32
33
  capsule_list: true,
@@ -17,3 +17,26 @@ test("empty at is missing_at", () => {
17
17
  test("invalid at is invalid_at", () => {
18
18
  assert.deepEqual(parseEnvelopeAt("not-a-date"), { ok: false, error: "invalid_at" });
19
19
  });
20
+
21
+ /**
22
+ * Regression (issue #1957 review round 3): permissive `Date.parse` accepted
23
+ * these and silently reinterpreted them — "2026-02-30" as March 2 2026, "1"
24
+ * as January 1 2001 — so the persisted governance deadline differed from the
25
+ * caller's input. The calendar components are validated against the exact
26
+ * value now, and an out-of-range or non-string input is rejected.
27
+ */
28
+ test("Date.parse-permissive expiries are rejected, not reinterpreted", () => {
29
+ for (const value of ["2026-02-30T00:00:00.000Z", "2026-02-30", "1", "2026-13-01T00:00:00Z", "2026-08-18T25:00:00Z"]) {
30
+ assert.deepEqual(parseEnvelopeAt(value), { ok: false, error: "invalid_at" }, value);
31
+ }
32
+ // Non-finite / non-string inputs an in-process JS caller can still pass.
33
+ for (const value of [Number.NaN, Number.POSITIVE_INFINITY, 1, null, undefined, {}]) {
34
+ assert.deepEqual(parseEnvelopeAt(value as never), { ok: false, error: "invalid_at" }, String(value));
35
+ }
36
+ // A whitespace-padded timestamp is not the value the caller supplied.
37
+ assert.deepEqual(parseEnvelopeAt(` ${AT} `), { ok: false, error: "invalid_at" });
38
+ // Valid ISO instants still pass through unchanged.
39
+ assert.deepEqual(parseEnvelopeAt(AT), { ok: true, at: AT });
40
+ assert.deepEqual(parseEnvelopeAt("2026-02-28T23:59:59Z"), { ok: true, at: "2026-02-28T23:59:59.000Z" });
41
+ assert.deepEqual(parseEnvelopeAt("2024-02-29T00:00:00Z"), { ok: true, at: "2024-02-29T00:00:00.000Z" });
42
+ });
@@ -1,17 +1,23 @@
1
1
  /**
2
2
  * Shared-item envelope at parse (issue #1957 leftover).
3
3
  *
4
- * Pure. Empty is missing_at. Invalid Date.parse is invalid_at.
4
+ * Pure. Blank is missing_at. Anything that is not a calendar-valid ISO-8601
5
+ * instant is invalid_at — including values permissive `Date.parse` would
6
+ * silently reinterpret (`"2026-02-30"` -> March 2, `"1"` -> January 1 2001),
7
+ * a whitespace-padded timestamp, and any non-string or non-finite input
8
+ * (review round 3). `trim()` only detects blankness; validation reads the
9
+ * exact value, so normalization can never widen what passes.
5
10
  */
6
11
 
12
+ import { isStrictIsoInstant } from "./iso-instant.js";
13
+
7
14
  export type ParseEnvelopeAtResult =
8
15
  | { ok: true; at: string }
9
16
  | { ok: false; error: "missing_at" | "invalid_at" };
10
17
 
11
18
  export function parseEnvelopeAt(value: string): ParseEnvelopeAtResult {
12
- const raw = value.trim();
13
- if (raw.length === 0) return { ok: false, error: "missing_at" };
14
- const ms = Date.parse(raw);
15
- if (!Number.isFinite(ms)) return { ok: false, error: "invalid_at" };
16
- return { ok: true, at: new Date(ms).toISOString() };
19
+ if (typeof value !== "string") return { ok: false, error: "invalid_at" };
20
+ if (value.trim().length === 0) return { ok: false, error: "missing_at" };
21
+ if (!isStrictIsoInstant(value)) return { ok: false, error: "invalid_at" };
22
+ return { ok: true, at: new Date(Date.parse(value)).toISOString() };
17
23
  }
@@ -0,0 +1,184 @@
1
+ /**
2
+ * Shared-item envelope wiring (issue #1957, control 1: origin + authority).
3
+ *
4
+ * Bridges the pure envelope helpers onto the markdown frontmatter the
5
+ * shared-context manager reads and writes.
6
+ *
7
+ * Write side rejects invalid input (an unrecognized authority or a binding
8
+ * request without the config opt-in throws — never silently reinterpreted).
9
+ * Read side resolves least privilege: a missing, malformed, or unrecognized
10
+ * authority never resolves above informational, and stored binding
11
+ * downgrades to advisory unless config opted in.
12
+ */
13
+
14
+ import { applyDefaultEnvelope, parseSharedEnvelope, type SharedEnvelope } from "./governance.js";
15
+ import { resolveSharedAuthority } from "./authority-precedence.js";
16
+ import type { SharedAuthority } from "./governance.js";
17
+ import { parseEnvelopeActor } from "./envelope-actor.js";
18
+ import { parseEnvelopeAt } from "./envelope-at.js";
19
+ import { parseEnvelopeId } from "./envelope-id.js";
20
+
21
+ export interface ComposeWriteEnvelopeInput {
22
+ /** Governance origin. Becomes the envelope's `sharedBy`. */
23
+ origin: string;
24
+ /** Requested authority class. Unrecognized values throw. */
25
+ authority?: string;
26
+ /** Optional ISO-8601 expiry. Invalid timestamps throw. */
27
+ expiresAt?: string;
28
+ /** Optional id of the item this one supersedes. */
29
+ supersedes?: string;
30
+ /** Config opt-in (`sharedContextAllowBindingAuthority`). Binding throws without it. */
31
+ allowBinding: boolean;
32
+ }
33
+
34
+ function requireEnvelopeActor(agentId: string): string {
35
+ const parsed = parseEnvelopeActor(agentId);
36
+ if (!parsed.ok) {
37
+ throw new Error(`composeWriteEnvelope: agentId must be a non-blank single-line string (${parsed.error})`);
38
+ }
39
+ return parsed.actor;
40
+ }
41
+
42
+ function optionalEnvelopeAt(expiresAt: string | undefined): string | undefined {
43
+ if (expiresAt === undefined) return undefined;
44
+ const parsed = parseEnvelopeAt(expiresAt);
45
+ if (!parsed.ok) {
46
+ throw new Error(`composeWriteEnvelope: expiresAt must be a valid ISO-8601 timestamp (${parsed.error})`);
47
+ }
48
+ return parsed.at;
49
+ }
50
+
51
+ function optionalEnvelopeId(supersedes: string | undefined): string | undefined {
52
+ if (supersedes === undefined) return undefined;
53
+ const parsed = parseEnvelopeId(supersedes);
54
+ if (!parsed.ok) {
55
+ throw new Error(`composeWriteEnvelope: supersedes must be a non-blank single-line id (${parsed.error})`);
56
+ }
57
+ return parsed.id;
58
+ }
59
+
60
+ /**
61
+ * Reserved governance origin for an authenticated external access write that
62
+ * resolved no principal (`agentAccessHttp.principal` unset, no adapter
63
+ * identity). Server-owned: the caller cannot mint or influence it, and the
64
+ * caller-supplied `agentId` never becomes audit metadata on that path.
65
+ */
66
+ export const UNATTRIBUTED_ACCESS_WRITE_ORIGIN = "unattributed:access-surface";
67
+
68
+ export interface ResolvedWriteIdentity {
69
+ /**
70
+ * Producer identity: frontmatter `agent`, on-disk segment, and the
71
+ * cross-signals grouping key. Self-declared by the caller only on
72
+ * surfaces that resolved no server identity; never decides authority.
73
+ */
74
+ agent: string;
75
+ /** Governance origin stamped as the envelope's `sharedBy`. */
76
+ origin: string;
77
+ }
78
+
79
+ /**
80
+ * Resolve the producer identity and governance origin for a shared-context
81
+ * write. They are different fields with different trust requirements:
82
+ *
83
+ * - The origin (`sharedBy`) is audit metadata and is always server-derived.
84
+ * When the surface resolved an authenticated identity, that identity IS the
85
+ * origin; when it resolved none but the write crosses an external
86
+ * boundary, the caller-supplied `unattributedOrigin` token is stamped
87
+ * instead — never the caller's value. Only a trusted in-process caller
88
+ * (no identity, no token) may stamp its own id as the origin.
89
+ * - The producer (`agent`) drives grouping and display only. When an
90
+ * authenticated identity exists it is also the producer, and a
91
+ * caller-supplied `agentId` naming a different agent is REJECTED, so a
92
+ * caller can never publish an item attributed to another agent. Without a
93
+ * server identity the caller's label stands as the producer — collapsing
94
+ * it instead would merge every writer into one agent and erase
95
+ * multi-agent overlaps from `synthesizeCrossSignals`.
96
+ */
97
+ export function resolveWriteOrigin(input: {
98
+ agentId: string;
99
+ authenticatedIdentity?: string;
100
+ unattributedOrigin?: string;
101
+ }): ResolvedWriteIdentity {
102
+ const identity = input.authenticatedIdentity?.trim() ?? "";
103
+ if (identity.length > 0) {
104
+ const requested = input.agentId.trim();
105
+ if (requested.length > 0 && requested !== identity) {
106
+ throw new Error(
107
+ `shared-context write origin mismatch: authenticated identity ${JSON.stringify(identity)} cannot publish as ${JSON.stringify(requested)}`,
108
+ );
109
+ }
110
+ return { agent: identity, origin: identity };
111
+ }
112
+ const unattributed = input.unattributedOrigin?.trim() ?? "";
113
+ if (unattributed.length > 0) {
114
+ const label = input.agentId.trim();
115
+ return {
116
+ agent: label.length > 0 ? requireProducer(label) : requireProducer(unattributed),
117
+ origin: requireProducer(unattributed),
118
+ };
119
+ }
120
+ const actor = requireProducer(input.agentId);
121
+ return { agent: actor, origin: actor };
122
+ }
123
+
124
+ function requireProducer(value: string): string {
125
+ const parsed = parseEnvelopeActor(value);
126
+ if (!parsed.ok) {
127
+ throw new Error(`shared-context write producer must be a non-blank single-line string (${parsed.error})`);
128
+ }
129
+ return parsed.actor;
130
+ }
131
+
132
+ /**
133
+ * Validate and compose the envelope for a shared-context write.
134
+ * `sharedBy` is stamped from the server-derived origin — provenance is
135
+ * never injected through item content or the caller's producer label.
136
+ */
137
+ export function composeWriteEnvelope(input: ComposeWriteEnvelopeInput): SharedEnvelope {
138
+ const sharedBy = requireEnvelopeActor(input.origin);
139
+ const expiresAt = optionalEnvelopeAt(input.expiresAt);
140
+ const supersedes = optionalEnvelopeId(input.supersedes);
141
+ return applyDefaultEnvelope(
142
+ { sharedBy, authority: input.authority, expiresAt, supersedes },
143
+ { binding: input.allowBinding },
144
+ );
145
+ }
146
+
147
+ /** Serialize an envelope into frontmatter lines (caller adds the `---` fences). */
148
+ export function envelopeToFrontmatterLines(envelope: SharedEnvelope): string[] {
149
+ const line = (key: string, value: string) => `${key}: ${JSON.stringify(value)}`;
150
+ const lines = [line("sharedBy", envelope.sharedBy ?? ""), line("authority", envelope.authority)];
151
+ if (envelope.expiresAt !== undefined) lines.push(line("expiresAt", envelope.expiresAt));
152
+ if (envelope.supersedes !== undefined) lines.push(line("supersedes", envelope.supersedes));
153
+ return lines;
154
+ }
155
+
156
+ /**
157
+ * Build an envelope from frontmatter scalars already read off a stored item.
158
+ * Missing scalars (legacy items) compose to informational with no expiry.
159
+ */
160
+ export function envelopeFromScalars(scalars: {
161
+ sharedBy: string | null;
162
+ authority: string | null;
163
+ expiresAt: string | null;
164
+ supersedes: string | null;
165
+ }): SharedEnvelope {
166
+ const record: Record<string, string> = {};
167
+ if (scalars.sharedBy !== null) record.sharedBy = scalars.sharedBy;
168
+ if (scalars.authority !== null) record.authority = scalars.authority;
169
+ if (scalars.expiresAt !== null) record.expiresAt = scalars.expiresAt;
170
+ if (scalars.supersedes !== null) record.supersedes = scalars.supersedes;
171
+ return parseSharedEnvelope(record);
172
+ }
173
+
174
+ /**
175
+ * Resolve a stored envelope's authority for read-side consumption.
176
+ * Least privilege: unrecognized/missing stays informational; binding
177
+ * requires the config opt-in or downgrades to advisory.
178
+ */
179
+ export function resolveReadAuthority(
180
+ envelope: Pick<SharedEnvelope, "authority">,
181
+ allowBinding: boolean,
182
+ ): SharedAuthority {
183
+ return resolveSharedAuthority({ authority: envelope.authority, allowBinding });
184
+ }
@@ -0,0 +1,193 @@
1
+ /**
2
+ * Regression: shared-item authority envelope wiring (issue #1957, control 1).
3
+ *
4
+ * Exercises the REAL manager write/read paths end to end:
5
+ * writeAgentOutput stamps `sharedBy`/`authority` (+ optional `expiresAt`/
6
+ * `supersedes`) frontmatter; cross-signals and daily curation resolve and
7
+ * surface them. Least privilege holds everywhere: a missing, unrecognized,
8
+ * or un-flagged binding authority denies — it never elevates.
9
+ */
10
+
11
+ import test from "node:test";
12
+ import assert from "node:assert/strict";
13
+ import os from "node:os";
14
+ import path from "node:path";
15
+ import { mkdtemp, mkdir, readFile, rm, writeFile } from "node:fs/promises";
16
+ import { SharedContextManager } from "./manager.js";
17
+ import { parseConfig } from "../config.js";
18
+
19
+ async function makeManager(overrides: Record<string, unknown> = {}) {
20
+ const dir = await mkdtemp(path.join(os.tmpdir(), "remnic-shared-envelope-"));
21
+ const config = parseConfig({
22
+ sharedContextEnabled: true,
23
+ sharedContextDir: dir,
24
+ ...overrides,
25
+ });
26
+ const manager = new SharedContextManager(config);
27
+ await manager.ensureStructure();
28
+ return { manager, dir };
29
+ }
30
+
31
+ function today(): string {
32
+ return new Date().toISOString().slice(0, 10);
33
+ }
34
+
35
+ test("authority envelope round-trips write -> cross-signals -> curation", async (t) => {
36
+ const { manager, dir } = await makeManager();
37
+ t.after(() => rm(dir, { recursive: true, force: true }));
38
+
39
+ const fp = await manager.writeAgentOutput({
40
+ agentId: "agent-alpha",
41
+ title: "Deploy checklist",
42
+ content: "Verified the deploy checklist end to end.",
43
+ authority: "advisory",
44
+ expiresAt: "2099-01-01T00:00:00.000Z",
45
+ supersedes: "out-0001",
46
+ });
47
+
48
+ const raw = await readFile(fp, "utf-8");
49
+ assert.match(raw, /^kind: agent_output$/m);
50
+ assert.match(raw, /^sharedBy: "agent-alpha"$/m);
51
+ assert.match(raw, /^authority: "advisory"$/m);
52
+ assert.match(raw, /^expiresAt: "2099-01-01T00:00:00\.000Z"$/m);
53
+ assert.match(raw, /^supersedes: "out-0001"$/m);
54
+
55
+ const signals = await manager.synthesizeCrossSignals({ date: today() });
56
+ const source = signals.report.sources.find((s) => s.path === fp);
57
+ assert.ok(source, "written output must appear in cross-signals sources");
58
+ assert.equal(source.authority, "advisory");
59
+ assert.equal(source.sharedBy, "agent-alpha");
60
+ const curation = await manager.curateDaily({ date: today() });
61
+ const roundtable = await readFile(curation.roundtablePath, "utf-8");
62
+ assert.match(roundtable, /authority: advisory; sharedBy: agent-alpha/);
63
+ assert.ok(roundtable.includes(fp), "roundtable cites the source path");
64
+ });
65
+
66
+ test("missing or unrecognized authority denies — never elevates", async (t) => {
67
+ const { manager, dir } = await makeManager();
68
+ t.after(() => rm(dir, { recursive: true, force: true }));
69
+
70
+ // Unrecognized authority at write time is rejected, not reinterpreted.
71
+ await assert.rejects(
72
+ manager.writeAgentOutput({
73
+ agentId: "agent-alpha",
74
+ title: "Malformed",
75
+ content: "x",
76
+ authority: " BINDING ",
77
+ }),
78
+ /authority must be informational, advisory, or binding/,
79
+ );
80
+
81
+ // Legacy item with no envelope resolves least-privileged on read.
82
+ const date = today();
83
+ const legacyDir = path.join(dir, "agent-outputs", "agent-legacy", date);
84
+ await mkdir(legacyDir, { recursive: true });
85
+ const legacyPath = path.join(legacyDir, "120000-legacy.md");
86
+ await writeFile(
87
+ legacyPath,
88
+ '---\nkind: agent_output\nagent: "agent-legacy"\ntitle: "Legacy"\n---\n\nOld item.\n',
89
+ "utf-8",
90
+ );
91
+
92
+ const signals = await manager.synthesizeCrossSignals({ date });
93
+ const legacy = signals.report.sources.find((s) => s.path === legacyPath);
94
+ assert.ok(legacy, "legacy item still appears in sources");
95
+ assert.equal(legacy.authority, "informational");
96
+ assert.equal(legacy.sharedBy, "agent-legacy");
97
+
98
+ // A stored unrecognized authority value also denies on read.
99
+ const bogusPath = path.join(legacyDir, "120100-bogus.md");
100
+ await writeFile(
101
+ bogusPath,
102
+ '---\nkind: agent_output\nagent: "agent-legacy"\ntitle: "Bogus"\nsharedBy: "agent-legacy"\nauthority: "imperative"\n---\n\nBogus item.\n',
103
+ "utf-8",
104
+ );
105
+ const reread = await manager.synthesizeCrossSignals({ date });
106
+ const bogus = reread.report.sources.find((s) => s.path === bogusPath);
107
+ assert.equal(bogus?.authority, "informational");
108
+ });
109
+
110
+ test("binding authority requires the config opt-in at write and on read", async (t) => {
111
+ const gated = await makeManager();
112
+ t.after(() => rm(gated.dir, { recursive: true, force: true }));
113
+
114
+ // Default config: a binding request is denied at the write boundary.
115
+ await assert.rejects(
116
+ gated.manager.writeAgentOutput({
117
+ agentId: "agent-alpha",
118
+ title: "Directive",
119
+ content: "x",
120
+ authority: "binding",
121
+ }),
122
+ /requires an explicit binding flag/,
123
+ );
124
+
125
+ // Stored binding without the flag downgrades to advisory on read.
126
+ const date = today();
127
+ const bindingDir = path.join(gated.dir, "agent-outputs", "agent-alpha", date);
128
+ await mkdir(bindingDir, { recursive: true });
129
+ const bindingPath = path.join(bindingDir, "130000-directive.md");
130
+ await writeFile(
131
+ bindingPath,
132
+ '---\nkind: agent_output\nagent: "agent-alpha"\ntitle: "Directive"\nsharedBy: "agent-alpha"\nauthority: "binding"\n---\n\nDirective.\n',
133
+ "utf-8",
134
+ );
135
+ const gatedSignals = await gated.manager.synthesizeCrossSignals({ date });
136
+ const stored = gatedSignals.report.sources.find((s) => s.path === bindingPath);
137
+ assert.equal(stored?.authority, "advisory", "un-flagged stored binding must downgrade");
138
+
139
+ // Opt-in config: binding writes succeed and resolve as binding on read.
140
+ const open = await makeManager({ sharedContextAllowBindingAuthority: true });
141
+ t.after(() => rm(open.dir, { recursive: true, force: true }));
142
+ const fp = await open.manager.writeAgentOutput({
143
+ agentId: "agent-alpha",
144
+ title: "Directive",
145
+ content: "x",
146
+ authority: "binding",
147
+ });
148
+ const raw = await readFile(fp, "utf-8");
149
+ assert.match(raw, /^authority: "binding"$/m);
150
+ const openSignals = await open.manager.synthesizeCrossSignals({ date });
151
+ const source = openSignals.report.sources.find((s) => s.path === fp);
152
+ assert.equal(source?.authority, "binding");
153
+ });
154
+
155
+ test("a whitespace-padded stored authority stays informational even with binding enabled", async (t) => {
156
+ // Regression (issue #1957 review): the stored token is validated EXACTLY.
157
+ // Trimming first would let `" binding "` resolve as binding when the opt-in
158
+ // is on, and as advisory when it is off — both above informational.
159
+ const date = today();
160
+ for (const allowBinding of [false, true]) {
161
+ const { manager, dir } = await makeManager({ sharedContextAllowBindingAuthority: allowBinding });
162
+ t.after(() => rm(dir, { recursive: true, force: true }));
163
+ const paddedDir = path.join(dir, "agent-outputs", "agent-padded", date);
164
+ await mkdir(paddedDir, { recursive: true });
165
+ const paddedPath = path.join(paddedDir, "140000-padded.md");
166
+ await writeFile(
167
+ paddedPath,
168
+ '---\nkind: agent_output\nagent: "agent-padded"\ntitle: "Padded"\nsharedBy: "agent-padded"\nauthority: " binding "\n---\n\nPadded item.\n',
169
+ "utf-8",
170
+ );
171
+ const signals = await manager.synthesizeCrossSignals({ date });
172
+ const padded = signals.report.sources.find((s) => s.path === paddedPath);
173
+ assert.equal(
174
+ padded?.authority,
175
+ "informational",
176
+ `padded authority must stay informational (allowBinding=${allowBinding})`,
177
+ );
178
+ }
179
+
180
+ // The same exactness holds at the write boundary: padded is rejected, not
181
+ // normalized into a privileged class.
182
+ const open = await makeManager({ sharedContextAllowBindingAuthority: true });
183
+ t.after(() => rm(open.dir, { recursive: true, force: true }));
184
+ await assert.rejects(
185
+ open.manager.writeAgentOutput({
186
+ agentId: "agent-padded",
187
+ title: "Padded",
188
+ content: "x",
189
+ authority: " binding ",
190
+ }),
191
+ /authority must be informational, advisory, or binding/,
192
+ );
193
+ });
@@ -1,8 +1,9 @@
1
1
  /**
2
2
  * Shared-item authority envelope (issue #1957).
3
3
  *
4
- * First slice: parse + default + expiry only. Write-path wiring and
5
- * curation come later. Binding is never inferred.
4
+ * Pure parse/default/expiry helpers over the authority classes. Binding is
5
+ * never inferred, and the authority token is validated exactly as supplied
6
+ * or stored — a padded value never resolves to a privileged class.
6
7
  */
7
8
 
8
9
  export const SHARED_AUTHORITIES = ["informational", "advisory", "binding"] as const;
@@ -36,6 +37,24 @@ function optionalString(value: unknown): string | undefined {
36
37
  return trimmed.length > 0 ? trimmed : undefined;
37
38
  }
38
39
 
40
+ type AuthorityToken =
41
+ | { kind: "absent" }
42
+ | { kind: "invalid"; raw: string }
43
+ | { kind: "valid"; authority: SharedAuthority };
44
+
45
+ /**
46
+ * Read the authority token EXACTLY as supplied or stored. A padded value
47
+ * such as `" binding "` is malformed data, never a normalized match for a
48
+ * privileged class: trimming first would let stored whitespace resolve as
49
+ * binding/advisory (AGENTS.md rule 45). Only the empty string counts as
50
+ * "unspecified"; whitespace-only is invalid.
51
+ */
52
+ function readExactAuthority(value: unknown): AuthorityToken {
53
+ if (typeof value !== "string" || value.length === 0) return { kind: "absent" };
54
+ if (!isSharedAuthority(value)) return { kind: "invalid", raw: value };
55
+ return { kind: "valid", authority: value };
56
+ }
57
+
39
58
  function withOptionalFields(
40
59
  authority: SharedAuthority,
41
60
  source: { sharedBy?: unknown; expiresAt?: unknown; supersedes?: unknown },
@@ -54,16 +73,16 @@ export function applyDefaultEnvelope(
54
73
  input: SharedEnvelopeInput = {},
55
74
  options: ApplyDefaultEnvelopeOptions = {},
56
75
  ): SharedEnvelope {
57
- const requested = optionalString(input.authority);
58
- if (requested !== undefined && !isSharedAuthority(requested)) {
76
+ const requested = readExactAuthority(input.authority);
77
+ if (requested.kind === "invalid") {
59
78
  throw new Error(
60
- `applyDefaultEnvelope: authority must be informational, advisory, or binding; got ${JSON.stringify(requested)}`,
79
+ `applyDefaultEnvelope: authority must be informational, advisory, or binding; got ${JSON.stringify(requested.raw)}`,
61
80
  );
62
81
  }
63
- if (requested === "binding" && options.binding !== true) {
82
+ if (requested.kind === "valid" && requested.authority === "binding" && options.binding !== true) {
64
83
  throw new Error("applyDefaultEnvelope: authority \"binding\" requires an explicit binding flag");
65
84
  }
66
- return withOptionalFields(requested ?? "informational", input);
85
+ return withOptionalFields(requested.kind === "valid" ? requested.authority : "informational", input);
67
86
  }
68
87
 
69
88
  export function parseSharedEnvelope(raw: unknown): SharedEnvelope {
@@ -71,8 +90,8 @@ export function parseSharedEnvelope(raw: unknown): SharedEnvelope {
71
90
  return { authority: "informational" };
72
91
  }
73
92
  const record = raw as Record<string, unknown>;
74
- const requested = optionalString(record.authority);
75
- const authority = requested !== undefined && isSharedAuthority(requested) ? requested : "informational";
93
+ const requested = readExactAuthority(record.authority);
94
+ const authority = requested.kind === "valid" ? requested.authority : "informational";
76
95
  return withOptionalFields(authority, record);
77
96
  }
78
97