@remnic/core 9.29.0 → 9.30.0

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 (359) hide show
  1. package/dist/access-admin-ops-surface.d.ts +11 -11
  2. package/dist/access-admin-ops-surface.js +19 -18
  3. package/dist/access-authorization-probe.d.ts +11 -11
  4. package/dist/access-authorization-probe.js +20 -19
  5. package/dist/access-boundary.d.ts +11 -11
  6. package/dist/access-boundary.js +19 -18
  7. package/dist/access-citation-namespace.js +2 -2
  8. package/dist/access-cli.js +45 -44
  9. package/dist/access-cli.js.map +1 -1
  10. package/dist/access-health-types.d.ts +1 -1
  11. package/dist/access-http-lcm-compaction.d.ts +11 -11
  12. package/dist/access-http.d.ts +11 -11
  13. package/dist/access-http.js +25 -24
  14. package/dist/access-identity-continuity-surface.d.ts +8 -8
  15. package/dist/access-identity-continuity-surface.js +19 -18
  16. package/dist/access-lcm-surface.d.ts +10 -10
  17. package/dist/access-lcm-surface.js +19 -18
  18. package/dist/access-mcp.d.ts +11 -11
  19. package/dist/access-mcp.js +23 -22
  20. package/dist/access-memory-search-fanout.d.ts +2 -2
  21. package/dist/{access-namespace-preflight-DCXBkDp0.d.ts → access-namespace-preflight-VfXssvoI.d.ts} +1 -1
  22. package/dist/access-namespace-preflight.d.ts +3 -3
  23. package/dist/access-namespace-preflight.js +19 -18
  24. package/dist/access-observe-write-surface.d.ts +10 -10
  25. package/dist/access-observe-write-surface.js +19 -18
  26. package/dist/access-operations-batch.js +20 -19
  27. package/dist/access-operations.d.ts +11 -11
  28. package/dist/access-operations.js +22 -21
  29. package/dist/access-recall-concurrency.d.ts +11 -11
  30. package/dist/access-recall-concurrency.js +19 -18
  31. package/dist/access-recall-response.d.ts +10 -10
  32. package/dist/access-recall-response.js +19 -18
  33. package/dist/access-recall-surface.d.ts +10 -10
  34. package/dist/access-recall-surface.js +19 -18
  35. package/dist/access-schema.d.ts +7 -7
  36. package/dist/access-schema.js +3 -3
  37. package/dist/{access-service-DvPW_M5j.d.ts → access-service-B5RwVsTV.d.ts} +7 -7
  38. package/dist/access-service.d.ts +11 -11
  39. package/dist/access-service.js +19 -18
  40. package/dist/access-surface-catalog.d.ts +11 -11
  41. package/dist/access-wearables-meetings-surface.d.ts +4 -3
  42. package/dist/action-confidence.d.ts +1 -1
  43. package/dist/active-memory-bridge.d.ts +1 -1
  44. package/dist/active-recall.d.ts +1 -1
  45. package/dist/active-recall.js +3 -3
  46. package/dist/behavior-learner.d.ts +1 -1
  47. package/dist/behavior-signals.d.ts +1 -1
  48. package/dist/bootstrap.d.ts +8 -8
  49. package/dist/briefing.d.ts +3 -2
  50. package/dist/briefing.js +10 -9
  51. package/dist/buffer-surprise-report.d.ts +1 -1
  52. package/dist/buffer.d.ts +3 -2
  53. package/dist/bulk-import/index.d.ts +3 -3
  54. package/dist/calibration.d.ts +1 -1
  55. package/dist/capabilities.d.ts +1 -1
  56. package/dist/{catalog-BIVgftWu.d.ts → catalog-V7inUQdp.d.ts} +1 -1
  57. package/dist/causal-behavior.d.ts +1 -1
  58. package/dist/causal-consolidation.d.ts +1 -1
  59. package/dist/causal-consolidation.js +11 -10
  60. package/dist/causal-consolidation.js.map +1 -1
  61. package/dist/causal-trajectory-graph.d.ts +1 -1
  62. package/dist/{chunk-KUJQHXPH.js → chunk-2EUVEDF5.js} +2 -2
  63. package/dist/{chunk-2XC73SHY.js → chunk-4WKA6I65.js} +20 -20
  64. package/dist/{chunk-2XC73SHY.js.map → chunk-4WKA6I65.js.map} +1 -1
  65. package/dist/{chunk-AIK5W3IW.js → chunk-5TFP4CUL.js} +68 -2
  66. package/dist/chunk-5TFP4CUL.js.map +1 -0
  67. package/dist/{chunk-EVX44I7C.js → chunk-5W4ZLBEZ.js} +9 -9
  68. package/dist/{chunk-P3MH72CI.js → chunk-62U4J2GN.js} +2 -2
  69. package/dist/{chunk-YGHMSDLK.js → chunk-66772WBP.js} +2 -2
  70. package/dist/{chunk-EP5BVCRI.js → chunk-6BNE62PM.js} +2 -2
  71. package/dist/{chunk-AAP5T6QG.js → chunk-6DNMUYEE.js} +2 -2
  72. package/dist/{chunk-SG265CVF.js → chunk-6FUPCJUL.js} +7 -7
  73. package/dist/{chunk-WZ7UB7XQ.js → chunk-6U7F52DE.js} +19 -19
  74. package/dist/{chunk-E4OCKU67.js → chunk-7XC2HX75.js} +2 -2
  75. package/dist/{chunk-OVRQLAYR.js → chunk-AZ5BTEKX.js} +2 -2
  76. package/dist/{chunk-2HNUMF5V.js → chunk-CZRYLSSW.js} +3 -3
  77. package/dist/chunk-FBUE6PD3.js +1769 -0
  78. package/dist/chunk-FBUE6PD3.js.map +1 -0
  79. package/dist/{chunk-WONS4RZ2.js → chunk-FDAMS4PK.js} +2 -2
  80. package/dist/{chunk-WL5EBRDH.js → chunk-FFAZ2XFU.js} +9 -8
  81. package/dist/chunk-FFAZ2XFU.js.map +1 -0
  82. package/dist/{chunk-Q6VFVAKZ.js → chunk-GIBMDSJ2.js} +2 -2
  83. package/dist/{chunk-ZXAGJFHJ.js → chunk-H5CPS5JP.js} +3 -3
  84. package/dist/{chunk-NBDCZWP4.js → chunk-I5NLEENJ.js} +2 -2
  85. package/dist/{chunk-DRBXHRXE.js → chunk-IB26HVAJ.js} +2 -2
  86. package/dist/{chunk-XEQ7OT7U.js → chunk-IC6CBHCA.js} +3 -3
  87. package/dist/{chunk-CMRQ34J5.js → chunk-JCBWCYEJ.js} +2 -2
  88. package/dist/{chunk-3PDOVUHC.js → chunk-KXB4VXHY.js} +2 -2
  89. package/dist/{chunk-G6LBWZRF.js → chunk-LBOD4U5B.js} +7 -7
  90. package/dist/{chunk-ZGOQTOYA.js → chunk-LGHKJABJ.js} +3 -3
  91. package/dist/{chunk-T3GCXULH.js → chunk-M3C2V3PV.js} +10 -10
  92. package/dist/{chunk-OFHFH655.js → chunk-MJCGLM25.js} +8 -8
  93. package/dist/{chunk-JDZRYH2N.js → chunk-NHWB6HG2.js} +2 -2
  94. package/dist/{chunk-TC3VNKGX.js → chunk-NM2WP3B7.js} +4 -4
  95. package/dist/{chunk-IMA2EWLV.js → chunk-P5PXWTW7.js} +2 -2
  96. package/dist/chunk-PH3ZWL3W.js +786 -0
  97. package/dist/chunk-PH3ZWL3W.js.map +1 -0
  98. package/dist/{chunk-QMBNMPQM.js → chunk-PUS63Q3G.js} +24 -22
  99. package/dist/{chunk-QMBNMPQM.js.map → chunk-PUS63Q3G.js.map} +1 -1
  100. package/dist/{chunk-2QMKMVHH.js → chunk-QNWXCJ76.js} +2 -2
  101. package/dist/{chunk-FCDWWCLX.js → chunk-RGIWINDN.js} +427 -795
  102. package/dist/chunk-RGIWINDN.js.map +1 -0
  103. package/dist/{chunk-CSMCNOPH.js → chunk-SPJXKAVF.js} +3 -3
  104. package/dist/{chunk-4PBVXX7L.js → chunk-TH2LSRMG.js} +2 -2
  105. package/dist/{chunk-ESBQWC3U.js → chunk-VI2JQPNQ.js} +2 -2
  106. package/dist/{chunk-GGUBDXRR.js → chunk-W5EG6LE3.js} +2 -2
  107. package/dist/{chunk-DEBHXHJR.js → chunk-WIPEXG6R.js} +2 -2
  108. package/dist/{chunk-SH6YO3LT.js → chunk-WVO4G37W.js} +2 -2
  109. package/dist/{chunk-VVIW3PTA.js → chunk-YTQNQ4KB.js} +14 -14
  110. package/dist/{chunk-PKRIQL3V.js → chunk-YTSNAUXN.js} +2 -2
  111. package/dist/{chunk-QAOGGNE3.js → chunk-ZPSVBSOF.js} +4 -4
  112. package/dist/{cli-CxoSOiG0.d.ts → cli-C4GbETPC.d.ts} +5 -5
  113. package/dist/cli.d.ts +13 -13
  114. package/dist/cli.js +36 -35
  115. package/dist/compounding/engine.d.ts +3 -2
  116. package/dist/compounding/engine.js +10 -9
  117. package/dist/compounding/preference-consolidator.d.ts +1 -1
  118. package/dist/compression-optimizer.d.ts +1 -1
  119. package/dist/config.d.ts +1 -1
  120. package/dist/config.js +3 -3
  121. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  122. package/dist/connectors/codex-materialize-runner.js +10 -9
  123. package/dist/connectors/codex-materialize.d.ts +1 -1
  124. package/dist/connectors/index.d.ts +1 -1
  125. package/dist/connectors/index.js +10 -9
  126. package/dist/consolidation-provenance-check.d.ts +3 -2
  127. package/dist/consolidation-undo.d.ts +3 -2
  128. package/dist/contradiction/index.d.ts +3 -2
  129. package/dist/conversation-index/backend.d.ts +1 -1
  130. package/dist/conversation-index/chunker.d.ts +1 -1
  131. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  132. package/dist/conversation-index/indexer.d.ts +1 -1
  133. package/dist/conversation-index/search.d.ts +1 -1
  134. package/dist/corpus-watermark.d.ts +1 -1
  135. package/dist/corpus-watermark.js +12 -11
  136. package/dist/day-summary.d.ts +1 -1
  137. package/dist/delinearize.d.ts +1 -1
  138. package/dist/direct-answer-wiring.d.ts +1 -1
  139. package/dist/direct-answer.d.ts +1 -1
  140. package/dist/embedding-fallback.d.ts +1 -1
  141. package/dist/enrichment/index.d.ts +1 -1
  142. package/dist/entity-retrieval.d.ts +3 -2
  143. package/dist/entity-retrieval.js +10 -9
  144. package/dist/entity-schema.d.ts +1 -1
  145. package/dist/explicit-capture.d.ts +52 -10
  146. package/dist/explicit-capture.js +13 -1
  147. package/dist/extraction-error-classification.d.ts +1 -1
  148. package/dist/extraction-faithfulness.d.ts +1 -1
  149. package/dist/extraction-judge-telemetry.d.ts +1 -1
  150. package/dist/extraction-judge-training.d.ts +1 -1
  151. package/dist/extraction-judge.d.ts +1 -1
  152. package/dist/extraction-liveness.d.ts +1 -1
  153. package/dist/extraction-source-grounding-rules.d.ts +1 -1
  154. package/dist/extraction-source-grounding.d.ts +1 -1
  155. package/dist/extraction.d.ts +1 -1
  156. package/dist/fallback-llm.d.ts +1 -1
  157. package/dist/{forget-HRPLVB3W.js → forget-4UY2EOKH.js} +3 -3
  158. package/dist/graph-dashboard-diff.d.ts +1 -1
  159. package/dist/graph-dashboard-key.d.ts +1 -1
  160. package/dist/graph-dashboard-parser.d.ts +1 -1
  161. package/dist/graph-edge-reinforcement.d.ts +1 -1
  162. package/dist/graph-snapshot.d.ts +1 -1
  163. package/dist/graph.d.ts +1 -1
  164. package/dist/importance.d.ts +1 -1
  165. package/dist/importers/index.d.ts +1 -1
  166. package/dist/in-flight-reads.d.ts +1 -1
  167. package/dist/index.d.ts +21 -21
  168. package/dist/index.js +47 -45
  169. package/dist/intent.d.ts +1 -1
  170. package/dist/lcm/engine.d.ts +1 -1
  171. package/dist/lcm/index.d.ts +1 -1
  172. package/dist/lcm/tools.d.ts +1 -1
  173. package/dist/lifecycle.d.ts +1 -1
  174. package/dist/live-connectors-runner.d.ts +1 -1
  175. package/dist/local-llm.d.ts +1 -1
  176. package/dist/local-model-endpoint.d.ts +1 -1
  177. package/dist/maintenance/memory-governance.d.ts +1 -1
  178. package/dist/maintenance/memory-governance.js +10 -9
  179. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
  180. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +10 -9
  181. package/dist/maintenance/rebuild-memory-projection.d.ts +3 -2
  182. package/dist/maintenance/rebuild-memory-projection.js +11 -10
  183. package/dist/{maintenance-Cb-PjxQd.d.ts → maintenance-CL30NWtc.d.ts} +3 -3
  184. package/dist/mcp-memory-inspector-app.d.ts +11 -11
  185. package/dist/memory-action-policy.d.ts +1 -1
  186. package/dist/memory-cache.d.ts +1 -1
  187. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  188. package/dist/memory-projection-store.d.ts +1 -1
  189. package/dist/memory-provenance.d.ts +1 -1
  190. package/dist/memory-worth-outcomes.d.ts +3 -2
  191. package/dist/models-json.d.ts +1 -1
  192. package/dist/namespaces/migrate.d.ts +4 -3
  193. package/dist/namespaces/migrate.js +11 -10
  194. package/dist/namespaces/principal.d.ts +1 -1
  195. package/dist/namespaces/search.d.ts +1 -1
  196. package/dist/namespaces/storage.d.ts +4 -3
  197. package/dist/namespaces/storage.js +10 -9
  198. package/dist/native-knowledge.d.ts +1 -1
  199. package/dist/offline-sync-impression-drain.d.ts +1 -1
  200. package/dist/offline-sync-impression-drain.js +5 -5
  201. package/dist/offline-sync.js +2 -2
  202. package/dist/operator-doctor-corpus.d.ts +1 -1
  203. package/dist/operator-doctor-corpus.js +13 -12
  204. package/dist/operator-doctor-replica.d.ts +1 -1
  205. package/dist/operator-toolkit.d.ts +4 -3
  206. package/dist/operator-toolkit.js +18 -17
  207. package/dist/orchestration/compression-guideline-coordinator.d.ts +3 -2
  208. package/dist/orchestration/maintenance.d.ts +5 -4
  209. package/dist/orchestration/maintenance.js +15 -14
  210. package/dist/{orchestrator-5GKqb_HL.d.ts → orchestrator-CKTCRwWV.d.ts} +7 -7
  211. package/dist/orchestrator.d.ts +8 -8
  212. package/dist/orchestrator.js +45 -44
  213. package/dist/patterns-cli.d.ts +1 -1
  214. package/dist/{pipeline-3Qi1TpRo.d.ts → pipeline-B7wj4rRZ.d.ts} +1 -1
  215. package/dist/policy-runtime.d.ts +1 -1
  216. package/dist/proactive-contention.d.ts +1 -1
  217. package/dist/provenance.d.ts +1 -1
  218. package/dist/{purge-YSGX5BOG.js → purge-533FZLS4.js} +16 -9
  219. package/dist/purge-533FZLS4.js.map +1 -0
  220. package/dist/qmd-preflight.d.ts +2 -2
  221. package/dist/{qmd-D9JqzzRX.d.ts → qmd-q9tg4dHp.d.ts} +1 -1
  222. package/dist/qmd-recall-cache.d.ts +1 -1
  223. package/dist/qmd.d.ts +2 -2
  224. package/dist/recall-concurrency-config.d.ts +1 -1
  225. package/dist/recall-disclosure-escalation.d.ts +1 -1
  226. package/dist/recall-explain-renderer.d.ts +1 -1
  227. package/dist/recall-memory-map.d.ts +1 -1
  228. package/dist/recall-planner-llm.d.ts +1 -1
  229. package/dist/recall-state.d.ts +1 -1
  230. package/dist/recall-state.js +2 -2
  231. package/dist/recall-tag-filter.d.ts +1 -1
  232. package/dist/recall-timings.d.ts +1 -1
  233. package/dist/recall-xray-cli.d.ts +1 -1
  234. package/dist/recall-xray-renderer.d.ts +1 -1
  235. package/dist/recall-xray.d.ts +1 -1
  236. package/dist/replay/normalizers/chatgpt.d.ts +1 -1
  237. package/dist/replay/normalizers/claude.d.ts +1 -1
  238. package/dist/replay/normalizers/openclaw.d.ts +1 -1
  239. package/dist/replay/normalizers/shared.d.ts +1 -1
  240. package/dist/replay/runner.d.ts +1 -1
  241. package/dist/replay/types.d.ts +1 -1
  242. package/dist/replica-divergence.d.ts +1 -1
  243. package/dist/replica-peers-config.d.ts +1 -1
  244. package/dist/resolve-auth-token.d.ts +1 -1
  245. package/dist/resume-bundles.js +4 -4
  246. package/dist/retrieval-agents.d.ts +2 -2
  247. package/dist/retrieval-tiers.d.ts +1 -1
  248. package/dist/routing/engine.d.ts +1 -1
  249. package/dist/routing/store.d.ts +1 -1
  250. package/dist/salvage-envelope.d.ts +1 -1
  251. package/dist/schemas.d.ts +22 -22
  252. package/dist/{scope-profiles-C4g6_UdP.d.ts → scope-profiles-CWDyglPM.d.ts} +1 -1
  253. package/dist/search/embed-helper.d.ts +1 -1
  254. package/dist/search/factory.d.ts +1 -1
  255. package/dist/search/index.d.ts +1 -1
  256. package/dist/search/lancedb-backend.d.ts +1 -1
  257. package/dist/search/meilisearch-backend.d.ts +1 -1
  258. package/dist/search/noop-backend.d.ts +1 -1
  259. package/dist/search/orama-backend.d.ts +1 -1
  260. package/dist/search/port.d.ts +1 -1
  261. package/dist/search/remote-backend.d.ts +1 -1
  262. package/dist/secure-store/index.js +2 -2
  263. package/dist/{semantic-consolidation-BrxqnzTW.d.ts → semantic-consolidation-BUE3deLn.d.ts} +1 -1
  264. package/dist/semantic-consolidation.d.ts +2 -2
  265. package/dist/semantic-consolidation.js +11 -10
  266. package/dist/semantic-rule-promotion.js +10 -9
  267. package/dist/semantic-rule-verifier.d.ts +1 -1
  268. package/dist/semantic-rule-verifier.js +10 -9
  269. package/dist/{service-Bi1JgxdP.d.ts → service-CXgM0bQG.d.ts} +2 -2
  270. package/dist/session-observer-bands.d.ts +1 -1
  271. package/dist/session-observer-state.d.ts +1 -1
  272. package/dist/shared-context/manager.d.ts +1 -1
  273. package/dist/signal.d.ts +1 -1
  274. package/dist/{storage-CcH6yPk2.d.ts → storage-DysJq-XH.d.ts} +163 -27
  275. package/dist/storage.d.ts +3 -2
  276. package/dist/storage.js +12 -10
  277. package/dist/summarizer.d.ts +1 -1
  278. package/dist/summarizer.js +3 -3
  279. package/dist/summary-snapshot.d.ts +1 -1
  280. package/dist/summary-snapshot.js +2 -2
  281. package/dist/temporal-supersession.d.ts +3 -2
  282. package/dist/temporal-timeline-recall.d.ts +1 -1
  283. package/dist/temporal-validity.d.ts +1 -1
  284. package/dist/threading.d.ts +1 -1
  285. package/dist/tier-migration.d.ts +3 -2
  286. package/dist/tier-routing.d.ts +1 -1
  287. package/dist/topics.d.ts +1 -1
  288. package/dist/transcript.d.ts +1 -1
  289. package/dist/transfer/types.d.ts +12 -12
  290. package/dist/trust-score-stage.d.ts +1 -1
  291. package/dist/trust-score.d.ts +1 -1
  292. package/dist/{types-Dg0w9ADr.d.ts → types-aPPzhnjT.d.ts} +1 -1
  293. package/dist/types.d.ts +1 -1
  294. package/dist/utility-runtime.d.ts +1 -1
  295. package/dist/utils/serialize-mutations.d.ts +11 -7
  296. package/dist/utils/serialize-mutations.js +1 -1
  297. package/dist/verified-recall.js +10 -9
  298. package/dist/write-envelope.d.ts +1 -1
  299. package/package.json +2 -2
  300. package/src/access-observe-write-surface.ts +1 -1
  301. package/src/access-service-coding-write.test.ts +40 -0
  302. package/src/explicit-capture.test.ts +1110 -1
  303. package/src/explicit-capture.ts +534 -135
  304. package/src/maintenance/purge.test.ts +157 -1
  305. package/src/maintenance/purge.ts +15 -9
  306. package/src/secure-store/secure-fs.ts +78 -1
  307. package/src/storage/content-hash-index.ts +43 -17
  308. package/src/storage/entity-canonical-id-migration.ts +151 -23
  309. package/src/storage/tombstone-blocked-capture-index.ts +562 -0
  310. package/src/storage/tombstone-blocked-capture-mutation.ts +284 -0
  311. package/src/storage/tombstone-blocked-capture-sync.ts +872 -0
  312. package/src/storage-fact-hash-index-defer.test.ts +2900 -57
  313. package/src/storage.ts +266 -265
  314. package/src/testing/subjects/tombstone-blocked-capture.test.ts +181 -0
  315. package/src/utils/serialize-mutations.test.ts +4 -1
  316. package/src/utils/serialize-mutations.ts +26 -27
  317. package/dist/chunk-55MDBZLC.js +0 -490
  318. package/dist/chunk-55MDBZLC.js.map +0 -1
  319. package/dist/chunk-AIK5W3IW.js.map +0 -1
  320. package/dist/chunk-FCDWWCLX.js.map +0 -1
  321. package/dist/chunk-WL5EBRDH.js.map +0 -1
  322. package/dist/purge-YSGX5BOG.js.map +0 -1
  323. /package/dist/{chunk-KUJQHXPH.js.map → chunk-2EUVEDF5.js.map} +0 -0
  324. /package/dist/{chunk-EVX44I7C.js.map → chunk-5W4ZLBEZ.js.map} +0 -0
  325. /package/dist/{chunk-P3MH72CI.js.map → chunk-62U4J2GN.js.map} +0 -0
  326. /package/dist/{chunk-YGHMSDLK.js.map → chunk-66772WBP.js.map} +0 -0
  327. /package/dist/{chunk-EP5BVCRI.js.map → chunk-6BNE62PM.js.map} +0 -0
  328. /package/dist/{chunk-AAP5T6QG.js.map → chunk-6DNMUYEE.js.map} +0 -0
  329. /package/dist/{chunk-SG265CVF.js.map → chunk-6FUPCJUL.js.map} +0 -0
  330. /package/dist/{chunk-WZ7UB7XQ.js.map → chunk-6U7F52DE.js.map} +0 -0
  331. /package/dist/{chunk-E4OCKU67.js.map → chunk-7XC2HX75.js.map} +0 -0
  332. /package/dist/{chunk-OVRQLAYR.js.map → chunk-AZ5BTEKX.js.map} +0 -0
  333. /package/dist/{chunk-2HNUMF5V.js.map → chunk-CZRYLSSW.js.map} +0 -0
  334. /package/dist/{chunk-WONS4RZ2.js.map → chunk-FDAMS4PK.js.map} +0 -0
  335. /package/dist/{chunk-Q6VFVAKZ.js.map → chunk-GIBMDSJ2.js.map} +0 -0
  336. /package/dist/{chunk-ZXAGJFHJ.js.map → chunk-H5CPS5JP.js.map} +0 -0
  337. /package/dist/{chunk-NBDCZWP4.js.map → chunk-I5NLEENJ.js.map} +0 -0
  338. /package/dist/{chunk-DRBXHRXE.js.map → chunk-IB26HVAJ.js.map} +0 -0
  339. /package/dist/{chunk-XEQ7OT7U.js.map → chunk-IC6CBHCA.js.map} +0 -0
  340. /package/dist/{chunk-CMRQ34J5.js.map → chunk-JCBWCYEJ.js.map} +0 -0
  341. /package/dist/{chunk-3PDOVUHC.js.map → chunk-KXB4VXHY.js.map} +0 -0
  342. /package/dist/{chunk-G6LBWZRF.js.map → chunk-LBOD4U5B.js.map} +0 -0
  343. /package/dist/{chunk-ZGOQTOYA.js.map → chunk-LGHKJABJ.js.map} +0 -0
  344. /package/dist/{chunk-T3GCXULH.js.map → chunk-M3C2V3PV.js.map} +0 -0
  345. /package/dist/{chunk-OFHFH655.js.map → chunk-MJCGLM25.js.map} +0 -0
  346. /package/dist/{chunk-JDZRYH2N.js.map → chunk-NHWB6HG2.js.map} +0 -0
  347. /package/dist/{chunk-TC3VNKGX.js.map → chunk-NM2WP3B7.js.map} +0 -0
  348. /package/dist/{chunk-IMA2EWLV.js.map → chunk-P5PXWTW7.js.map} +0 -0
  349. /package/dist/{chunk-2QMKMVHH.js.map → chunk-QNWXCJ76.js.map} +0 -0
  350. /package/dist/{chunk-CSMCNOPH.js.map → chunk-SPJXKAVF.js.map} +0 -0
  351. /package/dist/{chunk-4PBVXX7L.js.map → chunk-TH2LSRMG.js.map} +0 -0
  352. /package/dist/{chunk-ESBQWC3U.js.map → chunk-VI2JQPNQ.js.map} +0 -0
  353. /package/dist/{chunk-GGUBDXRR.js.map → chunk-W5EG6LE3.js.map} +0 -0
  354. /package/dist/{chunk-DEBHXHJR.js.map → chunk-WIPEXG6R.js.map} +0 -0
  355. /package/dist/{chunk-SH6YO3LT.js.map → chunk-WVO4G37W.js.map} +0 -0
  356. /package/dist/{chunk-VVIW3PTA.js.map → chunk-YTQNQ4KB.js.map} +0 -0
  357. /package/dist/{chunk-PKRIQL3V.js.map → chunk-YTSNAUXN.js.map} +0 -0
  358. /package/dist/{chunk-QAOGGNE3.js.map → chunk-ZPSVBSOF.js.map} +0 -0
  359. /package/dist/{forget-HRPLVB3W.js.map → forget-4UY2EOKH.js.map} +0 -0
