@remnic/core 9.3.725 → 9.3.727

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 (352) hide show
  1. package/dist/access-boundary.d.ts +5 -5
  2. package/dist/access-boundary.js +28 -27
  3. package/dist/access-cli.js +65 -63
  4. package/dist/access-cli.js.map +1 -1
  5. package/dist/access-http.d.ts +20 -5
  6. package/dist/access-http.js +34 -33
  7. package/dist/access-mcp.d.ts +5 -5
  8. package/dist/access-mcp.js +31 -30
  9. package/dist/access-operations-batch.js +29 -28
  10. package/dist/access-operations.d.ts +5 -5
  11. package/dist/access-operations.js +30 -29
  12. package/dist/{access-service-B2PlPtxh.d.ts → access-service-Bgpjxo4f.d.ts} +36 -4
  13. package/dist/access-service.d.ts +5 -5
  14. package/dist/access-service.js +27 -26
  15. package/dist/access-surface-catalog.d.ts +5 -5
  16. package/dist/action-confidence.d.ts +1 -1
  17. package/dist/active-memory-bridge.d.ts +1 -1
  18. package/dist/active-recall.d.ts +1 -1
  19. package/dist/active-recall.js +3 -3
  20. package/dist/adapters/index.js +4 -4
  21. package/dist/adapters/registry.js +2 -2
  22. package/dist/behavior-learner.d.ts +1 -1
  23. package/dist/behavior-signals.d.ts +1 -1
  24. package/dist/bootstrap.d.ts +4 -4
  25. package/dist/briefing.d.ts +1 -1
  26. package/dist/briefing.js +9 -8
  27. package/dist/buffer-surprise-report.d.ts +1 -1
  28. package/dist/buffer.d.ts +1 -1
  29. package/dist/calibration.d.ts +1 -1
  30. package/dist/capabilities.d.ts +1 -1
  31. package/dist/{catalog-CzUb-GyD.d.ts → catalog-bMczlO2G.d.ts} +1 -1
  32. package/dist/causal-behavior.d.ts +1 -1
  33. package/dist/causal-consolidation.d.ts +1 -1
  34. package/dist/causal-consolidation.js +10 -9
  35. package/dist/causal-consolidation.js.map +1 -1
  36. package/dist/causal-trajectory-graph.d.ts +1 -1
  37. package/dist/{chunk-KGZF2VO3.js → chunk-27QQC7ZX.js} +80 -19
  38. package/dist/{chunk-KGZF2VO3.js.map → chunk-27QQC7ZX.js.map} +1 -1
  39. package/dist/{chunk-HCVWF657.js → chunk-2KAYTPPT.js} +12 -12
  40. package/dist/{chunk-4SF232E6.js → chunk-36SEDFAU.js} +19 -7
  41. package/dist/chunk-36SEDFAU.js.map +1 -0
  42. package/dist/{chunk-ZK2L72VN.js → chunk-37436GML.js} +2 -2
  43. package/dist/{chunk-SC2YAWRF.js → chunk-3TSTGI6F.js} +2 -2
  44. package/dist/{chunk-FACTVMXQ.js → chunk-4H4F3BFL.js} +2 -2
  45. package/dist/{chunk-WAFDHKES.js → chunk-4NOI577P.js} +2 -2
  46. package/dist/{chunk-YQMPUYHE.js → chunk-4NR2PDZ5.js} +2 -2
  47. package/dist/{chunk-TAPSNIMA.js → chunk-5CEJH5ZN.js} +4 -4
  48. package/dist/{chunk-FN6QP7JQ.js → chunk-6PY5YJAV.js} +100 -14
  49. package/dist/{chunk-FN6QP7JQ.js.map → chunk-6PY5YJAV.js.map} +1 -1
  50. package/dist/{chunk-PKMQK2WY.js → chunk-773DPI6T.js} +4 -4
  51. package/dist/{chunk-4R3CGCI5.js → chunk-7RLCCNHU.js} +15 -12
  52. package/dist/chunk-7RLCCNHU.js.map +1 -0
  53. package/dist/{chunk-XGTBNVIU.js → chunk-AAD2ZS6P.js} +11 -1
  54. package/dist/chunk-AAD2ZS6P.js.map +1 -0
  55. package/dist/{chunk-Z3FGC3QE.js → chunk-AQLOP5F4.js} +139 -30
  56. package/dist/chunk-AQLOP5F4.js.map +1 -0
  57. package/dist/{chunk-FXCIOLRB.js → chunk-ASKXIAHD.js} +2 -2
  58. package/dist/{chunk-5OPYYPJN.js → chunk-CBWI22JN.js} +2 -2
  59. package/dist/{chunk-ZOHMPFOB.js → chunk-CKFLLAIS.js} +3 -3
  60. package/dist/{chunk-GZQXOQQ2.js → chunk-CSRXQ6NB.js} +5 -5
  61. package/dist/{chunk-QR67FU5G.js → chunk-CTOQEZSN.js} +2 -2
  62. package/dist/{chunk-ZUDM75KG.js → chunk-DCWIQFNA.js} +4 -4
  63. package/dist/{chunk-6CWGS2LY.js → chunk-DKJCRGWM.js} +3 -3
  64. package/dist/{chunk-JJJCVCCQ.js → chunk-DMQWV6SQ.js} +2 -2
  65. package/dist/{chunk-F3XZN24Z.js → chunk-DRUDC2UX.js} +2 -2
  66. package/dist/{chunk-4WZ3J7M6.js → chunk-EY6MDMHK.js} +2 -2
  67. package/dist/{chunk-YNDLCWXS.js → chunk-EZ25VE3G.js} +4 -4
  68. package/dist/{chunk-C4X4QGIO.js → chunk-G6NKALRN.js} +5 -2
  69. package/dist/chunk-G6NKALRN.js.map +1 -0
  70. package/dist/{chunk-6SQQOJ4U.js → chunk-GKRLPHPU.js} +2 -2
  71. package/dist/{chunk-D7EBTQ24.js → chunk-HOHVIVDR.js} +2 -2
  72. package/dist/{chunk-RKNJBZ55.js → chunk-JBPKEARU.js} +4 -4
  73. package/dist/{chunk-UBHVAGO7.js → chunk-JYLFZWUX.js} +2 -2
  74. package/dist/{chunk-LD53WPMU.js → chunk-LQ6JI4VH.js} +4 -4
  75. package/dist/chunk-LTHVM4XN.js +109 -0
  76. package/dist/chunk-LTHVM4XN.js.map +1 -0
  77. package/dist/{chunk-WM7DNKBD.js → chunk-M4V2JVSZ.js} +2 -2
  78. package/dist/{chunk-I2HL5M6T.js → chunk-MJIHJ7OG.js} +52 -52
  79. package/dist/{chunk-J334N6QV.js → chunk-MLKWJOAJ.js} +2 -2
  80. package/dist/{chunk-C6BWLYW5.js → chunk-N3VNUM4Z.js} +171 -79
  81. package/dist/chunk-N3VNUM4Z.js.map +1 -0
  82. package/dist/{chunk-DF3I6JGP.js → chunk-NSA5ZRUL.js} +15 -15
  83. package/dist/{chunk-VI5SGGXB.js → chunk-OEEW4KJA.js} +4 -4
  84. package/dist/{chunk-7AG54AF3.js → chunk-PUR2CKX2.js} +1 -1
  85. package/dist/chunk-PUR2CKX2.js.map +1 -0
  86. package/dist/{chunk-NT36GU6X.js → chunk-R7IYU5DZ.js} +2 -2
  87. package/dist/{chunk-TT5U3UDO.js → chunk-SNKPUJHR.js} +4 -4
  88. package/dist/{chunk-T55EGZSJ.js → chunk-UVPL565C.js} +2 -2
  89. package/dist/chunk-W5H6ZRPT.js +14 -0
  90. package/dist/chunk-W5H6ZRPT.js.map +1 -0
  91. package/dist/{chunk-YQGHW5ML.js → chunk-WRFKZEO6.js} +4 -4
  92. package/dist/{chunk-KLFYKC3K.js → chunk-XPHVAOBT.js} +195 -74
  93. package/dist/chunk-XPHVAOBT.js.map +1 -0
  94. package/dist/{chunk-H7HUQIY7.js → chunk-Y4YD5TYW.js} +3 -3
  95. package/dist/{chunk-MDBZTH7N.js → chunk-YKBHOBJK.js} +44 -10
  96. package/dist/chunk-YKBHOBJK.js.map +1 -0
  97. package/dist/{chunk-YUYPWJD3.js → chunk-YOLZS7NY.js} +2 -2
  98. package/dist/{chunk-6OIDDKAA.js → chunk-YTU7WKYN.js} +35 -9
  99. package/dist/chunk-YTU7WKYN.js.map +1 -0
  100. package/dist/{cli-IOlDHSBT.d.ts → cli-BLME420h.d.ts} +3 -3
  101. package/dist/cli.d.ts +6 -6
  102. package/dist/cli.js +60 -59
  103. package/dist/compat/codex-cli-fallback.d.ts +1 -0
  104. package/dist/compat/codex-cli-fallback.js +22 -0
  105. package/dist/compat/codex-cli-fallback.js.map +1 -0
  106. package/dist/compat/codex-thread-key.d.ts +1 -0
  107. package/dist/compat/codex-thread-key.js +18 -0
  108. package/dist/compat/codex-thread-key.js.map +1 -0
  109. package/dist/compounding/engine.d.ts +1 -1
  110. package/dist/compounding/engine.js +9 -8
  111. package/dist/compounding/preference-consolidator.d.ts +1 -1
  112. package/dist/compression-optimizer.d.ts +1 -1
  113. package/dist/config.d.ts +1 -1
  114. package/dist/config.js +3 -3
  115. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  116. package/dist/connectors/codex-materialize-runner.js +9 -8
  117. package/dist/connectors/codex-materialize.d.ts +1 -1
  118. package/dist/connectors/index.d.ts +1 -1
  119. package/dist/connectors/index.js +9 -8
  120. package/dist/consolidation-provenance-check.d.ts +1 -1
  121. package/dist/consolidation-undo.d.ts +1 -1
  122. package/dist/content-hash.d.ts +14 -0
  123. package/dist/content-hash.js +10 -0
  124. package/dist/content-hash.js.map +1 -0
  125. package/dist/contradiction/index.d.ts +1 -1
  126. package/dist/conversation-index/backend.d.ts +1 -1
  127. package/dist/conversation-index/backend.js +2 -2
  128. package/dist/conversation-index/chunker.d.ts +1 -1
  129. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  130. package/dist/conversation-index/indexer.d.ts +1 -1
  131. package/dist/conversation-index/search.d.ts +1 -1
  132. package/dist/dashboard-runtime.js +2 -2
  133. package/dist/day-summary.d.ts +1 -1
  134. package/dist/delinearize.d.ts +1 -1
  135. package/dist/direct-answer-wiring.d.ts +1 -1
  136. package/dist/direct-answer.d.ts +1 -1
  137. package/dist/embedding-fallback.d.ts +1 -1
  138. package/dist/enrichment/index.d.ts +1 -1
  139. package/dist/entity-retrieval.d.ts +1 -1
  140. package/dist/entity-retrieval.js +9 -8
  141. package/dist/entity-schema.d.ts +1 -1
  142. package/dist/explicit-capture.d.ts +4 -4
  143. package/dist/extraction-faithfulness.d.ts +1 -1
  144. package/dist/extraction-faithfulness.js +2 -2
  145. package/dist/extraction-judge-telemetry.d.ts +1 -1
  146. package/dist/extraction-judge-training.d.ts +1 -1
  147. package/dist/extraction-judge.d.ts +1 -1
  148. package/dist/extraction-redaction-rules.d.ts +33 -0
  149. package/dist/extraction-redaction-rules.js +14 -0
  150. package/dist/extraction-redaction-rules.js.map +1 -0
  151. package/dist/extraction.d.ts +1 -1
  152. package/dist/extraction.js +3 -3
  153. package/dist/faithfulness-config.d.ts +1 -0
  154. package/dist/faithfulness-config.js +1 -1
  155. package/dist/fallback-llm.d.ts +1 -1
  156. package/dist/{forget-OEE5OELK.js → forget-WYLR4ZFV.js} +2 -2
  157. package/dist/graph-dashboard-diff.d.ts +1 -1
  158. package/dist/graph-dashboard-key.d.ts +1 -1
  159. package/dist/graph-dashboard-parser.d.ts +1 -1
  160. package/dist/graph-edge-reinforcement.d.ts +1 -1
  161. package/dist/graph-snapshot.d.ts +1 -1
  162. package/dist/graph.d.ts +1 -1
  163. package/dist/identity-continuity.d.ts +1 -1
  164. package/dist/importance.d.ts +1 -1
  165. package/dist/index.d.ts +9 -9
  166. package/dist/index.js +107 -105
  167. package/dist/index.js.map +1 -1
  168. package/dist/intent.d.ts +1 -1
  169. package/dist/lcm/engine.d.ts +1 -1
  170. package/dist/lcm/engine.js +2 -2
  171. package/dist/lcm/index.d.ts +1 -1
  172. package/dist/lcm/index.js +4 -4
  173. package/dist/lcm/tools.d.ts +1 -1
  174. package/dist/lifecycle.d.ts +1 -1
  175. package/dist/live-connectors-runner.d.ts +1 -1
  176. package/dist/local-llm.d.ts +1 -1
  177. package/dist/local-model-endpoint.d.ts +9 -4
  178. package/dist/local-model-endpoint.js +1 -1
  179. package/dist/maintenance/memory-governance.d.ts +1 -1
  180. package/dist/maintenance/memory-governance.js +9 -8
  181. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +9 -8
  182. package/dist/maintenance/rebuild-memory-projection.js +10 -9
  183. package/dist/mcp-memory-inspector-app.d.ts +5 -5
  184. package/dist/memory-action-policy.d.ts +1 -1
  185. package/dist/memory-cache.d.ts +1 -1
  186. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  187. package/dist/memory-projection-store.d.ts +1 -1
  188. package/dist/memory-provenance.d.ts +1 -1
  189. package/dist/memory-worth-outcomes.d.ts +1 -1
  190. package/dist/models-json.d.ts +1 -1
  191. package/dist/namespaces/migrate.d.ts +2 -2
  192. package/dist/namespaces/migrate.js +19 -18
  193. package/dist/namespaces/principal.d.ts +1 -1
  194. package/dist/namespaces/search.d.ts +1 -1
  195. package/dist/namespaces/search.js +9 -9
  196. package/dist/namespaces/storage.d.ts +2 -2
  197. package/dist/namespaces/storage.js +9 -8
  198. package/dist/native-knowledge.d.ts +1 -1
  199. package/dist/operator-toolkit.d.ts +1 -1
  200. package/dist/operator-toolkit.js +28 -27
  201. package/dist/orchestration/maintenance.d.ts +2 -2
  202. package/dist/orchestration/maintenance.js +11 -10
  203. package/dist/{orchestrator-C_OMSIMZ.d.ts → orchestrator-DqPAz8ot.d.ts} +3 -3
  204. package/dist/orchestrator.d.ts +4 -4
  205. package/dist/orchestrator.js +51 -49
  206. package/dist/patterns-cli.d.ts +1 -1
  207. package/dist/policy-runtime.d.ts +1 -1
  208. package/dist/provenance.d.ts +1 -1
  209. package/dist/provenance.js +1 -1
  210. package/dist/qmd-recall-cache.d.ts +1 -1
  211. package/dist/qmd.d.ts +1 -1
  212. package/dist/recall-disclosure-escalation.d.ts +1 -1
  213. package/dist/recall-explain-renderer.d.ts +1 -1
  214. package/dist/recall-explain-renderer.js +3 -3
  215. package/dist/recall-planner-llm.d.ts +1 -1
  216. package/dist/recall-state.d.ts +1 -1
  217. package/dist/recall-tag-filter.d.ts +1 -1
  218. package/dist/recall-xray-cli.d.ts +1 -1
  219. package/dist/recall-xray-cli.js +4 -4
  220. package/dist/recall-xray-renderer.d.ts +1 -1
  221. package/dist/recall-xray-renderer.js +3 -3
  222. package/dist/recall-xray.d.ts +1 -1
  223. package/dist/recall-xray.js +2 -2
  224. package/dist/resolve-auth-token.d.ts +1 -1
  225. package/dist/resume-bundles.js +4 -4
  226. package/dist/retrieval-agents.d.ts +1 -1
  227. package/dist/retrieval-tiers.d.ts +1 -1
  228. package/dist/routing/engine.d.ts +1 -1
  229. package/dist/routing/store.d.ts +1 -1
  230. package/dist/schemas.d.ts +22 -22
  231. package/dist/search/embed-helper.d.ts +1 -1
  232. package/dist/search/factory.d.ts +1 -1
  233. package/dist/search/factory.js +8 -8
  234. package/dist/search/index.d.ts +1 -1
  235. package/dist/search/index.js +14 -14
  236. package/dist/search/lancedb-backend.d.ts +1 -1
  237. package/dist/search/lancedb-backend.js +2 -2
  238. package/dist/search/meilisearch-backend.d.ts +1 -1
  239. package/dist/search/meilisearch-backend.js +2 -2
  240. package/dist/search/noop-backend.d.ts +1 -1
  241. package/dist/search/orama-backend.d.ts +1 -1
  242. package/dist/search/orama-backend.js +2 -2
  243. package/dist/search/port.d.ts +1 -1
  244. package/dist/search/remote-backend.d.ts +1 -1
  245. package/dist/{semantic-consolidation-B8LiYtvx.d.ts → semantic-consolidation-Cl15ksZy.d.ts} +1 -1
  246. package/dist/semantic-consolidation.d.ts +2 -2
  247. package/dist/semantic-consolidation.js +10 -9
  248. package/dist/semantic-rule-promotion.js +9 -8
  249. package/dist/semantic-rule-verifier.d.ts +1 -1
  250. package/dist/semantic-rule-verifier.js +9 -8
  251. package/dist/session-observer-bands.d.ts +1 -1
  252. package/dist/session-observer-state.d.ts +1 -1
  253. package/dist/shared-context/manager.d.ts +1 -1
  254. package/dist/signal.d.ts +1 -1
  255. package/dist/storage.d.ts +3 -3
  256. package/dist/storage.js +9 -8
  257. package/dist/summarizer.d.ts +1 -1
  258. package/dist/summary-snapshot.d.ts +1 -1
  259. package/dist/temporal-supersession.d.ts +1 -1
  260. package/dist/temporal-validity.d.ts +1 -1
  261. package/dist/threading.d.ts +1 -1
  262. package/dist/tier-migration.d.ts +1 -1
  263. package/dist/tier-routing.d.ts +1 -1
  264. package/dist/topics.d.ts +1 -1
  265. package/dist/transcript.d.ts +1 -1
  266. package/dist/transfer/types.d.ts +12 -12
  267. package/dist/trust-score-stage.d.ts +1 -1
  268. package/dist/trust-score.d.ts +1 -1
  269. package/dist/{types-DmTaqob2.d.ts → types-ChQb9D6s.d.ts} +8 -0
  270. package/dist/types.d.ts +1 -1
  271. package/dist/types.js +1 -1
  272. package/dist/utility-runtime.d.ts +1 -1
  273. package/dist/verified-recall.js +9 -8
  274. package/package.json +26 -2
  275. package/src/access-http.ts +68 -1
  276. package/src/admin/admin-surfaces.test.ts +289 -0
  277. package/src/admin/admin-surfaces.ts +138 -7
  278. package/src/bitemporal-dedup-backfill.test.ts +294 -0
  279. package/src/chat/chat-engine.test.ts +66 -1
  280. package/src/chat/chat-http.test.ts +119 -1
  281. package/src/chat/chat-http.ts +252 -97
  282. package/src/chat/chat-session.ts +143 -7
  283. package/src/compat/codex-cli-fallback.ts +23 -0
  284. package/src/compat/codex-subpath-aliases.test.ts +93 -0
  285. package/src/compat/codex-thread-key.ts +23 -0
  286. package/src/config.test.ts +50 -0
  287. package/src/config.ts +21 -4
  288. package/src/content-hash.ts +24 -0
  289. package/src/correction/correction-access-wiring.ts +104 -19
  290. package/src/correction/correction-contract.ts +68 -10
  291. package/src/correction/correction-executor.test.ts +112 -2
  292. package/src/correction/correction-executor.ts +65 -5
  293. package/src/correction/correction-planner.test.ts +47 -0
  294. package/src/correction/correction-planner.ts +40 -1
  295. package/src/correction/correction-storage-integration.test.ts +183 -0
  296. package/src/extraction-faithfulness.test.ts +240 -0
  297. package/src/extraction-faithfulness.ts +58 -6
  298. package/src/extraction-redaction-rules.test.ts +213 -0
  299. package/src/extraction-redaction-rules.ts +208 -0
  300. package/src/faithfulness-config.ts +16 -1
  301. package/src/local-model-endpoint.ts +24 -3
  302. package/src/orchestrator.ts +252 -9
  303. package/src/provenance-extraction.test.ts +266 -0
  304. package/src/provenance.ts +66 -16
  305. package/src/storage.ts +6 -10
  306. package/src/types.ts +8 -0
  307. package/dist/chunk-4R3CGCI5.js.map +0 -1
  308. package/dist/chunk-4SF232E6.js.map +0 -1
  309. package/dist/chunk-6OIDDKAA.js.map +0 -1
  310. package/dist/chunk-7AG54AF3.js.map +0 -1
  311. package/dist/chunk-C4X4QGIO.js.map +0 -1
  312. package/dist/chunk-C6BWLYW5.js.map +0 -1
  313. package/dist/chunk-KLFYKC3K.js.map +0 -1
  314. package/dist/chunk-MDBZTH7N.js.map +0 -1
  315. package/dist/chunk-XGTBNVIU.js.map +0 -1
  316. package/dist/chunk-Z3FGC3QE.js.map +0 -1
  317. /package/dist/{chunk-HCVWF657.js.map → chunk-2KAYTPPT.js.map} +0 -0
  318. /package/dist/{chunk-ZK2L72VN.js.map → chunk-37436GML.js.map} +0 -0
  319. /package/dist/{chunk-SC2YAWRF.js.map → chunk-3TSTGI6F.js.map} +0 -0
  320. /package/dist/{chunk-FACTVMXQ.js.map → chunk-4H4F3BFL.js.map} +0 -0
  321. /package/dist/{chunk-WAFDHKES.js.map → chunk-4NOI577P.js.map} +0 -0
  322. /package/dist/{chunk-YQMPUYHE.js.map → chunk-4NR2PDZ5.js.map} +0 -0
  323. /package/dist/{chunk-TAPSNIMA.js.map → chunk-5CEJH5ZN.js.map} +0 -0
  324. /package/dist/{chunk-PKMQK2WY.js.map → chunk-773DPI6T.js.map} +0 -0
  325. /package/dist/{chunk-FXCIOLRB.js.map → chunk-ASKXIAHD.js.map} +0 -0
  326. /package/dist/{chunk-5OPYYPJN.js.map → chunk-CBWI22JN.js.map} +0 -0
  327. /package/dist/{chunk-ZOHMPFOB.js.map → chunk-CKFLLAIS.js.map} +0 -0
  328. /package/dist/{chunk-GZQXOQQ2.js.map → chunk-CSRXQ6NB.js.map} +0 -0
  329. /package/dist/{chunk-QR67FU5G.js.map → chunk-CTOQEZSN.js.map} +0 -0
  330. /package/dist/{chunk-ZUDM75KG.js.map → chunk-DCWIQFNA.js.map} +0 -0
  331. /package/dist/{chunk-6CWGS2LY.js.map → chunk-DKJCRGWM.js.map} +0 -0
  332. /package/dist/{chunk-JJJCVCCQ.js.map → chunk-DMQWV6SQ.js.map} +0 -0
  333. /package/dist/{chunk-F3XZN24Z.js.map → chunk-DRUDC2UX.js.map} +0 -0
  334. /package/dist/{chunk-4WZ3J7M6.js.map → chunk-EY6MDMHK.js.map} +0 -0
  335. /package/dist/{chunk-YNDLCWXS.js.map → chunk-EZ25VE3G.js.map} +0 -0
  336. /package/dist/{chunk-6SQQOJ4U.js.map → chunk-GKRLPHPU.js.map} +0 -0
  337. /package/dist/{chunk-D7EBTQ24.js.map → chunk-HOHVIVDR.js.map} +0 -0
  338. /package/dist/{chunk-RKNJBZ55.js.map → chunk-JBPKEARU.js.map} +0 -0
  339. /package/dist/{chunk-UBHVAGO7.js.map → chunk-JYLFZWUX.js.map} +0 -0
  340. /package/dist/{chunk-LD53WPMU.js.map → chunk-LQ6JI4VH.js.map} +0 -0
  341. /package/dist/{chunk-WM7DNKBD.js.map → chunk-M4V2JVSZ.js.map} +0 -0
  342. /package/dist/{chunk-I2HL5M6T.js.map → chunk-MJIHJ7OG.js.map} +0 -0
  343. /package/dist/{chunk-J334N6QV.js.map → chunk-MLKWJOAJ.js.map} +0 -0
  344. /package/dist/{chunk-DF3I6JGP.js.map → chunk-NSA5ZRUL.js.map} +0 -0
  345. /package/dist/{chunk-VI5SGGXB.js.map → chunk-OEEW4KJA.js.map} +0 -0
  346. /package/dist/{chunk-NT36GU6X.js.map → chunk-R7IYU5DZ.js.map} +0 -0
  347. /package/dist/{chunk-TT5U3UDO.js.map → chunk-SNKPUJHR.js.map} +0 -0
  348. /package/dist/{chunk-T55EGZSJ.js.map → chunk-UVPL565C.js.map} +0 -0
  349. /package/dist/{chunk-YQGHW5ML.js.map → chunk-WRFKZEO6.js.map} +0 -0
  350. /package/dist/{chunk-H7HUQIY7.js.map → chunk-Y4YD5TYW.js.map} +0 -0
  351. /package/dist/{chunk-YUYPWJD3.js.map → chunk-YOLZS7NY.js.map} +0 -0
  352. /package/dist/{forget-OEE5OELK.js.map → forget-WYLR4ZFV.js.map} +0 -0
