@remnic/core 9.54.4 → 9.54.5

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 (526) hide show
  1. package/dist/access-admin-ops-surface.d.ts +12 -11
  2. package/dist/access-admin-ops-surface.js +46 -44
  3. package/dist/access-authorization-probe.d.ts +12 -11
  4. package/dist/access-authorization-probe.js +47 -45
  5. package/dist/access-boundary.d.ts +12 -11
  6. package/dist/access-boundary.js +46 -44
  7. package/dist/access-cli.js +92 -90
  8. package/dist/access-cli.js.map +1 -1
  9. package/dist/access-coding-context-resolution.d.ts +1 -1
  10. package/dist/access-extraction-force-flush.d.ts +12 -11
  11. package/dist/access-extraction-force-flush.js +46 -44
  12. package/dist/access-health-types.d.ts +1 -1
  13. package/dist/access-http-lcm-compaction.d.ts +12 -11
  14. package/dist/access-http-lifecycle-flush.d.ts +12 -11
  15. package/dist/access-http-offline-stream.d.ts +12 -11
  16. package/dist/access-http-query.js +46 -44
  17. package/dist/access-http.d.ts +12 -11
  18. package/dist/access-http.js +56 -54
  19. package/dist/access-identity-continuity-surface.d.ts +9 -9
  20. package/dist/access-identity-continuity-surface.js +46 -44
  21. package/dist/access-lcm-surface.d.ts +12 -11
  22. package/dist/access-lcm-surface.js +46 -44
  23. package/dist/access-mcp.d.ts +12 -11
  24. package/dist/access-mcp.js +52 -50
  25. package/dist/access-memory-search-fanout.d.ts +22 -2
  26. package/dist/access-memory-search-fanout.js +1 -1
  27. package/dist/{access-namespace-preflight-C7n4tgWC.d.ts → access-namespace-preflight-BdHlGd_T.d.ts} +1 -1
  28. package/dist/access-namespace-preflight.d.ts +3 -3
  29. package/dist/access-namespace-preflight.js +46 -44
  30. package/dist/access-observe-write-surface.d.ts +12 -11
  31. package/dist/access-observe-write-surface.js +46 -44
  32. package/dist/access-offline-manifest.d.ts +10 -9
  33. package/dist/access-offline-manifest.js +12 -10
  34. package/dist/access-operations-batch.js +48 -46
  35. package/dist/access-operations.d.ts +15 -14
  36. package/dist/access-operations.js +51 -49
  37. package/dist/access-recall-concurrency.d.ts +12 -11
  38. package/dist/access-recall-concurrency.js +46 -44
  39. package/dist/access-recall-response.d.ts +12 -11
  40. package/dist/access-recall-response.js +46 -44
  41. package/dist/access-recall-surface.d.ts +12 -11
  42. package/dist/access-recall-surface.js +46 -44
  43. package/dist/access-schema.d.ts +90 -90
  44. package/dist/access-schema.js +3 -2
  45. package/dist/{access-service-CXvbxLK-.d.ts → access-service-DL7X9hrg.d.ts} +7 -7
  46. package/dist/access-service-helpers.d.ts +12 -11
  47. package/dist/access-service.d.ts +12 -11
  48. package/dist/access-service.js +46 -44
  49. package/dist/access-surface-catalog.d.ts +12 -11
  50. package/dist/access-wearables-meetings-surface.d.ts +3 -3
  51. package/dist/action-confidence.d.ts +1 -1
  52. package/dist/active-memory-bridge.d.ts +13 -1
  53. package/dist/active-memory-bridge.js +6 -1
  54. package/dist/active-recall.d.ts +1 -1
  55. package/dist/active-recall.js +3 -2
  56. package/dist/active-recall.js.map +1 -1
  57. package/dist/adapters/index.js +4 -4
  58. package/dist/adapters/registry.js +2 -2
  59. package/dist/ambient-provenance.d.ts +1 -1
  60. package/dist/artifact-search.d.ts +1 -1
  61. package/dist/behavior-learner.d.ts +1 -1
  62. package/dist/behavior-signals.d.ts +1 -1
  63. package/dist/bootstrap.d.ts +9 -9
  64. package/dist/briefing.d.ts +2 -2
  65. package/dist/briefing.js +30 -9
  66. package/dist/buffer-surprise-report.d.ts +1 -1
  67. package/dist/buffer-turn-helpers.d.ts +1 -1
  68. package/dist/buffer.d.ts +2 -2
  69. package/dist/buffer.js +3 -3
  70. package/dist/bulk-import/index.d.ts +3 -3
  71. package/dist/calibration.d.ts +1 -1
  72. package/dist/capabilities.d.ts +1 -1
  73. package/dist/{catalog-BOOxl-I2.d.ts → catalog-B90is4d8.d.ts} +1 -1
  74. package/dist/causal-behavior.d.ts +1 -1
  75. package/dist/causal-consolidation.d.ts +1 -1
  76. package/dist/causal-consolidation.js +31 -10
  77. package/dist/causal-consolidation.js.map +1 -1
  78. package/dist/causal-trajectory-graph.d.ts +1 -1
  79. package/dist/{chunk-6LAPLZOS.js → chunk-2DD6ZHOM.js} +8 -3
  80. package/dist/chunk-2DD6ZHOM.js.map +1 -0
  81. package/dist/{chunk-47P3RYZP.js → chunk-2INWPC6E.js} +2 -2
  82. package/dist/{chunk-3CSX3ETE.js → chunk-2LWQSV6A.js} +23 -11
  83. package/dist/chunk-2LWQSV6A.js.map +1 -0
  84. package/dist/{chunk-7BZOBA5J.js → chunk-2PNXOQ4P.js} +69 -11
  85. package/dist/chunk-2PNXOQ4P.js.map +1 -0
  86. package/dist/{chunk-WOPA3SGI.js → chunk-3OTSVCPK.js} +8 -8
  87. package/dist/{chunk-PX2LSHYM.js → chunk-3SXLD5T3.js} +3 -3
  88. package/dist/{chunk-T2JHZWH6.js → chunk-3WGI7F4V.js} +237 -93
  89. package/dist/chunk-3WGI7F4V.js.map +1 -0
  90. package/dist/{chunk-C4ZNGVK3.js → chunk-5JKUSBMX.js} +2 -2
  91. package/dist/{chunk-S75M5ZRK.js → chunk-6LEIWWAF.js} +16 -1
  92. package/dist/chunk-6LEIWWAF.js.map +1 -0
  93. package/dist/{chunk-MAXVH44E.js → chunk-6NNNURLK.js} +4 -4
  94. package/dist/{chunk-LJS7KUPV.js → chunk-6PZGKGAO.js} +2 -2
  95. package/dist/{chunk-YN6ASZUG.js → chunk-6QPI2ITJ.js} +5 -5
  96. package/dist/{chunk-CYF6WVE7.js → chunk-7HG7MGAP.js} +2688 -496
  97. package/dist/chunk-7HG7MGAP.js.map +1 -0
  98. package/dist/{chunk-CGVHPCP2.js → chunk-7Q7JWLQ4.js} +2 -2
  99. package/dist/{chunk-227UFSEQ.js → chunk-7RZJWZ46.js} +5 -5
  100. package/dist/{chunk-JBPKEARU.js → chunk-AU7Q3LSC.js} +4 -4
  101. package/dist/{chunk-PDDTI7IC.js → chunk-B4T3FQMT.js} +1 -1
  102. package/dist/{chunk-UU3G6GUP.js → chunk-BIF4SHMD.js} +1 -1
  103. package/dist/{chunk-UU3G6GUP.js.map → chunk-BIF4SHMD.js.map} +1 -1
  104. package/dist/{chunk-APPFNGX6.js → chunk-BSXGTDVJ.js} +2 -2
  105. package/dist/{chunk-4IIFL7GC.js → chunk-CLKBV3Z3.js} +10 -10
  106. package/dist/{chunk-ZYLC7NFO.js → chunk-CSY44OKU.js} +4 -4
  107. package/dist/{chunk-HLYR2TQL.js → chunk-CUTFSLSD.js} +2 -2
  108. package/dist/{chunk-RDJRFDJY.js → chunk-DBY26JJJ.js} +2 -2
  109. package/dist/{chunk-QWGE2PUH.js → chunk-DDA55IVB.js} +10 -10
  110. package/dist/{chunk-VMMQDEN5.js → chunk-DN2IDKI5.js} +2 -2
  111. package/dist/{chunk-2GFK22OZ.js → chunk-DOOWFDWN.js} +2 -2
  112. package/dist/{chunk-7FGL6CGA.js → chunk-DVYRD4HY.js} +2 -2
  113. package/dist/{chunk-YGLY6QFV.js → chunk-F2Y6I74C.js} +2 -2
  114. package/dist/{chunk-UU7TRFNE.js → chunk-FFEBSFVT.js} +2 -2
  115. package/dist/chunk-HNDIND7P.js +331 -0
  116. package/dist/chunk-HNDIND7P.js.map +1 -0
  117. package/dist/{chunk-NIS256NW.js → chunk-JKW663ZN.js} +2 -2
  118. package/dist/{chunk-G7A5HLUS.js → chunk-KJH6W2I7.js} +2 -2
  119. package/dist/{chunk-IXEBUYO4.js → chunk-KM55SMLG.js} +11 -2
  120. package/dist/{chunk-IXEBUYO4.js.map → chunk-KM55SMLG.js.map} +1 -1
  121. package/dist/{chunk-G2LUMAUF.js → chunk-L7RTUEDG.js} +12 -5
  122. package/dist/chunk-L7RTUEDG.js.map +1 -0
  123. package/dist/chunk-LC2BDILZ.js +57 -0
  124. package/dist/chunk-LC2BDILZ.js.map +1 -0
  125. package/dist/{chunk-JV5YUBIZ.js → chunk-LC3FD4BV.js} +52 -46
  126. package/dist/chunk-LC3FD4BV.js.map +1 -0
  127. package/dist/{chunk-HWRD23DW.js → chunk-LVKYLMSM.js} +3 -3
  128. package/dist/{chunk-RUMNY5DT.js → chunk-MRGJZ75M.js} +6 -2
  129. package/dist/chunk-MRGJZ75M.js.map +1 -0
  130. package/dist/{chunk-ZMYDYNI4.js → chunk-N7CXQ5TA.js} +4 -4
  131. package/dist/{chunk-3JLPGJ43.js → chunk-NGT35IGQ.js} +5 -5
  132. package/dist/{chunk-GUKBW4HL.js → chunk-NQMSEB5D.js} +6 -6
  133. package/dist/{chunk-WRJVB3C2.js → chunk-PO7NXBG2.js} +2 -2
  134. package/dist/{chunk-WM65LU67.js → chunk-QOQQMVR2.js} +2 -2
  135. package/dist/{chunk-QHFV6VNU.js → chunk-QPAQSG3F.js} +2 -2
  136. package/dist/{chunk-UTRO5UJU.js → chunk-QPW3PAIH.js} +5 -1
  137. package/dist/chunk-QPW3PAIH.js.map +1 -0
  138. package/dist/{chunk-6R4G7N4S.js → chunk-QQXWFDRD.js} +128 -74
  139. package/dist/chunk-QQXWFDRD.js.map +1 -0
  140. package/dist/{chunk-UES4BHA2.js → chunk-QTO6BMQZ.js} +2 -2
  141. package/dist/{chunk-THPPCISA.js → chunk-RBII7637.js} +5 -5
  142. package/dist/{chunk-QT2FRYI4.js → chunk-RG426DJO.js} +2 -2
  143. package/dist/{chunk-XUAMCLY4.js → chunk-TKFGFDPJ.js} +17 -13
  144. package/dist/chunk-TKFGFDPJ.js.map +1 -0
  145. package/dist/{chunk-VKXWK44Q.js → chunk-TY6MKIWP.js} +3 -3
  146. package/dist/{chunk-AZM4CCAC.js → chunk-UWJNKGBA.js} +5 -5
  147. package/dist/{chunk-JDZPNCMA.js → chunk-UYOXFFEY.js} +6 -3
  148. package/dist/chunk-UYOXFFEY.js.map +1 -0
  149. package/dist/{chunk-ZPJ4QSGP.js → chunk-VTU5IEKY.js} +2 -2
  150. package/dist/{chunk-RZ4XGKOJ.js → chunk-VYQ4URQB.js} +8 -8
  151. package/dist/{chunk-WDBX6VER.js → chunk-VZRFGJCH.js} +5 -5
  152. package/dist/{chunk-IBKR2TFR.js → chunk-WM5LD6AT.js} +2 -2
  153. package/dist/{chunk-K4QS7LXU.js → chunk-WZWZRZ2V.js} +2 -2
  154. package/dist/{chunk-G4T7L557.js → chunk-XKAR4RF6.js} +2 -2
  155. package/dist/{chunk-DZD576ZU.js → chunk-XSV2YDCJ.js} +2 -2
  156. package/dist/{chunk-G7Z6EENO.js → chunk-YDWPYDML.js} +4 -4
  157. package/dist/{chunk-6HPHEFXT.js → chunk-YKZLOPTC.js} +2 -2
  158. package/dist/{chunk-NH5IR2WM.js → chunk-YR65W7BV.js} +6 -2
  159. package/dist/chunk-YR65W7BV.js.map +1 -0
  160. package/dist/{chunk-GYPQL6XN.js → chunk-Z4N7SVVF.js} +35 -47
  161. package/dist/chunk-Z4N7SVVF.js.map +1 -0
  162. package/dist/{cli-DVUFIa5E.d.ts → cli-jfuZXixq.d.ts} +5 -5
  163. package/dist/cli.d.ts +14 -13
  164. package/dist/cli.js +74 -72
  165. package/dist/coding/pre-action-gate.d.ts +1 -1
  166. package/dist/compounding/engine.d.ts +2 -2
  167. package/dist/compounding/engine.js +30 -9
  168. package/dist/compounding/preference-consolidator.d.ts +1 -1
  169. package/dist/compression-optimizer.d.ts +1 -1
  170. package/dist/config.d.ts +1 -1
  171. package/dist/config.js +3 -2
  172. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  173. package/dist/connectors/codex-materialize-runner.js +30 -9
  174. package/dist/connectors/codex-materialize.d.ts +1 -1
  175. package/dist/connectors/index.d.ts +1 -1
  176. package/dist/connectors/index.js +29 -9
  177. package/dist/consolidation-provenance-check.d.ts +2 -2
  178. package/dist/consolidation-undo.d.ts +2 -2
  179. package/dist/contradiction/index.d.ts +2 -2
  180. package/dist/contradiction/index.js +3 -1
  181. package/dist/contradiction-scan-KCADHXPE.js +20 -0
  182. package/dist/converge-config.d.ts +1 -1
  183. package/dist/convergence-refresh.d.ts +2 -2
  184. package/dist/convergence-refresh.js +32 -11
  185. package/dist/conversation-index/backend.d.ts +1 -1
  186. package/dist/conversation-index/backend.js +2 -2
  187. package/dist/conversation-index/chunker.d.ts +1 -1
  188. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  189. package/dist/conversation-index/indexer.d.ts +1 -1
  190. package/dist/conversation-index/search.d.ts +1 -1
  191. package/dist/corpus-watermark.d.ts +1 -1
  192. package/dist/corpus-watermark.js +21 -20
  193. package/dist/day-summary.d.ts +1 -1
  194. package/dist/delinearize.d.ts +1 -1
  195. package/dist/dependency-propagation-config.d.ts +1 -1
  196. package/dist/{dependency-propagation-delivery-XzF76C9n.d.ts → dependency-propagation-delivery-CTDuAVJc.d.ts} +1 -1
  197. package/dist/direct-answer-wiring.d.ts +1 -1
  198. package/dist/direct-answer.d.ts +1 -1
  199. package/dist/embedding-fallback.d.ts +1 -1
  200. package/dist/enrichment/index.d.ts +1 -1
  201. package/dist/entity-retrieval.d.ts +2 -2
  202. package/dist/entity-retrieval.js +30 -9
  203. package/dist/entity-schema.d.ts +1 -1
  204. package/dist/explicit-capture.d.ts +9 -9
  205. package/dist/explicit-capture.js +6 -4
  206. package/dist/external-wiki-access.d.ts +12 -11
  207. package/dist/external-wiki-access.js +47 -45
  208. package/dist/external-wiki-collection-registration.d.ts +1 -1
  209. package/dist/external-wiki-collection.d.ts +1 -1
  210. package/dist/external-wiki-mcp-tools.d.ts +12 -11
  211. package/dist/extraction-error-classification.d.ts +1 -1
  212. package/dist/extraction-faithfulness.d.ts +1 -1
  213. package/dist/extraction-judge-telemetry.d.ts +1 -1
  214. package/dist/extraction-judge-training.d.ts +1 -1
  215. package/dist/extraction-judge.d.ts +1 -1
  216. package/dist/extraction-liveness.d.ts +1 -1
  217. package/dist/extraction-normalization.d.ts +1 -1
  218. package/dist/extraction-prompt.d.ts +1 -1
  219. package/dist/extraction-source-grounding-rules.d.ts +1 -1
  220. package/dist/extraction-source-grounding.d.ts +1 -1
  221. package/dist/extraction.d.ts +1 -1
  222. package/dist/extraction.js +29 -13
  223. package/dist/fallback-llm.d.ts +1 -1
  224. package/dist/{first-start-migration-626C5554.js → first-start-migration-LMMZFLKK.js} +13 -5
  225. package/dist/first-start-migration-LMMZFLKK.js.map +1 -0
  226. package/dist/graph-dashboard-diff.d.ts +1 -1
  227. package/dist/graph-dashboard-key.d.ts +1 -1
  228. package/dist/graph-dashboard-parser.d.ts +1 -1
  229. package/dist/graph-edge-reinforcement.d.ts +1 -1
  230. package/dist/graph-path-reconstruction.d.ts +1 -1
  231. package/dist/graph-path-scoring.d.ts +1 -1
  232. package/dist/graph-snapshot.d.ts +1 -1
  233. package/dist/graph.d.ts +1 -1
  234. package/dist/harmonic-retrieval.js +1 -1
  235. package/dist/importance.d.ts +1 -1
  236. package/dist/importers/index.d.ts +1 -1
  237. package/dist/in-flight-reads.d.ts +1 -1
  238. package/dist/index.d.ts +1439 -716
  239. package/dist/index.js +207 -121
  240. package/dist/intent.d.ts +1 -1
  241. package/dist/lcm/engine.d.ts +1 -1
  242. package/dist/lcm/engine.js +2 -2
  243. package/dist/lcm/index.d.ts +1 -1
  244. package/dist/lcm/index.js +5 -5
  245. package/dist/lcm/tools.d.ts +1 -1
  246. package/dist/lifecycle.d.ts +1 -1
  247. package/dist/live-connectors-runner.d.ts +1 -1
  248. package/dist/local-llm.d.ts +1 -1
  249. package/dist/local-model-endpoint.d.ts +1 -1
  250. package/dist/maintenance/memory-governance.d.ts +1 -1
  251. package/dist/maintenance/memory-governance.js +30 -9
  252. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
  253. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +30 -9
  254. package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
  255. package/dist/maintenance/rebuild-memory-projection.js +31 -10
  256. package/dist/{maintenance-BJzNIKBE.d.ts → maintenance-heMZSq7G.d.ts} +3 -3
  257. package/dist/mcp-memory-inspector-app.d.ts +12 -11
  258. package/dist/memory-action-policy.d.ts +1 -1
  259. package/dist/memory-cache.d.ts +1 -1
  260. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  261. package/dist/memory-projection-mutations.js +2 -2
  262. package/dist/memory-projection-store.d.ts +6 -2
  263. package/dist/memory-projection-store.js +1 -1
  264. package/dist/memory-provenance.d.ts +1 -1
  265. package/dist/memory-snapshot.d.ts +1 -1
  266. package/dist/memory-worth-outcomes.d.ts +2 -2
  267. package/dist/models-json.d.ts +1 -1
  268. package/dist/namespaces/migrate.d.ts +3 -3
  269. package/dist/namespaces/migrate.js +20 -19
  270. package/dist/namespaces/principal.d.ts +1 -1
  271. package/dist/namespaces/search.d.ts +1 -1
  272. package/dist/namespaces/search.js +6 -6
  273. package/dist/namespaces/storage.d.ts +3 -3
  274. package/dist/namespaces/storage.js +30 -9
  275. package/dist/native-knowledge.d.ts +1 -1
  276. package/dist/offline-sync-file-io.d.ts +20 -0
  277. package/dist/offline-sync-file-io.js +18 -0
  278. package/dist/offline-sync-file-io.js.map +1 -0
  279. package/dist/offline-sync-impression-drain.d.ts +1 -1
  280. package/dist/offline-sync-impression-drain.js +5 -5
  281. package/dist/offline-sync.d.ts +8 -6
  282. package/dist/offline-sync.js +2 -1
  283. package/dist/operator-doctor-corpus.d.ts +1 -1
  284. package/dist/operator-doctor-corpus.js +22 -21
  285. package/dist/operator-doctor-replica.d.ts +1 -1
  286. package/dist/operator-toolkit.d.ts +3 -3
  287. package/dist/operator-toolkit.js +34 -32
  288. package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
  289. package/dist/orchestration/maintenance.d.ts +4 -4
  290. package/dist/orchestration/maintenance.js +35 -15
  291. package/dist/{orchestrator-BiXgBJBQ.d.ts → orchestrator-BQQPsSjs.d.ts} +11 -8
  292. package/dist/orchestrator.d.ts +9 -9
  293. package/dist/orchestrator.js +93 -91
  294. package/dist/patterns-cli.d.ts +1 -1
  295. package/dist/{pipeline-sz_dcuLg.d.ts → pipeline-DFfmsnGk.d.ts} +1 -1
  296. package/dist/policy-runtime.d.ts +1 -1
  297. package/dist/proactive-contention.d.ts +1 -1
  298. package/dist/provenance.d.ts +1 -1
  299. package/dist/{purge-533FZLS4.js → purge-GB7PZHT2.js} +2 -2
  300. package/dist/{qmd-eAWObK4M.d.ts → qmd-BF5bcVRs.d.ts} +1 -1
  301. package/dist/qmd-preflight.d.ts +2 -2
  302. package/dist/qmd-recall-cache.d.ts +1 -1
  303. package/dist/qmd.d.ts +2 -2
  304. package/dist/recall-concurrency-config.d.ts +1 -1
  305. package/dist/recall-disclosure-escalation.d.ts +1 -1
  306. package/dist/recall-explain-renderer.d.ts +1 -1
  307. package/dist/recall-explain-renderer.js +3 -3
  308. package/dist/recall-memory-map.d.ts +1 -1
  309. package/dist/recall-planner-llm.d.ts +1 -1
  310. package/dist/recall-state.d.ts +1 -1
  311. package/dist/recall-tag-filter.d.ts +1 -1
  312. package/dist/recall-timings.d.ts +1 -1
  313. package/dist/recall-xray-cli.d.ts +1 -1
  314. package/dist/recall-xray-cli.js +4 -4
  315. package/dist/recall-xray-renderer.d.ts +1 -1
  316. package/dist/recall-xray-renderer.js +3 -3
  317. package/dist/recall-xray.d.ts +1 -1
  318. package/dist/recall-xray.js +2 -2
  319. package/dist/reconcile/cursor.d.ts +2 -1
  320. package/dist/reconcile/manifest.d.ts +2 -1
  321. package/dist/reconcile/manifest.js +6 -5
  322. package/dist/reconcile/plan.d.ts +2 -1
  323. package/dist/reconcile/plan.js +3 -2
  324. package/dist/replay/normalizers/chatgpt.d.ts +1 -1
  325. package/dist/replay/normalizers/claude.d.ts +1 -1
  326. package/dist/replay/normalizers/openclaw.d.ts +1 -1
  327. package/dist/replay/normalizers/shared.d.ts +1 -1
  328. package/dist/replay/runner.d.ts +1 -1
  329. package/dist/replay/types.d.ts +1 -1
  330. package/dist/replica-divergence.d.ts +1 -1
  331. package/dist/replica-peers-config.d.ts +1 -1
  332. package/dist/resolve-auth-token.d.ts +1 -1
  333. package/dist/resume-bundles.js +4 -3
  334. package/dist/retrieval-agents.d.ts +2 -2
  335. package/dist/retrieval-tiers.d.ts +1 -1
  336. package/dist/routing/engine.d.ts +1 -1
  337. package/dist/routing/store.d.ts +1 -1
  338. package/dist/salvage-envelope.d.ts +1 -1
  339. package/dist/schemas.d.ts +138 -138
  340. package/dist/{scope-profiles-BBQsXuyj.d.ts → scope-profiles-CbUOsE_E.d.ts} +1 -1
  341. package/dist/search/embed-helper.d.ts +1 -1
  342. package/dist/search/factory.d.ts +1 -1
  343. package/dist/search/factory.js +4 -4
  344. package/dist/search/index.d.ts +1 -1
  345. package/dist/search/index.js +6 -6
  346. package/dist/search/lancedb-backend.d.ts +1 -1
  347. package/dist/search/meilisearch-backend.d.ts +1 -1
  348. package/dist/search/noop-backend.d.ts +1 -1
  349. package/dist/search/orama-backend.d.ts +1 -1
  350. package/dist/search/port.d.ts +1 -1
  351. package/dist/search/remote-backend.d.ts +1 -1
  352. package/dist/{semantic-consolidation-HD8RkzVA.d.ts → semantic-consolidation-DAB3xdKM.d.ts} +1 -1
  353. package/dist/semantic-consolidation.d.ts +2 -2
  354. package/dist/semantic-consolidation.js +31 -10
  355. package/dist/semantic-rule-promotion.js +30 -9
  356. package/dist/semantic-rule-verifier.d.ts +1 -1
  357. package/dist/semantic-rule-verifier.js +30 -9
  358. package/dist/{service-DIrtHHEg.d.ts → service-DGKg2O6r.d.ts} +2 -2
  359. package/dist/session-observer-bands.d.ts +1 -1
  360. package/dist/session-observer-state.d.ts +1 -1
  361. package/dist/shared-context/manager.d.ts +9 -9
  362. package/dist/signal.d.ts +1 -1
  363. package/dist/source-agent-qualifier.d.ts +1 -1
  364. package/dist/source-agent-qualifier.js +28 -12
  365. package/dist/{storage-DqCzXi56.d.ts → storage-CC1jKcWg.d.ts} +46 -13
  366. package/dist/storage.d.ts +2 -2
  367. package/dist/storage.js +30 -9
  368. package/dist/summarizer.d.ts +1 -1
  369. package/dist/summary-snapshot.d.ts +1 -1
  370. package/dist/temporal-supersession.d.ts +2 -2
  371. package/dist/temporal-timeline-recall.d.ts +1 -1
  372. package/dist/temporal-validity.d.ts +1 -1
  373. package/dist/threading.d.ts +1 -1
  374. package/dist/tier-migration.d.ts +2 -2
  375. package/dist/tier-routing.d.ts +2 -2
  376. package/dist/tier-routing.js +7 -1
  377. package/dist/{tier-stats-2JCZYEF7.js → tier-stats-JDN6HRNT.js} +8 -2
  378. package/dist/{tier-stats-2JCZYEF7.js.map → tier-stats-JDN6HRNT.js.map} +1 -1
  379. package/dist/topics.d.ts +1 -1
  380. package/dist/transcript.d.ts +1 -1
  381. package/dist/transfer/types.d.ts +66 -66
  382. package/dist/trust-score-stage.d.ts +1 -1
  383. package/dist/trust-score.d.ts +1 -1
  384. package/dist/{types-d_j4vC6N.d.ts → types-BnQza1y8.d.ts} +2 -1
  385. package/dist/types.d.ts +1 -1
  386. package/dist/types.js +1 -1
  387. package/dist/utility-runtime.d.ts +2 -2
  388. package/dist/verified-recall.js +30 -9
  389. package/dist/write-envelope.d.ts +1 -1
  390. package/package.json +2 -2
  391. package/src/access-http.test.ts +31 -0
  392. package/src/access-memory-search-fanout.ts +24 -1
  393. package/src/access-offline-manifest.ts +5 -0
  394. package/src/access-service-namespace.test.ts +14 -0
  395. package/src/access-service-observe-scope.test.ts +2 -0
  396. package/src/access-service-offline-file-content.test.ts +211 -0
  397. package/src/access-service.ts +20 -43
  398. package/src/active-memory-bridge.test.ts +151 -0
  399. package/src/active-memory-bridge.ts +87 -11
  400. package/src/briefing.test.ts +38 -0
  401. package/src/briefing.ts +3 -3
  402. package/src/cli.ts +6 -1
  403. package/src/connectors/codex-materialize-runner.ts +2 -0
  404. package/src/contradiction/contradiction-scan.ts +2 -0
  405. package/src/contradiction/contradiction.test.ts +42 -0
  406. package/src/correction/correction-access-wiring.ts +8 -2
  407. package/src/correction/correction-storage-integration.test.ts +7 -0
  408. package/src/explicit-capture.test.ts +24 -0
  409. package/src/explicit-capture.ts +2 -0
  410. package/src/index.ts +3 -0
  411. package/src/maintenance/first-start-migration.ts +2 -1
  412. package/src/maintenance/memory-governance.test.ts +25 -0
  413. package/src/maintenance/memory-governance.ts +4 -1
  414. package/src/maintenance/pattern-reinforcement.test.ts +20 -0
  415. package/src/maintenance/pattern-reinforcement.ts +2 -1
  416. package/src/maintenance/rebuild-memory-projection.ts +8 -8
  417. package/src/memory-projection-store.ts +25 -27
  418. package/src/offline-sync-file-io.ts +68 -0
  419. package/src/offline-sync.ts +43 -57
  420. package/src/orchestration/consolidation-run.ts +5 -4
  421. package/src/orchestration/contradiction-linking-coordinator.ts +7 -0
  422. package/src/orchestration/contradiction-localization.integration.test.ts +115 -0
  423. package/src/orchestration/lifecycle-policy-coordinator.ts +2 -1
  424. package/src/orchestration/qmd-result-resolver.test.ts +215 -14
  425. package/src/orchestration/qmd-result-resolver.ts +142 -82
  426. package/src/orchestration/recall-search-pipeline.test.ts +41 -0
  427. package/src/orchestration/recall-search-pipeline.ts +12 -0
  428. package/src/orchestration/semantic-consolidation-coordinator.ts +2 -1
  429. package/src/orchestration/tier-migration-coordinator.ts +23 -56
  430. package/src/orchestration/workspace-ops.test.ts +37 -0
  431. package/src/orchestration/workspace-ops.ts +5 -29
  432. package/src/orchestrator.ts +7 -8
  433. package/src/storage/supersession-audit.ts +7 -1
  434. package/src/storage/supersession-side-effects.ts +17 -5
  435. package/src/storage.ts +18 -19
  436. package/src/support-passport/card-projection.test.ts +129 -0
  437. package/src/support-passport/card-projection.ts +287 -0
  438. package/src/support-passport/card-service.test.ts +2462 -0
  439. package/src/support-passport/card-service.ts +1042 -0
  440. package/src/support-passport/contracts.test.ts +143 -0
  441. package/src/support-passport/contracts.ts +136 -0
  442. package/src/support-passport/errors.ts +24 -0
  443. package/src/support-passport/grant-contracts.ts +139 -0
  444. package/src/support-passport/grant-service-cache.test.ts +148 -0
  445. package/src/support-passport/grant-service-cancellation.test.ts +81 -0
  446. package/src/support-passport/grant-service.test.ts +2882 -0
  447. package/src/support-passport/grant-service.ts +364 -0
  448. package/src/support-passport/grant-store-commit-hook.test.ts +123 -0
  449. package/src/support-passport/grant-store-order.test.ts +60 -0
  450. package/src/support-passport/grant-store-path-safety.test.ts +30 -0
  451. package/src/support-passport/grant-store-recovery.test.ts +448 -0
  452. package/src/support-passport/grant-store.ts +902 -0
  453. package/src/support-passport/index.ts +7 -0
  454. package/src/support-passport/offline-sync-guard.ts +230 -0
  455. package/src/support-passport/owner-lock.ts +53 -0
  456. package/src/support-passport/private-file.ts +371 -0
  457. package/src/tier-routing.ts +28 -17
  458. package/src/training-export/converter.test.ts +24 -0
  459. package/src/training-export/converter.ts +2 -0
  460. package/src/types.ts +1 -1
  461. package/src/wearables/service.test.ts +13 -0
  462. package/src/wearables/service.ts +2 -0
  463. package/dist/chunk-3CSX3ETE.js.map +0 -1
  464. package/dist/chunk-6LAPLZOS.js.map +0 -1
  465. package/dist/chunk-6R4G7N4S.js.map +0 -1
  466. package/dist/chunk-7BZOBA5J.js.map +0 -1
  467. package/dist/chunk-CYF6WVE7.js.map +0 -1
  468. package/dist/chunk-G2LUMAUF.js.map +0 -1
  469. package/dist/chunk-GYPQL6XN.js.map +0 -1
  470. package/dist/chunk-JDZPNCMA.js.map +0 -1
  471. package/dist/chunk-JV5YUBIZ.js.map +0 -1
  472. package/dist/chunk-NH5IR2WM.js.map +0 -1
  473. package/dist/chunk-RUMNY5DT.js.map +0 -1
  474. package/dist/chunk-S75M5ZRK.js.map +0 -1
  475. package/dist/chunk-T2JHZWH6.js.map +0 -1
  476. package/dist/chunk-UTRO5UJU.js.map +0 -1
  477. package/dist/chunk-XUAMCLY4.js.map +0 -1
  478. package/dist/contradiction-scan-HYLIRMJ2.js +0 -14
  479. package/dist/first-start-migration-626C5554.js.map +0 -1
  480. /package/dist/{chunk-47P3RYZP.js.map → chunk-2INWPC6E.js.map} +0 -0
  481. /package/dist/{chunk-WOPA3SGI.js.map → chunk-3OTSVCPK.js.map} +0 -0
  482. /package/dist/{chunk-PX2LSHYM.js.map → chunk-3SXLD5T3.js.map} +0 -0
  483. /package/dist/{chunk-C4ZNGVK3.js.map → chunk-5JKUSBMX.js.map} +0 -0
  484. /package/dist/{chunk-MAXVH44E.js.map → chunk-6NNNURLK.js.map} +0 -0
  485. /package/dist/{chunk-LJS7KUPV.js.map → chunk-6PZGKGAO.js.map} +0 -0
  486. /package/dist/{chunk-YN6ASZUG.js.map → chunk-6QPI2ITJ.js.map} +0 -0
  487. /package/dist/{chunk-CGVHPCP2.js.map → chunk-7Q7JWLQ4.js.map} +0 -0
  488. /package/dist/{chunk-227UFSEQ.js.map → chunk-7RZJWZ46.js.map} +0 -0
  489. /package/dist/{chunk-JBPKEARU.js.map → chunk-AU7Q3LSC.js.map} +0 -0
  490. /package/dist/{chunk-PDDTI7IC.js.map → chunk-B4T3FQMT.js.map} +0 -0
  491. /package/dist/{chunk-APPFNGX6.js.map → chunk-BSXGTDVJ.js.map} +0 -0
  492. /package/dist/{chunk-4IIFL7GC.js.map → chunk-CLKBV3Z3.js.map} +0 -0
  493. /package/dist/{chunk-ZYLC7NFO.js.map → chunk-CSY44OKU.js.map} +0 -0
  494. /package/dist/{chunk-HLYR2TQL.js.map → chunk-CUTFSLSD.js.map} +0 -0
  495. /package/dist/{chunk-RDJRFDJY.js.map → chunk-DBY26JJJ.js.map} +0 -0
  496. /package/dist/{chunk-QWGE2PUH.js.map → chunk-DDA55IVB.js.map} +0 -0
  497. /package/dist/{chunk-VMMQDEN5.js.map → chunk-DN2IDKI5.js.map} +0 -0
  498. /package/dist/{chunk-2GFK22OZ.js.map → chunk-DOOWFDWN.js.map} +0 -0
  499. /package/dist/{chunk-7FGL6CGA.js.map → chunk-DVYRD4HY.js.map} +0 -0
  500. /package/dist/{chunk-YGLY6QFV.js.map → chunk-F2Y6I74C.js.map} +0 -0
  501. /package/dist/{chunk-UU7TRFNE.js.map → chunk-FFEBSFVT.js.map} +0 -0
  502. /package/dist/{chunk-NIS256NW.js.map → chunk-JKW663ZN.js.map} +0 -0
  503. /package/dist/{chunk-G7A5HLUS.js.map → chunk-KJH6W2I7.js.map} +0 -0
  504. /package/dist/{chunk-HWRD23DW.js.map → chunk-LVKYLMSM.js.map} +0 -0
  505. /package/dist/{chunk-ZMYDYNI4.js.map → chunk-N7CXQ5TA.js.map} +0 -0
  506. /package/dist/{chunk-3JLPGJ43.js.map → chunk-NGT35IGQ.js.map} +0 -0
  507. /package/dist/{chunk-GUKBW4HL.js.map → chunk-NQMSEB5D.js.map} +0 -0
  508. /package/dist/{chunk-WRJVB3C2.js.map → chunk-PO7NXBG2.js.map} +0 -0
  509. /package/dist/{chunk-WM65LU67.js.map → chunk-QOQQMVR2.js.map} +0 -0
  510. /package/dist/{chunk-QHFV6VNU.js.map → chunk-QPAQSG3F.js.map} +0 -0
  511. /package/dist/{chunk-UES4BHA2.js.map → chunk-QTO6BMQZ.js.map} +0 -0
  512. /package/dist/{chunk-THPPCISA.js.map → chunk-RBII7637.js.map} +0 -0
  513. /package/dist/{chunk-QT2FRYI4.js.map → chunk-RG426DJO.js.map} +0 -0
  514. /package/dist/{chunk-VKXWK44Q.js.map → chunk-TY6MKIWP.js.map} +0 -0
  515. /package/dist/{chunk-AZM4CCAC.js.map → chunk-UWJNKGBA.js.map} +0 -0
  516. /package/dist/{chunk-ZPJ4QSGP.js.map → chunk-VTU5IEKY.js.map} +0 -0
  517. /package/dist/{chunk-RZ4XGKOJ.js.map → chunk-VYQ4URQB.js.map} +0 -0
  518. /package/dist/{chunk-WDBX6VER.js.map → chunk-VZRFGJCH.js.map} +0 -0
  519. /package/dist/{chunk-IBKR2TFR.js.map → chunk-WM5LD6AT.js.map} +0 -0
  520. /package/dist/{chunk-K4QS7LXU.js.map → chunk-WZWZRZ2V.js.map} +0 -0
  521. /package/dist/{chunk-G4T7L557.js.map → chunk-XKAR4RF6.js.map} +0 -0
  522. /package/dist/{chunk-DZD576ZU.js.map → chunk-XSV2YDCJ.js.map} +0 -0
  523. /package/dist/{chunk-G7Z6EENO.js.map → chunk-YDWPYDML.js.map} +0 -0
  524. /package/dist/{chunk-6HPHEFXT.js.map → chunk-YKZLOPTC.js.map} +0 -0
  525. /package/dist/{contradiction-scan-HYLIRMJ2.js.map → contradiction-scan-KCADHXPE.js.map} +0 -0
  526. /package/dist/{purge-533FZLS4.js.map → purge-GB7PZHT2.js.map} +0 -0