@@ -13,7 +13,7 @@ import {
13
13
  TombstoneStore,
14
14
  buildRetiredFactTombstoneInputs,
15
15
  collectRetiredMemoriesForRebuild
16
- } from "./chunk-2QMKMVHH.js";
16
+ } from "./chunk-QNWXCJ76.js";
17
17
  import {
18
18
  computeSupersessionKey,
19
19
  normalizeSupersessionKey,
@@ -42,13 +42,10 @@ import {
42
42
  readMaybeEncryptedLines,
43
43
  readMemoryActionEventRowsFromLines,
44
44
  serializeLifecycleAppendPayload
45
- } from "./chunk-OFHFH655.js";
45
+ } from "./chunk-MJCGLM25.js";
46
46
  import {
47
47
  namespaceIdentityFromToken
48
48
  } from "./chunk-EGGE52UU.js";
49
- import {
50
- withHeldFileLock
51
- } from "./chunk-WL5EBRDH.js";
52
49
  import {
53
50
  rewriteProjectedEntityReferences,
54
51
  rewriteProjectedMemoryEntityReference
@@ -57,15 +54,6 @@ import {
57
54
  assertPathInsideRoot,
58
55
  pathIsInside
59
56
  } from "./chunk-GCASGYIO.js";
60
- import {
61
- markProjectedMemoryPathInvalid,
62
- openProjectionReadonly,
63
- readProjectedGovernanceRecord,
64
- readProjectedMemoryBrowse,
65
- readProjectedMemoryState,
66
- readProjectedMemoryTimeline,
67
- updateProjectedMemoryPath
68
- } from "./chunk-3CSX3ETE.js";
69
57
  import {
70
58
  inferMemoryStatus,
71
59
  isArchivedMemoryPath,
@@ -91,6 +79,26 @@ import {
91
79
  parseFaithfulnessField,
92
80
  serializeFaithfulnessFields
93
81
  } from "./chunk-JYIJNNN3.js";
82
+ import {
83
+ CONTENT_HASH_INDEX_RETRY_MAX_DELAY_MS,
84
+ ContentHashIndex,
85
+ FactHashIndexNotAuthoritativeError,
86
+ TombstoneBlockedCaptureIndexHost,
87
+ buildExplicitCaptureDedupKey,
88
+ parseTombstoneBlockedOfflineSyncMemory
89
+ } from "./chunk-FBUE6PD3.js";
90
+ import {
91
+ withHeldFileLock
92
+ } from "./chunk-FFAZ2XFU.js";
93
+ import {
94
+ markProjectedMemoryPathInvalid,
95
+ openProjectionReadonly,
96
+ readProjectedGovernanceRecord,
97
+ readProjectedMemoryBrowse,
98
+ readProjectedMemoryState,
99
+ readProjectedMemoryTimeline,
100
+ updateProjectedMemoryPath
101
+ } from "./chunk-3CSX3ETE.js";
94
102
  import {
95
103
  composeMemoryEnvelope,
96
104
  isSealedMemoryEnvelope,
@@ -126,10 +134,6 @@ import {
126
134
  getInFlightRead,
127
135
  setInFlightRead
128
136
  } from "./chunk-PDJTHRAW.js";
129
- import {
130
- computeContentHash,
131
- normalizeContent
132
- } from "./chunk-W5H6ZRPT.js";
133
137
  import {
134
138
  isConsolidationOperator,
135
139
  isValidDerivedFromEntry
@@ -164,9 +168,8 @@ import {
164
168
  probeEncryptedRegularFileHeader,
165
169
  readMaybeEncryptedFile,
166
170
  readMaybeEncryptedFileBuffer,
167
- writeMaybeEncryptedFile,
168
- writeMaybeEncryptedFileFromChunks
169
- } from "./chunk-AIK5W3IW.js";
171
+ writeMaybeEncryptedFile
172
+ } from "./chunk-5TFP4CUL.js";
170
173
  import {
171
174
  isErrnoCode
172
175
  } from "./chunk-5UZXUTVO.js";
@@ -208,16 +211,16 @@ import {
208
211
  readdir as readdir5,
209
212
  readFile as readFile2,
210
213
  realpath as realpath3,
211
- stat as stat3,
214
+ stat as stat2,
212
215
  writeFile as writeFile2,
213
- mkdir as mkdir2,
216
+ mkdir,
214
217
  unlink as unlink3,
215
218
  appendFile,
216
219
  open
217
220
  } from "fs/promises";
218
221
  import { appendFileSync, createReadStream, mkdirSync, readFileSync as readFileSync2, statSync } from "fs";
219
222
  import { createHash as createHash5 } from "crypto";
220
- import path10 from "path";
223
+ import path9 from "path";
221
224
 
222
225
  // src/storage/memory-read-store.ts
223
226
  import { lstat, readdir, realpath, stat } from "fs/promises";
@@ -1478,7 +1481,15 @@ function resolveHistoricalEntityCanonicalId(normalized, mappings) {
1478
1481
  var EntityCanonicalIdMigrationStateSchema = z.object({
1479
1482
  version: z.literal(ENTITY_CANONICAL_ID_MIGRATION_VERSION),
1480
1483
  complete: z.boolean(),
1481
- mappings: z.record(z.string().min(1))
1484
+ mappings: z.record(z.string().min(1)),
1485
+ /**
1486
+ * Pairs the migration refused to resolve, PARKED rather than dropped.
1487
+ * Deleting the record would strand the collision: once an operator removes
1488
+ * the legacy file, no later scan can rediscover the mapping, so references
1489
+ * still naming the legacy id would never be rewritten. Optional so a journal
1490
+ * written by an older build still parses.
1491
+ */
1492
+ blocked: z.record(z.string().min(1)).optional()
1482
1493
  });
1483
1494
  async function fingerprintPath(filePath) {
1484
1495
  let fileStat;
@@ -1642,26 +1653,26 @@ function assertSafeEntityId(entityId) {
1642
1653
  }
1643
1654
  }
1644
1655
  async function assertNotSymlink(filePath, label) {
1645
- let stat4;
1656
+ let stat3;
1646
1657
  try {
1647
- stat4 = await lstat2(filePath);
1658
+ stat3 = await lstat2(filePath);
1648
1659
  } catch (error) {
1649
1660
  if (isErrnoCode(error, "ENOENT")) return;
1650
1661
  throw error;
1651
1662
  }
1652
- if (stat4.isSymbolicLink()) {
1663
+ if (stat3.isSymbolicLink()) {
1653
1664
  throw new Error(`Refusing entity canonical-id migration through symlink: ${label}.`);
1654
1665
  }
1655
1666
  }
1656
1667
  async function assertNotMemorySymlink(filePath) {
1657
- let stat4;
1668
+ let stat3;
1658
1669
  try {
1659
- stat4 = await lstat2(filePath);
1670
+ stat3 = await lstat2(filePath);
1660
1671
  } catch (error) {
1661
1672
  if (isErrnoCode(error, "ENOENT")) return;
1662
1673
  throw error;
1663
1674
  }
1664
- if (stat4.isSymbolicLink()) {
1675
+ if (stat3.isSymbolicLink()) {
1665
1676
  throw new Error(`Refusing entity canonical-id migration through symlinked memory: ${filePath}.`);
1666
1677
  }
1667
1678
  }
@@ -1682,9 +1693,10 @@ async function readSafeEntityEntries(entitiesDir) {
1682
1693
  }
1683
1694
  return entries;
1684
1695
  }
1685
- async function discoverMappings(deps, knownMappings = {}) {
1696
+ async function discoverMappings(deps, knownMappings = {}, blocked = /* @__PURE__ */ new Map()) {
1686
1697
  const mappings = {};
1687
1698
  const canonicalOwners = /* @__PURE__ */ new Map();
1699
+ blocked.clear();
1688
1700
  const entityEntries = await readSafeEntityEntries(deps.entitiesDir);
1689
1701
  for (const entry of entityEntries) {
1690
1702
  if (!entry.endsWith(".md")) continue;
@@ -1710,18 +1722,20 @@ async function discoverMappings(deps, knownMappings = {}) {
1710
1722
  if (canonicalExists) {
1711
1723
  const canonicalContent2 = await deps.readStorageSecureFile(canonicalPath);
1712
1724
  if (entityContent !== canonicalContent2) {
1713
- throw new Error(`Cannot migrate legacy entity id ${legacyId}: ${canonicalId} already exists.`);
1725
+ blocked.set(legacyId, canonicalId);
1726
+ continue;
1714
1727
  }
1715
1728
  }
1716
- const previousOwner = canonicalOwners.get(canonicalId);
1717
- if (previousOwner !== void 0 && previousOwner !== legacyId) {
1718
- throw new Error(
1719
- `Cannot migrate legacy entity ids ${previousOwner} and ${legacyId}: both normalize to ${canonicalId}.`
1720
- );
1721
- }
1722
- canonicalOwners.set(canonicalId, legacyId);
1729
+ canonicalOwners.set(canonicalId, [...canonicalOwners.get(canonicalId) ?? [], legacyId]);
1723
1730
  mappings[legacyId] = canonicalId;
1724
1731
  }
1732
+ for (const [canonicalId, claimants] of canonicalOwners) {
1733
+ if (claimants.length < 2) continue;
1734
+ for (const legacyId of claimants) {
1735
+ blocked.set(legacyId, canonicalId);
1736
+ delete mappings[legacyId];
1737
+ }
1738
+ }
1725
1739
  return mappings;
1726
1740
  }
1727
1741
  async function rewriteReferences(deps, mappings, refreshLock) {
@@ -1923,7 +1937,16 @@ function mergeDiscoveredMappings(existing, discovered) {
1923
1937
  for (const [legacyId, canonicalId] of Object.entries(discovered)) {
1924
1938
  const previousMapping = merged[legacyId];
1925
1939
  if (previousMapping !== void 0 && previousMapping !== canonicalId) {
1926
- throw new Error(`Legacy entity id ${legacyId} changed canonical target during migration.`);
1940
+ let hop = canonicalId;
1941
+ const seen = /* @__PURE__ */ new Set();
1942
+ while (hop !== void 0 && hop !== previousMapping && !seen.has(hop)) {
1943
+ seen.add(hop);
1944
+ hop = merged[hop];
1945
+ }
1946
+ if (hop !== previousMapping) {
1947
+ throw new Error(`Legacy entity id ${legacyId} changed canonical target during migration.`);
1948
+ }
1949
+ continue;
1927
1950
  }
1928
1951
  if (previousMapping === void 0 && wouldCreateMappingCycle(merged, legacyId, canonicalId)) continue;
1929
1952
  const previousOwner = canonicalOwners.get(canonicalId);
@@ -1978,7 +2001,7 @@ async function migrateEntityFilePair(deps, legacyId, canonicalId, refreshMigrati
1978
2001
  deps.isEncryptedStorageFile(canonicalPath)
1979
2002
  ]);
1980
2003
  if (legacyContent !== canonicalContent2) {
1981
- throw new Error(`Cannot migrate legacy entity id ${legacyId}: ${canonicalId} already exists.`);
2004
+ return { deferred: false, progressed: false, blocked: true };
1982
2005
  }
1983
2006
  if (legacyEncrypted && !canonicalEncrypted) {
1984
2007
  if (!await refreshMigrationLock() || !await refreshEntityLock()) {
@@ -2055,6 +2078,46 @@ async function migrateLegacyEntityCanonicalIds(deps) {
2055
2078
  mappings: {}
2056
2079
  };
2057
2080
  }
2081
+ const blocked = /* @__PURE__ */ new Map();
2082
+ const finish = () => {
2083
+ if (blocked.size > 0) {
2084
+ const pairs = [...blocked].map(([legacyId, canonicalId]) => `${legacyId} -> ${canonicalId}`).join(", ");
2085
+ log.warn(
2086
+ `entity canonical-id migration skipped ${blocked.size} unresolvable pair(s): ${pairs}. Both files were kept and the legacy id still resolves; merge or delete one side to migrate it.`
2087
+ );
2088
+ }
2089
+ return deps.readMigrationFingerprint?.();
2090
+ };
2091
+ const pruneBlocked = async () => {
2092
+ const current = state;
2093
+ if (!current) return false;
2094
+ let revived = false;
2095
+ const parked = { ...current.blocked ?? {} };
2096
+ const active = {};
2097
+ for (const [legacyId, canonicalId] of Object.entries(current.mappings)) {
2098
+ if (!blocked.has(legacyId)) active[legacyId] = canonicalId;
2099
+ }
2100
+ for (const [legacyId, canonicalId] of blocked) parked[legacyId] = canonicalId;
2101
+ for (const [legacyId, canonicalId] of Object.entries(parked)) {
2102
+ if (blocked.has(legacyId)) continue;
2103
+ delete parked[legacyId];
2104
+ if (active[legacyId] !== void 0) continue;
2105
+ const legacyPath = deps.resolveEntityFilePath(legacyId);
2106
+ if (legacyPath !== null && await fileExists(legacyPath)) continue;
2107
+ active[legacyId] = canonicalId;
2108
+ revived = true;
2109
+ }
2110
+ const collapsed = collapseMappings(active);
2111
+ for (const [legacyId, canonicalId] of Object.entries(parked)) {
2112
+ const moved = collapsed[canonicalId];
2113
+ if (moved !== void 0 && moved !== legacyId) parked[legacyId] = moved;
2114
+ }
2115
+ const same = (a, b) => Object.keys(a).length === Object.keys(b).length && Object.entries(a).every(([key, value]) => b[key] === value);
2116
+ if (same(collapsed, current.mappings) && same(parked, current.blocked ?? {})) return revived;
2117
+ state = { ...current, mappings: collapsed, blocked: parked };
2118
+ await writeState(deps, state);
2119
+ return revived;
2120
+ };
2058
2121
  const previousMappings = state.mappings;
2059
2122
  const collapsedMappings = collapseMappings(previousMappings);
2060
2123
  const mappingsChanged = Object.keys(collapsedMappings).length !== Object.keys(previousMappings).length || Object.entries(collapsedMappings).some(
@@ -2065,11 +2128,12 @@ async function migrateLegacyEntityCanonicalIds(deps) {
2065
2128
  if (!await lock.refresh()) throw new Error("Lost entity canonical-id migration lock.");
2066
2129
  const discoveredBefore = rejectMappingCycles(
2067
2130
  state.mappings,
2068
- await discoverMappings(deps, state.mappings)
2131
+ await discoverMappings(deps, state.mappings, blocked)
2069
2132
  );
2133
+ await pruneBlocked();
2070
2134
  const mergedBefore = collapseMappings(mergeDiscoveredMappings(state.mappings, discoveredBefore));
2071
2135
  if (state.complete && Object.keys(discoveredBefore).length === 0 && !mappingsChanged) {
2072
- if (Object.keys(state.mappings).length === 0) return deps.readMigrationFingerprint?.();
2136
+ if (Object.keys(state.mappings).length === 0) return finish();
2073
2137
  const rewroteColdMemory2 = await rewriteKnownReferences(
2074
2138
  deps,
2075
2139
  state.mappings,
@@ -2079,7 +2143,7 @@ async function migrateLegacyEntityCanonicalIds(deps) {
2079
2143
  deps.invalidateAllMemoriesCache();
2080
2144
  if (rewroteColdMemory2) deps.invalidateColdMemoriesCache();
2081
2145
  deps.bumpMemoryStatusVersion();
2082
- return deps.readMigrationFingerprint?.();
2146
+ return finish();
2083
2147
  }
2084
2148
  if (state.complete || Object.keys(discoveredBefore).length > 0 || Object.keys(mergedBefore).length !== Object.keys(state.mappings).length) {
2085
2149
  state = { ...state, complete: false, mappings: mergedBefore };
@@ -2089,11 +2153,12 @@ async function migrateLegacyEntityCanonicalIds(deps) {
2089
2153
  if (!await lock.refresh()) throw new Error("Lost entity canonical-id migration lock.");
2090
2154
  const discoveredAfter2 = rejectMappingCycles(
2091
2155
  state.mappings,
2092
- await discoverMappings(deps, state.mappings)
2156
+ await discoverMappings(deps, state.mappings, blocked)
2093
2157
  );
2094
- if (Object.keys(discoveredAfter2).length === 0) {
2158
+ const revivedInRescan = await pruneBlocked();
2159
+ if (Object.keys(discoveredAfter2).length === 0 && !revivedInRescan) {
2095
2160
  await writeState(deps, { ...state, complete: true });
2096
- return deps.readMigrationFingerprint?.();
2161
+ return finish();
2097
2162
  }
2098
2163
  state = {
2099
2164
  ...state,
@@ -2114,9 +2179,8 @@ async function migrateLegacyEntityCanonicalIds(deps) {
2114
2179
  canonicalId,
2115
2180
  () => lock.refresh()
2116
2181
  );
2117
- if (result.deferred) {
2118
- deferredMappings.push([legacyId, canonicalId]);
2119
- }
2182
+ if (result.blocked) blocked.set(legacyId, canonicalId);
2183
+ else if (result.deferred) deferredMappings.push([legacyId, canonicalId]);
2120
2184
  progressed ||= result.progressed;
2121
2185
  }
2122
2186
  if (deferredMappings.length === 0) break;
@@ -2128,6 +2192,7 @@ async function migrateLegacyEntityCanonicalIds(deps) {
2128
2192
  }
2129
2193
  pendingMappings = deferredMappings;
2130
2194
  }
2195
+ await pruneBlocked();
2131
2196
  const rewroteColdMemory = await rewriteKnownReferences(
2132
2197
  deps,
2133
2198
  state.mappings,
@@ -2140,11 +2205,12 @@ async function migrateLegacyEntityCanonicalIds(deps) {
2140
2205
  if (!await lock.refresh()) throw new Error("Lost entity canonical-id migration lock.");
2141
2206
  const discoveredAfter = rejectMappingCycles(
2142
2207
  state.mappings,
2143
- await discoverMappings(deps, state.mappings)
2208
+ await discoverMappings(deps, state.mappings, blocked)
2144
2209
  );
2145
- if (Object.keys(discoveredAfter).length === 0) {
2210
+ const revivedAfterRewrite = await pruneBlocked();
2211
+ if (Object.keys(discoveredAfter).length === 0 && !revivedAfterRewrite) {
2146
2212
  await writeState(deps, { ...state, complete: true });
2147
- return deps.readMigrationFingerprint?.();
2213
+ return finish();
2148
2214
  }
2149
2215
  state = {
2150
2216
  ...state,
@@ -4112,14 +4178,14 @@ var FusionArtifactStore = class {
4112
4178
  */
4113
4179
  async assertFusionDirNotSymlinked() {
4114
4180
  const fusionDir = path7.join(this.wearablesDir, FUSION_DIR_NAME);
4115
- let stat4;
4181
+ let stat3;
4116
4182
  try {
4117
- stat4 = await this.io.lstat(fusionDir);
4183
+ stat3 = await this.io.lstat(fusionDir);
4118
4184
  } catch (err) {
4119
4185
  if (err.code === "ENOENT") return;
4120
4186
  throw err;
4121
4187
  }
4122
- if (stat4.isSymbolicLink) {
4188
+ if (stat3.isSymbolicLink) {
4123
4189
  throw new Error(
4124
4190
  "wearable fusion dir '_fusion' is a symbolic link \u2014 refusing to follow it even when it resolves inside the memory dir (AGENTS.md pattern #3)"
4125
4191
  );
@@ -4551,14 +4617,14 @@ var MeetingRecordStore = class {
4551
4617
  return path8.join(this.meetingsDir, first);
4552
4618
  }
4553
4619
  async assertNotSymlink(target, kind) {
4554
- let stat4;
4620
+ let stat3;
4555
4621
  try {
4556
- stat4 = await this.io.lstat(target);
4622
+ stat3 = await this.io.lstat(target);
4557
4623
  } catch (err) {
4558
4624
  if (err.code === "ENOENT") return;
4559
4625
  throw err;
4560
4626
  }
4561
- if (stat4.isSymbolicLink) {
4627
+ if (stat3.isSymbolicLink) {
4562
4628
  const label = path8.relative(this.memoryDir, target) || MEETINGS_DIR_NAME;
4563
4629
  throw new Error(
4564
4630
  `meetings ${kind} '${label}' is a symbolic link \u2014 refusing to follow it even when it resolves inside the memory dir (AGENTS.md pattern #3)`
@@ -4975,471 +5041,6 @@ function isEntitySynthesisStale(entity) {
4975
5041
  return entity.timeline.length > entity.synthesisTimelineCount || structuredFactCount > (entity.synthesisStructuredFactCount ?? 0) || structuredFactDigest !== storedStructuredFactDigest;
4976
5042
  }
4977
5043
 
4978
- // src/storage/content-hash-index.ts
4979
- import { mkdir, stat as stat2 } from "fs/promises";
4980
- import path9 from "path";
4981
- var CONTENT_HASH_INDEX_LOCK_STALE_MS = 3e4;
4982
- var CONTENT_HASH_INDEX_RETRY_MAX_ATTEMPTS = 5;
4983
- var CONTENT_HASH_INDEX_RETRY_BASE_MS = 500;
4984
- var CONTENT_HASH_INDEX_RETRY_MAX_DELAY_MS = 5e3;
4985
- var FactHashIndexNotAuthoritativeError = class extends Error {
4986
- constructor(stateDir) {
4987
- super(
4988
- `fact-hash index is not authoritative: the cross-process rebuild lock for ${stateDir} could not be acquired within the bounded retry budget`
4989
- );
4990
- this.name = "FactHashIndexNotAuthoritativeError";
4991
- }
4992
- };
4993
- var ContentHashIndex = class _ContentHashIndex {
4994
- hashes = /* @__PURE__ */ new Set();
4995
- dirty = false;
4996
- /**
4997
- * Hashes explicitly removed since the last successful save (issue #1909 review
4998
- * round 8 thread 3). Tracked separately so `saveMergingWithDisk` can be
4999
- * removal-AWARE: under the file lock it reads the latest on-disk set, DROPS
5000
- * these, then unions our additions — so a removal batch cannot resurrect a
5001
- * hash (union alone would) and cannot clobber a concurrent extraction's
5002
- * appended hash (blind overwrite would). Consumed + cleared by every save.
5003
- */
5004
- removed = /* @__PURE__ */ new Set();
5005
- /**
5006
- * Hashes added by THIS instance since the last successful save (issue #1909
5007
- * review round 9 finding 3). Tracked separately from the loaded snapshot so a
5008
- * reconciling save publishes `(on-disk \ removed) ∪ added` — it re-applies only
5009
- * OUR additions, never the stale loaded entries. Without this, seeding the
5010
- * merge from `this.hashes` (loaded ∪ added) would resurrect a hash a peer
5011
- * removed on disk while this instance held a stale snapshot.
5012
- */
5013
- added = /* @__PURE__ */ new Set();
5014
- filePath;
5015
- secureStoreKeyProvider;
5016
- secureStoreWriteKeyProvider;
5017
- memoryDir;
5018
- lockOptions;
5019
- /**
5020
- * Deferred reconcile-save durable-retry state (issue #1909 / PR #2016). At
5021
- * most ONE retry is ever armed (`reconcileRetryTimer` is the reentrancy guard)
5022
- * so successive timed-out saves cannot stack duplicate/parallel retries.
5023
- * `reconcileRetryBarrier` resolves when the chain settles (published or gave
5024
- * up) — awaited by tests and any caller wanting the eventual result.
5025
- */
5026
- reconcileRetryTimer = null;
5027
- reconcileRetryAttempts = 0;
5028
- reconcileRetryBarrier = null;
5029
- reconcileRetryResolve = null;
5030
- /**
5031
- * On-disk fingerprint (mtime + byte size) of `fact-hashes.txt` captured at the
5032
- * last point THIS instance's in-memory set matched disk — after `load()`,
5033
- * `save()`, or a reconcile publish (PR #2016 review). A peer process that
5034
- * advances the durable index changes this fingerprint;
5035
- * {@link isDiskFingerprintCurrent} compares a single cheap `stat` against it so
5036
- * a stale-but-"authoritative" snapshot is detected without an O(file-size)
5037
- * re-read on the hot path.
5038
- */
5039
- lastSyncedFingerprint = null;
5040
- constructor(stateDir, secureStoreKeyProvider = () => null, secureStoreWriteKeyProvider = secureStoreKeyProvider, memoryDir = path9.dirname(stateDir), lockOptions = {}) {
5041
- this.filePath = path9.join(stateDir, "fact-hashes.txt");
5042
- this.secureStoreKeyProvider = secureStoreKeyProvider;
5043
- this.secureStoreWriteKeyProvider = secureStoreWriteKeyProvider;
5044
- this.memoryDir = memoryDir;
5045
- this.lockOptions = lockOptions;
5046
- }
5047
- /** Load existing hashes from disk. Safe to call multiple times. */
5048
- async load() {
5049
- try {
5050
- const raw = await readMaybeEncryptedFile(this.filePath, this.secureStoreKeyProvider(), this.memoryDir);
5051
- for (const line of raw.split("\n")) {
5052
- const trimmed = line.trim();
5053
- if (trimmed.length > 0) {
5054
- this.hashes.add(trimmed);
5055
- }
5056
- }
5057
- log.debug(`content-hash index: loaded ${this.hashes.size} hashes`);
5058
- } catch (err) {
5059
- if (err instanceof SecureStoreLockedError) throw err;
5060
- if (!isErrnoCode(err, "ENOENT")) throw err;
5061
- log.debug("content-hash index: no existing index \u2014 starting fresh");
5062
- }
5063
- await this.captureSyncedFingerprint();
5064
- }
5065
- /** Cheap `stat` of the durable index file; null when it does not exist yet. */
5066
- async statIndexFile() {
5067
- try {
5068
- const s = await stat2(this.filePath);
5069
- return { mtimeMs: s.mtimeMs, size: s.size };
5070
- } catch (err) {
5071
- if (isErrnoCode(err, "ENOENT")) return null;
5072
- throw err;
5073
- }
5074
- }
5075
- /** Record the current on-disk fingerprint as this instance's synced baseline. */
5076
- async captureSyncedFingerprint() {
5077
- try {
5078
- this.lastSyncedFingerprint = await this.statIndexFile();
5079
- } catch (err) {
5080
- this.lastSyncedFingerprint = null;
5081
- log.debug(`content-hash index: could not fingerprint ${this.filePath}: ${err}`);
5082
- }
5083
- }
5084
- /**
5085
- * True when the durable index file is unchanged since this instance last
5086
- * synced it (load / save / reconcile). False when a peer advanced it, when the
5087
- * file appeared or vanished, or when freshness cannot be established (stat
5088
- * error) — the caller then treats the in-memory snapshot as non-authoritative
5089
- * and confirms a dedup miss against the durable corpus (PR #2016 review). One
5090
- * `stat`, never an O(file-size) read, so the hot path stays cheap.
5091
- */
5092
- async isDiskFingerprintCurrent() {
5093
- let current;
5094
- try {
5095
- current = await this.statIndexFile();
5096
- } catch {
5097
- return false;
5098
- }
5099
- const last = this.lastSyncedFingerprint;
5100
- if (last === null || current === null) {
5101
- return last === null && current === null;
5102
- }
5103
- return current.mtimeMs === last.mtimeMs && current.size === last.size;
5104
- }
5105
- /** Check if content already exists in the index. */
5106
- has(content) {
5107
- return this.hashes.has(_ContentHashIndex.computeHash(content));
5108
- }
5109
- /** Add content hash to the index. */
5110
- add(content) {
5111
- const hash = _ContentHashIndex.computeHash(content);
5112
- this.removed.delete(hash);
5113
- this.hashes.add(hash);
5114
- this.added.add(hash);
5115
- this.dirty = true;
5116
- }
5117
- get size() {
5118
- return this.hashes.size;
5119
- }
5120
- /** Clear all loaded hashes so the next save rewrites the index from scratch. */
5121
- clear() {
5122
- if (this.hashes.size > 0) {
5123
- this.hashes.clear();
5124
- }
5125
- this.added.clear();
5126
- this.removed.clear();
5127
- this.cancelReconcileRetry();
5128
- this.dirty = true;
5129
- }
5130
- /** Persist index to disk if changed (plain whole-file overwrite). */
5131
- async save() {
5132
- if (!this.dirty) return;
5133
- await mkdir(path9.dirname(this.filePath), { recursive: true });
5134
- const publishedAdded = new Set(this.added);
5135
- const publishedRemoved = new Set(this.removed);
5136
- const serialized = [...this.hashes].join("\n") + "\n";
5137
- await writeMaybeEncryptedFile(
5138
- this.filePath,
5139
- serialized,
5140
- this.secureStoreWriteKeyProvider(),
5141
- {},
5142
- this.memoryDir
5143
- );
5144
- for (const h of publishedAdded) this.added.delete(h);
5145
- for (const h of publishedRemoved) this.removed.delete(h);
5146
- this.dirty = this.added.size > 0 || this.removed.size > 0;
5147
- await this.captureSyncedFingerprint();
5148
- if (this.dirty) {
5149
- this.scheduleReconcileRetry();
5150
- } else {
5151
- this.cancelReconcileRetry();
5152
- }
5153
- log.debug(`content-hash index: saved ${this.hashes.size} hashes`);
5154
- }
5155
- /**
5156
- * Persist the index by RECONCILING with the latest on-disk state under a
5157
- * cross-process lock (issue #1909). Used by the extraction-persist batch save
5158
- * for BOTH append and removal batches, so appends and removals to the same
5159
- * index serialize against each other:
5160
- * final = (on-disk \ this.removed) ∪ this.added
5161
- * Note it re-applies only OUR local additions (`added`), NOT the loaded
5162
- * snapshot (review round 9 finding 3): seeding from `this.hashes` would
5163
- * resurrect a hash a peer removed on disk while we held a stale snapshot. This
5164
- * preserves a concurrent writer's appended hashes (a blind overwrite would
5165
- * drop them), never resurrects a removed hash, and never loses our additions.
5166
- *
5167
- * Hardening:
5168
- * - Dirty short-circuit (round 7 finding 3): when this instance neither added
5169
- * nor removed anything this run, skip the O(file) read+rewrite entirely.
5170
- * - Cross-process lock (round 7 finding 2): serialize the read→reconcile→write
5171
- * window on a per-file advisory lock. If the lock is NOT acquired (timeout),
5172
- * do NOT publish (round 9 finding 2): keep `dirty` set AND schedule a bounded
5173
- * durable background retry (PR #2016) that keeps re-attempting the locked
5174
- * publish until the deferred additions land — never an unlocked write that
5175
- * could clobber a peer, and never a silent "batch save complete" that leaves
5176
- * the addition in this process's memory only.
5177
- */
5178
- async saveMergingWithDisk() {
5179
- if (!this.dirty) return;
5180
- await mkdir(path9.dirname(this.filePath), { recursive: true });
5181
- const publish = async () => {
5182
- const publishedAdded = new Set(this.added);
5183
- const publishedRemoved = new Set(this.removed);
5184
- const merged = new Set(publishedAdded);
5185
- try {
5186
- const raw = await readMaybeEncryptedFile(
5187
- this.filePath,
5188
- this.secureStoreKeyProvider(),
5189
- this.memoryDir
5190
- );
5191
- for (const line of raw.split("\n")) {
5192
- const trimmed = line.trim();
5193
- if (trimmed.length > 0 && !publishedRemoved.has(trimmed)) merged.add(trimmed);
5194
- }
5195
- } catch (err) {
5196
- if (err instanceof SecureStoreLockedError) throw err;
5197
- if (!isErrnoCode(err, "ENOENT")) throw err;
5198
- }
5199
- await mkdir(path9.dirname(this.filePath), { recursive: true });
5200
- await writeMaybeEncryptedFile(
5201
- this.filePath,
5202
- [...merged].join("\n") + "\n",
5203
- this.secureStoreWriteKeyProvider(),
5204
- {},
5205
- this.memoryDir
5206
- );
5207
- for (const h of publishedAdded) this.added.delete(h);
5208
- for (const h of publishedRemoved) this.removed.delete(h);
5209
- for (const h of this.added) merged.add(h);
5210
- for (const h of this.removed) merged.delete(h);
5211
- this.hashes = merged;
5212
- this.dirty = this.added.size > 0 || this.removed.size > 0;
5213
- await this.captureSyncedFingerprint();
5214
- };
5215
- await withHeldFileLock(
5216
- `${this.filePath}.lock`,
5217
- {
5218
- staleMs: CONTENT_HASH_INDEX_LOCK_STALE_MS,
5219
- ...this.lockOptions.maxWaitMs !== void 0 ? { maxWaitMs: this.lockOptions.maxWaitMs } : {},
5220
- ...this.lockOptions.pollMs !== void 0 ? { pollMs: this.lockOptions.pollMs } : {}
5221
- },
5222
- async (acquired) => {
5223
- if (!acquired) {
5224
- log.warn(
5225
- `content-hash index: lock not acquired for ${this.filePath}; deferring reconcile save (dirty retained, scheduling durable retry)`
5226
- );
5227
- this.scheduleReconcileRetry();
5228
- return;
5229
- }
5230
- await publish();
5231
- if (this.dirty) {
5232
- this.scheduleReconcileRetry();
5233
- } else {
5234
- this.cancelReconcileRetry();
5235
- }
5236
- }
5237
- );
5238
- log.debug(`content-hash index: reconcile-saved ${this.hashes.size} hashes`);
5239
- }
5240
- /**
5241
- * Rebuild-and-publish the index from an authoritative source (the durable
5242
- * corpus) under the SAME per-file cross-process lock the reconciling
5243
- * append/removal saves (`saveMergingWithDisk`) use (issue #1909 / PR #2016).
5244
- * The `populate` callback runs WHILE the lock is held and MUST repopulate this
5245
- * index from the corpus (`clear()` then `addByHash(...)` for every corpus
5246
- * hash); the rebuilt set is then published with a plain overwrite that is now
5247
- * serialized against every locked writer.
5248
- *
5249
- * This closes the finding where the previous unlocked clear→scan→save() could
5250
- * overwrite a peer's newer lock-merged or deferred additions: a locked writer
5251
- * that committed BEFORE the rebuild acquired the lock has its memory `.md` on
5252
- * disk and is re-scanned; one that commits AFTER the rebuild releases
5253
- * reconciles its additions on top of the freshly-published set. No union with
5254
- * the raw on-disk file is performed, so the rebuild keeps its
5255
- * garbage-collection property (orphaned hashes for deleted memories drop).
5256
- *
5257
- * Lock-acquisition failure is explicit and non-destructive: `populate` is NOT
5258
- * run and nothing is written (never an unlocked overwrite). Returns true when
5259
- * the rebuild was published under the lock, false when the lock timed out —
5260
- * the caller keeps the index non-authoritative and retries on next use. Uses
5261
- * the same non-reentrant file lock as the reconcile path, so it can never
5262
- * deadlock with the deferred reconcile-retry: a concurrent locked writer (or a
5263
- * fired retry) simply yields `acquired=false` after the bounded wait.
5264
- */
5265
- async rebuildUnderLock(populate) {
5266
- await mkdir(path9.dirname(this.filePath), { recursive: true });
5267
- let published = false;
5268
- await withHeldFileLock(
5269
- `${this.filePath}.lock`,
5270
- {
5271
- staleMs: CONTENT_HASH_INDEX_LOCK_STALE_MS,
5272
- ...this.lockOptions.maxWaitMs !== void 0 ? { maxWaitMs: this.lockOptions.maxWaitMs } : {},
5273
- ...this.lockOptions.pollMs !== void 0 ? { pollMs: this.lockOptions.pollMs } : {}
5274
- },
5275
- async (acquired) => {
5276
- if (!acquired) {
5277
- log.warn(
5278
- `content-hash index: lock not acquired for ${this.filePath}; deferring authoritative rebuild (index left non-authoritative, retried on next use)`
5279
- );
5280
- return;
5281
- }
5282
- await populate();
5283
- await this.save();
5284
- published = true;
5285
- }
5286
- );
5287
- return published;
5288
- }
5289
- /**
5290
- * True while a background durable reconcile-save retry is armed (PR #2016).
5291
- * Test/introspection hook.
5292
- */
5293
- get hasPendingReconcileRetry() {
5294
- return this.reconcileRetryTimer !== null;
5295
- }
5296
- /**
5297
- * Resolve once any armed background reconcile-save retry chain has settled —
5298
- * either it published the deferred additions, or it exhausted its bounded
5299
- * attempts and fell back to the corpus-rebuild safety net. Resolves
5300
- * immediately when nothing is armed. Lets a caller (or a test) await the
5301
- * eventual durability outcome of a lock-timed-out save.
5302
- */
5303
- async whenReconcileRetrySettled() {
5304
- await (this.reconcileRetryBarrier ?? Promise.resolve());
5305
- }
5306
- /**
5307
- * Drive any deferred lock-timeout reconcile save to completion INLINE at a
5308
- * lifecycle boundary (PR #2016 finding 3). The background retry timer is
5309
- * `unref`'d so it never keeps a long-lived daemon alive — but a short-lived
5310
- * writer (a one-shot CLI) can exit before it fires, leaving a durable fact
5311
- * `.md` whose hash never reached `fact-hashes.txt` for peers that already
5312
- * built their in-memory index. `orchestrator.destroy()` calls this so the
5313
- * addition publishes before the process exits; long-lived hosts only reach it
5314
- * at their own shutdown, so their in-flight retries keep running in the
5315
- * background until then. Bounded by the same attempt ceiling as the background
5316
- * retry; a permanently contended lock falls back to the corpus-rebuild-on-
5317
- * restart safety net (the fact `.md` is already durable). No deadlock: each
5318
- * attempt is the same non-reentrant, bounded-wait file lock.
5319
- */
5320
- async flushReconcileRetry() {
5321
- if (!this.dirty) return;
5322
- const maxAttempts = this.lockOptions.retryMaxAttempts ?? CONTENT_HASH_INDEX_RETRY_MAX_ATTEMPTS;
5323
- const baseMs = this.lockOptions.retryBaseMs ?? CONTENT_HASH_INDEX_RETRY_BASE_MS;
5324
- for (let attempt = 0; this.dirty && attempt < maxAttempts; attempt += 1) {
5325
- if (this.reconcileRetryTimer) {
5326
- clearTimeout(this.reconcileRetryTimer);
5327
- this.reconcileRetryTimer = null;
5328
- }
5329
- await this.saveMergingWithDisk();
5330
- if (!this.dirty) break;
5331
- if (attempt < maxAttempts - 1) {
5332
- const wait = Math.min(baseMs * 2 ** attempt, CONTENT_HASH_INDEX_RETRY_MAX_DELAY_MS);
5333
- await new Promise((resolve3) => setTimeout(resolve3, wait));
5334
- }
5335
- }
5336
- if (this.reconcileRetryTimer) {
5337
- clearTimeout(this.reconcileRetryTimer);
5338
- this.reconcileRetryTimer = null;
5339
- }
5340
- this.reconcileRetryAttempts = 0;
5341
- this.settleReconcileRetry();
5342
- }
5343
- /**
5344
- * Schedule ONE bounded, exponentially-backed-off background retry of the
5345
- * deferred reconcile save (PR #2016). Reentrant-safe: an already-armed timer
5346
- * short-circuits, so successive timed-out saves never stack duplicate retries.
5347
- * When attempts are exhausted the chain settles without publishing — the
5348
- * durable fact `.md` is on disk and a process restart rebuilds the index from
5349
- * the corpus, so this degrades to that safety net, never a fatal failure.
5350
- */
5351
- scheduleReconcileRetry() {
5352
- if (this.reconcileRetryTimer) return;
5353
- const maxAttempts = this.lockOptions.retryMaxAttempts ?? CONTENT_HASH_INDEX_RETRY_MAX_ATTEMPTS;
5354
- if (this.reconcileRetryAttempts >= maxAttempts) {
5355
- log.warn(
5356
- `content-hash index: exhausted ${maxAttempts} deferred reconcile-save retries for ${this.filePath}; ${this.added.size} addition(s) remain dirty in-memory (a process restart rebuilds the index from the durable corpus)`
5357
- );
5358
- this.reconcileRetryAttempts = 0;
5359
- this.settleReconcileRetry();
5360
- return;
5361
- }
5362
- if (!this.reconcileRetryBarrier) {
5363
- this.reconcileRetryBarrier = new Promise((resolve3) => {
5364
- this.reconcileRetryResolve = resolve3;
5365
- });
5366
- }
5367
- const attempt = this.reconcileRetryAttempts + 1;
5368
- const baseMs = this.lockOptions.retryBaseMs ?? CONTENT_HASH_INDEX_RETRY_BASE_MS;
5369
- const delay = Math.min(baseMs * 2 ** (attempt - 1), CONTENT_HASH_INDEX_RETRY_MAX_DELAY_MS);
5370
- this.reconcileRetryTimer = setTimeout(() => {
5371
- this.reconcileRetryTimer = null;
5372
- this.reconcileRetryAttempts = attempt;
5373
- void this.saveMergingWithDisk().catch((err) => {
5374
- log.warn(`content-hash index: deferred reconcile-save retry failed for ${this.filePath}: ${err}`);
5375
- }).finally(() => {
5376
- if (this.dirty && !this.reconcileRetryTimer) this.settleReconcileRetry();
5377
- });
5378
- }, delay);
5379
- this.reconcileRetryTimer.unref?.();
5380
- }
5381
- /** Cancel any armed reconcile-save retry and settle the barrier (a publish landed). */
5382
- cancelReconcileRetry() {
5383
- if (this.reconcileRetryTimer) {
5384
- clearTimeout(this.reconcileRetryTimer);
5385
- this.reconcileRetryTimer = null;
5386
- }
5387
- this.reconcileRetryAttempts = 0;
5388
- this.settleReconcileRetry();
5389
- }
5390
- /** Resolve and clear the retry barrier if one is outstanding. */
5391
- settleReconcileRetry() {
5392
- const resolve3 = this.reconcileRetryResolve;
5393
- this.reconcileRetryBarrier = null;
5394
- this.reconcileRetryResolve = null;
5395
- resolve3?.();
5396
- }
5397
- /** Remove a hash from the index (used when archiving/deleting). */
5398
- remove(content) {
5399
- const hash = _ContentHashIndex.computeHash(content);
5400
- this.added.delete(hash);
5401
- this.removed.add(hash);
5402
- this.hashes.delete(hash);
5403
- this.dirty = true;
5404
- }
5405
- /**
5406
- * Remove a pre-computed SHA-256 hash directly from the index without
5407
- * re-hashing. Use this when the caller already holds the stored hash
5408
- * (e.g. `memory.frontmatter.contentHash`) to avoid the double-hash bug
5409
- * where `remove(hash)` would compute `hash(hash)` and never match the
5410
- * entry.
5411
- */
5412
- removeByHash(hash) {
5413
- this.added.delete(hash);
5414
- this.removed.add(hash);
5415
- this.hashes.delete(hash);
5416
- this.dirty = true;
5417
- }
5418
- /**
5419
- * Add a pre-computed SHA-256 hash directly to the index without re-hashing.
5420
- * Use this when the caller already holds the stored hash
5421
- * (e.g. `memory.frontmatter.contentHash`) so that the index records the raw
5422
- * content hash rather than re-hashing the citation-annotated body.
5423
- *
5424
- * @internal Only called from `StorageManager.ensureFactHashIndexAuthoritative`.
5425
- * Not part of the public API — prefer `add(content)` for external callers.
5426
- */
5427
- addByHash(hash) {
5428
- this.removed.delete(hash);
5429
- this.hashes.add(hash);
5430
- this.added.add(hash);
5431
- this.dirty = true;
5432
- }
5433
- /** Normalize content (delegates to content-hash.ts for a single source of truth). */
5434
- static normalizeContent(content) {
5435
- return normalizeContent(content);
5436
- }
5437
- /** Compute SHA-256 hash (delegates to content-hash.ts for a single source of truth). */
5438
- static computeHash(content) {
5439
- return computeContentHash(content);
5440
- }
5441
- };
5442
-
5443
5044
  // src/storage.ts
5444
5045
  var ARTIFACT_SEARCH_STOPWORDS = /* @__PURE__ */ new Set([
5445
5046
  "a",
@@ -6064,17 +5665,17 @@ function inferEntityTypeFromContent(content) {
6064
5665
  }
6065
5666
  var KNOWN_ENTITY_FILENAME_PREFIXES = /* @__PURE__ */ new Set(["company", "other", "person", "place", "project", "tool", "topic"]);
6066
5667
  function inferEntityTypeFromFilename(pathRel) {
6067
- const basename = path10.basename(pathRel, ".md").toLowerCase();
5668
+ const basename = path9.basename(pathRel, ".md").toLowerCase();
6068
5669
  const separator = basename.indexOf("-");
6069
5670
  if (separator <= 0) return void 0;
6070
5671
  const candidate = basename.slice(0, separator);
6071
5672
  return KNOWN_ENTITY_FILENAME_PREFIXES.has(candidate) ? candidate : void 0;
6072
5673
  }
6073
5674
  function normalizeFrontmatterForPath(frontmatter, pathRel, content = "") {
6074
- const normalizedPath = pathRel.split(path10.sep).join("/");
5675
+ const normalizedPath = pathRel.split(path9.sep).join("/");
6075
5676
  let normalizedFrontmatter = frontmatter;
6076
5677
  if (normalizedPath === "entities" || normalizedPath.startsWith("entities/") || normalizedPath.includes("/entities/")) {
6077
- const basename = path10.basename(pathRel, ".md");
5678
+ const basename = path9.basename(pathRel, ".md");
6078
5679
  const inferredType = inferEntityTypeFromContent(content) || inferEntityTypeFromFilename(pathRel) || "entity";
6079
5680
  const existingTags = Array.isArray(frontmatter.tags) ? frontmatter.tags : [];
6080
5681
  normalizedFrontmatter = {
@@ -6534,8 +6135,9 @@ function parseExtractionRetryStateEntries(raw) {
6534
6135
  }
6535
6136
  return valid;
6536
6137
  }
6537
- var StorageManager3 = class _StorageManager {
6138
+ var StorageManager3 = class _StorageManager extends TombstoneBlockedCaptureIndexHost {
6538
6139
  constructor(baseDir, entitySchemas, hotMemoriesCacheEnabledOverride) {
6140
+ super();
6539
6141
  this.baseDir = baseDir;
6540
6142
  this.entitySchemas = entitySchemas;
6541
6143
  this.hotMemoriesCacheEnabled = hotMemoriesCacheEnabledOverride ?? _StorageManager.hotMemoriesCacheDefaultByDir.get(baseDir) ?? _StorageManager.hotMemoriesCacheDefault;
@@ -6720,8 +6322,8 @@ var StorageManager3 = class _StorageManager {
6720
6322
  }
6721
6323
  /** Whether `filePath` resolves to `stateDir` itself or a path contained in it. */
6722
6324
  isStateFilePath(filePath) {
6723
- const rel = path10.relative(this.stateDir, path10.resolve(filePath));
6724
- return rel === "" || !rel.startsWith("..") && !path10.isAbsolute(rel);
6325
+ const rel = path9.relative(this.stateDir, path9.resolve(filePath));
6326
+ return rel === "" || !rel.startsWith("..") && !path9.isAbsolute(rel);
6725
6327
  }
6726
6328
  // ── Tombstone store (issue #1579) ───────────────────────────────────────
6727
6329
  // Instance-scoped (rule 11) + namespace-scoped (rule 42) tombstone index.
@@ -6838,8 +6440,8 @@ var StorageManager3 = class _StorageManager {
6838
6440
  * /srv/cold/remnic), skipping the patch and stranding a stale hot entry.
6839
6441
  */
6840
6442
  isColdOrArchiveTierPath(p) {
6841
- const rel = path10.relative(this.baseDir, p);
6842
- return rel === "cold" || rel === "archive" || rel.startsWith(`cold${path10.sep}`) || rel.startsWith(`archive${path10.sep}`);
6443
+ const rel = path9.relative(this.baseDir, p);
6444
+ return rel === "cold" || rel === "archive" || rel.startsWith(`cold${path9.sep}`) || rel.startsWith(`archive${path9.sep}`);
6843
6445
  }
6844
6446
  /**
6845
6447
  * Mark the secure-store as required for this storage instance.
@@ -6926,7 +6528,7 @@ var StorageManager3 = class _StorageManager {
6926
6528
  void 0,
6927
6529
  this.baseDir
6928
6530
  );
6929
- const rel = path10.relative(this.baseDir, filePath).split(path10.sep).join("/");
6531
+ const rel = path9.relative(this.baseDir, filePath).split(path9.sep).join("/");
6930
6532
  return `${rel}:${version.versionId}`;
6931
6533
  } catch (err) {
6932
6534
  log.warn(
@@ -7006,13 +6608,13 @@ var StorageManager3 = class _StorageManager {
7006
6608
  }
7007
6609
  identityFilePath(workspaceDir, namespace) {
7008
6610
  const rawNamespace = typeof namespace === "string" ? namespace.trim() : "";
7009
- if (!rawNamespace) return path10.join(workspaceDir, "IDENTITY.md");
6611
+ if (!rawNamespace) return path9.join(workspaceDir, "IDENTITY.md");
7010
6612
  const safeNamespace = rawNamespace.replace(/[^a-zA-Z0-9._-]/g, "-");
7011
- return path10.join(workspaceDir, `IDENTITY.${safeNamespace}.md`);
6613
+ return path9.join(workspaceDir, `IDENTITY.${safeNamespace}.md`);
7012
6614
  }
7013
6615
  versionFilePath(kind) {
7014
6616
  const fileName = kind === "memory-status" ? ".memory-status-version.log" : kind === "artifact-write" ? ".artifact-write-version.log" : kind === "cold-write" ? ".cold-write-version.log" : ".memory-corpus-version.log";
7015
- return path10.join(this.stateDir, fileName);
6617
+ return path9.join(this.stateDir, fileName);
7016
6618
  }
7017
6619
  bumpSharedVersion(kind, fallbackMap) {
7018
6620
  const filePath = this.versionFilePath(kind);
@@ -7104,7 +6706,7 @@ var StorageManager3 = class _StorageManager {
7104
6706
  // memories.
7105
6707
  // -------------------------------------------------------------------------
7106
6708
  get wearablesDir() {
7107
- return path10.join(this.baseDir, WEARABLES_DIR_NAME);
6709
+ return path9.join(this.baseDir, WEARABLES_DIR_NAME);
7108
6710
  }
7109
6711
  /**
7110
6712
  * Resolve the on-disk path for a source/day transcript. Throws on
@@ -7120,7 +6722,7 @@ var StorageManager3 = class _StorageManager {
7120
6722
  if (!isValidTranscriptDate(date)) {
7121
6723
  throw new Error(`invalid wearable transcript date '${String(date)}' \u2014 expected YYYY-MM-DD`);
7122
6724
  }
7123
- return path10.join(this.wearablesDir, sourceId, `${date}.md`);
6725
+ return path9.join(this.wearablesDir, sourceId, `${date}.md`);
7124
6726
  }
7125
6727
  async writeWearableDayTranscript(sourceId, date, serialized) {
7126
6728
  const targetPath = this.wearableTranscriptPath(sourceId, date);
@@ -7236,25 +6838,25 @@ var StorageManager3 = class _StorageManager {
7236
6838
  });
7237
6839
  }
7238
6840
  get factsDir() {
7239
- return path10.join(this.baseDir, "facts");
6841
+ return path9.join(this.baseDir, "facts");
7240
6842
  }
7241
6843
  get correctionsDir() {
7242
- return path10.join(this.baseDir, "corrections");
6844
+ return path9.join(this.baseDir, "corrections");
7243
6845
  }
7244
6846
  get proceduresDir() {
7245
- return path10.join(this.baseDir, "procedures");
6847
+ return path9.join(this.baseDir, "procedures");
7246
6848
  }
7247
6849
  get reasoningTracesDir() {
7248
- return path10.join(this.baseDir, "reasoning-traces");
6850
+ return path9.join(this.baseDir, "reasoning-traces");
7249
6851
  }
7250
6852
  get entitiesDir() {
7251
- return path10.join(this.baseDir, "entities");
6853
+ return path9.join(this.baseDir, "entities");
7252
6854
  }
7253
6855
  resolveEntityFilePath(name) {
7254
6856
  if (typeof name !== "string") return null;
7255
- const filePath = path10.resolve(this.entitiesDir, `${name}.md`);
7256
- const relative2 = path10.relative(this.entitiesDir, filePath);
7257
- if (relative2 === "" || relative2.startsWith("..") || path10.isAbsolute(relative2)) {
6857
+ const filePath = path9.resolve(this.entitiesDir, `${name}.md`);
6858
+ const relative2 = path9.relative(this.entitiesDir, filePath);
6859
+ if (relative2 === "" || relative2.startsWith("..") || path9.isAbsolute(relative2)) {
7258
6860
  return null;
7259
6861
  }
7260
6862
  return filePath;
@@ -7268,17 +6870,11 @@ var StorageManager3 = class _StorageManager {
7268
6870
  this.notifyCatalogWriteForPath(filePath);
7269
6871
  });
7270
6872
  }
7271
- writeStorageSecureFileChunks(filePath, chunks) {
7272
- const writeKey = this.resolveWriteKey();
7273
- return writeMaybeEncryptedFileFromChunks(filePath, chunks, writeKey, {}, this.baseDir).then(() => {
7274
- this.notifyCatalogWriteForPath(filePath);
7275
- });
7276
- }
7277
6873
  assertManagedStoragePath(filePath, method) {
7278
- const resolved = path10.resolve(filePath);
7279
- const base = path10.resolve(this.baseDir);
7280
- const rel = path10.relative(base, resolved);
7281
- if (rel === "" || rel === ".." || rel.startsWith(`..${path10.sep}`) || path10.isAbsolute(rel)) {
6874
+ const resolved = path9.resolve(filePath);
6875
+ const base = path9.resolve(this.baseDir);
6876
+ const rel = path9.relative(base, resolved);
6877
+ if (rel === "" || rel === ".." || rel.startsWith(`..${path9.sep}`) || path9.isAbsolute(rel)) {
7282
6878
  throw new Error(`${method}: file path escapes memory dir`);
7283
6879
  }
7284
6880
  return resolved;
@@ -7289,8 +6885,8 @@ var StorageManager3 = class _StorageManager {
7289
6885
  }
7290
6886
  async digestOfflineSyncFile(filePath) {
7291
6887
  const target = this.assertManagedStoragePath(filePath, "storage.digestOfflineSyncFile");
7292
- const st = await stat3(target);
7293
- const relPath = path10.relative(this.baseDir, target).split(path10.sep).join("/");
6888
+ const st = await stat2(target);
6889
+ const relPath = path9.relative(this.baseDir, target).split(path9.sep).join("/");
7294
6890
  const cache = await this.loadOfflineSyncDigestCache();
7295
6891
  const cached = cache.get(relPath);
7296
6892
  if (cached && cached.statBytes === st.size && cached.mtimeMs === st.mtimeMs && cached.ctimeMs === st.ctimeMs && !cached.encrypted) {
@@ -7351,7 +6947,7 @@ var StorageManager3 = class _StorageManager {
7351
6947
  const bytes = typeof record.bytes === "number" ? record.bytes : NaN;
7352
6948
  const sha256 = typeof record.sha256 === "string" ? record.sha256 : "";
7353
6949
  const encrypted = record.encrypted === true;
7354
- if (cachePath.length === 0 || cachePath === ".." || cachePath.startsWith("../") || path10.isAbsolute(cachePath) || !Number.isFinite(statBytes) || !Number.isFinite(mtimeMs) || !Number.isFinite(ctimeMs) || !Number.isFinite(bytes) || !/^[a-f0-9]{64}$/i.test(sha256)) {
6950
+ if (cachePath.length === 0 || cachePath === ".." || cachePath.startsWith("../") || path9.isAbsolute(cachePath) || !Number.isFinite(statBytes) || !Number.isFinite(mtimeMs) || !Number.isFinite(ctimeMs) || !Number.isFinite(bytes) || !/^[a-f0-9]{64}$/i.test(sha256)) {
7355
6951
  continue;
7356
6952
  }
7357
6953
  cache.set(cachePath, { statBytes, mtimeMs, ctimeMs, encrypted, sha256, bytes });
@@ -7393,7 +6989,7 @@ var StorageManager3 = class _StorageManager {
7393
6989
  const cache = this.offlineSyncDigestCache;
7394
6990
  if (!cache) return;
7395
6991
  const entries = [...cache.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([entryPath, entry]) => ({ path: entryPath, ...entry }));
7396
- await mkdir2(path10.dirname(this.offlineSyncDigestCachePath), { recursive: true });
6992
+ await mkdir(path9.dirname(this.offlineSyncDigestCachePath), { recursive: true });
7397
6993
  await writeFile2(this.offlineSyncDigestCachePath, `${JSON.stringify({ version: 1, entries })}
7398
6994
  `, "utf-8");
7399
6995
  }).catch((err) => {
@@ -7412,40 +7008,10 @@ var StorageManager3 = class _StorageManager {
7412
7008
  await handle.close();
7413
7009
  }
7414
7010
  }
7415
- async writeOfflineSyncFile(filePath, content) {
7416
- const target = this.assertManagedStoragePath(filePath, "storage.writeOfflineSyncFile");
7417
- await this.writeStorageSecureFile(target, content);
7418
- await this.invalidateAfterOfflineSyncMutation(target);
7419
- }
7420
7011
  async writeOfflineSyncStagingFile(filePath, content) {
7421
7012
  const target = this.assertManagedStoragePath(filePath, "storage.writeOfflineSyncStagingFile");
7422
7013
  await this.writeStorageSecureFile(target, content);
7423
7014
  }
7424
- async writeOfflineSyncFileChunks(filePath, chunks) {
7425
- const target = this.assertManagedStoragePath(filePath, "storage.writeOfflineSyncFileChunks");
7426
- await this.writeStorageSecureFileChunks(target, chunks);
7427
- await this.invalidateAfterOfflineSyncMutation(target);
7428
- }
7429
- async deleteOfflineSyncFile(filePath) {
7430
- const target = this.assertManagedStoragePath(filePath, "storage.deleteOfflineSyncFile");
7431
- await unlink3(target).catch((error) => {
7432
- if (isErrnoCode(error, "ENOENT")) return;
7433
- throw error;
7434
- });
7435
- await this.invalidateAfterOfflineSyncMutation(target);
7436
- }
7437
- async invalidateAfterOfflineSyncMutation(filePath) {
7438
- this.invalidateAllMemoriesCache();
7439
- this.invalidateKnowledgeIndexCache();
7440
- this.factHashIndexAuthoritative = false;
7441
- if (filePath.includes(`${path10.sep}cold${path10.sep}`)) {
7442
- this.invalidateColdMemoriesCache();
7443
- }
7444
- if (filePath.includes(`${path10.sep}artifacts${path10.sep}`)) {
7445
- this.bumpArtifactWriteVersion();
7446
- }
7447
- this.bumpMemoryStatusVersion();
7448
- }
7449
7015
  createContentHashIndex() {
7450
7016
  return new ContentHashIndex(
7451
7017
  this.stateDir,
@@ -7481,7 +7047,7 @@ var StorageManager3 = class _StorageManager {
7481
7047
  async isEncryptedFileHeader(filePath) {
7482
7048
  let st;
7483
7049
  try {
7484
- st = await stat3(filePath);
7050
+ st = await stat2(filePath);
7485
7051
  } catch (err) {
7486
7052
  if (isErrnoCode(err, "ENOENT")) return false;
7487
7053
  throw err;
@@ -7512,7 +7078,7 @@ var StorageManager3 = class _StorageManager {
7512
7078
  }
7513
7079
  async appendStorageSecureFileUnlocked(filePath, content) {
7514
7080
  const writeKey = this.resolveWriteKey();
7515
- await mkdir2(path10.dirname(filePath), { recursive: true });
7081
+ await mkdir(path9.dirname(filePath), { recursive: true });
7516
7082
  if (writeKey === null) {
7517
7083
  try {
7518
7084
  if (await this.isEncryptedFileHeader(filePath)) {
@@ -7538,13 +7104,13 @@ var StorageManager3 = class _StorageManager {
7538
7104
  this.notifyCatalogWriteForPath(filePath);
7539
7105
  }
7540
7106
  get stateDir() {
7541
- return path10.join(this.baseDir, "state");
7107
+ return path9.join(this.baseDir, "state");
7542
7108
  }
7543
7109
  get offlineSyncDigestCachePath() {
7544
- return path10.join(this.baseDir, ".offline-sync", "digest-cache.v1.json");
7110
+ return path9.join(this.baseDir, ".offline-sync", "digest-cache.v1.json");
7545
7111
  }
7546
7112
  get entitySynthesisQueuePath() {
7547
- return path10.join(this.stateDir, "entity-synthesis-queue.json");
7113
+ return path9.join(this.stateDir, "entity-synthesis-queue.json");
7548
7114
  }
7549
7115
  // ── Tombstone store access (issue #1579) ─────────────────────────────────
7550
7116
  /**
@@ -7554,7 +7120,7 @@ var StorageManager3 = class _StorageManager {
7554
7120
  * helpers are injected into the store).
7555
7121
  */
7556
7122
  get tombstonesPath() {
7557
- return path10.join(this.stateDir, "tombstones.jsonl");
7123
+ return path9.join(this.stateDir, "tombstones.jsonl");
7558
7124
  }
7559
7125
  /**
7560
7126
  * Configure the tombstone invariant for this storage instance. Installed
@@ -7683,6 +7249,28 @@ var StorageManager3 = class _StorageManager {
7683
7249
  });
7684
7250
  return await store.rebuild(retired);
7685
7251
  }
7252
+ markFactHashIndexNotAuthoritative() {
7253
+ this.factHashIndexAuthoritative = false;
7254
+ }
7255
+ tombstoneBlockedCaptureIndexOptions() {
7256
+ return {
7257
+ stateDir: this.stateDir,
7258
+ memoryDir: this.baseDir,
7259
+ secureStoreKeyProvider: () => this._secureStoreKey,
7260
+ secureStoreWriteKeyProvider: () => this.resolveWriteKey(),
7261
+ lockOptions: () => this.factHashIndexLockOptions,
7262
+ parseMemory: (filePath, content) => parseTombstoneBlockedOfflineSyncMemory(
7263
+ filePath,
7264
+ content,
7265
+ this.baseDir,
7266
+ parseFrontmatter,
7267
+ normalizeFrontmatterForPath,
7268
+ toMemoryPathRel
7269
+ ),
7270
+ readAllMemories: () => this.readAllMemories(),
7271
+ readAllColdMemories: () => this.readAllColdMemories()
7272
+ };
7273
+ }
7686
7274
  async getFactHashIndex() {
7687
7275
  if (this.factHashIndex) {
7688
7276
  return this.factHashIndex;
@@ -7744,9 +7332,7 @@ var StorageManager3 = class _StorageManager {
7744
7332
  const baseMs = this.factHashIndexLockOptions.retryBaseMs ?? FACT_HASH_INDEX_REBUILD_RETRY_BASE_MS;
7745
7333
  let published = false;
7746
7334
  for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
7747
- published = await factHashIndex.rebuildUnderLock(
7748
- () => this.rebuildFactHashIndexFromCorpus(factHashIndex)
7749
- );
7335
+ published = await factHashIndex.rebuildUnderLock(() => this.rebuildFactHashIndexFromCorpus(factHashIndex));
7750
7336
  if (published || attempt === maxAttempts - 1) break;
7751
7337
  const wait = Math.min(baseMs * 2 ** attempt, CONTENT_HASH_INDEX_RETRY_MAX_DELAY_MS);
7752
7338
  await new Promise((resolve3) => setTimeout(resolve3, wait));
@@ -7772,10 +7358,7 @@ var StorageManager3 = class _StorageManager {
7772
7358
  async rebuildFactHashIndexFromCorpus(factHashIndex) {
7773
7359
  factHashIndex.clear();
7774
7360
  this.factOnlyHashes.clear();
7775
- const existing = [
7776
- ...await this.readAllMemories(),
7777
- ...await this.readAllColdMemories()
7778
- ];
7361
+ const existing = [...await this.readAllMemories(), ...await this.readAllColdMemories()];
7779
7362
  let legacyRecovered = 0;
7780
7363
  for (const memory of existing) {
7781
7364
  if (inferMemoryStatus(memory.frontmatter, memory.path) !== "active") continue;
@@ -7827,55 +7410,55 @@ var StorageManager3 = class _StorageManager {
7827
7410
  return null;
7828
7411
  }
7829
7412
  get questionsDir() {
7830
- return path10.join(this.baseDir, "questions");
7413
+ return path9.join(this.baseDir, "questions");
7831
7414
  }
7832
7415
  get artifactsDir() {
7833
- return path10.join(this.baseDir, "artifacts");
7416
+ return path9.join(this.baseDir, "artifacts");
7834
7417
  }
7835
7418
  get identityDir() {
7836
- return path10.join(this.baseDir, "identity");
7419
+ return path9.join(this.baseDir, "identity");
7837
7420
  }
7838
7421
  get identityAnchorPath() {
7839
- return path10.join(this.identityDir, "identity-anchor.md");
7422
+ return path9.join(this.identityDir, "identity-anchor.md");
7840
7423
  }
7841
7424
  get identityIncidentsDir() {
7842
- return path10.join(this.identityDir, "incidents");
7425
+ return path9.join(this.identityDir, "incidents");
7843
7426
  }
7844
7427
  get identityAuditsWeeklyDir() {
7845
- return path10.join(this.identityDir, "audits", "weekly");
7428
+ return path9.join(this.identityDir, "audits", "weekly");
7846
7429
  }
7847
7430
  get identityAuditsMonthlyDir() {
7848
- return path10.join(this.identityDir, "audits", "monthly");
7431
+ return path9.join(this.identityDir, "audits", "monthly");
7849
7432
  }
7850
7433
  get identityImprovementLoopsPath() {
7851
- return path10.join(this.identityDir, "improvement-loops.md");
7434
+ return path9.join(this.identityDir, "improvement-loops.md");
7852
7435
  }
7853
7436
  get identityReflectionsPath() {
7854
- return path10.join(this.identityDir, "reflections.md");
7437
+ return path9.join(this.identityDir, "reflections.md");
7855
7438
  }
7856
7439
  get profilePath() {
7857
- return path10.join(this.baseDir, "profile.md");
7440
+ return path9.join(this.baseDir, "profile.md");
7858
7441
  }
7859
7442
  get memoryActionsPath() {
7860
- return path10.join(this.stateDir, "memory-actions.jsonl");
7443
+ return path9.join(this.stateDir, "memory-actions.jsonl");
7861
7444
  }
7862
7445
  get memoryLifecycleLedgerPath() {
7863
- return path10.join(this.stateDir, "memory-lifecycle-ledger.jsonl");
7446
+ return path9.join(this.stateDir, "memory-lifecycle-ledger.jsonl");
7864
7447
  }
7865
7448
  get compressionGuidelinesPath() {
7866
- return path10.join(this.stateDir, "compression-guidelines.md");
7449
+ return path9.join(this.stateDir, "compression-guidelines.md");
7867
7450
  }
7868
7451
  get compressionGuidelineDraftPath() {
7869
- return path10.join(this.stateDir, "compression-guidelines.draft.md");
7452
+ return path9.join(this.stateDir, "compression-guidelines.draft.md");
7870
7453
  }
7871
7454
  get compressionGuidelineStatePath() {
7872
- return path10.join(this.stateDir, "compression-guideline-state.json");
7455
+ return path9.join(this.stateDir, "compression-guideline-state.json");
7873
7456
  }
7874
7457
  get compressionGuidelineDraftStatePath() {
7875
- return path10.join(this.stateDir, "compression-guideline-draft-state.json");
7458
+ return path9.join(this.stateDir, "compression-guideline-draft-state.json");
7876
7459
  }
7877
7460
  get behaviorSignalsPath() {
7878
- return path10.join(this.stateDir, "behavior-signals.jsonl");
7461
+ return path9.join(this.stateDir, "behavior-signals.jsonl");
7879
7462
  }
7880
7463
  /**
7881
7464
  * In-memory dedup key set for behavior-signals appends (issue #1909),
@@ -7907,7 +7490,7 @@ var StorageManager3 = class _StorageManager {
7907
7490
  * governance sweeps can treat it uniformly.
7908
7491
  */
7909
7492
  get bufferSurpriseLedgerPath() {
7910
- return path10.join(this.stateDir, "buffer-surprise-ledger.jsonl");
7493
+ return path9.join(this.stateDir, "buffer-surprise-ledger.jsonl");
7911
7494
  }
7912
7495
  /**
7913
7496
  * Entity alias table loaded from THIS store's config/aliases.json.
@@ -7947,7 +7530,7 @@ var StorageManager3 = class _StorageManager {
7947
7530
  this.loadAliasesSync();
7948
7531
  }
7949
7532
  loadAliasesSync() {
7950
- const aliasPath = path10.join(this.baseDir, "config", "aliases.json");
7533
+ const aliasPath = path9.join(this.baseDir, "config", "aliases.json");
7951
7534
  this.userAliases = {};
7952
7535
  try {
7953
7536
  const raw = readFileSync2(aliasPath, "utf-8");
@@ -7982,22 +7565,22 @@ var StorageManager3 = class _StorageManager {
7982
7565
  return completionFingerprint;
7983
7566
  }
7984
7567
  async ensureDirectories() {
7985
- await mkdir2(this.baseDir, { recursive: true });
7568
+ await mkdir(this.baseDir, { recursive: true });
7986
7569
  await validateRoots(this.baseDir, this.entitiesDir, this.stateDir, this.archiveDir);
7987
7570
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
7988
- await mkdir2(path10.join(this.factsDir, today), { recursive: true });
7989
- await mkdir2(path10.join(this.proceduresDir, today), { recursive: true });
7990
- await mkdir2(path10.join(this.reasoningTracesDir, today), { recursive: true });
7991
- await mkdir2(this.correctionsDir, { recursive: true });
7992
- await mkdir2(this.entitiesDir, { recursive: true });
7993
- await mkdir2(this.stateDir, { recursive: true });
7994
- await mkdir2(this.questionsDir, { recursive: true });
7995
- await mkdir2(this.artifactsDir, { recursive: true });
7996
- await mkdir2(this.identityDir, { recursive: true });
7997
- await mkdir2(this.identityIncidentsDir, { recursive: true });
7998
- await mkdir2(this.identityAuditsWeeklyDir, { recursive: true });
7999
- await mkdir2(this.identityAuditsMonthlyDir, { recursive: true });
8000
- await mkdir2(path10.join(this.baseDir, "config"), { recursive: true });
7571
+ await mkdir(path9.join(this.factsDir, today), { recursive: true });
7572
+ await mkdir(path9.join(this.proceduresDir, today), { recursive: true });
7573
+ await mkdir(path9.join(this.reasoningTracesDir, today), { recursive: true });
7574
+ await mkdir(this.correctionsDir, { recursive: true });
7575
+ await mkdir(this.entitiesDir, { recursive: true });
7576
+ await mkdir(this.stateDir, { recursive: true });
7577
+ await mkdir(this.questionsDir, { recursive: true });
7578
+ await mkdir(this.artifactsDir, { recursive: true });
7579
+ await mkdir(this.identityDir, { recursive: true });
7580
+ await mkdir(this.identityIncidentsDir, { recursive: true });
7581
+ await mkdir(this.identityAuditsWeeklyDir, { recursive: true });
7582
+ await mkdir(this.identityAuditsMonthlyDir, { recursive: true });
7583
+ await mkdir(path9.join(this.baseDir, "config"), { recursive: true });
8001
7584
  await this.entityCanonicalIdMigration.ensure();
8002
7585
  if (this.hotMemoriesCacheEnabled && this.getMemoryCorpusVersion() === 0) {
8003
7586
  this.bumpMemoryCorpusVersion();
@@ -8018,12 +7601,24 @@ var StorageManager3 = class _StorageManager {
8018
7601
  */
8019
7602
  async resolveCategoryWritePath(category, id, today) {
8020
7603
  if (category === "correction") {
8021
- await mkdir2(this.correctionsDir, { recursive: true });
8022
- return path10.join(this.correctionsDir, `${id}.md`);
8023
- }
8024
- const datedDir = path10.join(getCategoryDir(this.baseDir, category), today);
8025
- await mkdir2(datedDir, { recursive: true });
8026
- return path10.join(datedDir, `${id}.md`);
7604
+ await mkdir(this.correctionsDir, { recursive: true });
7605
+ return path9.join(this.correctionsDir, `${id}.md`);
7606
+ }
7607
+ const datedDir = path9.join(getCategoryDir(this.baseDir, category), today);
7608
+ await mkdir(datedDir, { recursive: true });
7609
+ return path9.join(datedDir, `${id}.md`);
7610
+ }
7611
+ async findExistingTombstoneBlockedMemory(content, category, sourceConnector) {
7612
+ const identity = buildExplicitCaptureDedupKey(content, category, sourceConnector);
7613
+ const memories = [...await this.readAllMemories(), ...await this.readAllColdMemories()];
7614
+ return memories.find((memory) => {
7615
+ if (memory.frontmatter.status !== "pending_review" || !memory.frontmatter.blockedBy) return false;
7616
+ return buildExplicitCaptureDedupKey(
7617
+ memory.content,
7618
+ memory.frontmatter.category,
7619
+ memory.frontmatter.sourceConnector
7620
+ ) === identity;
7621
+ }) ?? null;
8027
7622
  }
8028
7623
  async writeMemory(category, content, options = {}) {
8029
7624
  await this.ensureDirectories();
@@ -8139,8 +7734,29 @@ var StorageManager3 = class _StorageManager {
8139
7734
  ${sanitized.text}
8140
7735
  `;
8141
7736
  const filePath = await this.resolveCategoryWritePath(category, id, today);
8142
- await this.snapshotBeforeWrite(filePath, "write");
8143
- await this.writeStorageSecureFile(filePath, fileContent);
7737
+ const persistFile = async () => {
7738
+ if (tombstoneBlocked) {
7739
+ const duplicate = await this.findExistingTombstoneBlockedMemory(sanitized.text, category, fm.sourceConnector);
7740
+ if (duplicate) return duplicate;
7741
+ }
7742
+ await this.snapshotBeforeWrite(filePath, "write");
7743
+ await this.writeTombstoneBlockedMemory(filePath, fileContent, fm, sanitized.text, async () => {
7744
+ this.invalidateAllMemoriesCache();
7745
+ });
7746
+ return null;
7747
+ };
7748
+ const duplicateBlocked = tombstoneBlocked ? await this.withTombstoneBlockedCaptureWriteLock(
7749
+ persistFile,
7750
+ buildExplicitCaptureDedupKey(sanitized.text, category, fm.sourceConnector)
7751
+ ) : await persistFile();
7752
+ if (duplicateBlocked) {
7753
+ return {
7754
+ id: duplicateBlocked.frontmatter.id,
7755
+ tombstoneBlocked: true,
7756
+ blockedBy: duplicateBlocked.frontmatter.blockedBy,
7757
+ duplicateOf: duplicateBlocked.frontmatter.id
7758
+ };
7759
+ }
8144
7760
  await this.patchHotMemoriesCache({ addedPath: filePath }, "memory-create");
8145
7761
  this.notifyMemoryWrite(filePath);
8146
7762
  await this.appendGeneratedMemoryLifecycleEventFailOpen("storage.writeMemory", {
@@ -8209,10 +7825,7 @@ ${sanitized.text}
8209
7825
  return await this.factContentHashPresentInCorpus(hash);
8210
7826
  }
8211
7827
  async factContentHashPresentInCorpus(targetHash) {
8212
- const existing = [
8213
- ...await this.readAllMemories(),
8214
- ...await this.readAllColdMemories()
8215
- ];
7828
+ const existing = [...await this.readAllMemories(), ...await this.readAllColdMemories()];
8216
7829
  for (const memory of existing) {
8217
7830
  if (memory.frontmatter.category !== "fact") continue;
8218
7831
  if (inferMemoryStatus(memory.frontmatter, memory.path) !== "active") continue;
@@ -8328,8 +7941,8 @@ ${sanitized.text}
8328
7941
  await this.ensureDirectories();
8329
7942
  const now = /* @__PURE__ */ new Date();
8330
7943
  const day = now.toISOString().slice(0, 10);
8331
- const dir = path10.join(this.artifactsDir, day);
8332
- await mkdir2(dir, { recursive: true });
7944
+ const dir = path9.join(this.artifactsDir, day);
7945
+ await mkdir(dir, { recursive: true });
8333
7946
  const id = `artifact-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
8334
7947
  const fm = {
8335
7948
  id,
@@ -8353,7 +7966,7 @@ ${sanitized.text}
8353
7966
  log.warn(`artifact content rejected for ${id}; violations=${sanitized.violations.join(", ")}`);
8354
7967
  return "";
8355
7968
  }
8356
- const filePath = path10.join(dir, `${id}.md`);
7969
+ const filePath = path9.join(dir, `${id}.md`);
8357
7970
  await this.writeStorageSecureFile(filePath, `${serializeFrontmatter(fm)}
8358
7971
 
8359
7972
  ${sanitized.text}
@@ -8624,7 +8237,7 @@ ${sanitized.text}
8624
8237
  * per-process in-memory cache safe across process boundaries.
8625
8238
  */
8626
8239
  invalidateColdMemoriesCache() {
8627
- const coldRoot = path10.join(this.baseDir, "cold");
8240
+ const coldRoot = path9.join(this.baseDir, "cold");
8628
8241
  _StorageManager.coldMemoriesCache.delete(coldRoot);
8629
8242
  this.bumpColdWriteVersion();
8630
8243
  invalidateAllForDir(this.baseDir);
@@ -8726,7 +8339,7 @@ ${sanitized.text}
8726
8339
  return updatedMs >= updatedAfterMs ? filePath : null;
8727
8340
  }
8728
8341
  try {
8729
- const fileStat = await stat3(filePath);
8342
+ const fileStat = await stat2(filePath);
8730
8343
  return fileStat.mtimeMs >= updatedAfterMs ? filePath : null;
8731
8344
  } catch {
8732
8345
  return filePath;
@@ -8739,7 +8352,7 @@ ${sanitized.text}
8739
8352
  const correctionPaths = [];
8740
8353
  const factPaths = [];
8741
8354
  for (const filePath of filePaths) {
8742
- if (filePath === this.correctionsDir || filePath.startsWith(`${this.correctionsDir}${path10.sep}`)) {
8355
+ if (filePath === this.correctionsDir || filePath.startsWith(`${this.correctionsDir}${path9.sep}`)) {
8743
8356
  correctionPaths.push(filePath);
8744
8357
  } else {
8745
8358
  factPaths.push(filePath);
@@ -8802,7 +8415,7 @@ ${sanitized.text}
8802
8415
  try {
8803
8416
  const entries = await readdir5(dir, { withFileTypes: true });
8804
8417
  for (const entry of entries) {
8805
- const fullPath = path10.join(dir, entry.name);
8418
+ const fullPath = path9.join(dir, entry.name);
8806
8419
  if (entry.isDirectory()) {
8807
8420
  await readDir(fullPath);
8808
8421
  } else if (entry.name.endsWith(".md")) {
@@ -8835,7 +8448,7 @@ ${sanitized.text}
8835
8448
  return this.memoryReadStore.readMemoryByPath(filePath);
8836
8449
  }
8837
8450
  resolveTierRootDir(tier) {
8838
- return tier === "cold" ? path10.join(this.baseDir, "cold") : this.baseDir;
8451
+ return tier === "cold" ? path9.join(this.baseDir, "cold") : this.baseDir;
8839
8452
  }
8840
8453
  resolveMemoryDateDir(memory) {
8841
8454
  const preferred = memory.frontmatter.created || memory.frontmatter.updated;
@@ -8850,13 +8463,13 @@ ${sanitized.text}
8850
8463
  buildTierMemoryPath(memory, tier) {
8851
8464
  const root = this.resolveTierRootDir(tier);
8852
8465
  if (this.isArtifactMemory(memory)) {
8853
- return path10.join(root, "artifacts", this.resolveMemoryDateDir(memory), `${memory.frontmatter.id}.md`);
8466
+ return path9.join(root, "artifacts", this.resolveMemoryDateDir(memory), `${memory.frontmatter.id}.md`);
8854
8467
  }
8855
8468
  if (memory.frontmatter.category === "correction") {
8856
- return path10.join(root, "corrections", `${memory.frontmatter.id}.md`);
8469
+ return path9.join(root, "corrections", `${memory.frontmatter.id}.md`);
8857
8470
  }
8858
8471
  const dir = categoryDirName(memory.frontmatter.category);
8859
- return path10.join(root, dir, this.resolveMemoryDateDir(memory), `${memory.frontmatter.id}.md`);
8472
+ return path9.join(root, dir, this.resolveMemoryDateDir(memory), `${memory.frontmatter.id}.md`);
8860
8473
  }
8861
8474
  async writeMemoryFileAtomic(targetPath, memory) {
8862
8475
  const fileContent = `${serializeFrontmatter(memory.frontmatter)}
@@ -8869,8 +8482,8 @@ ${memory.content}
8869
8482
  }
8870
8483
  async moveMemoryToPath(memory, targetPath) {
8871
8484
  await this.writeMemoryFileAtomic(targetPath, memory);
8872
- const sourcePath = path10.resolve(memory.path);
8873
- const destPath = path10.resolve(targetPath);
8485
+ const sourcePath = path9.resolve(memory.path);
8486
+ const destPath = path9.resolve(targetPath);
8874
8487
  if (sourcePath !== destPath) {
8875
8488
  try {
8876
8489
  await unlink3(memory.path);
@@ -8886,8 +8499,8 @@ ${memory.content}
8886
8499
  }
8887
8500
  async migrateMemoryToTier(memory, targetTier) {
8888
8501
  const targetPath = this.buildTierMemoryPath(memory, targetTier);
8889
- const sourcePath = path10.resolve(memory.path);
8890
- const destPath = path10.resolve(targetPath);
8502
+ const sourcePath = path9.resolve(memory.path);
8503
+ const destPath = path9.resolve(targetPath);
8891
8504
  if (sourcePath === destPath) {
8892
8505
  return { changed: false, targetPath };
8893
8506
  }
@@ -8914,7 +8527,7 @@ ${memory.content}
8914
8527
  return { changed: true, targetPath };
8915
8528
  }
8916
8529
  get archiveDir() {
8917
- return path10.join(this.baseDir, "archive");
8530
+ return path9.join(this.baseDir, "archive");
8918
8531
  }
8919
8532
  /**
8920
8533
  * Archive a memory by moving it from facts/ to archive/YYYY-MM-DD/.
@@ -8922,48 +8535,52 @@ ${memory.content}
8922
8535
  * Returns the new file path on success, null on failure.
8923
8536
  */
8924
8537
  async archiveMemory(memory, lifecycle) {
8925
- try {
8926
- const now = lifecycle?.at ?? /* @__PURE__ */ new Date();
8927
- const today = now.toISOString().slice(0, 10);
8928
- const destDir = path10.join(this.archiveDir, today);
8929
- await mkdir2(destDir, { recursive: true });
8930
- const updatedFm = {
8931
- ...memory.frontmatter,
8932
- status: "archived",
8933
- archivedAt: now.toISOString(),
8934
- updated: now.toISOString()
8935
- };
8936
- const fileContent = `${serializeFrontmatter(updatedFm)}
8538
+ const archiveCurrent = async (current, markDurable) => {
8539
+ try {
8540
+ const now = lifecycle?.at ?? /* @__PURE__ */ new Date();
8541
+ const today = now.toISOString().slice(0, 10);
8542
+ const destDir = path9.join(this.archiveDir, today);
8543
+ await mkdir(destDir, { recursive: true });
8544
+ const updatedFm = {
8545
+ ...current.frontmatter,
8546
+ status: "archived",
8547
+ archivedAt: now.toISOString(),
8548
+ updated: now.toISOString()
8549
+ };
8550
+ const fileContent = `${serializeFrontmatter(updatedFm)}
8937
8551
 
8938
- ${memory.content}
8552
+ ${current.content}
8939
8553
  `;
8940
- const destPath = path10.join(destDir, path10.basename(memory.path));
8941
- await this.writeStorageSecureFile(destPath, fileContent);
8942
- await unlink3(memory.path);
8943
- markProjectedMemoryPathInvalid(this.baseDir, memory.frontmatter.id);
8944
- this.invalidateAllMemoriesCache();
8945
- await this.appendGeneratedMemoryLifecycleEventFailOpen(
8946
- "storage.archiveMemory",
8947
- {
8948
- memoryId: memory.frontmatter.id,
8949
- eventType: "archived",
8950
- timestamp: updatedFm.archivedAt ?? updatedFm.updated,
8951
- actor: lifecycle?.actor ?? "storage.archiveMemory",
8952
- reasonCode: lifecycle?.reasonCode,
8953
- before: this.summarizeLifecycleState(memory.frontmatter, memory.path),
8954
- after: this.summarizeLifecycleState(updatedFm, destPath),
8955
- relatedMemoryIds: lifecycle?.relatedMemoryIds,
8956
- correlationId: lifecycle?.correlationId
8957
- },
8958
- lifecycle?.ruleVersion
8959
- );
8960
- this.bumpMemoryStatusVersion();
8961
- log.debug(`archived memory ${memory.frontmatter.id} \u2192 ${destPath}`);
8962
- return destPath;
8963
- } catch (err) {
8964
- log.warn(`failed to archive memory ${memory.frontmatter.id}: ${err}`);
8965
- return null;
8966
- }
8554
+ const destPath = path9.join(destDir, path9.basename(current.path));
8555
+ await this.writeStorageSecureFile(destPath, fileContent);
8556
+ await unlink3(current.path);
8557
+ markDurable();
8558
+ markProjectedMemoryPathInvalid(this.baseDir, current.frontmatter.id);
8559
+ this.invalidateAllMemoriesCache();
8560
+ await this.appendGeneratedMemoryLifecycleEventFailOpen(
8561
+ "storage.archiveMemory",
8562
+ {
8563
+ memoryId: current.frontmatter.id,
8564
+ eventType: "archived",
8565
+ timestamp: updatedFm.archivedAt ?? updatedFm.updated,
8566
+ actor: lifecycle?.actor ?? "storage.archiveMemory",
8567
+ reasonCode: lifecycle?.reasonCode,
8568
+ before: this.summarizeLifecycleState(current.frontmatter, current.path),
8569
+ after: this.summarizeLifecycleState(updatedFm, destPath),
8570
+ relatedMemoryIds: lifecycle?.relatedMemoryIds,
8571
+ correlationId: lifecycle?.correlationId
8572
+ },
8573
+ lifecycle?.ruleVersion
8574
+ );
8575
+ this.bumpMemoryStatusVersion();
8576
+ log.debug(`archived memory ${current.frontmatter.id} \u2192 ${destPath}`);
8577
+ return destPath;
8578
+ } catch (err) {
8579
+ log.warn(`failed to archive memory ${current.frontmatter.id}: ${err}`);
8580
+ return null;
8581
+ }
8582
+ };
8583
+ return await this.runTombstoneBlockedArchive(memory, archiveCurrent);
8967
8584
  }
8968
8585
  async readEntities() {
8969
8586
  try {
@@ -9016,18 +8633,21 @@ ${memory.content}
9016
8633
  }
9017
8634
  async invalidateMemory(id) {
9018
8635
  const memories = await this.readAllMemories();
9019
- const memory = memories.find((m) => m.frontmatter.id === id);
8636
+ const memory = memories.find((candidate) => candidate.frontmatter.id === id);
9020
8637
  if (!memory) return false;
9021
- try {
9022
- await unlink3(memory.path);
9023
- markProjectedMemoryPathInvalid(this.baseDir, id);
9024
- this.invalidateAllMemoriesCache();
9025
- this.bumpMemoryStatusVersion();
9026
- log.debug(`invalidated memory ${id}`);
9027
- return true;
9028
- } catch {
9029
- return false;
9030
- }
8638
+ return await this.runTombstoneBlockedInvalidation(
8639
+ memory,
8640
+ async (current, rebuildMarker, markDurable) => {
8641
+ await unlink3(current.path);
8642
+ markDurable();
8643
+ markProjectedMemoryPathInvalid(this.baseDir, id);
8644
+ this.invalidateAllMemoriesCache();
8645
+ await this.rebuildTombstoneBlockedCaptureAfterInvalidation(rebuildMarker);
8646
+ this.bumpMemoryStatusVersion();
8647
+ log.debug(`invalidated memory ${id}`);
8648
+ return true;
8649
+ }
8650
+ );
9031
8651
  }
9032
8652
  async updateMemory(id, newContent, options) {
9033
8653
  const memories = await this.readAllMemories();
@@ -9051,7 +8671,9 @@ ${memory.content}
9051
8671
 
9052
8672
  ${sanitized.text}
9053
8673
  `;
9054
- await this.writeStorageSecureFile(memory.path, fileContent);
8674
+ await this.writeTombstoneBlockedUpdate(memory, fileContent, updated, sanitized.text, async () => {
8675
+ this.invalidateAllMemoriesCache();
8676
+ });
9055
8677
  await this.patchHotMemoriesCache({ addedPath: memory.path });
9056
8678
  await this.appendGeneratedMemoryLifecycleEventFailOpen("storage.updateMemory", {
9057
8679
  memoryId: id,
@@ -9083,9 +8705,14 @@ ${sanitized.text}
9083
8705
 
9084
8706
  ${memory.content}
9085
8707
  `;
9086
- await this.writeStorageSecureFile(memory.path, fileContent);
8708
+ await this.writeTombstoneBlockedFrontmatter(memory, fileContent, updated, async () => {
8709
+ this.invalidateAllMemoriesCache();
8710
+ if (memory.path.includes(`${path9.sep}cold${path9.sep}`)) {
8711
+ this.invalidateColdMemoriesCache();
8712
+ }
8713
+ });
9087
8714
  await this.patchHotMemoriesCache({ addedPath: memory.path });
9088
- if (memory.path.includes(`${path10.sep}cold${path10.sep}`)) {
8715
+ if (memory.path.includes(`${path9.sep}cold${path9.sep}`)) {
9089
8716
  this.invalidateColdMemoriesCache();
9090
8717
  }
9091
8718
  try {
@@ -9138,15 +8765,14 @@ ${memory.content}
9138
8765
  for (const m of memories) {
9139
8766
  if (!m.frontmatter.expiresAt) continue;
9140
8767
  const expiresAt = new Date(m.frontmatter.expiresAt).getTime();
9141
- if (expiresAt < now) {
9142
- try {
9143
- await unlink3(m.path);
9144
- markProjectedMemoryPathInvalid(this.baseDir, m.frontmatter.id);
9145
- this.bumpMemoryCorpusVersion();
9146
- deleted.push(m);
9147
- log.debug(`cleaned expired memory ${m.frontmatter.id} (TTL expired)`);
9148
- } catch {
9149
- }
8768
+ if (expiresAt >= now) continue;
8769
+ const removed = await this.deleteMemoryForMaintenance(m, (current) => {
8770
+ const currentExpiresAt = current.frontmatter.expiresAt ? new Date(current.frontmatter.expiresAt).getTime() : Number.NaN;
8771
+ return Number.isFinite(currentExpiresAt) && currentExpiresAt < now;
8772
+ });
8773
+ if (removed) {
8774
+ deleted.push(removed);
8775
+ log.debug(`cleaned expired memory ${removed.frontmatter.id} (TTL expired)`);
9150
8776
  }
9151
8777
  }
9152
8778
  if (deleted.length > 0) {
@@ -9156,7 +8782,7 @@ ${memory.content}
9156
8782
  return deleted;
9157
8783
  }
9158
8784
  async loadBuffer() {
9159
- const bufferPath = path10.join(this.stateDir, "buffer.json");
8785
+ const bufferPath = path9.join(this.stateDir, "buffer.json");
9160
8786
  try {
9161
8787
  const raw = await this.readStorageSecureFile(bufferPath);
9162
8788
  return JSON.parse(raw);
@@ -9168,11 +8794,11 @@ ${memory.content}
9168
8794
  }
9169
8795
  async saveBuffer(state) {
9170
8796
  await this.ensureDirectories();
9171
- const bufferPath = path10.join(this.stateDir, "buffer.json");
8797
+ const bufferPath = path9.join(this.stateDir, "buffer.json");
9172
8798
  await this.writeStorageSecureFile(bufferPath, JSON.stringify(state, null, 2));
9173
8799
  }
9174
8800
  async loadMeta() {
9175
- const metaPath = path10.join(this.stateDir, "meta.json");
8801
+ const metaPath = path9.join(this.stateDir, "meta.json");
9176
8802
  try {
9177
8803
  const raw = await this.readStorageSecureFile(metaPath);
9178
8804
  const parsed = JSON.parse(raw);
@@ -9205,7 +8831,7 @@ ${memory.content}
9205
8831
  }
9206
8832
  async saveMeta(state) {
9207
8833
  await this.ensureDirectories();
9208
- const metaPath = path10.join(this.stateDir, "meta.json");
8834
+ const metaPath = path9.join(this.stateDir, "meta.json");
9209
8835
  await this.writeStorageSecureFile(metaPath, JSON.stringify(state, null, 2));
9210
8836
  }
9211
8837
  async appendMemoryActionEvents(events) {
@@ -9260,10 +8886,7 @@ ${memory.content}
9260
8886
  * The offline CLI uses this path-aware variant for per-namespace ledgers so
9261
8887
  * secure-store encryption and path-bound authentication remain consistent. */
9262
8888
  async drainPendingMemoryLifecycleEventsForSyncAt(ledgerPath) {
9263
- const target = this.assertManagedStoragePath(
9264
- ledgerPath,
9265
- "storage.drainPendingMemoryLifecycleEventsForSyncAt"
9266
- );
8889
+ const target = this.assertManagedStoragePath(ledgerPath, "storage.drainPendingMemoryLifecycleEventsForSyncAt");
9267
8890
  return drainPendingLifecycleLedgerForSync(
9268
8891
  target,
9269
8892
  {
@@ -9272,7 +8895,7 @@ ${memory.content}
9272
8895
  },
9273
8896
  (payload) => this.appendStorageSecureFile(target, payload),
9274
8897
  async () => {
9275
- await mkdir2(path10.dirname(target), { recursive: true });
8898
+ await mkdir(path9.dirname(target), { recursive: true });
9276
8899
  }
9277
8900
  );
9278
8901
  }
@@ -9304,7 +8927,7 @@ ${memory.content}
9304
8927
  let existingKeys;
9305
8928
  let identity = null;
9306
8929
  try {
9307
- const st = await stat3(this.behaviorSignalsPath);
8930
+ const st = await stat2(this.behaviorSignalsPath);
9308
8931
  identity = { size: st.size, mtimeMs: st.mtimeMs };
9309
8932
  if (this.behaviorSignalsKeyCache && this.behaviorSignalsKeyCache.identity.size === identity.size && this.behaviorSignalsKeyCache.identity.mtimeMs === identity.mtimeMs) {
9310
8933
  existingKeys = this.behaviorSignalsKeyCache.keys;
@@ -9352,7 +8975,7 @@ ${memory.content}
9352
8975
  await this.appendStorageSecureFile(this.behaviorSignalsPath, payload);
9353
8976
  for (const key of pending) existingKeys.add(key);
9354
8977
  try {
9355
- const st = await stat3(this.behaviorSignalsPath);
8978
+ const st = await stat2(this.behaviorSignalsPath);
9356
8979
  const expectedSize = (identity?.size ?? 0) + Buffer.byteLength(payload, "utf-8");
9357
8980
  if (st.size === expectedSize) {
9358
8981
  this.behaviorSignalsKeyCache = {
@@ -9370,7 +8993,7 @@ ${memory.content}
9370
8993
  async appendReextractJobs(events) {
9371
8994
  if (events.length === 0) return 0;
9372
8995
  await this.ensureDirectories();
9373
- const filePath = path10.join(this.stateDir, "reextract-jobs.jsonl");
8996
+ const filePath = path9.join(this.stateDir, "reextract-jobs.jsonl");
9374
8997
  const lines = events.map((event) => JSON.stringify(event)).join("\n") + "\n";
9375
8998
  try {
9376
8999
  await this.appendStorageSecureFile(filePath, lines);
@@ -9383,7 +9006,7 @@ ${memory.content}
9383
9006
  }
9384
9007
  async readReextractJobs(limit = 200) {
9385
9008
  const safeLimit = Number.isFinite(limit) ? Math.max(1, Math.min(1e3, Math.floor(limit))) : 200;
9386
- const filePath = path10.join(this.stateDir, "reextract-jobs.jsonl");
9009
+ const filePath = path9.join(this.stateDir, "reextract-jobs.jsonl");
9387
9010
  try {
9388
9011
  const raw = await this.readStorageSecureFile(filePath);
9389
9012
  const lines = raw.split("\n").filter((line) => line.trim().length > 0);
@@ -9463,10 +9086,7 @@ ${memory.content}
9463
9086
  }
9464
9087
  async readAllMemoryLifecycleEventsForCompaction() {
9465
9088
  if (!await probeEncryptedRegularFileHeader(this.memoryLifecycleLedgerPath)) {
9466
- return readAllLifecycleEventsFromLedger(
9467
- this.memoryLifecycleLedgerPath,
9468
- (p) => this.readStorageSecureFile(p)
9469
- );
9089
+ return readAllLifecycleEventsFromLedger(this.memoryLifecycleLedgerPath, (p) => this.readStorageSecureFile(p));
9470
9090
  }
9471
9091
  return readAllLifecycleEventsFromLedgerBuffer(
9472
9092
  this.memoryLifecycleLedgerPath,
@@ -9597,7 +9217,7 @@ ${memory.content}
9597
9217
  return `${prefix}-${ts}-${rand}`;
9598
9218
  }
9599
9219
  async writeQuestion(question, context, priority) {
9600
- await mkdir2(this.questionsDir, { recursive: true });
9220
+ await mkdir(this.questionsDir, { recursive: true });
9601
9221
  const id = this.generateId("q");
9602
9222
  const frontmatter = {
9603
9223
  id,
@@ -9613,7 +9233,7 @@ ${question}
9613
9233
 
9614
9234
  **Context:** ${context}
9615
9235
  `;
9616
- const filePath = path10.join(this.questionsDir, `${id}.md`);
9236
+ const filePath = path9.join(this.questionsDir, `${id}.md`);
9617
9237
  await this.writeStorageSecureFile(filePath, content);
9618
9238
  log.debug(`wrote question ${id} to ${filePath}`);
9619
9239
  this.invalidateQuestionsCache();
@@ -9631,7 +9251,7 @@ ${question}
9631
9251
  if (!match) return null;
9632
9252
  const frontmatterStr = match[1];
9633
9253
  const body = match[2].trim();
9634
- const id = this.extractFrontmatterValue(frontmatterStr, "id") ?? path10.basename(filePath, ".md");
9254
+ const id = this.extractFrontmatterValue(frontmatterStr, "id") ?? path9.basename(filePath, ".md");
9635
9255
  const created = this.extractFrontmatterValue(frontmatterStr, "created") ?? "";
9636
9256
  const priority = parseFloat(this.extractFrontmatterValue(frontmatterStr, "priority") ?? "0.5");
9637
9257
  const resolved = this.extractFrontmatterValue(frontmatterStr, "resolved") === "true";
@@ -9687,11 +9307,11 @@ ${question}
9687
9307
  } catch {
9688
9308
  }
9689
9309
  const hygiene = opts?.hygiene;
9690
- const rotateEnabled = hygiene?.enabled === true && hygiene.rotateEnabled === true && Array.isArray(hygiene.rotatePaths) && hygiene.rotatePaths.includes(path10.basename(identityPath));
9310
+ const rotateEnabled = hygiene?.enabled === true && hygiene.rotateEnabled === true && Array.isArray(hygiene.rotatePaths) && hygiene.rotatePaths.includes(path9.basename(identityPath));
9691
9311
  if (rotateEnabled) {
9692
9312
  const maxBytes = hygiene.rotateMaxBytes;
9693
9313
  if (existing.length > maxBytes) {
9694
- const archiveDir = path10.join(workspaceDir, hygiene.archiveDir);
9314
+ const archiveDir = path9.join(workspaceDir, hygiene.archiveDir);
9695
9315
  const { newContent } = await rotateMarkdownFileToArchive({
9696
9316
  filePath: identityPath,
9697
9317
  archiveDir,
@@ -9743,7 +9363,7 @@ ${reflection}
9743
9363
  }
9744
9364
  }
9745
9365
  async writeIdentityReflections(content) {
9746
- await mkdir2(this.identityDir, { recursive: true });
9366
+ await mkdir(this.identityDir, { recursive: true });
9747
9367
  await this.writeStorageSecureFile(this.identityReflectionsPath, content);
9748
9368
  }
9749
9369
  async appendIdentityReflection(reflection) {
@@ -9775,7 +9395,7 @@ ${reflection}
9775
9395
 
9776
9396
  ${reflection}
9777
9397
  `;
9778
- await mkdir2(this.identityDir, { recursive: true });
9398
+ await mkdir(this.identityDir, { recursive: true });
9779
9399
  await this.writeStorageSecureFile(this.identityReflectionsPath, `${existing.trimEnd()}${section}`);
9780
9400
  log.debug(`appended namespace-local reflection to ${this.identityReflectionsPath}`);
9781
9401
  }
@@ -9787,7 +9407,7 @@ ${reflection}
9787
9407
  * Deduplicates by target+label.
9788
9408
  */
9789
9409
  async addEntityRelationship(name, rel) {
9790
- const filePath = path10.join(this.entitiesDir, `${name}.md`);
9410
+ const filePath = path9.join(this.entitiesDir, `${name}.md`);
9791
9411
  let entity;
9792
9412
  try {
9793
9413
  const content = await this.readStorageSecureFile(filePath);
@@ -9810,7 +9430,7 @@ ${reflection}
9810
9430
  * Prepends to the beginning, prunes oldest entries beyond maxEntries.
9811
9431
  */
9812
9432
  async addEntityActivity(name, entry, maxEntries) {
9813
- const filePath = path10.join(this.entitiesDir, `${name}.md`);
9433
+ const filePath = path9.join(this.entitiesDir, `${name}.md`);
9814
9434
  let entity;
9815
9435
  try {
9816
9436
  const content = await this.readStorageSecureFile(filePath);
@@ -9830,7 +9450,7 @@ ${reflection}
9830
9450
  this.invalidateKnowledgeIndexCache();
9831
9451
  }
9832
9452
  async addEntityAlias(name, alias) {
9833
- const filePath = path10.join(this.entitiesDir, `${name}.md`);
9453
+ const filePath = path9.join(this.entitiesDir, `${name}.md`);
9834
9454
  let entity;
9835
9455
  try {
9836
9456
  const content = await this.readStorageSecureFile(filePath);
@@ -9858,7 +9478,7 @@ ${reflection}
9858
9478
  const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
9859
9479
  let synthesisTimelineCount;
9860
9480
  try {
9861
- const filePath = path10.join(this.entitiesDir, `${name}.md`);
9481
+ const filePath = path9.join(this.entitiesDir, `${name}.md`);
9862
9482
  const content = await this.readStorageSecureFile(filePath);
9863
9483
  synthesisTimelineCount = parseEntityFile(content, this.entitySchemas).timeline.length;
9864
9484
  } catch (err) {
@@ -9900,7 +9520,7 @@ ${reflection}
9900
9520
  const rightTs = latestEntityTimelineTimestamp(right.entity) ?? "";
9901
9521
  return compareEntityTimestamps(rightTs, leftTs);
9902
9522
  }).map(({ entityName }) => entityName);
9903
- await mkdir2(this.stateDir, { recursive: true });
9523
+ await mkdir(this.stateDir, { recursive: true });
9904
9524
  await this.writeStorageSecureFile(
9905
9525
  this.entitySynthesisQueuePath,
9906
9526
  JSON.stringify(
@@ -9920,7 +9540,7 @@ ${reflection}
9920
9540
  if (queue.length === 0) return;
9921
9541
  const removals = new Set(entityNames);
9922
9542
  const nextQueue = queue.filter((name) => !removals.has(name));
9923
- await mkdir2(this.stateDir, { recursive: true });
9543
+ await mkdir(this.stateDir, { recursive: true });
9924
9544
  await this.writeStorageSecureFile(
9925
9545
  this.entitySynthesisQueuePath,
9926
9546
  JSON.stringify(
@@ -9941,7 +9561,7 @@ ${reflection}
9941
9561
  if (!raw) continue;
9942
9562
  const serialized = serializeEntityFile(parseEntityFile(raw, this.entitySchemas), this.entitySchemas);
9943
9563
  if (raw.trimEnd() === serialized.trimEnd()) continue;
9944
- await this.writeStorageSecureFile(path10.join(this.entitiesDir, `${entityName}.md`), serialized);
9564
+ await this.writeStorageSecureFile(path9.join(this.entitiesDir, `${entityName}.md`), serialized);
9945
9565
  migrated += 1;
9946
9566
  }
9947
9567
  if (migrated > 0) {
@@ -10007,15 +9627,18 @@ ${reflection}
10007
9627
  const isResolved = m.frontmatter.tags.some((t) => t === "fulfilled" || t === "expired");
10008
9628
  if (!isResolved) continue;
10009
9629
  const updatedAt = new Date(m.frontmatter.updated).getTime();
10010
- if (updatedAt < cutoff) {
10011
- try {
10012
- await unlink3(m.path);
10013
- markProjectedMemoryPathInvalid(this.baseDir, m.frontmatter.id);
10014
- this.bumpMemoryCorpusVersion();
10015
- deleted.push(m);
10016
- log.debug(`cleaned expired commitment ${m.frontmatter.id}`);
10017
- } catch {
9630
+ if (updatedAt >= cutoff) continue;
9631
+ try {
9632
+ const removed = await this.deleteMemoryForMaintenance(m, (current) => {
9633
+ const currentResolved = current.frontmatter.tags.some((tag) => tag === "fulfilled" || tag === "expired");
9634
+ const currentUpdatedAt = new Date(current.frontmatter.updated).getTime();
9635
+ return currentResolved && currentUpdatedAt < cutoff;
9636
+ });
9637
+ if (removed) {
9638
+ deleted.push(removed);
9639
+ log.debug(`cleaned expired commitment ${removed.frontmatter.id}`);
10018
9640
  }
9641
+ } catch {
10019
9642
  }
10020
9643
  }
10021
9644
  if (deleted.length > 0) {
@@ -10034,14 +9657,14 @@ ${reflection}
10034
9657
  if (entries.length === 0) return 0;
10035
9658
  const memories = await this.readAllMemories();
10036
9659
  const memoryMap = new Map(memories.map((m) => [m.frontmatter.id, m]));
10037
- const memoryPathMap = new Map(memories.map((m) => [path10.resolve(m.path), m]));
9660
+ const memoryPathMap = new Map(memories.map((m) => [path9.resolve(m.path), m]));
10038
9661
  let updated = 0;
10039
9662
  const prevVersion = this.getMemoryCorpusVersion();
10040
9663
  const keyId = this.hotCacheKeyId();
10041
9664
  const warm = this.hotMemoriesCacheEnabled && getCachedMemories(this.baseDir, prevVersion, keyId, this.hotCacheTtlMs()) !== null;
10042
9665
  const appliedPatches = /* @__PURE__ */ new Map();
10043
9666
  for (const entry of entries) {
10044
- const memory = entry.memoryPath ? memoryPathMap.get(path10.resolve(entry.memoryPath)) : memoryMap.get(entry.memoryId);
9667
+ const memory = entry.memoryPath ? memoryPathMap.get(path9.resolve(entry.memoryPath)) : memoryMap.get(entry.memoryId);
10045
9668
  if (!memory) continue;
10046
9669
  const newFm = {
10047
9670
  ...memory.frontmatter,
@@ -10057,7 +9680,7 @@ ${memory.content}
10057
9680
  if (warm) {
10058
9681
  updateCacheOnWrite(this.baseDir, { ...memory, frontmatter: newFm }, keyId);
10059
9682
  }
10060
- appliedPatches.set(path10.resolve(memory.path), {
9683
+ appliedPatches.set(path9.resolve(memory.path), {
10061
9684
  accessCount: entry.newCount,
10062
9685
  lastAccessed: entry.lastAccessed
10063
9686
  });
@@ -10073,8 +9696,11 @@ ${memory.content}
10073
9696
  const cur = getCachedMemories(this.baseDir, prevVersion, keyId);
10074
9697
  if (cur) {
10075
9698
  const reapplied = cur.map((m) => {
10076
- const patch = appliedPatches.get(path10.resolve(m.path));
10077
- return patch ? { ...m, frontmatter: { ...m.frontmatter, accessCount: patch.accessCount, lastAccessed: patch.lastAccessed } } : m;
9699
+ const patch = appliedPatches.get(path9.resolve(m.path));
9700
+ return patch ? {
9701
+ ...m,
9702
+ frontmatter: { ...m.frontmatter, accessCount: patch.accessCount, lastAccessed: patch.lastAccessed }
9703
+ } : m;
10078
9704
  });
10079
9705
  setCachedMemories(this.baseDir, reapplied, produced, keyId, this.hotCacheTtlMs());
10080
9706
  }
@@ -10105,7 +9731,7 @@ ${memory.content}
10105
9731
  const pathsById = /* @__PURE__ */ new Map();
10106
9732
  const filePathsById = /* @__PURE__ */ new Map();
10107
9733
  for (const filePath of filePaths) {
10108
- const memoryId = path10.basename(filePath, ".md");
9734
+ const memoryId = path9.basename(filePath, ".md");
10109
9735
  if (!wantedIds.has(memoryId)) continue;
10110
9736
  const paths = filePathsById.get(memoryId) ?? [];
10111
9737
  paths.push(filePath);
@@ -10116,12 +9742,8 @@ ${memory.content}
10116
9742
  const preferred = preferredPaths.get(id) ?? [];
10117
9743
  const preferredMatches = [];
10118
9744
  for (const preferredPath of preferred) {
10119
- const directCandidates = new Set(
10120
- qmdResultPathCandidates(this.baseDir, preferredPath)
10121
- );
10122
- const directMatch = existingPaths.find(
10123
- (filePath) => directCandidates.has(path10.resolve(filePath))
10124
- );
9745
+ const directCandidates = new Set(qmdResultPathCandidates(this.baseDir, preferredPath));
9746
+ const directMatch = existingPaths.find((filePath) => directCandidates.has(path9.resolve(filePath)));
10125
9747
  if (directMatch) {
10126
9748
  preferredMatches.push(directMatch);
10127
9749
  continue;
@@ -10133,7 +9755,7 @@ ${memory.content}
10133
9755
  candidates.add(candidate);
10134
9756
  }
10135
9757
  }
10136
- const match = existingPaths.find((filePath) => candidates.has(path10.resolve(filePath)));
9758
+ const match = existingPaths.find((filePath) => candidates.has(path9.resolve(filePath)));
10137
9759
  if (match) preferredMatches.push(match);
10138
9760
  }
10139
9761
  if (preferredMatches.length > 0) {
@@ -10266,10 +9888,17 @@ ${memory.content}
10266
9888
  ${sanitized.text}
10267
9889
  `;
10268
9890
  const filePath = await this.resolveCategoryWritePath(category, id, today);
10269
- await this.writeStorageSecureFile(filePath, fileContent);
10270
- await this.patchHotMemoriesCache({ addedPath: filePath }, "memory-create");
10271
- log.debug(`wrote chunk ${id} (${chunkIndex + 1}/${chunkTotal}) to ${filePath}`);
10272
- return id;
9891
+ return await this.writeTombstoneBlockedChunk(
9892
+ filePath,
9893
+ fileContent,
9894
+ fm,
9895
+ sanitized.text,
9896
+ () => this.findExistingTombstoneBlockedMemory(sanitized.text, category, fm.sourceConnector),
9897
+ async () => {
9898
+ await this.patchHotMemoriesCache({ addedPath: filePath }, "memory-create");
9899
+ log.debug(`wrote chunk ${id} (${chunkIndex + 1}/${chunkTotal}) to ${filePath}`);
9900
+ }
9901
+ );
10273
9902
  }
10274
9903
  /**
10275
9904
  * Get all chunks for a given parent memory ID.
@@ -10339,7 +9968,12 @@ ${oldMemory.content}
10339
9968
  const auditBody = `Superseded: ${oldMemory.content}
10340
9969
 
10341
9970
  Reason: ${reason}`;
10342
- const auditInput = { content: auditBody, category: "correction", confidence: 1, tags: ["supersession", "auto-resolved"] };
9971
+ const auditInput = {
9972
+ content: auditBody,
9973
+ category: "correction",
9974
+ confidence: 1,
9975
+ tags: ["supersession", "auto-resolved"]
9976
+ };
10343
9977
  const auditEnvelope = composeMemoryEnvelope(auditInput, { source: "contradiction-detection" });
10344
9978
  await this.writeSealedMemory(auditEnvelope, { lineage: [oldMemoryId, newMemoryId] });
10345
9979
  return true;
@@ -10352,14 +9986,14 @@ Reason: ${reason}`;
10352
9986
  // Memory Summarization (Phase 4A)
10353
9987
  // ---------------------------------------------------------------------------
10354
9988
  get summariesDir() {
10355
- return path10.join(this.baseDir, "summaries");
9989
+ return path9.join(this.baseDir, "summaries");
10356
9990
  }
10357
9991
  /**
10358
9992
  * Write a memory summary.
10359
9993
  */
10360
9994
  async writeSummary(summary) {
10361
- await mkdir2(this.summariesDir, { recursive: true });
10362
- const filePath = path10.join(this.summariesDir, `${summary.id}.json`);
9995
+ await mkdir(this.summariesDir, { recursive: true });
9996
+ const filePath = path9.join(this.summariesDir, `${summary.id}.json`);
10363
9997
  await this.writeStorageSecureFile(filePath, JSON.stringify(summary, null, 2));
10364
9998
  log.debug(`wrote summary ${summary.id}`);
10365
9999
  }
@@ -10372,7 +10006,7 @@ Reason: ${reason}`;
10372
10006
  const summaries = [];
10373
10007
  for (const file of files) {
10374
10008
  if (!file.endsWith(".json")) continue;
10375
- const filePath = path10.join(this.summariesDir, file);
10009
+ const filePath = path9.join(this.summariesDir, file);
10376
10010
  const raw = await this.readStorageSecureFile(filePath);
10377
10011
  summaries.push(JSON.parse(raw));
10378
10012
  }
@@ -10434,8 +10068,8 @@ ${memory.content}
10434
10068
  * Save topic scores to meta.json.
10435
10069
  */
10436
10070
  async saveTopics(topics) {
10437
- const metaPath = path10.join(this.stateDir, "topics.json");
10438
- await mkdir2(this.stateDir, { recursive: true });
10071
+ const metaPath = path9.join(this.stateDir, "topics.json");
10072
+ await mkdir(this.stateDir, { recursive: true });
10439
10073
  await this.writeStorageSecureFile(
10440
10074
  metaPath,
10441
10075
  JSON.stringify({ topics, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2)
@@ -10446,7 +10080,7 @@ ${memory.content}
10446
10080
  * Load topic scores from meta.json.
10447
10081
  */
10448
10082
  async loadTopics() {
10449
- const metaPath = path10.join(this.stateDir, "topics.json");
10083
+ const metaPath = path9.join(this.stateDir, "topics.json");
10450
10084
  try {
10451
10085
  const raw = await this.readStorageSecureFile(metaPath);
10452
10086
  return JSON.parse(raw);
@@ -10557,8 +10191,6 @@ export {
10557
10191
  countEntityStructuredFacts,
10558
10192
  fingerprintEntityStructuredFacts,
10559
10193
  isEntitySynthesisStale,
10560
- FactHashIndexNotAuthoritativeError,
10561
- ContentHashIndex,
10562
10194
  parseFrontmatterStringValue,
10563
10195
  parseFrontmatter,
10564
10196
  normalizeFrontmatterForPath,
@@ -10568,4 +10200,4 @@ export {
10568
10200
  isValidBufferSurpriseEvent,
10569
10201
  StorageManager3 as StorageManager
10570
10202
  };
10571
- //# sourceMappingURL=chunk-FCDWWCLX.js.map
10203
+ //# sourceMappingURL=chunk-RGIWINDN.js.map