@@ -15,6 +15,15 @@ async function callOpenAiCompatibleChat(endpoint, messages, options, fetchImpl =
15
15
  const url = joinBaseUrl(endpoint.baseUrl, "/chat/completions");
16
16
  const controller = new AbortController();
17
17
  const timer = setTimeout(() => controller.abort(), options.timeoutMs);
18
+ const batchSignal = options.signal;
19
+ const onBatchAbort = () => controller.abort();
20
+ if (batchSignal) {
21
+ if (batchSignal.aborted) {
22
+ controller.abort();
23
+ } else {
24
+ batchSignal.addEventListener("abort", onBatchAbort, { once: true });
25
+ }
26
+ }
18
27
  try {
19
28
  const body = {
20
29
  model: endpoint.model,
@@ -45,6 +54,7 @@ async function callOpenAiCompatibleChat(endpoint, messages, options, fetchImpl =
45
54
  return { content, modelUsed: extractModel(parsed) ?? endpoint.model };
46
55
  } finally {
47
56
  clearTimeout(timer);
57
+ if (batchSignal) batchSignal.removeEventListener("abort", onBatchAbort);
48
58
  }
49
59
  }
50
60
  function joinBaseUrl(base, path) {
@@ -76,4 +86,4 @@ export {
76
86
  resolveCorrectionIntentEndpoint,
77
87
  callOpenAiCompatibleChat
78
88
  };
79
- //# sourceMappingURL=chunk-XGTBNVIU.js.map
89
+ //# sourceMappingURL=chunk-AAD2ZS6P.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/local-model-endpoint.ts"],"sourcesContent":["/**\n * Local fine-tuned model endpoint resolver + openai-compatible caller\n * (issue #1585 model-lab integration).\n *\n * Remnic's two classification workloads — the extraction faithfulness gate\n * (#1576) and passive-correction intent detection (#1581) — can run on small\n * fine-tuned models served locally (Ollama / vLLM) instead of prompted\n * frontier LLMs. The model-lab (`model-lab/`) produces those models; this\n * module is the config-side half: it resolves the optional local endpoint\n * pointer from config and, when set, makes a minimal openai-compatible\n * chat-completions call to it.\n *\n * Design:\n * - **Pointers are optional.** Empty defaults preserve the existing routing\n * chain exactly (rule 39 / byte-identical pre-feature). A resolver returns\n * `null` when the pointer is unset, so callers short-circuit before any\n * network.\n * - **Graceful degradation.** A local-endpoint failure (network, non-2xx,\n * malformed body, timeout) returns `null`; callers fall back to the\n * configured chain (checklist §4 — never block writes on a classifier).\n * - **No inline casts.** The fetch JSON is narrowed with `in` / `typeof`\n * guards (project rule: never assert a shape to read one property).\n * - **Injectable fetch.** `callOpenAiCompatibleChat` takes an optional\n * `fetchImpl` so the caller is unit-testable without a live server.\n */\n\nimport type { PluginConfig } from \"./types.js\";\n\n/** A resolved local endpoint: where to call + which model to name. */\nexport interface LocalModelEndpoint {\n /** Base URL, e.g. `http://localhost:11434/v1` (no trailing slash required). */\n baseUrl: string;\n /** Model name the server expects, e.g. `remnic-faithfulness-gate-v1`. */\n model: string;\n}\n\n/** A chat message in the openai-compatible shape this caller sends. */\nexport interface EndpointChatMessage {\n role: \"system\" | \"user\" | \"assistant\";\n content: string;\n}\n\n/** Options for a single local-endpoint chat call. */\nexport interface EndpointChatOptions {\n /** Per-call timeout in ms. Bounds each attempt so one slow server can't\n * starve the batch (matches the local-LLM precedent). */\n timeoutMs: number;\n /** Optional batch AbortSignal forwarded into the probe (issue #1700 nit #5).\n * When the batch budget elapses (or the caller aborts), the in-flight probe\n * aborts immediately instead of waiting for its own `timeoutMs` — a\n * micro-optimization, not a correctness fix (the outer race already bounds\n * the total). Undefined preserves the prior per-attempt-only behavior. */\n signal?: AbortSignal;\n /** Sampling temperature — classification wants low entropy (0.0–0.2). */\n temperature?: number;\n /** Max output tokens. */\n maxTokens?: number;\n /** Request JSON-object output (the gate emits a JSON verdict array). */\n responseFormatJson?: boolean;\n}\n\n/** Result of a local-endpoint chat call. */\nexport interface EndpointChatResult {\n content: string;\n /** The model the server reports it used (falls back to the requested name). */\n modelUsed: string;\n}\n\n/**\n * Resolve the faithfulness-gate local endpoint from config (issue #1585).\n *\n * Returns the endpoint only when BOTH a base URL and a model name are\n * configured; otherwise `null` (gate uses its existing routing chain). The\n * gate's verifier needs a model identity, so a base URL alone is intentionally\n * insufficient — silently calling whatever the server's default model is would\n * be an unreviewed behavioral change.\n */\nexport function resolveFaithfulnessGateEndpoint(\n config: Pick<PluginConfig, \"extractionFaithfulnessModel\" | \"extractionFaithfulnessBaseUrl\">,\n): LocalModelEndpoint | null {\n const baseUrl = config.extractionFaithfulnessBaseUrl.trim();\n const model = config.extractionFaithfulnessModel.trim();\n if (!baseUrl || !model) return null;\n return { baseUrl, model };\n}\n\n/**\n * Resolve the correction-intent local endpoint from config (issue #1581/#1585).\n *\n * Same contract as the gate resolver. Consumption by the model-backed\n * detector is the consuming child's job — the rule-based\n * `detectPassiveCorrections` remains the default path; this pointer lets a\n * future model-backed detector route to a fine-tuned local classifier when an\n * operator configures one.\n */\nexport function resolveCorrectionIntentEndpoint(\n config: Pick<PluginConfig, \"correctionIntentModel\" | \"correctionIntentBaseUrl\">,\n): LocalModelEndpoint | null {\n const baseUrl = config.correctionIntentBaseUrl.trim();\n const model = config.correctionIntentModel.trim();\n if (!baseUrl || !model) return null;\n return { baseUrl, model };\n}\n\ntype FetchLike = typeof fetch;\n\n/**\n * Make an openai-compatible chat-completions call to a local endpoint.\n *\n * POSTs to `${baseUrl}/chat/completions` with `{ model, messages, ... }` and\n * returns the first choice's content. Any failure (non-2xx, network error,\n * malformed body, timeout) returns `null` so callers fall back gracefully.\n *\n * The response is narrowed with runtime guards — never an unchecked cast — so\n * a surprising server response fails closed (`null`) rather than reading a\n * fabricated field.\n */\nexport async function callOpenAiCompatibleChat(\n endpoint: LocalModelEndpoint,\n messages: EndpointChatMessage[],\n options: EndpointChatOptions,\n fetchImpl: FetchLike = fetch,\n): Promise<EndpointChatResult | null> {\n const url = joinBaseUrl(endpoint.baseUrl, \"/chat/completions\");\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), options.timeoutMs);\n // Forward the batch AbortSignal into the probe (issue #1700 nit #5): if the\n // batch budget already elapsed, abort the in-flight probe immediately rather\n // than waiting for the probe's own timeoutMs. AbortSignal.any is ES2024\n // (forbidden here); wire the listener manually + guard the already-aborted\n // case. The fetch still uses the probe's controller, so clearing the timer\n // below is the only cleanup needed.\n const batchSignal = options.signal;\n const onBatchAbort = () => controller.abort();\n if (batchSignal) {\n if (batchSignal.aborted) {\n controller.abort();\n } else {\n batchSignal.addEventListener(\"abort\", onBatchAbort, { once: true });\n }\n }\n try {\n const body: Record<string, unknown> = {\n model: endpoint.model,\n messages,\n temperature: options.temperature ?? 0.1,\n };\n if (typeof options.maxTokens === \"number\") {\n body.max_tokens = options.maxTokens;\n }\n if (options.responseFormatJson) {\n body.response_format = { type: \"json_object\" };\n }\n let response: Response;\n try {\n response = await fetchImpl(url, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n } catch {\n // Network error or abort — fail closed, let the caller fall back.\n return null;\n }\n if (!response.ok) return null;\n const parsed: unknown = await response.json().catch(() => null);\n const content = extractFirstChoiceContent(parsed);\n if (content === null) return null;\n return { content, modelUsed: extractModel(parsed) ?? endpoint.model };\n } finally {\n clearTimeout(timer);\n if (batchSignal) batchSignal.removeEventListener(\"abort\", onBatchAbort);\n }\n}\n\n/** Join a base URL and a path, tolerating a trailing slash on the base. */\nfunction joinBaseUrl(base: string, path: string): string {\n return base.endsWith(\"/\") ? `${base.slice(0, -1)}${path}` : `${base}${path}`;\n}\n\n/**\n * Narrow the openai-compatible response and pull the first choice's content.\n *\n * `in` / `typeof` guards only — no `as` cast (project rule). Returns `null`\n * for any shape that isn't `{ choices: [{ message: { content: string } }, …] }`.\n */\nfunction extractFirstChoiceContent(data: unknown): string | null {\n if (!data || typeof data !== \"object\") return null;\n // After `in`, TS narrows the property to `unknown` — read it directly, no cast.\n if (!(\"choices\" in data) || !Array.isArray(data.choices)) return null;\n const choices: unknown[] = data.choices;\n for (const choice of choices) {\n if (!choice || typeof choice !== \"object\") continue;\n if (!(\"message\" in choice)) continue;\n const message = choice.message;\n if (!message || typeof message !== \"object\") continue;\n if (!(\"content\" in message)) continue;\n const content = message.content;\n if (typeof content === \"string\" && content.length > 0) return content;\n }\n return null;\n}\n\n/** Narrow the `model` field from the response (best-effort, may be absent). */\nfunction extractModel(data: unknown): string | null {\n if (!data || typeof data !== \"object\" || !(\"model\" in data)) return null;\n const model = data.model;\n return typeof model === \"string\" && model.length > 0 ? model : null;\n}\n"],"mappings":"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","names":[]}
@@ -1,12 +1,21 @@
1
1
  import {
2
2
  enqueuePassiveCorrectionNotification
3
- } from "./chunk-4WZ3J7M6.js";
3
+ } from "./chunk-EY6MDMHK.js";
4
4
  import {
5
5
  stripAttributesSuffix
6
6
  } from "./chunk-SVOZFLIQ.js";
7
7
  import {
8
8
  serializeMutations
9
9
  } from "./chunk-LTJAMRGI.js";
10
+ import {
11
+ supersessionKeysForFact
12
+ } from "./chunk-TKZ3AL5V.js";
13
+ import {
14
+ computeContentHash
15
+ } from "./chunk-W5H6ZRPT.js";
16
+ import {
17
+ sanitizeMemoryContent
18
+ } from "./chunk-5GKPFL3S.js";
10
19
  import {
11
20
  log
12
21
  } from "./chunk-NU3CSQ4H.js";
@@ -79,22 +88,68 @@ function validateRedactionPattern(pattern) {
79
88
  `redaction_rule.pattern exceeds the ${REDACTION_PATTERN_MAX}-character bound.`
80
89
  );
81
90
  }
82
- if (isRegexLike(trimmed) && isOverlyBroadRegex(trimmed)) {
91
+ if (isRegexLike(trimmed) && isUnsafeRedactionRegex(trimmed)) {
83
92
  throw new CorrectionContractError(
84
- "redaction_rule.pattern is too broad \u2014 use a bounded literal or a more specific pattern."
93
+ "redaction_rule.pattern is unsafe \u2014 use a bounded literal or a regex without nested quantifiers / overlapping alternation."
85
94
  );
86
95
  }
96
+ if (isRegexLike(trimmed)) {
97
+ const regexBody = trimmed.slice(1, -1);
98
+ if (regexBody.length === 0) {
99
+ throw new CorrectionContractError("redaction_rule.pattern body is empty \u2014 use a non-empty regex.");
100
+ }
101
+ try {
102
+ if (new RegExp(regexBody).test("")) {
103
+ throw new CorrectionContractError(
104
+ "redaction_rule.pattern matches the empty string \u2014 it would withhold every fact."
105
+ );
106
+ }
107
+ } catch (e) {
108
+ if (e instanceof CorrectionContractError) throw e;
109
+ }
110
+ }
87
111
  return trimmed;
88
112
  }
89
113
  function isRegexLike(pattern) {
90
- if (pattern.startsWith("/") && pattern.endsWith("/") && pattern.length >= 2) return true;
91
- return /[\\^$.|?*+()[\]{}]/.test(pattern);
114
+ return pattern.startsWith("/") && pattern.endsWith("/") && pattern.length >= 2;
92
115
  }
93
- function isOverlyBroadRegex(pattern) {
116
+ function isUnsafeRedactionRegex(pattern) {
94
117
  const body = pattern.startsWith("/") && pattern.endsWith("/") ? pattern.slice(1, -1) : pattern;
95
118
  if (/(?:^|[^\\])\(\.\*\)|(?:^|[^\\])\.\*|(?:^|[^\\])\.\+|^\.([^*+]?)$/.test(body)) {
96
119
  return true;
97
120
  }
121
+ if (body.length > 512) return true;
122
+ for (let i = 0; i < body.length; i++) {
123
+ if (body[i] !== "(") continue;
124
+ let depth = 1;
125
+ let j = i + 1;
126
+ while (j < body.length && depth > 0) {
127
+ if (body[j] === "\\") {
128
+ j += 2;
129
+ continue;
130
+ }
131
+ if (body[j] === "(") depth++;
132
+ else if (body[j] === ")") depth--;
133
+ j++;
134
+ }
135
+ if (depth !== 0) continue;
136
+ const afterGroup = body[j];
137
+ if (afterGroup !== "+" && afterGroup !== "*" && afterGroup !== "{") continue;
138
+ const groupBody = body.slice(i + 1, j - 1);
139
+ if (/[+*?]$/.test(groupBody) || /\{\d+,?\d*\}[+*?]?$/.test(groupBody)) {
140
+ return true;
141
+ }
142
+ if (groupBody.includes("|")) {
143
+ const branches = groupBody.split("|");
144
+ if (branches.length >= 2) {
145
+ const firstChars = new Set(branches.map((b) => b[0]).filter(Boolean));
146
+ if (firstChars.size < branches.filter((b) => b.length > 0).length) {
147
+ return true;
148
+ }
149
+ }
150
+ }
151
+ i = j;
152
+ }
98
153
  return false;
99
154
  }
100
155
  function validateCorrectionAction(action) {
@@ -198,11 +253,13 @@ var CorrectionContractError = class extends Error {
198
253
 
199
254
  // src/correction/correction-access-wiring.ts
200
255
  import path2 from "path";
256
+ import { createHash } from "crypto";
201
257
  import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
202
258
 
203
259
  // src/correction/correction-planner.ts
204
260
  import { mkdir, readFile, rename, unlink, readdir, writeFile } from "fs/promises";
205
261
  import path from "path";
262
+ var REDACTED_REQUEST_TEXT = "[redacted \u2014 never-store/redaction correction text withheld from the pending-plan file]";
206
263
  var CorrectionPlanner = class {
207
264
  constructor(deps) {
208
265
  this.deps = deps;
@@ -386,10 +443,12 @@ var CorrectionPlanner = class {
386
443
  async persist(plan) {
387
444
  const dir = await this.pendingDir(plan.namespace);
388
445
  const target = path.join(dir, `${plan.planId}.json`);
446
+ const sensitive = plan.classification === "never_store" || plan.actions.some((a) => a.kind === "redaction_rule");
447
+ const persistedPlan = sensitive ? { ...plan, request: { ...plan.request, text: REDACTED_REQUEST_TEXT } } : plan;
389
448
  await serializeMutations(`correction-plan:${target}`, async () => {
390
449
  await mkdir(dir, { recursive: true });
391
450
  const tmp = `${target}.${process.pid}.${Date.now().toString(36)}.tmp`;
392
- await writeFile(tmp, `${JSON.stringify(plan)}
451
+ await writeFile(tmp, `${JSON.stringify(persistedPlan)}
393
452
  `, "utf-8");
394
453
  await rename(tmp, target);
395
454
  });
@@ -451,6 +510,11 @@ var CorrectionPlanner = class {
451
510
  const plan = parsePlan(raw);
452
511
  if (!plan) return;
453
512
  plan.status = status;
513
+ if (status !== "applying") {
514
+ plan.actions = plan.actions.map(
515
+ (a) => a.kind === "redaction_rule" ? { ...a, pattern: "[redacted \u2014 pattern applied]" } : a
516
+ );
517
+ }
454
518
  const tmp = `${file}.${process.pid}.${Date.now().toString(36)}.tmp`;
455
519
  await writeFile(tmp, `${JSON.stringify(plan)}
456
520
  `, "utf-8");
@@ -652,7 +716,7 @@ var CorrectionExecutor = class {
652
716
  continue;
653
717
  }
654
718
  const destId = await this.deps.rescopeMemory(namespace, action.memoryId, action.toNamespace);
655
- results.push({ action, status: "applied", memoryId: action.memoryId });
719
+ results.push({ action, status: "applied", memoryId: destId });
656
720
  appliedTouched.push(action.memoryId);
657
721
  try {
658
722
  await this.deps.propagate(action.toNamespace, [destId]);
@@ -726,7 +790,14 @@ var CorrectionExecutor = class {
726
790
  sourceMemoryId: memoryId,
727
791
  rawContent: memory.rawContent,
728
792
  ...memory.entityRef ? { entityRef: memory.entityRef } : {},
729
- ...memory.supersessionKey ? { supersessionKey: memory.supersessionKey } : {}
793
+ ...memory.supersessionKey ? { supersessionKey: memory.supersessionKey } : {},
794
+ // #1672 item 4: carry the canonical contentHash (exact tier) and the
795
+ // full supersession-key set (keyed tier) so paraphrased re-observations
796
+ // of the same supersession identity are blocked, not just the literal
797
+ // body. Without these the tombstone projected from a structured fact
798
+ // dropped both fields and the fact could resurrect.
799
+ ...memory.contentHash ? { contentHash: memory.contentHash } : {},
800
+ ...memory.supersessionKeys && memory.supersessionKeys.length > 0 ? { supersessionKeys: memory.supersessionKeys } : {}
730
801
  });
731
802
  await this.deps.retireMemory(namespace, memoryId, {
732
803
  status: reason === "supersession" ? "superseded" : "retracted",
@@ -745,9 +816,15 @@ var CorrectionExecutor = class {
745
816
  }
746
817
  }
747
818
  };
819
+ var CORRECTION_ERROR_MAX = 500;
820
+ function sanitizeErrorMessage(raw) {
821
+ const stripped = raw.replace(/(^|[\s:'"(])\/(?:[^\s'">)\\]+\/)+[^\s'">)\\]*/g, "$1<path>").replace(/(^|[\s:'"(])[A-Za-z]:\\[^\s'">)\\]+(?:\\[^\s'">) ]*)*/g, "$1<path>");
822
+ const trimmed = stripped.trim();
823
+ return trimmed.length > CORRECTION_ERROR_MAX ? `${trimmed.slice(0, CORRECTION_ERROR_MAX)}\u2026` : trimmed;
824
+ }
748
825
  function errMsg(err) {
749
- if (err instanceof Error) return err.message;
750
- return String(err);
826
+ const raw = err instanceof Error ? err.message : String(err);
827
+ return sanitizeErrorMessage(raw);
751
828
  }
752
829
 
753
830
  // src/correction/correction-service.ts
@@ -868,7 +945,7 @@ async function searchMemories(wiring, text, namespaces, limit) {
868
945
  const storage = await wiring.orchestrator.getStorage(ns);
869
946
  const all = await storage.readAllMemories();
870
947
  for (const m of all) {
871
- if (m.frontmatter.status && m.frontmatter.status !== "active") continue;
948
+ if (!isEligibleCorrectionCandidate(m)) continue;
872
949
  const hay = `${m.content} ${m.frontmatter.tags?.join(" ") ?? ""}`.toLowerCase();
873
950
  let hits = 0;
874
951
  for (const tok of tokens) {
@@ -1016,7 +1093,7 @@ async function expandEntityNeighbors(wiring, seedIds, namespaces, limit) {
1016
1093
  for (const m of all) {
1017
1094
  if (out.length >= limit) break;
1018
1095
  if (seen.has(m.frontmatter.id)) continue;
1019
- if (m.frontmatter.status && m.frontmatter.status !== "active") continue;
1096
+ if (!isEligibleCorrectionCandidate(m)) continue;
1020
1097
  if (m.frontmatter.entityRef && seedRefs.has(m.frontmatter.entityRef)) {
1021
1098
  out.push(toCandidate(m, ns, 0.5));
1022
1099
  seen.add(m.frontmatter.id);
@@ -1107,9 +1184,13 @@ async function applyEditMemory(wiring, namespace, memoryId, patch) {
1107
1184
  const storage = await wiring.orchestrator.getStorage(namespace);
1108
1185
  const existing = await storage.getMemoryById(memoryId);
1109
1186
  if (!existing) throw new CorrectionContractError(`memory not found for edit: ${memoryId}`);
1187
+ const contentHashForPatch = existing.frontmatter.category === "fact" ? computeContentHash(sanitizeMemoryContent(patch).text) : void 0;
1110
1188
  await storage.writeMemoryFrontmatter(
1111
1189
  { ...existing, content: patch },
1112
- { updated: (/* @__PURE__ */ new Date()).toISOString() }
1190
+ {
1191
+ updated: (/* @__PURE__ */ new Date()).toISOString(),
1192
+ ...contentHashForPatch ? { contentHash: contentHashForPatch } : {}
1193
+ }
1113
1194
  );
1114
1195
  return memoryId;
1115
1196
  }
@@ -1173,26 +1254,42 @@ async function rescopeMemoryFn(wiring, namespace, memoryId, toNamespace) {
1173
1254
  async function appendTombstoneFn(wiring, namespace, input) {
1174
1255
  const storage = await wiring.orchestrator.getStorage(namespace);
1175
1256
  const enabled = typeof storage.isTombstonesEnabled === "function" ? storage.isTombstonesEnabled() : true;
1176
- const result = await storage.appendTombstone({
1177
- reason: input.reason,
1178
- createdBy: "user_correction",
1179
- sourceMemoryId: input.sourceMemoryId,
1180
- rawContent: input.rawContent,
1181
- ...input.entityRef ? { entityRef: input.entityRef } : {},
1182
- ...input.supersessionKey ? { supersessionKey: input.supersessionKey } : {}
1183
- });
1184
- if (result === null && enabled) {
1185
- throw new CorrectionContractError(
1186
- `tombstone persistence failed for memory ${input.sourceMemoryId} (tombstones enabled but store returned null \u2014 I/O error swallowed)`
1187
- );
1257
+ const keys = input.supersessionKeys && input.supersessionKeys.length > 0 ? input.supersessionKeys : input.supersessionKey ? [input.supersessionKey] : [void 0];
1258
+ const writtenIds = [];
1259
+ let firstId = null;
1260
+ for (const key of keys) {
1261
+ const result = await storage.appendTombstone({
1262
+ reason: input.reason,
1263
+ createdBy: "user_correction",
1264
+ sourceMemoryId: input.sourceMemoryId,
1265
+ rawContent: input.rawContent,
1266
+ ...input.entityRef ? { entityRef: input.entityRef } : {},
1267
+ ...key ? { supersessionKey: key } : {},
1268
+ ...input.contentHash ? { contentHash: input.contentHash } : {}
1269
+ });
1270
+ if (result === null && enabled) {
1271
+ for (const id of writtenIds) {
1272
+ try {
1273
+ await storage.revokeTombstone(id, "user_correction");
1274
+ } catch {
1275
+ }
1276
+ }
1277
+ throw new CorrectionContractError(
1278
+ `tombstone persistence failed for memory ${input.sourceMemoryId} (tombstones enabled but store returned null \u2014 I/O error swallowed)`
1279
+ );
1280
+ }
1281
+ if (firstId === null) firstId = result;
1282
+ if (result) writtenIds.push(result);
1188
1283
  }
1189
- return result;
1284
+ return firstId;
1190
1285
  }
1191
1286
  async function registerRedactionRuleFn(wiring, namespace, pattern) {
1192
1287
  const storage = await wiring.orchestrator.getStorage(namespace);
1193
1288
  const dir = path2.join(storage.dir, "state", "corrections", "redaction-rules");
1194
1289
  await mkdir2(dir, { recursive: true });
1195
- const slug = pattern.replace(/[^a-zA-Z0-9]+/g, "-").slice(0, 64) || "rule";
1290
+ const slugBase = pattern.replace(/[^a-zA-Z0-9]+/g, "-").slice(0, 48) || "rule";
1291
+ const patternHash = createHash("sha256").update(pattern).digest("hex").slice(0, 16);
1292
+ const slug = `${slugBase}-${patternHash}`;
1196
1293
  await writeFile2(
1197
1294
  path2.join(dir, `${slug}.json`),
1198
1295
  `${JSON.stringify({ pattern, namespace, createdAt: (/* @__PURE__ */ new Date()).toISOString() })}
@@ -1252,15 +1349,27 @@ function toCandidate(m, namespace, score) {
1252
1349
  // candidate for diff rendering if needed.
1253
1350
  };
1254
1351
  }
1352
+ function isEligibleCorrectionCandidate(m) {
1353
+ if (m.frontmatter.status && m.frontmatter.status !== "active") return false;
1354
+ if (typeof m.frontmatter.archivedAt === "string" && m.frontmatter.archivedAt.length > 0) return false;
1355
+ return true;
1356
+ }
1255
1357
  function toExecutorMemory(m) {
1256
1358
  const fm = m.frontmatter;
1257
1359
  const rawBody = fm.structuredAttributes ? stripAttributesSuffix(m.content) : m.content;
1360
+ const supersessionKeys = supersessionKeysForFact({
1361
+ entityRef: fm.entityRef,
1362
+ structuredAttributes: fm.structuredAttributes
1363
+ });
1258
1364
  return {
1259
1365
  memoryId: fm.id,
1260
1366
  content: m.content,
1261
1367
  category: fm.category,
1262
1368
  rawContent: rawBody,
1263
- ...fm.entityRef ? { entityRef: fm.entityRef } : {}
1369
+ ...fm.entityRef ? { entityRef: fm.entityRef } : {},
1370
+ ...supersessionKeys.length > 0 ? { supersessionKeys } : {},
1371
+ ...supersessionKeys.length > 0 ? { supersessionKey: supersessionKeys[0] } : {},
1372
+ ...typeof fm.contentHash === "string" && fm.contentHash.length > 0 ? { contentHash: fm.contentHash } : {}
1264
1373
  };
1265
1374
  }
1266
1375
  function isCorrectionFeatureEnabled(config) {
@@ -1685,4 +1794,4 @@ export {
1685
1794
  capturePassiveCorrections,
1686
1795
  clusterByKey
1687
1796
  };
1688
- //# sourceMappingURL=chunk-Z3FGC3QE.js.map
1797
+ //# sourceMappingURL=chunk-AQLOP5F4.js.map