@@ -0,0 +1,1042 @@
1
+ import type { StorageManager } from "../index.js";
2
+ import { log } from "../logger.js";
3
+ import { stripAttributesSuffix } from "../structured-attributes.js";
4
+ import type { MemoryFile } from "../types.js";
5
+ import type { HeldFileLockController } from "../utils/serialize-mutations.js";
6
+ import { composeMemoryEnvelope } from "../write-envelope.js";
7
+ import {
8
+ SUPPORT_PASSPORT_ATTRIBUTE_KEYS,
9
+ SUPPORT_PASSPORT_CARD_TAG,
10
+ type StoredSupportPassportCard,
11
+ computeSupportPassportOwnerKey,
12
+ decodeSupportPassportNamespaceAttributes,
13
+ encodeSupportPassportNamespaceAttributes,
14
+ projectSupportPassportCard,
15
+ } from "./card-projection.js";
16
+ import {
17
+ type SupportPassportCard,
18
+ type SupportPassportCardCategory,
19
+ SupportPassportCardListSchema,
20
+ type SupportPassportCardMutationInput,
21
+ SupportPassportCardMutationInputSchema,
22
+ SupportPassportListCardsInputSchema,
23
+ type SupportPassportManualDraftInput,
24
+ SupportPassportManualDraftInputSchema,
25
+ SupportPassportNamespaceSchema,
26
+ type SupportPassportReplaceCardInput,
27
+ SupportPassportReplaceCardInputSchema,
28
+ computeSupportPassportCardRevision,
29
+ } from "./contracts.js";
30
+ import { SupportPassportError } from "./errors.js";
31
+ import { withSupportPassportOwnerLock } from "./owner-lock.js";
32
+
33
+ export interface SupportPassportOwnerScope {
34
+ principal: string;
35
+ namespace: string;
36
+ storage: StorageManager;
37
+ }
38
+
39
+ export interface SupportPassportCardServiceDependencies {
40
+ resolveOwner(principal: string): Promise<SupportPassportOwnerScope>;
41
+ now?: () => Date;
42
+ }
43
+
44
+ const OWNER_VISIBLE_STATUSES = new Set(["pending_review", "active"]);
45
+ const MAX_OWNER_VISIBLE_CARDS = 100;
46
+
47
+ function invalidInput(): SupportPassportError {
48
+ return new SupportPassportError("invalid_input", "The support card request is invalid.", 400);
49
+ }
50
+
51
+ function isStorageConflict(error: unknown): error is SupportPassportError {
52
+ return error instanceof SupportPassportError && error.code === "storage_conflict";
53
+ }
54
+
55
+ export class SupportPassportCardService {
56
+ private readonly resolveOwner: SupportPassportCardServiceDependencies["resolveOwner"];
57
+ private readonly now: () => Date;
58
+
59
+ constructor(dependencies: SupportPassportCardServiceDependencies) {
60
+ this.resolveOwner = dependencies.resolveOwner;
61
+ this.now = dependencies.now ?? (() => new Date());
62
+ }
63
+
64
+ async listCards(input: { principal: string }): Promise<SupportPassportCard[]> {
65
+ const parsed = SupportPassportListCardsInputSchema.safeParse(input);
66
+ if (!parsed.success) throw invalidInput();
67
+ const { principal, namespace, storage } = await this.resolveOwnerScope(parsed.data.principal);
68
+ return await withSupportPassportOwnerLock(storage, { namespace, principal }, async (lock) => {
69
+ const stored = await this.readStoredCards(storage, lock, principal, namespace);
70
+ const cards = this.ownerVisibleCards(stored)
71
+ .sort((a, b) => a.order - b.order || a.card.cardId.localeCompare(b.card.cardId))
72
+ .map((item) => item.card);
73
+ const output = SupportPassportCardListSchema.safeParse(cards);
74
+ if (!output.success) {
75
+ throw new SupportPassportError("card_data_invalid", "The support card data is invalid.", 500);
76
+ }
77
+ return output.data;
78
+ });
79
+ }
80
+
81
+ async createManualDraft(input: SupportPassportManualDraftInput): Promise<SupportPassportCard> {
82
+ const parsed = SupportPassportManualDraftInputSchema.safeParse(input);
83
+ if (!parsed.success) throw invalidInput();
84
+ const { principal, namespace, storage } = await this.resolveOwnerScope(parsed.data.principal);
85
+ return await withSupportPassportOwnerLock(storage, { namespace, principal }, (lock) =>
86
+ this.createDraft(
87
+ storage,
88
+ {
89
+ title: parsed.data.title,
90
+ statement: parsed.data.statement,
91
+ category: parsed.data.category,
92
+ reviewBy: parsed.data.reviewBy,
93
+ sourceMemoryIds: [],
94
+ },
95
+ lock,
96
+ principal,
97
+ namespace
98
+ )
99
+ );
100
+ }
101
+
102
+ async replaceCard(input: SupportPassportReplaceCardInput): Promise<SupportPassportCard> {
103
+ const parsed = SupportPassportReplaceCardInputSchema.safeParse(input);
104
+ if (!parsed.success) throw invalidInput();
105
+ const { principal, namespace, storage } = await this.resolveOwnerScope(parsed.data.principal);
106
+ return await withSupportPassportOwnerLock(storage, { namespace, principal }, async (lock) => {
107
+ const loadedPrior = await this.requireCard(storage, parsed.data.cardId, namespace, principal);
108
+ const storedCards = await this.readProjectedCards(storage, namespace, principal);
109
+ const interruptedReplacements = storedCards.filter(
110
+ (item) =>
111
+ item.card.status === "pending_review" &&
112
+ (item.replacesDraftId === loadedPrior.card.cardId ||
113
+ item.memory.frontmatter.supersedes === loadedPrior.card.cardId)
114
+ );
115
+ if (interruptedReplacements.length > 1) {
116
+ throw new SupportPassportError(
117
+ "storage_conflict",
118
+ "Multiple support card edits already completed. Reload the support passport.",
119
+ 409
120
+ );
121
+ }
122
+ const [interruptedReplacement] = interruptedReplacements;
123
+ if (interruptedReplacement) {
124
+ if (interruptedReplacement.replacedRevision !== parsed.data.expectedRevision) {
125
+ throw new SupportPassportError("revision_conflict", "The support card changed after it was loaded.", 409);
126
+ }
127
+ const matchesRetry =
128
+ interruptedReplacement.card.title === parsed.data.title &&
129
+ interruptedReplacement.card.statement === parsed.data.statement &&
130
+ interruptedReplacement.card.category === parsed.data.category &&
131
+ interruptedReplacement.card.reviewBy === parsed.data.reviewBy;
132
+ if (!matchesRetry) {
133
+ throw new SupportPassportError(
134
+ "storage_conflict",
135
+ "A different support card edit already completed. Reload the support passport.",
136
+ 409
137
+ );
138
+ }
139
+ if (!interruptedReplacement.draftReplacementPrepared) return interruptedReplacement.card;
140
+ const recovered = await this.recoverReplacementTransition(
141
+ storage,
142
+ interruptedReplacement.memory,
143
+ lock,
144
+ principal,
145
+ namespace
146
+ );
147
+ return this.projectRequiredCard(recovered, namespace, principal).card;
148
+ }
149
+ this.requireRevision(loadedPrior, parsed.data.expectedRevision);
150
+ await this.readStoredCards(storage, lock, principal, namespace);
151
+ const refreshedPrior = await this.requireCard(storage, parsed.data.cardId, namespace, principal);
152
+ this.requireRevision(refreshedPrior, parsed.data.expectedRevision);
153
+ const recoveredMemory = await this.recoverReplacementTransition(
154
+ storage,
155
+ refreshedPrior.memory,
156
+ lock,
157
+ principal,
158
+ namespace
159
+ );
160
+ const prior = this.projectRequiredCard(recoveredMemory, namespace, principal);
161
+ if (prior.card.status !== "active" && prior.card.status !== "pending_review") {
162
+ throw new SupportPassportError(
163
+ "invalid_card_status",
164
+ "Only a draft or approved support card can be edited.",
165
+ 409
166
+ );
167
+ }
168
+ const replacement = await this.createDraft(
169
+ storage,
170
+ {
171
+ title: parsed.data.title,
172
+ statement: parsed.data.statement,
173
+ category: parsed.data.category,
174
+ reviewBy: parsed.data.reviewBy,
175
+ sourceMemoryIds: prior.sourceMemoryIds,
176
+ supersedes: prior.card.status === "active" ? prior.card.cardId : prior.memory.frontmatter.supersedes,
177
+ replacesDraftId: prior.card.status === "pending_review" ? prior.card.cardId : undefined,
178
+ replacedRevision: prior.card.revision,
179
+ order: prior.order,
180
+ draftReplacementPrepared: prior.card.status === "pending_review",
181
+ },
182
+ lock,
183
+ principal,
184
+ namespace
185
+ );
186
+ if (prior.card.status === "active") return replacement;
187
+
188
+ const replacedAt = this.now().toISOString();
189
+ await this.requireOwnerLock(lock);
190
+ const rejected = await storage.writeMemoryFrontmatterIfUnchanged(
191
+ prior.memory,
192
+ { status: "rejected", updated: replacedAt },
193
+ { actor: principal, reasonCode: "owner-replaced-draft" }
194
+ );
195
+ if (rejected) {
196
+ return await this.finishPreparedDraftReplacement(storage, replacement.cardId, lock, principal, namespace);
197
+ }
198
+ const currentPrior = await storage.getMemoryById(prior.card.cardId);
199
+ const currentPriorCard = currentPrior ? this.projectOwnedCard(currentPrior, namespace, principal) : null;
200
+ if (currentPriorCard?.card.status === "rejected") {
201
+ return await this.finishPreparedDraftReplacement(storage, replacement.cardId, lock, principal, namespace);
202
+ }
203
+
204
+ await this.rejectCreatedDraft(
205
+ storage,
206
+ replacement.cardId,
207
+ "draft-replacement-failed",
208
+ lock,
209
+ principal,
210
+ namespace
211
+ );
212
+ throw new SupportPassportError("storage_conflict", "The support card changed before it was edited.", 409);
213
+ });
214
+ }
215
+
216
+ async approveCard(input: SupportPassportCardMutationInput): Promise<SupportPassportCard> {
217
+ const parsed = SupportPassportCardMutationInputSchema.safeParse(input);
218
+ if (!parsed.success) throw invalidInput();
219
+ const { principal, namespace, storage } = await this.resolveOwnerScope(parsed.data.principal);
220
+ return await withSupportPassportOwnerLock(storage, { namespace, principal }, async (lock) => {
221
+ const loadedCard = await this.requireCard(storage, parsed.data.cardId, namespace, principal);
222
+ this.requireRevision(loadedCard, parsed.data.expectedRevision);
223
+ this.requireStatus(loadedCard, "pending_review");
224
+ const recoveredMemory = await this.recoverReplacementTransition(
225
+ storage,
226
+ loadedCard.memory,
227
+ lock,
228
+ principal,
229
+ namespace
230
+ );
231
+ const card = this.projectRequiredCard(recoveredMemory, namespace, principal);
232
+ if (card.card.status === "active") return card.card;
233
+ if (card.card.status === "rejected") {
234
+ throw new SupportPassportError(
235
+ "storage_conflict",
236
+ "The support card was rejected while its replacement state was recovered.",
237
+ 409
238
+ );
239
+ }
240
+ this.requireStatus(card, "pending_review");
241
+ await this.validatePriorForReplacement(storage, card, namespace, principal);
242
+ const updatedAt = this.now().toISOString();
243
+ await this.requireOwnerLock(lock);
244
+ let approved: boolean;
245
+ try {
246
+ approved = await storage.writeMemoryFrontmatterIfUnchanged(
247
+ card.memory,
248
+ { status: "active", updated: updatedAt },
249
+ { actor: principal, reasonCode: "owner-approved" }
250
+ );
251
+ } catch (error) {
252
+ const current = await storage.getMemoryById(card.card.cardId);
253
+ const currentCard = current ? this.projectOwnedCard(current, namespace, principal) : null;
254
+ if (currentCard?.card.status === "active") {
255
+ return await this.finishCommittedApproval(storage, currentCard, lock, principal, namespace);
256
+ }
257
+ throw error;
258
+ }
259
+ if (!approved) {
260
+ const current = await storage.getMemoryById(card.card.cardId);
261
+ const currentCard = current ? this.projectOwnedCard(current, namespace, principal) : null;
262
+ if (currentCard?.card.status === "active") {
263
+ return await this.finishCommittedApproval(storage, currentCard, lock, principal, namespace);
264
+ }
265
+ throw new SupportPassportError("storage_conflict", "The support card changed before approval.", 409);
266
+ }
267
+ const committedCard: SupportPassportCard = {
268
+ ...card.card,
269
+ status: "active",
270
+ updatedAt,
271
+ revision: this.revisionFor(card.card, "active", updatedAt),
272
+ };
273
+ try {
274
+ const current = await this.requireCard(storage, card.card.cardId, namespace, principal);
275
+ return await this.finishCommittedApproval(storage, current, lock, principal, namespace);
276
+ } catch (error) {
277
+ if (isStorageConflict(error)) throw error;
278
+ log.warn(
279
+ `support passport could not finish replacement approval side effects: ${error instanceof Error ? error.message : String(error)}`
280
+ );
281
+ return committedCard;
282
+ }
283
+ });
284
+ }
285
+
286
+ async rejectCard(input: SupportPassportCardMutationInput): Promise<SupportPassportCard> {
287
+ return await this.changeStatus(input, "pending_review", "rejected");
288
+ }
289
+
290
+ async withdrawCard(input: SupportPassportCardMutationInput): Promise<SupportPassportCard> {
291
+ return await this.changeStatus(input, "active", "archived");
292
+ }
293
+
294
+ private async createDraft(
295
+ storage: StorageManager,
296
+ input: {
297
+ title: string;
298
+ statement: string;
299
+ category: SupportPassportCardCategory;
300
+ reviewBy?: string;
301
+ sourceMemoryIds: string[];
302
+ supersedes?: string;
303
+ replacesDraftId?: string;
304
+ replacedRevision?: string;
305
+ order?: number;
306
+ draftReplacementPrepared?: boolean;
307
+ },
308
+ lock: HeldFileLockController,
309
+ principal: string,
310
+ namespace: string
311
+ ): Promise<SupportPassportCard> {
312
+ const now = this.now();
313
+ const reviewBy = input.reviewBy ?? now.toISOString();
314
+ const storedCards = await this.readStoredCards(storage, lock, principal, namespace);
315
+ const visibleCards = this.ownerVisibleCards(storedCards);
316
+ const replacesVisibleCard = visibleCards.some(
317
+ (item) =>
318
+ (input.replacesDraftId === item.card.cardId && item.card.status === "pending_review") ||
319
+ (input.supersedes === item.card.cardId && item.card.status === "active")
320
+ );
321
+ if (visibleCards.length - (replacesVisibleCard ? 1 : 0) >= MAX_OWNER_VISIBLE_CARDS) {
322
+ throw new SupportPassportError("invalid_input", "A support passport can contain at most 100 visible cards.", 400);
323
+ }
324
+ const maximumOrder = storedCards.reduce((maximum, card) => Math.max(maximum, card.order), -1);
325
+ const order = input.order ?? maximumOrder + 1;
326
+ if (!Number.isSafeInteger(order)) {
327
+ throw new SupportPassportError("storage_conflict", "The support card order range is exhausted.", 409);
328
+ }
329
+ const envelope = composeMemoryEnvelope(
330
+ {
331
+ content: input.statement,
332
+ category: "preference",
333
+ tags: [SUPPORT_PASSPORT_CARD_TAG],
334
+ structuredAttributes: {
335
+ ...encodeSupportPassportNamespaceAttributes(namespace),
336
+ [SUPPORT_PASSPORT_ATTRIBUTE_KEYS.owner]: computeSupportPassportOwnerKey(principal),
337
+ [SUPPORT_PASSPORT_ATTRIBUTE_KEYS.title]: input.title,
338
+ [SUPPORT_PASSPORT_ATTRIBUTE_KEYS.category]: input.category,
339
+ [SUPPORT_PASSPORT_ATTRIBUTE_KEYS.order]: String(order),
340
+ [SUPPORT_PASSPORT_ATTRIBUTE_KEYS.reviewBy]: reviewBy,
341
+ [SUPPORT_PASSPORT_ATTRIBUTE_KEYS.sourceMemoryIds]: input.sourceMemoryIds.join(","),
342
+ ...(input.replacesDraftId
343
+ ? { [SUPPORT_PASSPORT_ATTRIBUTE_KEYS.replacesDraftId]: input.replacesDraftId }
344
+ : {}),
345
+ ...(input.replacedRevision
346
+ ? { [SUPPORT_PASSPORT_ATTRIBUTE_KEYS.replacedRevision]: input.replacedRevision }
347
+ : {}),
348
+ ...(input.draftReplacementPrepared
349
+ ? { [SUPPORT_PASSPORT_ATTRIBUTE_KEYS.draftReplacementPrepared]: "true" }
350
+ : {}),
351
+ },
352
+ sourceReason: "support-passport",
353
+ },
354
+ { source: "support-passport", now: this.now }
355
+ );
356
+ if (envelope.sanitizeViolations.length > 0) throw invalidInput();
357
+ await this.requireOwnerLock(lock);
358
+ const written = await storage.writeSealedMemory(envelope, {
359
+ actor: principal,
360
+ status: "pending_review",
361
+ lineage: input.sourceMemoryIds.length > 0 ? input.sourceMemoryIds : undefined,
362
+ supersedes: input.supersedes,
363
+ });
364
+ if (written.tombstoneBlocked) {
365
+ throw new SupportPassportError("storage_conflict", "The support card needs memory review before use.", 409);
366
+ }
367
+ return this.projectRequiredCard(written.memory, namespace, principal).card;
368
+ }
369
+
370
+ private async changeStatus(
371
+ input: SupportPassportCardMutationInput,
372
+ expectedStatus: "pending_review" | "active",
373
+ nextStatus: "rejected" | "archived"
374
+ ): Promise<SupportPassportCard> {
375
+ const parsed = SupportPassportCardMutationInputSchema.safeParse(input);
376
+ if (!parsed.success) throw invalidInput();
377
+ const { principal, namespace, storage } = await this.resolveOwnerScope(parsed.data.principal);
378
+ return await withSupportPassportOwnerLock(storage, { namespace, principal }, async (lock) => {
379
+ let card = await this.requireCard(storage, parsed.data.cardId, namespace, principal);
380
+ this.requireRevision(card, parsed.data.expectedRevision);
381
+ this.requireStatus(card, expectedStatus);
382
+ if (expectedStatus === "pending_review" && nextStatus === "rejected") {
383
+ await this.rejectPendingReplacementForPredecessor(storage, card, lock, principal, namespace);
384
+ card = await this.requireCard(storage, card.card.cardId, namespace, principal);
385
+ this.requireRevision(card, parsed.data.expectedRevision);
386
+ this.requireStatus(card, expectedStatus);
387
+ }
388
+ if (
389
+ expectedStatus === "pending_review" ||
390
+ (expectedStatus === "active" && (card.replacesDraftId || card.memory.frontmatter.supersedes))
391
+ ) {
392
+ card = this.projectRequiredCard(
393
+ await this.recoverReplacementTransition(storage, card.memory, lock, principal, namespace, {
394
+ rollbackConflictedApproval: expectedStatus !== "active",
395
+ }),
396
+ namespace,
397
+ principal
398
+ );
399
+ }
400
+ if (card.card.status === nextStatus) return card.card;
401
+ this.requireStatus(card, expectedStatus);
402
+ if (expectedStatus === "active" && nextStatus === "archived") {
403
+ await this.rejectPendingReplacementForPredecessor(storage, card, lock, principal, namespace);
404
+ card = await this.requireCard(storage, card.card.cardId, namespace, principal);
405
+ this.requireRevision(card, parsed.data.expectedRevision);
406
+ this.requireStatus(card, expectedStatus);
407
+ }
408
+ const updatedAt = this.now().toISOString();
409
+ await this.requireOwnerLock(lock);
410
+ const changed = await storage.writeMemoryFrontmatterIfUnchanged(
411
+ card.memory,
412
+ {
413
+ status: nextStatus,
414
+ updated: updatedAt,
415
+ ...(nextStatus === "archived" ? { archivedAt: updatedAt } : {}),
416
+ },
417
+ { actor: principal, reasonCode: nextStatus === "archived" ? "owner-withdrew" : "owner-rejected" }
418
+ );
419
+ if (!changed)
420
+ throw new SupportPassportError(
421
+ "storage_conflict",
422
+ "The support card changed before the request completed.",
423
+ 409
424
+ );
425
+ return {
426
+ ...card.card,
427
+ status: nextStatus,
428
+ updatedAt,
429
+ revision: this.revisionFor(card.card, nextStatus, updatedAt),
430
+ };
431
+ });
432
+ }
433
+
434
+ private revisionFor(card: SupportPassportCard, status: SupportPassportCard["status"], updatedAt: string): string {
435
+ return computeSupportPassportCardRevision({
436
+ cardId: card.cardId,
437
+ title: card.title,
438
+ statement: card.statement,
439
+ category: card.category,
440
+ status,
441
+ updatedAt,
442
+ reviewBy: card.reviewBy,
443
+ });
444
+ }
445
+
446
+ private async resolveOwnerScope(principal: string): Promise<SupportPassportOwnerScope> {
447
+ const requestedPrincipal = SupportPassportListCardsInputSchema.safeParse({ principal });
448
+ const owner = await this.resolveOwner(principal);
449
+ const namespace = SupportPassportNamespaceSchema.safeParse(owner.namespace);
450
+ const ownerPrincipal = SupportPassportListCardsInputSchema.safeParse({ principal: owner.principal });
451
+ if (
452
+ !requestedPrincipal.success ||
453
+ !namespace.success ||
454
+ !ownerPrincipal.success ||
455
+ ownerPrincipal.data.principal !== requestedPrincipal.data.principal
456
+ ) {
457
+ throw new SupportPassportError("card_data_invalid", "The support passport owner scope is invalid.", 500);
458
+ }
459
+ return { ...owner, principal: ownerPrincipal.data.principal, namespace: namespace.data };
460
+ }
461
+
462
+ private async rejectCreatedDraft(
463
+ storage: StorageManager,
464
+ cardId: string,
465
+ reasonCode: string,
466
+ lock: HeldFileLockController,
467
+ principal: string,
468
+ namespace: string
469
+ ): Promise<void> {
470
+ try {
471
+ const current = await this.requireCard(storage, cardId, namespace, principal);
472
+ await this.requireOwnerLock(lock);
473
+ const rejected = await storage.writeMemoryFrontmatterIfUnchanged(
474
+ current.memory,
475
+ { status: "rejected", updated: this.now().toISOString() },
476
+ { actor: principal, reasonCode }
477
+ );
478
+ if (!rejected) log.warn("support passport could not roll back a replacement draft");
479
+ } catch (error) {
480
+ log.warn(
481
+ `support passport could not roll back a replacement draft: ${error instanceof Error ? error.message : String(error)}`
482
+ );
483
+ }
484
+ }
485
+
486
+ private async requireCard(
487
+ storage: StorageManager,
488
+ cardId: string,
489
+ namespace: string,
490
+ principal: string
491
+ ): Promise<StoredSupportPassportCard> {
492
+ const stored = await storage.getMemoryById(cardId);
493
+ const card = stored ? this.projectOwnedCard(stored, namespace, principal) : null;
494
+ if (!card) throw new SupportPassportError("card_not_found", "The support card was not found.", 404);
495
+ return card;
496
+ }
497
+
498
+ private projectRequiredCard(memory: MemoryFile, namespace: string, principal: string): StoredSupportPassportCard {
499
+ const card = projectSupportPassportCard(memory);
500
+ if (!card) throw new SupportPassportError("card_data_invalid", "The support card data is invalid.", 500);
501
+ if (
502
+ card.namespace !== namespace ||
503
+ card.owner !== computeSupportPassportOwnerKey(principal)
504
+ ) {
505
+ throw new SupportPassportError("card_not_found", "The support card was not found.", 404);
506
+ }
507
+ return card;
508
+ }
509
+
510
+ private projectOwnedCard(memory: MemoryFile, namespace: string, principal: string): StoredSupportPassportCard | null {
511
+ const card = projectSupportPassportCard(memory);
512
+ return card?.namespace === namespace &&
513
+ card.owner === computeSupportPassportOwnerKey(principal)
514
+ ? card
515
+ : null;
516
+ }
517
+
518
+ private ownsMemory(memory: MemoryFile, namespace: string, principal: string): boolean {
519
+ const attributes = memory.frontmatter.structuredAttributes;
520
+ return (
521
+ attributes !== undefined &&
522
+ decodeSupportPassportNamespaceAttributes(attributes) === namespace &&
523
+ attributes[SUPPORT_PASSPORT_ATTRIBUTE_KEYS.owner] === computeSupportPassportOwnerKey(principal)
524
+ );
525
+ }
526
+
527
+ private async readProjectedCards(
528
+ storage: StorageManager,
529
+ namespace: string,
530
+ principal: string
531
+ ): Promise<StoredSupportPassportCard[]> {
532
+ const owner = computeSupportPassportOwnerKey(principal);
533
+ const projected = (await storage.readAllMemories())
534
+ .map(projectSupportPassportCard)
535
+ .filter((card): card is StoredSupportPassportCard => card?.namespace === namespace && card.owner === owner);
536
+ const ids = new Set<string>();
537
+ for (const item of projected) {
538
+ if (ids.has(item.card.cardId)) {
539
+ throw new SupportPassportError("card_data_invalid", "Support card IDs must be unique.", 500);
540
+ }
541
+ ids.add(item.card.cardId);
542
+ }
543
+ return projected;
544
+ }
545
+
546
+ private requireRevision(card: StoredSupportPassportCard, expectedRevision: string): void {
547
+ if (card.card.revision !== expectedRevision) {
548
+ throw new SupportPassportError("revision_conflict", "The support card changed after it was loaded.", 409);
549
+ }
550
+ }
551
+
552
+ private requireStatus(card: StoredSupportPassportCard, status: SupportPassportCard["status"]): void {
553
+ if (card.card.status !== status) {
554
+ throw new SupportPassportError("invalid_card_status", `The support card must have status ${status}.`, 409);
555
+ }
556
+ }
557
+
558
+ private async readStoredCards(
559
+ storage: StorageManager,
560
+ lock: HeldFileLockController,
561
+ principal: string,
562
+ namespace: string
563
+ ): Promise<StoredSupportPassportCard[]> {
564
+ const initialVersion = storage.getCorpusScanVersion();
565
+ const initial = await storage.readAllMemories();
566
+ for (const memory of initial) {
567
+ const card = this.projectOwnedCard(memory, namespace, principal);
568
+ if (card) await this.recoverReplacementTransition(storage, memory, lock, principal, namespace);
569
+ }
570
+ const memories: MemoryFile[] =
571
+ storage.getCorpusScanVersion() === initialVersion ? initial : await storage.readAllMemories();
572
+ const owner = computeSupportPassportOwnerKey(principal);
573
+ const projected = memories
574
+ .map(projectSupportPassportCard)
575
+ .filter((card): card is StoredSupportPassportCard => card?.namespace === namespace && card.owner === owner);
576
+ const ids = new Set<string>();
577
+ for (const item of projected) {
578
+ if (ids.has(item.card.cardId)) {
579
+ throw new SupportPassportError("card_data_invalid", "Support card IDs must be unique.", 500);
580
+ }
581
+ ids.add(item.card.cardId);
582
+ }
583
+ return projected;
584
+ }
585
+
586
+ private ownerVisibleCards(storedCards: StoredSupportPassportCard[]): StoredSupportPassportCard[] {
587
+ const visibleCards = storedCards.filter(
588
+ (item) => OWNER_VISIBLE_STATUSES.has(item.card.status) && !item.draftReplacementPrepared
589
+ );
590
+ if (visibleCards.length <= MAX_OWNER_VISIBLE_CARDS) return visibleCards;
591
+ const activeCardsWithPendingReplacements = new Set(
592
+ visibleCards
593
+ .filter((item) => item.card.status === "pending_review")
594
+ .map((item) => item.memory.frontmatter.supersedes)
595
+ .filter((cardId): cardId is string => typeof cardId === "string")
596
+ );
597
+ return visibleCards.filter(
598
+ (item) => item.card.status !== "active" || !activeCardsWithPendingReplacements.has(item.card.cardId)
599
+ );
600
+ }
601
+
602
+ private async preparePriorForReplacement(
603
+ storage: StorageManager,
604
+ replacement: StoredSupportPassportCard,
605
+ lock: HeldFileLockController,
606
+ principal: string,
607
+ namespace: string
608
+ ): Promise<string | null> {
609
+ const priorId = replacement.memory.frontmatter.supersedes;
610
+ if (!priorId) return null;
611
+ const priorMemory = await storage.getMemoryById(priorId);
612
+ const priorIsOwned = priorMemory ? this.ownsMemory(priorMemory, namespace, principal) : false;
613
+ const alreadyRetired =
614
+ priorIsOwned &&
615
+ priorMemory?.frontmatter.status === "superseded" &&
616
+ priorMemory.frontmatter.supersededBy === replacement.card.cardId;
617
+ const prior = priorMemory && priorIsOwned && !alreadyRetired ? projectSupportPassportCard(priorMemory) : null;
618
+ if (prior?.card.status === "rejected") return null;
619
+ if (!priorMemory || (!alreadyRetired && prior?.card.status !== "active")) {
620
+ throw new SupportPassportError("storage_conflict", "The prior support card changed before replacement.", 409);
621
+ }
622
+ if (alreadyRetired) return priorId;
623
+ const retiredAt = this.now().toISOString();
624
+ await this.requireOwnerLock(lock);
625
+ const retired = await storage.writeMemoryFrontmatterIfUnchanged(
626
+ priorMemory,
627
+ {
628
+ status: "superseded",
629
+ supersededBy: replacement.card.cardId,
630
+ supersededAt: retiredAt,
631
+ supersessionCause: "direct",
632
+ updated: retiredAt,
633
+ },
634
+ {
635
+ actor: principal,
636
+ reasonCode: "support-passport-replacement-pending",
637
+ relatedMemoryIds: [replacement.card.cardId],
638
+ }
639
+ );
640
+ if (!retired) {
641
+ throw new SupportPassportError("storage_conflict", "The prior support card changed before replacement.", 409);
642
+ }
643
+ return priorId;
644
+ }
645
+
646
+ private async rejectPendingReplacementForPredecessor(
647
+ storage: StorageManager,
648
+ predecessor: StoredSupportPassportCard,
649
+ lock: HeldFileLockController,
650
+ principal: string,
651
+ namespace: string
652
+ ): Promise<void> {
653
+ const storedCards =
654
+ predecessor.card.status === "active"
655
+ ? await this.readStoredCards(storage, lock, principal, namespace)
656
+ : await this.readProjectedCards(storage, namespace, principal);
657
+ const replacements = storedCards.filter((item) => {
658
+ if (item.card.status !== "pending_review") return false;
659
+ return predecessor.card.status === "pending_review"
660
+ ? item.replacesDraftId === predecessor.card.cardId
661
+ : item.memory.frontmatter.supersedes === predecessor.card.cardId;
662
+ });
663
+ if (replacements.length > 1) {
664
+ throw new SupportPassportError(
665
+ "storage_conflict",
666
+ "Multiple support card edits target the card being withdrawn.",
667
+ 409
668
+ );
669
+ }
670
+ const [replacement] = replacements;
671
+ if (!replacement) return;
672
+ await this.requireOwnerLock(lock);
673
+ const rejected = await storage.writeMemoryFrontmatterIfUnchanged(
674
+ replacement.memory,
675
+ { status: "rejected", updated: this.now().toISOString() },
676
+ {
677
+ actor: principal,
678
+ reasonCode: predecessor.card.status === "pending_review" ? "source-draft-rejected" : "predecessor-withdrawn",
679
+ }
680
+ );
681
+ if (rejected) return;
682
+ const current = await storage.getMemoryById(replacement.card.cardId);
683
+ const currentCard = current ? this.projectOwnedCard(current, namespace, principal) : null;
684
+ if (currentCard?.card.status !== "rejected") {
685
+ throw new SupportPassportError("storage_conflict", "The pending support card edit could not be cancelled.", 409);
686
+ }
687
+ }
688
+
689
+ private async validatePriorForReplacement(
690
+ storage: StorageManager,
691
+ replacement: StoredSupportPassportCard,
692
+ namespace: string,
693
+ principal: string
694
+ ): Promise<void> {
695
+ const priorId = replacement.memory.frontmatter.supersedes;
696
+ if (!priorId) return;
697
+ const priorMemory = await storage.getMemoryById(priorId);
698
+ const priorIsOwned = priorMemory ? this.ownsMemory(priorMemory, namespace, principal) : false;
699
+ const alreadyRetired =
700
+ priorIsOwned &&
701
+ priorMemory?.frontmatter.status === "superseded" &&
702
+ priorMemory.frontmatter.supersededBy === replacement.card.cardId;
703
+ const prior = priorMemory && priorIsOwned && !alreadyRetired ? projectSupportPassportCard(priorMemory) : null;
704
+ if (prior?.card.status === "rejected" || alreadyRetired) return;
705
+ if (!priorMemory || prior?.card.status !== "active") {
706
+ throw new SupportPassportError("storage_conflict", "The prior support card changed before replacement.", 409);
707
+ }
708
+ }
709
+
710
+ private async recoverReplacementTransition(
711
+ storage: StorageManager,
712
+ memory: MemoryFile,
713
+ lock: HeldFileLockController,
714
+ principal: string,
715
+ namespace: string,
716
+ options: { rollbackConflictedApproval?: boolean } = {}
717
+ ): Promise<MemoryFile> {
718
+ const replacement = this.projectOwnedCard(memory, namespace, principal);
719
+ if (replacement?.card.status !== "pending_review" && replacement?.card.status !== "active") return memory;
720
+ if (!replacement.replacesDraftId && !memory.frontmatter.supersedes) return memory;
721
+ if (
722
+ replacement.card.status === "active" &&
723
+ memory.frontmatter.structuredAttributes?.[SUPPORT_PASSPORT_ATTRIBUTE_KEYS.replacementComplete] === "true"
724
+ ) {
725
+ return memory;
726
+ }
727
+ await this.recoverReplacedDraft(storage, replacement, lock, principal, namespace);
728
+ const currentMemory = (await storage.getMemoryById(replacement.card.cardId)) ?? memory;
729
+ const currentCard = this.projectOwnedCard(currentMemory, namespace, principal);
730
+ if (currentCard?.card.status !== "pending_review" && currentCard?.card.status !== "active") {
731
+ return currentMemory;
732
+ }
733
+ if (currentCard.card.status === "pending_review") {
734
+ const priorId = currentMemory.frontmatter.supersedes;
735
+ if (!priorId) return currentMemory;
736
+ const prior = await storage.getMemoryById(priorId);
737
+ if (
738
+ prior &&
739
+ this.ownsMemory(prior, namespace, principal) &&
740
+ prior.frontmatter.status === "superseded" &&
741
+ prior.frontmatter.supersededBy === replacement.card.cardId
742
+ ) {
743
+ await this.restorePriorAfterApprovalFailure(
744
+ storage,
745
+ priorId,
746
+ replacement.card.cardId,
747
+ lock,
748
+ principal,
749
+ namespace
750
+ );
751
+ }
752
+ return (await storage.getMemoryById(replacement.card.cardId)) ?? currentMemory;
753
+ }
754
+ try {
755
+ await this.completeReplacementAfterActivation(storage, currentCard, lock, principal, namespace);
756
+ } catch (error) {
757
+ if (!isStorageConflict(error)) throw error;
758
+ if (options.rollbackConflictedApproval === false) throw error;
759
+ await this.rollbackConflictedApproval(storage, currentCard.card.cardId, lock, principal, namespace);
760
+ }
761
+ return (await storage.getMemoryById(replacement.card.cardId)) ?? currentMemory;
762
+ }
763
+
764
+ private async completeReplacementAfterActivation(
765
+ storage: StorageManager,
766
+ replacement: StoredSupportPassportCard,
767
+ lock: HeldFileLockController,
768
+ principal: string,
769
+ namespace: string
770
+ ): Promise<void> {
771
+ const priorId = await this.preparePriorForReplacement(storage, replacement, lock, principal, namespace);
772
+ if (priorId && !(await this.completePriorRetirement(storage, priorId, replacement, lock, principal, namespace))) {
773
+ throw new SupportPassportError("storage_conflict", "The prior support card changed before replacement.", 409);
774
+ }
775
+ await this.markReplacementComplete(storage, replacement.card.cardId, lock, principal, namespace);
776
+ }
777
+
778
+ private async finishCommittedApproval(
779
+ storage: StorageManager,
780
+ replacement: StoredSupportPassportCard,
781
+ lock: HeldFileLockController,
782
+ principal: string,
783
+ namespace: string
784
+ ): Promise<SupportPassportCard> {
785
+ try {
786
+ if (replacement.replacesDraftId || replacement.memory.frontmatter.supersedes) {
787
+ await this.completeReplacementAfterActivation(storage, replacement, lock, principal, namespace);
788
+ }
789
+ } catch (error) {
790
+ if (isStorageConflict(error)) {
791
+ await this.rollbackConflictedApproval(storage, replacement.card.cardId, lock, principal, namespace);
792
+ throw error;
793
+ }
794
+ log.warn(
795
+ `support passport could not finish replacement approval side effects: ${error instanceof Error ? error.message : String(error)}`
796
+ );
797
+ }
798
+ return replacement.card;
799
+ }
800
+
801
+ private async rollbackConflictedApproval(
802
+ storage: StorageManager,
803
+ replacementId: string,
804
+ lock: HeldFileLockController,
805
+ principal: string,
806
+ namespace: string
807
+ ): Promise<void> {
808
+ const replacement = await this.requireCard(storage, replacementId, namespace, principal);
809
+ if (replacement.card.status !== "active") return;
810
+ await this.requireOwnerLock(lock);
811
+ const rolledBack = await storage.writeMemoryFrontmatterIfUnchanged(
812
+ replacement.memory,
813
+ { status: "pending_review", updated: this.now().toISOString() },
814
+ { actor: principal, reasonCode: "replacement-predecessor-conflict" }
815
+ );
816
+ if (!rolledBack) {
817
+ throw new SupportPassportError(
818
+ "storage_conflict",
819
+ "The replacement changed while its approval was rolled back.",
820
+ 409
821
+ );
822
+ }
823
+ const priorId = replacement.memory.frontmatter.supersedes;
824
+ if (priorId) {
825
+ await this.restorePriorAfterApprovalFailure(storage, priorId, replacementId, lock, principal, namespace);
826
+ }
827
+ }
828
+
829
+ private async completePriorRetirement(
830
+ storage: StorageManager,
831
+ priorId: string,
832
+ replacement: StoredSupportPassportCard,
833
+ lock: HeldFileLockController,
834
+ principal: string,
835
+ namespace: string
836
+ ): Promise<boolean> {
837
+ const replacementId = replacement.card.cardId;
838
+ const prior = await storage.getMemoryById(priorId);
839
+ if (
840
+ !prior ||
841
+ !this.ownsMemory(prior, namespace, principal) ||
842
+ prior.frontmatter.status !== "superseded" ||
843
+ prior.frontmatter.supersededBy !== replacementId
844
+ ) {
845
+ return false;
846
+ }
847
+ await this.requireOwnerLock(lock);
848
+ const completed = await storage.supersedeMemory(
849
+ priorId,
850
+ replacementId,
851
+ "support-passport-replacement",
852
+ { supersessionCause: "direct" },
853
+ {
854
+ actor: principal,
855
+ requireActive: true,
856
+ acceptExactReplay: true,
857
+ expectedSnapshot: prior,
858
+ audit: {
859
+ content: stripAttributesSuffix(prior.content),
860
+ tags: ["supersession", "auto-resolved", "support-passport-audit"],
861
+ structuredAttributes: {
862
+ ...encodeSupportPassportNamespaceAttributes(namespace),
863
+ [SUPPORT_PASSPORT_ATTRIBUTE_KEYS.owner]: computeSupportPassportOwnerKey(principal),
864
+ },
865
+ source: "support-passport",
866
+ },
867
+ }
868
+ );
869
+ if (!completed) log.warn("support passport could not complete replacement retirement side effects");
870
+ return completed;
871
+ }
872
+
873
+ private async recoverReplacedDraft(
874
+ storage: StorageManager,
875
+ replacement: StoredSupportPassportCard,
876
+ lock: HeldFileLockController,
877
+ principal: string,
878
+ namespace: string
879
+ ): Promise<void> {
880
+ if (!replacement.replacesDraftId) return;
881
+ const replacedDraft = await storage.getMemoryById(replacement.replacesDraftId);
882
+ const projectedDraft = replacedDraft ? this.projectOwnedCard(replacedDraft, namespace, principal) : null;
883
+ if (
884
+ replacedDraft &&
885
+ projectedDraft?.card.status === "pending_review" &&
886
+ projectedDraft.card.revision === replacement.replacedRevision
887
+ ) {
888
+ await this.requireOwnerLock(lock);
889
+ const rejected = await storage.writeMemoryFrontmatterIfUnchanged(
890
+ replacedDraft,
891
+ { status: "rejected", updated: this.now().toISOString() },
892
+ { actor: principal, reasonCode: "complete-draft-replacement" }
893
+ );
894
+ if (rejected) {
895
+ await this.finishPreparedDraftReplacement(storage, replacement.card.cardId, lock, principal, namespace);
896
+ return;
897
+ }
898
+ }
899
+ const currentDraft = await storage.getMemoryById(replacement.replacesDraftId);
900
+ if (
901
+ currentDraft &&
902
+ this.ownsMemory(currentDraft, namespace, principal) &&
903
+ currentDraft.frontmatter.status === "rejected"
904
+ ) {
905
+ await this.finishPreparedDraftReplacement(storage, replacement.card.cardId, lock, principal, namespace);
906
+ return;
907
+ }
908
+ if (
909
+ currentDraft &&
910
+ this.ownsMemory(currentDraft, namespace, principal) &&
911
+ currentDraft.frontmatter.status === "pending_review"
912
+ ) {
913
+ throw new SupportPassportError("storage_conflict", "The replaced draft changed during recovery.", 409);
914
+ }
915
+ await this.rejectOrphanedReplacement(storage, replacement.card.cardId, lock, principal, namespace);
916
+ }
917
+
918
+ private async finishPreparedDraftReplacement(
919
+ storage: StorageManager,
920
+ replacementId: string,
921
+ lock: HeldFileLockController,
922
+ principal: string,
923
+ namespace: string
924
+ ): Promise<SupportPassportCard> {
925
+ const replacement = await this.requireCard(storage, replacementId, namespace, principal);
926
+ if (!replacement.draftReplacementPrepared) return replacement.card;
927
+ const structuredAttributes = { ...replacement.memory.frontmatter.structuredAttributes };
928
+ delete structuredAttributes[SUPPORT_PASSPORT_ATTRIBUTE_KEYS.draftReplacementPrepared];
929
+ await this.requireOwnerLock(lock);
930
+ const finished = await storage.writeMemoryFrontmatterIfUnchanged(
931
+ replacement.memory,
932
+ { structuredAttributes },
933
+ { actor: principal, reasonCode: "draft-replacement-complete" }
934
+ );
935
+ if (finished) {
936
+ return this.projectRequiredCard(
937
+ { ...replacement.memory, frontmatter: { ...replacement.memory.frontmatter, structuredAttributes } },
938
+ namespace,
939
+ principal
940
+ ).card;
941
+ }
942
+ const current = await this.requireCard(storage, replacementId, namespace, principal);
943
+ if (!current.draftReplacementPrepared) return current.card;
944
+ throw new SupportPassportError("storage_conflict", "The support card edit could not be completed.", 409);
945
+ }
946
+
947
+ private async rejectOrphanedReplacement(
948
+ storage: StorageManager,
949
+ replacementId: string,
950
+ lock: HeldFileLockController,
951
+ principal: string,
952
+ namespace: string
953
+ ): Promise<void> {
954
+ const currentReplacement = await this.requireCard(storage, replacementId, namespace, principal);
955
+ if (currentReplacement.card.status === "rejected") return;
956
+ this.requireStatus(currentReplacement, "pending_review");
957
+ await this.requireOwnerLock(lock);
958
+ const rejected = await storage.writeMemoryFrontmatterIfUnchanged(
959
+ currentReplacement.memory,
960
+ { status: "rejected", updated: this.now().toISOString() },
961
+ { actor: principal, reasonCode: "replaced-draft-approved" }
962
+ );
963
+ if (rejected) return;
964
+ const latest = await storage.getMemoryById(replacementId);
965
+ if (latest?.frontmatter.status !== "rejected") {
966
+ throw new SupportPassportError("storage_conflict", "The orphaned replacement could not be rejected.", 409);
967
+ }
968
+ }
969
+
970
+ private async restorePriorAfterApprovalFailure(
971
+ storage: StorageManager,
972
+ priorId: string,
973
+ replacementId: string,
974
+ lock: HeldFileLockController,
975
+ principal: string,
976
+ namespace: string
977
+ ): Promise<void> {
978
+ const replacement = await storage.getMemoryById(replacementId);
979
+ if (replacement && !this.ownsMemory(replacement, namespace, principal)) {
980
+ throw new SupportPassportError("storage_conflict", "The replacement support card changed ownership.", 409);
981
+ }
982
+ if (replacement?.frontmatter.status === "active") return;
983
+ const prior = await storage.getMemoryById(priorId);
984
+ if (prior && !this.ownsMemory(prior, namespace, principal)) {
985
+ throw new SupportPassportError("storage_conflict", "The prior support card changed ownership.", 409);
986
+ }
987
+ if (prior?.frontmatter.status === "active" && prior.frontmatter.supersededBy === undefined) return;
988
+ if (prior?.frontmatter.status !== "superseded" || prior.frontmatter.supersededBy !== replacementId) {
989
+ throw new SupportPassportError("storage_conflict", "The prior support card could not be restored.", 409);
990
+ }
991
+ await this.requireOwnerLock(lock);
992
+ const restored = await storage.writeMemoryFrontmatterIfUnchanged(
993
+ prior,
994
+ {
995
+ status: "active",
996
+ supersededBy: undefined,
997
+ supersededAt: undefined,
998
+ supersessionCause: undefined,
999
+ invalidatedBy: undefined,
1000
+ updated: this.now().toISOString(),
1001
+ },
1002
+ { actor: principal, reasonCode: "replacement-activation-failed" }
1003
+ );
1004
+ if (restored) return;
1005
+ const currentPrior = await storage.getMemoryById(priorId);
1006
+ if (currentPrior?.frontmatter.status === "active" && currentPrior.frontmatter.supersededBy === undefined) return;
1007
+ throw new SupportPassportError("storage_conflict", "The prior support card could not be restored.", 409);
1008
+ }
1009
+
1010
+ private async markReplacementComplete(
1011
+ storage: StorageManager,
1012
+ replacementId: string,
1013
+ lock: HeldFileLockController,
1014
+ principal: string,
1015
+ namespace: string
1016
+ ): Promise<void> {
1017
+ const replacement = await this.requireCard(storage, replacementId, namespace, principal);
1018
+ if (
1019
+ replacement.memory.frontmatter.structuredAttributes?.[SUPPORT_PASSPORT_ATTRIBUTE_KEYS.replacementComplete] ===
1020
+ "true"
1021
+ ) {
1022
+ return;
1023
+ }
1024
+ await this.requireOwnerLock(lock);
1025
+ const marked = await storage.writeMemoryFrontmatterIfUnchanged(
1026
+ replacement.memory,
1027
+ {
1028
+ structuredAttributes: {
1029
+ ...replacement.memory.frontmatter.structuredAttributes,
1030
+ [SUPPORT_PASSPORT_ATTRIBUTE_KEYS.replacementComplete]: "true",
1031
+ },
1032
+ },
1033
+ { actor: principal, reasonCode: "replacement-side-effects-complete" }
1034
+ );
1035
+ if (!marked) log.warn("support passport could not mark replacement side effects complete");
1036
+ }
1037
+
1038
+ private async requireOwnerLock(lock: HeldFileLockController): Promise<void> {
1039
+ if (await lock.refresh()) return;
1040
+ throw new SupportPassportError("storage_conflict", "The support passport lock changed. Try again.", 409);
1041
+ }
1042
+ }