@remnic/core 9.52.2 → 9.54.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 (429) hide show
  1. package/dist/access-admin-ops-surface.d.ts +11 -11
  2. package/dist/access-admin-ops-surface.js +22 -22
  3. package/dist/access-authorization-probe.d.ts +11 -11
  4. package/dist/access-authorization-probe.js +23 -23
  5. package/dist/access-boundary.d.ts +11 -11
  6. package/dist/access-boundary.js +22 -22
  7. package/dist/access-cli.js +55 -55
  8. package/dist/access-coding-context-resolution.d.ts +1 -1
  9. package/dist/access-extraction-force-flush.d.ts +11 -11
  10. package/dist/access-extraction-force-flush.js +22 -22
  11. package/dist/access-health-types.d.ts +1 -1
  12. package/dist/access-http-lcm-compaction.d.ts +11 -11
  13. package/dist/access-http-lifecycle-flush.d.ts +11 -11
  14. package/dist/access-http-offline-stream.d.ts +11 -11
  15. package/dist/access-http-query.js +22 -22
  16. package/dist/access-http.d.ts +11 -11
  17. package/dist/access-http.js +29 -29
  18. package/dist/access-identity-continuity-surface.d.ts +9 -9
  19. package/dist/access-identity-continuity-surface.js +22 -22
  20. package/dist/access-lcm-surface.d.ts +11 -11
  21. package/dist/access-lcm-surface.js +22 -22
  22. package/dist/access-mcp.d.ts +11 -11
  23. package/dist/access-mcp.js +27 -27
  24. package/dist/access-memory-search-fanout.d.ts +2 -2
  25. package/dist/{access-namespace-preflight-Ds6CGlCP.d.ts → access-namespace-preflight-C7n4tgWC.d.ts} +1 -1
  26. package/dist/access-namespace-preflight.d.ts +3 -3
  27. package/dist/access-namespace-preflight.js +22 -22
  28. package/dist/access-observe-write-surface.d.ts +11 -11
  29. package/dist/access-observe-write-surface.js +22 -22
  30. package/dist/access-offline-manifest.d.ts +9 -9
  31. package/dist/access-offline-manifest.js +8 -4
  32. package/dist/access-operations-batch.js +24 -24
  33. package/dist/access-operations.d.ts +14 -14
  34. package/dist/access-operations.js +26 -26
  35. package/dist/access-recall-concurrency.d.ts +11 -11
  36. package/dist/access-recall-concurrency.js +22 -22
  37. package/dist/access-recall-response.d.ts +11 -11
  38. package/dist/access-recall-response.js +22 -22
  39. package/dist/access-recall-surface.d.ts +11 -11
  40. package/dist/access-recall-surface.js +22 -22
  41. package/dist/access-schema.d.ts +88 -88
  42. package/dist/{access-service-Cbk3bNbD.d.ts → access-service-CXvbxLK-.d.ts} +7 -7
  43. package/dist/access-service-helpers.d.ts +11 -11
  44. package/dist/access-service.d.ts +11 -11
  45. package/dist/access-service.js +22 -22
  46. package/dist/access-surface-catalog.d.ts +11 -11
  47. package/dist/access-wearables-meetings-surface.d.ts +3 -3
  48. package/dist/action-confidence.d.ts +1 -1
  49. package/dist/active-memory-bridge.d.ts +1 -1
  50. package/dist/active-recall.d.ts +1 -1
  51. package/dist/active-recall.js +5 -5
  52. package/dist/ambient-provenance.d.ts +1 -1
  53. package/dist/artifact-search.d.ts +1 -1
  54. package/dist/{auto-sync-QFQGOEO2.js → auto-sync-TDHLZPVP.js} +7 -7
  55. package/dist/behavior-learner.d.ts +1 -1
  56. package/dist/behavior-signals.d.ts +1 -1
  57. package/dist/bootstrap.d.ts +9 -9
  58. package/dist/briefing.d.ts +2 -2
  59. package/dist/briefing.js +12 -12
  60. package/dist/buffer-surprise-report.d.ts +1 -1
  61. package/dist/buffer-turn-helpers.d.ts +1 -1
  62. package/dist/buffer.d.ts +2 -2
  63. package/dist/bulk-import/index.d.ts +3 -3
  64. package/dist/calibration.d.ts +1 -1
  65. package/dist/capabilities.d.ts +1 -1
  66. package/dist/{catalog-D3B4RDy1.d.ts → catalog-BOOxl-I2.d.ts} +1 -1
  67. package/dist/causal-behavior.d.ts +1 -1
  68. package/dist/causal-consolidation.d.ts +1 -1
  69. package/dist/causal-consolidation.js +13 -13
  70. package/dist/causal-trajectory-graph.d.ts +1 -1
  71. package/dist/{chunk-MLXZD4WM.js → chunk-2GFK22OZ.js} +2 -2
  72. package/dist/{chunk-RANKJI5T.js → chunk-3JLPGJ43.js} +2 -2
  73. package/dist/{chunk-O5FFBO2M.js → chunk-47P3RYZP.js} +70 -8
  74. package/dist/{chunk-O5FFBO2M.js.map → chunk-47P3RYZP.js.map} +1 -1
  75. package/dist/{chunk-X7XEDOSL.js → chunk-4IIFL7GC.js} +8 -8
  76. package/dist/chunk-5FVVY2EB.js +27 -0
  77. package/dist/chunk-5FVVY2EB.js.map +1 -0
  78. package/dist/{chunk-GXSOUIA4.js → chunk-5WQMORU5.js} +4 -4
  79. package/dist/{chunk-J272WKX2.js → chunk-6HPHEFXT.js} +2 -2
  80. package/dist/{chunk-B6LZ4IBH.js → chunk-6LAPLZOS.js} +2 -2
  81. package/dist/{chunk-WD5B5AIE.js → chunk-6R4G7N4S.js} +118 -173
  82. package/dist/chunk-6R4G7N4S.js.map +1 -0
  83. package/dist/{chunk-VXCNQYTC.js → chunk-APPFNGX6.js} +2 -2
  84. package/dist/{chunk-GXFSQ6SD.js → chunk-C4ZNGVK3.js} +2 -2
  85. package/dist/{chunk-JSEJH2YQ.js → chunk-CGVHPCP2.js} +2 -2
  86. package/dist/{chunk-BQIFZ2MP.js → chunk-CX5SW2EW.js} +41 -24
  87. package/dist/chunk-CX5SW2EW.js.map +1 -0
  88. package/dist/{chunk-RMHMUUBW.js → chunk-CYF6WVE7.js} +105 -49
  89. package/dist/{chunk-RMHMUUBW.js.map → chunk-CYF6WVE7.js.map} +1 -1
  90. package/dist/{chunk-TEMSWHQD.js → chunk-DZD576ZU.js} +5 -5
  91. package/dist/{chunk-AMTEYNYK.js → chunk-EVWWT3KE.js} +4 -4
  92. package/dist/{chunk-P2KBDJJ6.js → chunk-G2LUMAUF.js} +4 -3
  93. package/dist/{chunk-P2KBDJJ6.js.map → chunk-G2LUMAUF.js.map} +1 -1
  94. package/dist/{chunk-AXIDQG5A.js → chunk-G4T7L557.js} +5 -5
  95. package/dist/{chunk-7M6NYQWB.js → chunk-G7Z6EENO.js} +4 -4
  96. package/dist/{chunk-IARXXZU4.js → chunk-HOIRB77A.js} +99 -20
  97. package/dist/chunk-HOIRB77A.js.map +1 -0
  98. package/dist/{chunk-NDAH7BJ5.js → chunk-HVP33QVW.js} +103 -6
  99. package/dist/chunk-HVP33QVW.js.map +1 -0
  100. package/dist/{chunk-YXKVLYXU.js → chunk-HWRD23DW.js} +2 -2
  101. package/dist/{chunk-SOEN6KCF.js → chunk-IBKR2TFR.js} +2 -2
  102. package/dist/{chunk-R3DJVOSM.js → chunk-JDSVLVCG.js} +8 -1
  103. package/dist/chunk-JDSVLVCG.js.map +1 -0
  104. package/dist/{chunk-F4EU6VUC.js → chunk-JDZPNCMA.js} +2 -2
  105. package/dist/{chunk-D5YOZ66N.js → chunk-JV5YUBIZ.js} +20 -20
  106. package/dist/{chunk-DLG5V6ND.js → chunk-K4QS7LXU.js} +4 -7
  107. package/dist/chunk-K4QS7LXU.js.map +1 -0
  108. package/dist/{chunk-BAKXNQ3C.js → chunk-KRTY3ENI.js} +2 -2
  109. package/dist/{chunk-NK5RGJ65.js → chunk-L4DLLKPN.js} +2 -2
  110. package/dist/{chunk-VFSAWRMZ.js → chunk-LJS7KUPV.js} +2 -2
  111. package/dist/{chunk-JJRVPWFY.js → chunk-MLPTFODV.js} +166 -37
  112. package/dist/chunk-MLPTFODV.js.map +1 -0
  113. package/dist/{chunk-NOEMGE56.js → chunk-NH5IR2WM.js} +2 -2
  114. package/dist/{chunk-5V6IXHPI.js → chunk-NSVDUN76.js} +2 -2
  115. package/dist/{chunk-W7Y5JDVB.js → chunk-PDDTI7IC.js} +4 -4
  116. package/dist/{chunk-QINJITDS.js → chunk-PX2LSHYM.js} +2 -2
  117. package/dist/{chunk-HDIUYMSB.js → chunk-QWGE2PUH.js} +6 -6
  118. package/dist/{chunk-X57M2Q4I.js → chunk-RDJRFDJY.js} +3 -3
  119. package/dist/{chunk-RYLEDKQ2.js → chunk-RUMNY5DT.js} +3 -3
  120. package/dist/{chunk-BKIFTXHR.js → chunk-RZ4XGKOJ.js} +2 -2
  121. package/dist/{chunk-66SE3BNH.js → chunk-SUPEYLH2.js} +2 -2
  122. package/dist/{chunk-BF6SXNQJ.js → chunk-T2JHZWH6.js} +20 -20
  123. package/dist/{chunk-VHFXP27N.js → chunk-THPPCISA.js} +60 -23
  124. package/dist/chunk-THPPCISA.js.map +1 -0
  125. package/dist/{chunk-QPOHMO6M.js → chunk-UES4BHA2.js} +2 -2
  126. package/dist/{chunk-XAPMEU3K.js → chunk-UU7TRFNE.js} +2 -2
  127. package/dist/{chunk-QBSFOKY6.js → chunk-VOELBUS4.js} +4 -4
  128. package/dist/{chunk-2LY6GIIE.js → chunk-WDBX6VER.js} +2 -2
  129. package/dist/{chunk-BMEYMKWX.js → chunk-WM65LU67.js} +2 -2
  130. package/dist/{chunk-WLRD2TXF.js → chunk-WOPA3SGI.js} +4 -4
  131. package/dist/{chunk-5UZ6UCOZ.js → chunk-XUAMCLY4.js} +3 -3
  132. package/dist/{chunk-7HXZJAID.js → chunk-YGLY6QFV.js} +3 -3
  133. package/dist/{chunk-2OIQDTDC.js → chunk-ZPJ4QSGP.js} +2 -2
  134. package/dist/{chunk-3OY7KXHM.js → chunk-ZYLC7NFO.js} +3 -3
  135. package/dist/{cli-DMAFI0qt.d.ts → cli-DVUFIa5E.d.ts} +5 -5
  136. package/dist/cli.d.ts +13 -13
  137. package/dist/cli.js +42 -42
  138. package/dist/coding/pre-action-gate.d.ts +1 -1
  139. package/dist/compounding/engine.d.ts +2 -2
  140. package/dist/compounding/engine.js +13 -13
  141. package/dist/compounding/preference-consolidator.d.ts +1 -1
  142. package/dist/compression-optimizer.d.ts +1 -1
  143. package/dist/config.d.ts +1 -1
  144. package/dist/config.js +5 -5
  145. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  146. package/dist/connectors/codex-materialize-runner.js +12 -12
  147. package/dist/connectors/codex-materialize.d.ts +1 -1
  148. package/dist/connectors/index.d.ts +1 -1
  149. package/dist/connectors/index.js +12 -12
  150. package/dist/consolidation-provenance-check.d.ts +2 -2
  151. package/dist/consolidation-undo.d.ts +2 -2
  152. package/dist/content-hash.d.ts +12 -2
  153. package/dist/content-hash.js +9 -3
  154. package/dist/contradiction/index.d.ts +2 -2
  155. package/dist/contradiction/index.js +3 -3
  156. package/dist/converge-config.d.ts +1 -1
  157. package/dist/convergence-refresh.d.ts +2 -2
  158. package/dist/convergence-refresh.js +14 -14
  159. package/dist/conversation-index/backend.d.ts +1 -1
  160. package/dist/conversation-index/chunker.d.ts +1 -1
  161. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  162. package/dist/conversation-index/indexer.d.ts +1 -1
  163. package/dist/conversation-index/search.d.ts +1 -1
  164. package/dist/corpus-watermark.d.ts +1 -1
  165. package/dist/corpus-watermark.js +14 -14
  166. package/dist/day-summary.d.ts +1 -1
  167. package/dist/delinearize.d.ts +1 -1
  168. package/dist/dependency-propagation-config.d.ts +1 -1
  169. package/dist/{dependency-propagation-delivery-D63r24pH.d.ts → dependency-propagation-delivery-XzF76C9n.d.ts} +1 -1
  170. package/dist/direct-answer-wiring.d.ts +1 -1
  171. package/dist/direct-answer.d.ts +1 -1
  172. package/dist/embedding-fallback.d.ts +1 -1
  173. package/dist/enrichment/index.d.ts +1 -1
  174. package/dist/entity-retrieval.d.ts +2 -2
  175. package/dist/entity-retrieval.js +12 -12
  176. package/dist/entity-schema.d.ts +1 -1
  177. package/dist/explicit-capture.d.ts +9 -9
  178. package/dist/explicit-capture.js +8 -8
  179. package/dist/external-wiki-access.d.ts +11 -11
  180. package/dist/external-wiki-access.js +23 -23
  181. package/dist/external-wiki-collection-registration.d.ts +1 -1
  182. package/dist/external-wiki-collection.d.ts +1 -1
  183. package/dist/external-wiki-mcp-tools.d.ts +11 -11
  184. package/dist/extraction-error-classification.d.ts +1 -1
  185. package/dist/extraction-faithfulness.d.ts +1 -1
  186. package/dist/extraction-judge-telemetry.d.ts +1 -1
  187. package/dist/extraction-judge-training.d.ts +1 -1
  188. package/dist/extraction-judge.d.ts +1 -1
  189. package/dist/extraction-liveness.d.ts +1 -1
  190. package/dist/extraction-normalization.d.ts +1 -1
  191. package/dist/extraction-normalization.js +2 -2
  192. package/dist/extraction-prompt.d.ts +1 -1
  193. package/dist/extraction-source-grounding-rules.d.ts +1 -1
  194. package/dist/extraction-source-grounding.d.ts +1 -1
  195. package/dist/extraction-source-grounding.js +3 -3
  196. package/dist/extraction.d.ts +1 -1
  197. package/dist/extraction.js +16 -16
  198. package/dist/fallback-llm.d.ts +1 -1
  199. package/dist/{forget-HDS4N6CG.js → forget-EHGGJZLX.js} +3 -2
  200. package/dist/{forget-HDS4N6CG.js.map → forget-EHGGJZLX.js.map} +1 -1
  201. package/dist/graph-dashboard-diff.d.ts +1 -1
  202. package/dist/graph-dashboard-key.d.ts +1 -1
  203. package/dist/graph-dashboard-parser.d.ts +1 -1
  204. package/dist/graph-edge-reinforcement.d.ts +1 -1
  205. package/dist/graph-path-reconstruction.d.ts +1 -1
  206. package/dist/graph-path-scoring.d.ts +1 -1
  207. package/dist/graph-snapshot.d.ts +1 -1
  208. package/dist/graph.d.ts +1 -1
  209. package/dist/harmonic-construction.js +2 -2
  210. package/dist/harmonic-retrieval.js +4 -4
  211. package/dist/importance.d.ts +1 -1
  212. package/dist/importers/index.d.ts +1 -1
  213. package/dist/in-flight-reads.d.ts +1 -1
  214. package/dist/index.d.ts +777 -705
  215. package/dist/index.js +77 -67
  216. package/dist/intent.d.ts +1 -1
  217. package/dist/lcm/engine.d.ts +1 -1
  218. package/dist/lcm/index.d.ts +1 -1
  219. package/dist/lcm/tools.d.ts +1 -1
  220. package/dist/lifecycle.d.ts +1 -1
  221. package/dist/live-connectors-runner.d.ts +1 -1
  222. package/dist/local-llm.d.ts +1 -1
  223. package/dist/local-model-endpoint.d.ts +1 -1
  224. package/dist/maintenance/memory-governance.d.ts +1 -1
  225. package/dist/maintenance/memory-governance.js +12 -12
  226. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
  227. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +12 -12
  228. package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
  229. package/dist/maintenance/rebuild-memory-projection.js +13 -13
  230. package/dist/{maintenance-kBII2qUI.d.ts → maintenance-BJzNIKBE.d.ts} +3 -3
  231. package/dist/mcp-memory-inspector-app.d.ts +11 -11
  232. package/dist/memory-action-policy.d.ts +1 -1
  233. package/dist/memory-cache.d.ts +1 -1
  234. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  235. package/dist/memory-projection-store.d.ts +1 -1
  236. package/dist/memory-provenance.d.ts +1 -1
  237. package/dist/memory-snapshot.d.ts +1 -1
  238. package/dist/memory-worth-outcomes.d.ts +2 -2
  239. package/dist/models-json.d.ts +1 -1
  240. package/dist/namespaces/migrate.d.ts +3 -3
  241. package/dist/namespaces/migrate.js +13 -13
  242. package/dist/namespaces/principal.d.ts +1 -1
  243. package/dist/namespaces/search.d.ts +1 -1
  244. package/dist/namespaces/storage.d.ts +3 -3
  245. package/dist/namespaces/storage.js +12 -12
  246. package/dist/native-knowledge.d.ts +1 -1
  247. package/dist/offline-sync-impression-drain.d.ts +1 -1
  248. package/dist/operator-doctor-corpus.d.ts +1 -1
  249. package/dist/operator-doctor-corpus.js +15 -15
  250. package/dist/operator-doctor-replica.d.ts +1 -1
  251. package/dist/operator-toolkit.d.ts +3 -3
  252. package/dist/operator-toolkit.js +21 -21
  253. package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
  254. package/dist/orchestration/maintenance.d.ts +4 -4
  255. package/dist/orchestration/maintenance.js +17 -17
  256. package/dist/{orchestrator-DHy5LtTy.d.ts → orchestrator-BiXgBJBQ.d.ts} +8 -8
  257. package/dist/orchestrator.d.ts +9 -9
  258. package/dist/orchestrator.js +55 -55
  259. package/dist/patterns-cli.d.ts +1 -1
  260. package/dist/{pipeline-D21Rs6gW.d.ts → pipeline-sz_dcuLg.d.ts} +1 -1
  261. package/dist/policy-runtime.d.ts +1 -1
  262. package/dist/proactive-contention.d.ts +1 -1
  263. package/dist/provenance.d.ts +1 -1
  264. package/dist/provenance.js +2 -2
  265. package/dist/{qmd-Dhle1P4X.d.ts → qmd-eAWObK4M.d.ts} +1 -1
  266. package/dist/qmd-preflight.d.ts +2 -2
  267. package/dist/qmd-recall-cache.d.ts +1 -1
  268. package/dist/qmd.d.ts +2 -2
  269. package/dist/recall-concurrency-config.d.ts +1 -1
  270. package/dist/recall-disclosure-escalation.d.ts +1 -1
  271. package/dist/recall-explain-renderer.d.ts +1 -1
  272. package/dist/recall-memory-map.d.ts +1 -1
  273. package/dist/recall-planner-llm.d.ts +1 -1
  274. package/dist/recall-state.d.ts +1 -1
  275. package/dist/recall-tag-filter.d.ts +1 -1
  276. package/dist/recall-timings.d.ts +1 -1
  277. package/dist/recall-xray-cli.d.ts +1 -1
  278. package/dist/recall-xray-renderer.d.ts +1 -1
  279. package/dist/recall-xray.d.ts +1 -1
  280. package/dist/reconcile/cursor.d.ts +1 -1
  281. package/dist/reconcile/manifest.d.ts +4 -2
  282. package/dist/reconcile/manifest.js +7 -3
  283. package/dist/reconcile/plan.d.ts +1 -1
  284. package/dist/replay/normalizers/chatgpt.d.ts +1 -1
  285. package/dist/replay/normalizers/claude.d.ts +1 -1
  286. package/dist/replay/normalizers/openclaw.d.ts +1 -1
  287. package/dist/replay/normalizers/shared.d.ts +1 -1
  288. package/dist/replay/runner.d.ts +1 -1
  289. package/dist/replay/types.d.ts +1 -1
  290. package/dist/replica-divergence.d.ts +1 -1
  291. package/dist/replica-peers-config.d.ts +1 -1
  292. package/dist/{resolution-MDPNOEG6.js → resolution-MMOD5WC4.js} +4 -4
  293. package/dist/resolve-auth-token.d.ts +1 -1
  294. package/dist/resume-bundles.js +6 -6
  295. package/dist/retrieval-agents.d.ts +2 -2
  296. package/dist/retrieval-tiers.d.ts +1 -1
  297. package/dist/routing/engine.d.ts +1 -1
  298. package/dist/routing/store.d.ts +1 -1
  299. package/dist/salvage-envelope.d.ts +1 -1
  300. package/dist/salvage-envelope.js +3 -3
  301. package/dist/schemas.d.ts +138 -138
  302. package/dist/{scope-profiles-NzGPDXLn.d.ts → scope-profiles-BBQsXuyj.d.ts} +1 -1
  303. package/dist/search/embed-helper.d.ts +1 -1
  304. package/dist/search/factory.d.ts +1 -1
  305. package/dist/search/index.d.ts +1 -1
  306. package/dist/search/lancedb-backend.d.ts +1 -1
  307. package/dist/search/meilisearch-backend.d.ts +1 -1
  308. package/dist/search/noop-backend.d.ts +1 -1
  309. package/dist/search/orama-backend.d.ts +1 -1
  310. package/dist/search/port.d.ts +1 -1
  311. package/dist/search/remote-backend.d.ts +1 -1
  312. package/dist/{semantic-consolidation-DLDKvyy5.d.ts → semantic-consolidation-HD8RkzVA.d.ts} +1 -1
  313. package/dist/semantic-consolidation.d.ts +2 -2
  314. package/dist/semantic-consolidation.js +13 -13
  315. package/dist/semantic-rule-promotion.js +12 -12
  316. package/dist/semantic-rule-verifier.d.ts +1 -1
  317. package/dist/semantic-rule-verifier.js +12 -12
  318. package/dist/{service-PT2_z7xm.d.ts → service-DIrtHHEg.d.ts} +2 -2
  319. package/dist/session-observer-bands.d.ts +1 -1
  320. package/dist/session-observer-state.d.ts +1 -1
  321. package/dist/shared-context/manager.d.ts +9 -9
  322. package/dist/signal.d.ts +1 -1
  323. package/dist/source-agent-qualifier.d.ts +1 -1
  324. package/dist/source-agent-qualifier.js +14 -14
  325. package/dist/{storage-BmVudhk4.d.ts → storage-DqCzXi56.d.ts} +37 -33
  326. package/dist/storage.d.ts +2 -2
  327. package/dist/storage.js +14 -14
  328. package/dist/structured-attributes.d.ts +3 -1
  329. package/dist/structured-attributes.js +3 -1
  330. package/dist/summarizer.d.ts +1 -1
  331. package/dist/summary-snapshot.d.ts +1 -1
  332. package/dist/temporal-supersession.d.ts +2 -2
  333. package/dist/temporal-timeline-recall.d.ts +1 -1
  334. package/dist/temporal-validity.d.ts +1 -1
  335. package/dist/threading.d.ts +1 -1
  336. package/dist/tier-migration.d.ts +2 -2
  337. package/dist/tier-routing.d.ts +1 -1
  338. package/dist/topics.d.ts +1 -1
  339. package/dist/transcript.d.ts +1 -1
  340. package/dist/transfer/types.d.ts +66 -66
  341. package/dist/trust-score-stage.d.ts +1 -1
  342. package/dist/trust-score.d.ts +1 -1
  343. package/dist/{types-CkiDUorT.d.ts → types-d_j4vC6N.d.ts} +26 -1
  344. package/dist/types.d.ts +1 -1
  345. package/dist/utility-runtime.d.ts +1 -1
  346. package/dist/verified-recall.js +12 -12
  347. package/dist/write-envelope.d.ts +1 -1
  348. package/dist/write-envelope.js +2 -2
  349. package/package.json +2 -2
  350. package/src/access-offline-manifest.ts +1 -0
  351. package/src/access-service-offline-file-content.test.ts +1 -0
  352. package/src/content-hash.ts +34 -1
  353. package/src/dedup/index.test.ts +56 -38
  354. package/src/dedup/index.ts +85 -38
  355. package/src/lifecycle/tombstones.test.ts +763 -16
  356. package/src/lifecycle/tombstones.ts +217 -50
  357. package/src/reconcile/manifest.test.ts +158 -1
  358. package/src/reconcile/manifest.ts +76 -22
  359. package/src/storage/content-hash-index.ts +56 -40
  360. package/src/storage/entity-ref-repair.ts +3 -3
  361. package/src/storage/memory-read-store.ts +9 -0
  362. package/src/storage/tombstone-blocked-capture-index.ts +4 -9
  363. package/src/storage-contract/content-hash.test.ts +13 -0
  364. package/src/storage-fact-hash-index-defer.test.ts +1 -1
  365. package/src/storage.ts +107 -93
  366. package/src/structured-attributes.ts +11 -0
  367. package/src/wearables/cleanup.test.ts +71 -0
  368. package/src/wearables/cleanup.ts +163 -16
  369. package/src/wearables/config.test.ts +62 -0
  370. package/src/wearables/config.ts +99 -5
  371. package/src/wearables/index.ts +10 -0
  372. package/src/wearables/pipeline.test.ts +36 -0
  373. package/src/wearables/pipeline.ts +18 -3
  374. package/src/wearables/redaction.test.ts +156 -0
  375. package/src/wearables/redaction.ts +102 -10
  376. package/src/wearables/text-language.ts +146 -0
  377. package/src/wearables/types.ts +26 -0
  378. package/dist/chunk-BQIFZ2MP.js.map +0 -1
  379. package/dist/chunk-DLG5V6ND.js.map +0 -1
  380. package/dist/chunk-IARXXZU4.js.map +0 -1
  381. package/dist/chunk-JJRVPWFY.js.map +0 -1
  382. package/dist/chunk-NDAH7BJ5.js.map +0 -1
  383. package/dist/chunk-R3DJVOSM.js.map +0 -1
  384. package/dist/chunk-VHFXP27N.js.map +0 -1
  385. package/dist/chunk-W5H6ZRPT.js +0 -14
  386. package/dist/chunk-W5H6ZRPT.js.map +0 -1
  387. package/dist/chunk-WD5B5AIE.js.map +0 -1
  388. /package/dist/{auto-sync-QFQGOEO2.js.map → auto-sync-TDHLZPVP.js.map} +0 -0
  389. /package/dist/{chunk-MLXZD4WM.js.map → chunk-2GFK22OZ.js.map} +0 -0
  390. /package/dist/{chunk-RANKJI5T.js.map → chunk-3JLPGJ43.js.map} +0 -0
  391. /package/dist/{chunk-X7XEDOSL.js.map → chunk-4IIFL7GC.js.map} +0 -0
  392. /package/dist/{chunk-GXSOUIA4.js.map → chunk-5WQMORU5.js.map} +0 -0
  393. /package/dist/{chunk-J272WKX2.js.map → chunk-6HPHEFXT.js.map} +0 -0
  394. /package/dist/{chunk-B6LZ4IBH.js.map → chunk-6LAPLZOS.js.map} +0 -0
  395. /package/dist/{chunk-VXCNQYTC.js.map → chunk-APPFNGX6.js.map} +0 -0
  396. /package/dist/{chunk-GXFSQ6SD.js.map → chunk-C4ZNGVK3.js.map} +0 -0
  397. /package/dist/{chunk-JSEJH2YQ.js.map → chunk-CGVHPCP2.js.map} +0 -0
  398. /package/dist/{chunk-TEMSWHQD.js.map → chunk-DZD576ZU.js.map} +0 -0
  399. /package/dist/{chunk-AMTEYNYK.js.map → chunk-EVWWT3KE.js.map} +0 -0
  400. /package/dist/{chunk-AXIDQG5A.js.map → chunk-G4T7L557.js.map} +0 -0
  401. /package/dist/{chunk-7M6NYQWB.js.map → chunk-G7Z6EENO.js.map} +0 -0
  402. /package/dist/{chunk-YXKVLYXU.js.map → chunk-HWRD23DW.js.map} +0 -0
  403. /package/dist/{chunk-SOEN6KCF.js.map → chunk-IBKR2TFR.js.map} +0 -0
  404. /package/dist/{chunk-F4EU6VUC.js.map → chunk-JDZPNCMA.js.map} +0 -0
  405. /package/dist/{chunk-D5YOZ66N.js.map → chunk-JV5YUBIZ.js.map} +0 -0
  406. /package/dist/{chunk-BAKXNQ3C.js.map → chunk-KRTY3ENI.js.map} +0 -0
  407. /package/dist/{chunk-NK5RGJ65.js.map → chunk-L4DLLKPN.js.map} +0 -0
  408. /package/dist/{chunk-VFSAWRMZ.js.map → chunk-LJS7KUPV.js.map} +0 -0
  409. /package/dist/{chunk-NOEMGE56.js.map → chunk-NH5IR2WM.js.map} +0 -0
  410. /package/dist/{chunk-5V6IXHPI.js.map → chunk-NSVDUN76.js.map} +0 -0
  411. /package/dist/{chunk-W7Y5JDVB.js.map → chunk-PDDTI7IC.js.map} +0 -0
  412. /package/dist/{chunk-QINJITDS.js.map → chunk-PX2LSHYM.js.map} +0 -0
  413. /package/dist/{chunk-HDIUYMSB.js.map → chunk-QWGE2PUH.js.map} +0 -0
  414. /package/dist/{chunk-X57M2Q4I.js.map → chunk-RDJRFDJY.js.map} +0 -0
  415. /package/dist/{chunk-RYLEDKQ2.js.map → chunk-RUMNY5DT.js.map} +0 -0
  416. /package/dist/{chunk-BKIFTXHR.js.map → chunk-RZ4XGKOJ.js.map} +0 -0
  417. /package/dist/{chunk-66SE3BNH.js.map → chunk-SUPEYLH2.js.map} +0 -0
  418. /package/dist/{chunk-BF6SXNQJ.js.map → chunk-T2JHZWH6.js.map} +0 -0
  419. /package/dist/{chunk-QPOHMO6M.js.map → chunk-UES4BHA2.js.map} +0 -0
  420. /package/dist/{chunk-XAPMEU3K.js.map → chunk-UU7TRFNE.js.map} +0 -0
  421. /package/dist/{chunk-QBSFOKY6.js.map → chunk-VOELBUS4.js.map} +0 -0
  422. /package/dist/{chunk-2LY6GIIE.js.map → chunk-WDBX6VER.js.map} +0 -0
  423. /package/dist/{chunk-BMEYMKWX.js.map → chunk-WM65LU67.js.map} +0 -0
  424. /package/dist/{chunk-WLRD2TXF.js.map → chunk-WOPA3SGI.js.map} +0 -0
  425. /package/dist/{chunk-5UZ6UCOZ.js.map → chunk-XUAMCLY4.js.map} +0 -0
  426. /package/dist/{chunk-7HXZJAID.js.map → chunk-YGLY6QFV.js.map} +0 -0
  427. /package/dist/{chunk-2OIQDTDC.js.map → chunk-ZPJ4QSGP.js.map} +0 -0
  428. /package/dist/{chunk-3OY7KXHM.js.map → chunk-ZYLC7NFO.js.map} +0 -0
  429. /package/dist/{resolution-MDPNOEG6.js.map → resolution-MMOD5WC4.js.map} +0 -0
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  listNamespaces
3
- } from "./chunk-RANKJI5T.js";
3
+ } from "./chunk-3JLPGJ43.js";
4
4
  import {
5
5
  capabilityAllowsNamespace
6
6
  } from "./chunk-MZWSOLMT.js";
@@ -282,4 +282,4 @@ export {
282
282
  computeServiceCorpusWatermarks,
283
283
  computeServiceCorpusCensus
284
284
  };
285
- //# sourceMappingURL=chunk-VXCNQYTC.js.map
285
+ //# sourceMappingURL=chunk-APPFNGX6.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  rebuildMemoryProjection
3
- } from "./chunk-5UZ6UCOZ.js";
3
+ } from "./chunk-XUAMCLY4.js";
4
4
 
5
5
  // src/convergence-refresh.ts
6
6
  async function refreshConvergedNamespaces(namespaces, namespaceSearchRouter, getStorage, searchEnabled) {
@@ -32,4 +32,4 @@ async function refreshConvergedNamespaces(namespaces, namespaceSearchRouter, get
32
32
  export {
33
33
  refreshConvergedNamespaces
34
34
  };
35
- //# sourceMappingURL=chunk-GXFSQ6SD.js.map
35
+ //# sourceMappingURL=chunk-C4ZNGVK3.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  resolveCorpusNamespaceRoots
3
- } from "./chunk-VXCNQYTC.js";
3
+ } from "./chunk-APPFNGX6.js";
4
4
  import {
5
5
  normalizeNamespaceIdentity
6
6
  } from "./chunk-EGGE52UU.js";
@@ -200,4 +200,4 @@ async function readAggregateExtractionWatermark(options) {
200
200
  export {
201
201
  readAggregateExtractionWatermark
202
202
  };
203
- //# sourceMappingURL=chunk-JSEJH2YQ.js.map
203
+ //# sourceMappingURL=chunk-CGVHPCP2.js.map
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  computeContentHash,
6
6
  normalizeContent
7
- } from "./chunk-W5H6ZRPT.js";
7
+ } from "./chunk-5FVVY2EB.js";
8
8
  import {
9
9
  SecureStoreLockedError,
10
10
  readMaybeEncryptedFile,
@@ -21,6 +21,19 @@ import {
21
21
  import { mkdir, stat } from "fs/promises";
22
22
  import path from "path";
23
23
  var CONTENT_HASH_INDEX_LOCK_STALE_MS = 3e4;
24
+ var CONTENT_HASH_INDEX_FORMAT_HEADER = "# remnic-content-hash-index:v2";
25
+ function parseHashIndex(raw) {
26
+ const lines = raw.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
27
+ if (lines[0] !== CONTENT_HASH_INDEX_FORMAT_HEADER) {
28
+ return { versioned: false, hashes: /* @__PURE__ */ new Set() };
29
+ }
30
+ return { versioned: true, hashes: new Set(lines.slice(1)) };
31
+ }
32
+ function serializeHashIndex(hashes) {
33
+ return `${CONTENT_HASH_INDEX_FORMAT_HEADER}
34
+ ${[...hashes].join("\n")}
35
+ `;
36
+ }
24
37
  var CONTENT_HASH_INDEX_RETRY_MAX_ATTEMPTS = 5;
25
38
  var CONTENT_HASH_INDEX_RETRY_BASE_MS = 500;
26
39
  var CONTENT_HASH_INDEX_RETRY_MAX_DELAY_MS = 5e3;
@@ -35,6 +48,8 @@ var FactHashIndexNotAuthoritativeError = class extends Error {
35
48
  var ContentHashIndex = class _ContentHashIndex {
36
49
  hashes = /* @__PURE__ */ new Set();
37
50
  dirty = false;
51
+ /** True when load() found the pre-Unicode, markerless on-disk format. */
52
+ formatMigrationRequired = false;
38
53
  /**
39
54
  * Hashes explicitly removed since the last successful save (issue #1909 review
40
55
  * round 8 thread 3). Tracked separately so `saveMergingWithDisk` can be
@@ -84,15 +99,21 @@ var ContentHashIndex = class _ContentHashIndex {
84
99
  this.memoryDir = memoryDir;
85
100
  this.lockOptions = lockOptions;
86
101
  }
102
+ /** Whether a caller with an authoritative corpus must rebuild this legacy index. */
103
+ get requiresFormatMigration() {
104
+ return this.formatMigrationRequired;
105
+ }
87
106
  /** Load existing hashes from disk. Safe to call multiple times. */
88
107
  async load() {
89
108
  try {
90
109
  const raw = await readMaybeEncryptedFile(this.filePath, this.secureStoreKeyProvider(), this.memoryDir);
91
- for (const line of raw.split("\n")) {
92
- const trimmed = line.trim();
93
- if (trimmed.length > 0) {
94
- this.hashes.add(trimmed);
95
- }
110
+ const parsed = parseHashIndex(raw);
111
+ this.formatMigrationRequired = !parsed.versioned;
112
+ if (!parsed.versioned) {
113
+ this.hashes.clear();
114
+ log.warn(`content-hash index: ignored legacy unversioned index at ${this.filePath}`);
115
+ } else {
116
+ for (const hash of parsed.hashes) this.hashes.add(hash);
96
117
  }
97
118
  log.debug(`content-hash index: loaded ${this.hashes.size} hashes`);
98
119
  } catch (err) {
@@ -181,14 +202,9 @@ var ContentHashIndex = class _ContentHashIndex {
181
202
  await mkdir(path.dirname(this.filePath), { recursive: true });
182
203
  const publishedAdded = new Set(this.added);
183
204
  const publishedRemoved = new Set(this.removed);
184
- const serialized = [...this.hashes].join("\n") + "\n";
185
- await writeMaybeEncryptedFile(
186
- this.filePath,
187
- serialized,
188
- this.secureStoreWriteKeyProvider(),
189
- {},
190
- this.memoryDir
191
- );
205
+ const serialized = serializeHashIndex(this.hashes);
206
+ await writeMaybeEncryptedFile(this.filePath, serialized, this.secureStoreWriteKeyProvider(), {}, this.memoryDir);
207
+ this.formatMigrationRequired = false;
192
208
  for (const h of publishedAdded) this.added.delete(h);
193
209
  for (const h of publishedRemoved) this.removed.delete(h);
194
210
  this.dirty = this.added.size > 0 || this.removed.size > 0;
@@ -231,14 +247,14 @@ var ContentHashIndex = class _ContentHashIndex {
231
247
  const publishedRemoved = new Set(this.removed);
232
248
  const merged = new Set(publishedAdded);
233
249
  try {
234
- const raw = await readMaybeEncryptedFile(
235
- this.filePath,
236
- this.secureStoreKeyProvider(),
237
- this.memoryDir
238
- );
239
- for (const line of raw.split("\n")) {
240
- const trimmed = line.trim();
241
- if (trimmed.length > 0 && !publishedRemoved.has(trimmed)) merged.add(trimmed);
250
+ const raw = await readMaybeEncryptedFile(this.filePath, this.secureStoreKeyProvider(), this.memoryDir);
251
+ const parsed = parseHashIndex(raw);
252
+ if (parsed.versioned) {
253
+ for (const hash of parsed.hashes) {
254
+ if (!publishedRemoved.has(hash)) merged.add(hash);
255
+ }
256
+ } else {
257
+ log.warn(`content-hash index: discarded legacy unversioned entries from ${this.filePath}`);
242
258
  }
243
259
  } catch (err) {
244
260
  if (err instanceof SecureStoreLockedError) throw err;
@@ -247,11 +263,12 @@ var ContentHashIndex = class _ContentHashIndex {
247
263
  await mkdir(path.dirname(this.filePath), { recursive: true });
248
264
  await writeMaybeEncryptedFile(
249
265
  this.filePath,
250
- [...merged].join("\n") + "\n",
266
+ serializeHashIndex(merged),
251
267
  this.secureStoreWriteKeyProvider(),
252
268
  {},
253
269
  this.memoryDir
254
270
  );
271
+ this.formatMigrationRequired = false;
255
272
  for (const h of publishedAdded) this.added.delete(h);
256
273
  for (const h of publishedRemoved) this.removed.delete(h);
257
274
  for (const h of this.added) merged.add(h);
@@ -514,4 +531,4 @@ export {
514
531
  FactHashIndexNotAuthoritativeError,
515
532
  ContentHashIndex
516
533
  };
517
- //# sourceMappingURL=chunk-BQIFZ2MP.js.map
534
+ //# sourceMappingURL=chunk-CX5SW2EW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/storage/content-hash-index.ts"],"sourcesContent":["// Content-hash dedup index for facts, extracted from storage.ts (issue #1909 /\n// PR #2016 write-hot-paths). Self-contained: cross-process locked reconcile /\n// rebuild saves plus the deferred durable-retry machinery. storage.ts imports\n// these back and re-exports the class + companion types that were previously\n// part of its public API.\nimport { mkdir, stat } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { computeContentHash, normalizeContent } from \"../content-hash.js\";\nimport { log } from \"../logger.js\";\nimport { SecureStoreLockedError, readMaybeEncryptedFile, writeMaybeEncryptedFile } from \"../secure-store/secure-fs.js\";\nimport { isErrnoCode } from \"../utils/errno.js\";\nimport { withHeldFileLock } from \"../utils/serialize-mutations.js\";\n\n/**\n * Stale threshold (ms) for the per-file advisory lock guarding a fact-hash\n * index merge-save (issue #1909 review round 7). The critical section is a\n * single read+atomic-rewrite of one index file (≤ a few MB), so a holder older\n * than this is treated as crashed. Generous to tolerate slow/encrypted disks\n * without breaking a legitimately in-progress publish.\n */\nconst CONTENT_HASH_INDEX_LOCK_STALE_MS = 30_000;\n/** Version marker for the normalized Unicode hash index format. */\nconst CONTENT_HASH_INDEX_FORMAT_HEADER = \"# remnic-content-hash-index:v2\";\n\nfunction parseHashIndex(raw: string): { versioned: boolean; hashes: Set<string> } {\n const lines = raw\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line.length > 0);\n if (lines[0] !== CONTENT_HASH_INDEX_FORMAT_HEADER) {\n return { versioned: false, hashes: new Set() };\n }\n return { versioned: true, hashes: new Set(lines.slice(1)) };\n}\n\nfunction serializeHashIndex(hashes: Set<string>): string {\n return `${CONTENT_HASH_INDEX_FORMAT_HEADER}\\n${[...hashes].join(\"\\n\")}\\n`;\n}\n\n/**\n * Durable-retry policy for a deferred content-hash reconcile save whose\n * cross-process lock acquire timed out (issue #1909 / PR #2016). When the lock\n * is contended past `withHeldFileLock`'s bounded wait, the added hashes are held\n * only in this process's memory; relying on \"some later batch save\" is not\n * durable (the run may be the last before idle/shutdown), and a long-lived peer\n * that already built its authoritative in-memory index will not see the write.\n * So we schedule a bounded, exponentially-backed-off background retry that keeps\n * re-attempting the locked publish until it lands. Bounded because the durable\n * fact `.md` is already on disk and a process restart rebuilds the index from\n * the corpus regardless — exhausting retries degrades to that rebuild safety\n * net, never to data loss or a fatal append failure.\n */\nconst CONTENT_HASH_INDEX_RETRY_MAX_ATTEMPTS = 5;\n/** Base backoff (ms) before the first deferred reconcile-save retry; doubles each attempt. */\nconst CONTENT_HASH_INDEX_RETRY_BASE_MS = 500;\n/** Ceiling (ms) for the exponential reconcile-save retry backoff. */\nexport const CONTENT_HASH_INDEX_RETRY_MAX_DELAY_MS = 5_000;\n\n/**\n * Tuning for {@link ContentHashIndex} cross-process lock waits and the\n * deferred reconcile-save durable retry (issue #1909 / PR #2016). All optional;\n * production uses the module defaults. Tests inject small values so the\n * lock-timeout + retry path is exercised deterministically without real\n * multi-second waits.\n */\nexport interface ContentHashIndexLockOptions {\n /** Bounded wait to acquire the per-file advisory lock; passed to `withHeldFileLock` (default 5000ms). */\n readonly maxWaitMs?: number;\n /** Poll interval while waiting for a busy lock (default 50ms). */\n readonly pollMs?: number;\n /** Base backoff before the first deferred-save retry (default 500ms). */\n readonly retryBaseMs?: number;\n /** Max deferred-save retries before falling back to the corpus-rebuild safety net (default 5). */\n readonly retryMaxAttempts?: number;\n}\n\n/**\n * Thrown when the fact-hash index cannot be made authoritative — the\n * cross-process rebuild lock could not be acquired within the bounded retry\n * budget (PR #2016). Callers that require an authoritative dedup answer surface\n * this instead of silently trusting a stale loaded snapshot.\n */\nexport class FactHashIndexNotAuthoritativeError extends Error {\n constructor(stateDir: string) {\n super(\n `fact-hash index is not authoritative: the cross-process rebuild lock for ${stateDir} could not be acquired within the bounded retry budget`\n );\n this.name = \"FactHashIndexNotAuthoritativeError\";\n }\n}\n\ntype DiskFingerprint = {\n mtimeMs: number;\n size: number;\n dev: number;\n ino: number;\n ctimeMs: number;\n birthtimeMs: number;\n};\nexport interface ContentHashPathEntry {\n readonly path: string;\n readonly contentHash: string;\n}\n\n/**\n * Content-hash dedup index for facts.\n * Normalizes content (lowercase, strip punctuation, collapse whitespace),\n * computes SHA-256, and stores hashes in a line-delimited file.\n * Prevents writing semantically identical facts.\n */\nexport class ContentHashIndex {\n private hashes: Set<string> = new Set();\n private dirty = false;\n /** True when load() found the pre-Unicode, markerless on-disk format. */\n private formatMigrationRequired = false;\n /**\n * Hashes explicitly removed since the last successful save (issue #1909 review\n * round 8 thread 3). Tracked separately so `saveMergingWithDisk` can be\n * removal-AWARE: under the file lock it reads the latest on-disk set, DROPS\n * these, then unions our additions — so a removal batch cannot resurrect a\n * hash (union alone would) and cannot clobber a concurrent extraction's\n * appended hash (blind overwrite would). Consumed + cleared by every save.\n */\n private removed: Set<string> = new Set();\n /**\n * Hashes added by THIS instance since the last successful save (issue #1909\n * review round 9 finding 3). Tracked separately from the loaded snapshot so a\n * reconciling save publishes `(on-disk \\ removed) ∪ added` — it re-applies only\n * OUR additions, never the stale loaded entries. Without this, seeding the\n * merge from `this.hashes` (loaded ∪ added) would resurrect a hash a peer\n * removed on disk while this instance held a stale snapshot.\n */\n private added: Set<string> = new Set();\n private readonly filePath: string;\n private readonly secureStoreKeyProvider: () => Buffer | null;\n private readonly secureStoreWriteKeyProvider: () => Buffer | null;\n private readonly memoryDir: string;\n private readonly lockOptions: ContentHashIndexLockOptions;\n /**\n * Deferred reconcile-save durable-retry state (issue #1909 / PR #2016). At\n * most ONE retry is ever armed (`reconcileRetryTimer` is the reentrancy guard)\n * so successive timed-out saves cannot stack duplicate/parallel retries.\n * `reconcileRetryBarrier` resolves when the chain settles (published or gave\n * up) — awaited by tests and any caller wanting the eventual result.\n */\n private reconcileRetryTimer: NodeJS.Timeout | null = null;\n private reconcileRetryAttempts = 0;\n private reconcileRetryBarrier: Promise<void> | null = null;\n private reconcileRetryResolve: (() => void) | null = null;\n /**\n * On-disk fingerprint captured at the last point THIS instance's in-memory\n * set matched disk — after `load()`, `save()`, or a reconcile publish. A peer\n * process that advances the durable index changes its file generation even\n * when byte size and mtime collide, so the freshness check remains safe\n * without an O(file-size) read on the hot path.\n */\n private lastSyncedFingerprint: DiskFingerprint | null = null;\n constructor(\n stateDir: string,\n secureStoreKeyProvider: () => Buffer | null = () => null,\n secureStoreWriteKeyProvider: () => Buffer | null = secureStoreKeyProvider,\n memoryDir: string = path.dirname(stateDir),\n lockOptions: ContentHashIndexLockOptions = {}\n ) {\n this.filePath = path.join(stateDir, \"fact-hashes.txt\");\n this.secureStoreKeyProvider = secureStoreKeyProvider;\n this.secureStoreWriteKeyProvider = secureStoreWriteKeyProvider;\n this.memoryDir = memoryDir;\n this.lockOptions = lockOptions;\n }\n /** Whether a caller with an authoritative corpus must rebuild this legacy index. */\n get requiresFormatMigration(): boolean {\n return this.formatMigrationRequired;\n }\n\n /** Load existing hashes from disk. Safe to call multiple times. */\n async load(): Promise<void> {\n try {\n const raw = await readMaybeEncryptedFile(this.filePath, this.secureStoreKeyProvider(), this.memoryDir);\n const parsed = parseHashIndex(raw);\n this.formatMigrationRequired = !parsed.versioned;\n if (!parsed.versioned) {\n // Hashes from the pre-NFC format are unsafe after normalization changes.\n // Ignore them until an authoritative corpus rebuild publishes v2.\n this.hashes.clear();\n log.warn(`content-hash index: ignored legacy unversioned index at ${this.filePath}`);\n } else {\n for (const hash of parsed.hashes) this.hashes.add(hash);\n }\n log.debug(`content-hash index: loaded ${this.hashes.size} hashes`);\n } catch (err) {\n if (err instanceof SecureStoreLockedError) throw err;\n if (!isErrnoCode(err, \"ENOENT\")) throw err;\n log.debug(\"content-hash index: no existing index — starting fresh\");\n }\n // The loaded set now reflects the on-disk file — baseline the fingerprint so\n // a later peer write is detectable (PR #2016 review).\n await this.captureSyncedFingerprint();\n }\n\n /** Cheap `stat` of the durable index file; null when it does not exist yet. */\n private async statIndexFile(): Promise<DiskFingerprint | null> {\n try {\n const s = await stat(this.filePath);\n return {\n mtimeMs: s.mtimeMs,\n size: s.size,\n dev: s.dev,\n ino: s.ino,\n ctimeMs: s.ctimeMs,\n birthtimeMs: s.birthtimeMs,\n };\n } catch (err) {\n if (isErrnoCode(err, \"ENOENT\")) return null;\n throw err;\n }\n }\n\n /** Record the current on-disk fingerprint as this instance's synced baseline. */\n private async captureSyncedFingerprint(): Promise<void> {\n try {\n this.lastSyncedFingerprint = await this.statIndexFile();\n } catch (err) {\n // A stat failure other than ENOENT leaves no baseline; the next freshness\n // check reports non-current and the caller confirms against the corpus.\n this.lastSyncedFingerprint = null;\n log.debug(`content-hash index: could not fingerprint ${this.filePath}: ${err}`);\n }\n }\n\n /**\n * True when the durable index file is unchanged since this instance last\n * synced it (load / save / reconcile). False when a peer advanced it, when\n * the file appeared or vanished, or when freshness cannot be established\n * (stat error) — the caller then treats the in-memory snapshot as\n * non-authoritative and confirms a dedup miss against the durable corpus.\n * The stat includes file identity and generation metadata so same-size,\n * same-mtime atomic replacements are detected without reading the file body.\n */\n async isDiskFingerprintCurrent(): Promise<boolean> {\n let current: DiskFingerprint | null;\n try {\n current = await this.statIndexFile();\n } catch {\n return false;\n }\n const last = this.lastSyncedFingerprint;\n if (last === null || current === null) {\n return last === null && current === null;\n }\n return (\n current.mtimeMs === last.mtimeMs &&\n current.size === last.size &&\n current.dev === last.dev &&\n current.ino === last.ino &&\n current.ctimeMs === last.ctimeMs &&\n current.birthtimeMs === last.birthtimeMs\n );\n }\n\n /** Check if content already exists in the index. */\n has(content: string): boolean {\n return this.hashes.has(ContentHashIndex.computeHash(content));\n }\n\n /** Add content hash to the index. */\n add(content: string): void {\n const hash = ContentHashIndex.computeHash(content);\n // A re-add supersedes a pending removal of the same hash (round 8 thread 3).\n this.removed.delete(hash);\n // Record OUR durable delta even when the local snapshot already holds the\n // hash (PR #2016 thread SD-nG): local membership can be STALE — a peer\n // removed this hash on disk while this instance kept it in memory. Skipping\n // `added`/`dirty` on that path let the reconciling save compute\n // (on-disk \\ removed) ∪ added and silently drop the reintroduced hash, so\n // the peer never saw it again. Set semantics keep this idempotent (no\n // duplicate entries) and the `removed.delete` above preserves remove/add\n // ordering.\n this.hashes.add(hash);\n this.added.add(hash);\n this.dirty = true;\n }\n\n get size(): number {\n return this.hashes.size;\n }\n\n /** Clear all loaded hashes so the next save rewrites the index from scratch. */\n clear(): void {\n if (this.hashes.size > 0) {\n this.hashes.clear();\n }\n // A full clear is always paired with a plain overwrite save() (rebuild);\n // pending per-hash add/remove deltas are subsumed by writing the rebuilt set.\n // Cancel any armed deferred-reconcile retry (PR #2016) so it cannot fire in\n // the clear→rebuild→save window and union the pre-clear on-disk rows back.\n this.added.clear();\n this.removed.clear();\n this.cancelReconcileRetry();\n this.dirty = true;\n }\n\n /** Persist index to disk if changed (plain whole-file overwrite). */\n async save(): Promise<void> {\n if (!this.dirty) return;\n await mkdir(path.dirname(this.filePath), { recursive: true });\n // Snapshot the deltas + overwrite body THIS save publishes BEFORE the write\n // yields the event loop. `writeMaybeEncryptedFile` materializes `serialized`\n // eagerly, then the disk await lets a concurrent same-process add()/remove()\n // land a late delta (PR #2016 thread PRRT_kwDORJXyws6SEBri). Clearing the\n // LIVE added/removed sets afterward — as the previous unconditional\n // clear()+`dirty = false` did — would drop that late hash from the index AND\n // leave no retry, so peers never see it until a corpus rebuild. Consume only\n // what we published; late deltas stay pending. Mirrors saveMergingWithDisk.\n const publishedAdded = new Set<string>(this.added);\n const publishedRemoved = new Set<string>(this.removed);\n const serialized = serializeHashIndex(this.hashes);\n await writeMaybeEncryptedFile(this.filePath, serialized, this.secureStoreWriteKeyProvider(), {}, this.memoryDir);\n this.formatMigrationRequired = false;\n // Consume ONLY the deltas this overwrite published; anything that arrived\n // during the awaits above remains pending for the next save.\n for (const h of publishedAdded) this.added.delete(h);\n for (const h of publishedRemoved) this.removed.delete(h);\n // Honest dirty state: true iff late deltas remain unpersisted.\n this.dirty = this.added.size > 0 || this.removed.size > 0;\n // This overwrite is now the on-disk state — re-baseline the freshness\n // fingerprint so our own write is not later mistaken for a peer's (PR #2016).\n await this.captureSyncedFingerprint();\n if (this.dirty) {\n // Late deltas landed mid-save: arm a bounded durable retry so they reach\n // disk even without a further batch save — never a silent in-memory-only\n // hash. The locked reconcile republishes only OUR delta onto the overwrite.\n this.scheduleReconcileRetry();\n } else {\n // Clean overwrite supersedes any pending deferred reconcile work.\n this.cancelReconcileRetry();\n }\n log.debug(`content-hash index: saved ${this.hashes.size} hashes`);\n }\n\n /**\n * Persist the index by RECONCILING with the latest on-disk state under a\n * cross-process lock (issue #1909). Used by the extraction-persist batch save\n * for BOTH append and removal batches, so appends and removals to the same\n * index serialize against each other:\n * final = (on-disk \\ this.removed) ∪ this.added\n * Note it re-applies only OUR local additions (`added`), NOT the loaded\n * snapshot (review round 9 finding 3): seeding from `this.hashes` would\n * resurrect a hash a peer removed on disk while we held a stale snapshot. This\n * preserves a concurrent writer's appended hashes (a blind overwrite would\n * drop them), never resurrects a removed hash, and never loses our additions.\n *\n * Hardening:\n * - Dirty short-circuit (round 7 finding 3): when this instance neither added\n * nor removed anything this run, skip the O(file) read+rewrite entirely.\n * - Cross-process lock (round 7 finding 2): serialize the read→reconcile→write\n * window on a per-file advisory lock. If the lock is NOT acquired (timeout),\n * do NOT publish (round 9 finding 2): keep `dirty` set AND schedule a bounded\n * durable background retry (PR #2016) that keeps re-attempting the locked\n * publish until the deferred additions land — never an unlocked write that\n * could clobber a peer, and never a silent \"batch save complete\" that leaves\n * the addition in this process's memory only.\n */\n async saveMergingWithDisk(): Promise<void> {\n if (!this.dirty) return;\n // The advisory lock file lives beside the index — ensure the dir exists\n // before acquiring it (the index dir may not exist on a first write).\n await mkdir(path.dirname(this.filePath), { recursive: true });\n const publish = async (): Promise<void> => {\n // Snapshot the deltas this publish is responsible for. The read+rewrite\n // below yields the event loop, so a concurrent add()/remove() can land\n // new deltas while we await disk (PR #2016 thread SD7Tj). Consuming the\n // LIVE sets afterward would drop those late deltas AND clear `dirty`,\n // stranding them in no save at all. We consume only what we published;\n // anything that arrived meanwhile stays pending for the next save.\n const publishedAdded = new Set<string>(this.added);\n const publishedRemoved = new Set<string>(this.removed);\n const merged = new Set<string>(publishedAdded);\n try {\n const raw = await readMaybeEncryptedFile(this.filePath, this.secureStoreKeyProvider(), this.memoryDir);\n const parsed = parseHashIndex(raw);\n if (parsed.versioned) {\n for (const hash of parsed.hashes) {\n // Keep prior/concurrent on-disk hashes EXCEPT the ones we removed.\n if (!publishedRemoved.has(hash)) merged.add(hash);\n }\n } else {\n // Do not carry hashes from the pre-NFC format into a v2 write.\n log.warn(`content-hash index: discarded legacy unversioned entries from ${this.filePath}`);\n }\n } catch (err) {\n if (err instanceof SecureStoreLockedError) throw err;\n if (!isErrnoCode(err, \"ENOENT\")) throw err;\n // ENOENT → no on-disk index yet; write our additions as-is.\n }\n await mkdir(path.dirname(this.filePath), { recursive: true });\n await writeMaybeEncryptedFile(\n this.filePath,\n serializeHashIndex(merged),\n this.secureStoreWriteKeyProvider(),\n {},\n this.memoryDir\n );\n this.formatMigrationRequired = false;\n // Consume ONLY the deltas we just published; deltas that arrived during\n // the awaits above remain pending.\n for (const h of publishedAdded) this.added.delete(h);\n for (const h of publishedRemoved) this.removed.delete(h);\n // Fold any still-pending deltas onto the reconciled set so the in-memory\n // view stays consistent with what the next save will publish.\n for (const h of this.added) merged.add(h);\n for (const h of this.removed) merged.delete(h);\n this.hashes = merged;\n // Honest dirty state: true iff late deltas remain to be persisted. A\n // subsequent batch save or the shutdown flush drains them.\n this.dirty = this.added.size > 0 || this.removed.size > 0;\n // The reconciled set is now the on-disk state — re-baseline the freshness\n // fingerprint (captured under the held lock) so our own publish is not\n // later mistaken for a peer's advance (PR #2016 review).\n await this.captureSyncedFingerprint();\n };\n await withHeldFileLock(\n `${this.filePath}.lock`,\n {\n staleMs: CONTENT_HASH_INDEX_LOCK_STALE_MS,\n ...(this.lockOptions.maxWaitMs !== undefined ? { maxWaitMs: this.lockOptions.maxWaitMs } : {}),\n ...(this.lockOptions.pollMs !== undefined ? { pollMs: this.lockOptions.pollMs } : {}),\n },\n async (acquired) => {\n if (!acquired) {\n // Never publish unlocked (round 9 finding 2): keep dirty AND schedule a\n // durable background retry (PR #2016). Relying on an unguaranteed later\n // batch save silently left the addition in this process's memory only;\n // the retry keeps re-attempting the locked publish until the addition\n // lands on disk.\n log.warn(\n `content-hash index: lock not acquired for ${this.filePath}; deferring reconcile save (dirty retained, scheduling durable retry)`\n );\n this.scheduleReconcileRetry();\n return;\n }\n await publish();\n if (this.dirty) {\n // A concurrent add()/remove() landed during publish's disk awaits, so\n // deltas remain unpersisted (PR #2016 thread SD7Tj). Arm a bounded\n // durable retry so they reach disk even if no further batch save comes\n // — never leave a settled barrier over pending work.\n this.scheduleReconcileRetry();\n } else {\n // Published cleanly: any pending deferred retry is now satisfied.\n this.cancelReconcileRetry();\n }\n }\n );\n log.debug(`content-hash index: reconcile-saved ${this.hashes.size} hashes`);\n }\n\n /**\n * Rebuild-and-publish the index from an authoritative source (the durable\n * corpus) under the SAME per-file cross-process lock the reconciling\n * append/removal saves (`saveMergingWithDisk`) use (issue #1909 / PR #2016).\n * The `populate` callback runs WHILE the lock is held and MUST repopulate this\n * index from the corpus (`clear()` then `addByHash(...)` for every corpus\n * hash); the rebuilt set is then published with a plain overwrite that is now\n * serialized against every locked writer.\n *\n * This closes the finding where the previous unlocked clear→scan→save() could\n * overwrite a peer's newer lock-merged or deferred additions: a locked writer\n * that committed BEFORE the rebuild acquired the lock has its memory `.md` on\n * disk and is re-scanned; one that commits AFTER the rebuild releases\n * reconciles its additions on top of the freshly-published set. No union with\n * the raw on-disk file is performed, so the rebuild keeps its\n * garbage-collection property (orphaned hashes for deleted memories drop).\n *\n * Lock-acquisition failure is explicit and non-destructive: `populate` is NOT\n * run and nothing is written (never an unlocked overwrite). Returns true when\n * the rebuild was published under the lock, false when the lock timed out —\n * the caller keeps the index non-authoritative and retries on next use. Uses\n * the same non-reentrant file lock as the reconcile path, so it can never\n * deadlock with the deferred reconcile-retry: a concurrent locked writer (or a\n * fired retry) simply yields `acquired=false` after the bounded wait.\n */\n async rebuildUnderLock(populate: () => Promise<void>): Promise<boolean> {\n // The advisory lock file lives beside the index — ensure the dir exists\n // before acquiring it (the index dir may not exist on a first rebuild).\n await mkdir(path.dirname(this.filePath), { recursive: true });\n let published = false;\n await withHeldFileLock(\n `${this.filePath}.lock`,\n {\n staleMs: CONTENT_HASH_INDEX_LOCK_STALE_MS,\n ...(this.lockOptions.maxWaitMs !== undefined ? { maxWaitMs: this.lockOptions.maxWaitMs } : {}),\n ...(this.lockOptions.pollMs !== undefined ? { pollMs: this.lockOptions.pollMs } : {}),\n },\n async (acquired) => {\n if (!acquired) {\n // Never publish unlocked: a concurrent locked writer holds the lock,\n // so overwriting now could clobber its addition. Leave the index as-is\n // and let the caller retry the authoritative rebuild on next use.\n log.warn(\n `content-hash index: lock not acquired for ${this.filePath}; deferring authoritative rebuild (index left non-authoritative, retried on next use)`\n );\n return;\n }\n await populate();\n // Publish under the held lock. save() takes no lock (no re-entrancy) and\n // is a full overwrite that supersedes any pending add/remove deltas.\n await this.save();\n published = true;\n }\n );\n return published;\n }\n\n /**\n * True while a background durable reconcile-save retry is armed (PR #2016).\n * Test/introspection hook.\n */\n get hasPendingReconcileRetry(): boolean {\n return this.reconcileRetryTimer !== null;\n }\n\n /** True while this index has in-memory changes not yet published to disk. */\n get hasPendingChanges(): boolean {\n return this.dirty;\n }\n\n /**\n * Resolve once any armed background reconcile-save retry chain has settled —\n * either it published the deferred additions, or it exhausted its bounded\n * attempts and fell back to the corpus-rebuild safety net. Resolves\n * immediately when nothing is armed. Lets a caller (or a test) await the\n * eventual durability outcome of a lock-timed-out save.\n */\n async whenReconcileRetrySettled(): Promise<void> {\n await (this.reconcileRetryBarrier ?? Promise.resolve());\n }\n\n /**\n * Drive any deferred lock-timeout reconcile save to completion INLINE at a\n * lifecycle boundary (PR #2016 finding 3). The background retry timer is\n * `unref`'d so it never keeps a long-lived daemon alive — but a short-lived\n * writer (a one-shot CLI) can exit before it fires, leaving a durable fact\n * `.md` whose hash never reached `fact-hashes.txt` for peers that already\n * built their in-memory index. `orchestrator.destroy()` calls this so the\n * addition publishes before the process exits; long-lived hosts only reach it\n * at their own shutdown, so their in-flight retries keep running in the\n * background until then. Bounded by the same attempt ceiling as the background\n * retry; a permanently contended lock falls back to the corpus-rebuild-on-\n * restart safety net (the fact `.md` is already durable). No deadlock: each\n * attempt is the same non-reentrant, bounded-wait file lock.\n */\n async flushReconcileRetry(): Promise<void> {\n if (!this.dirty) return;\n const maxAttempts = this.lockOptions.retryMaxAttempts ?? CONTENT_HASH_INDEX_RETRY_MAX_ATTEMPTS;\n const baseMs = this.lockOptions.retryBaseMs ?? CONTENT_HASH_INDEX_RETRY_BASE_MS;\n for (let attempt = 0; this.dirty && attempt < maxAttempts; attempt += 1) {\n // Cancel the unref'd background timer — we drive the locked publish inline.\n if (this.reconcileRetryTimer) {\n clearTimeout(this.reconcileRetryTimer);\n this.reconcileRetryTimer = null;\n }\n await this.saveMergingWithDisk();\n if (!this.dirty) break;\n if (attempt < maxAttempts - 1) {\n const wait = Math.min(baseMs * 2 ** attempt, CONTENT_HASH_INDEX_RETRY_MAX_DELAY_MS);\n await new Promise<void>((resolve) => setTimeout(resolve, wait));\n }\n }\n // Clear any timer the final saveMergingWithDisk armed and settle the barrier\n // so awaiters unblock — the bounded inline drain has done its best.\n if (this.reconcileRetryTimer) {\n clearTimeout(this.reconcileRetryTimer);\n this.reconcileRetryTimer = null;\n }\n this.reconcileRetryAttempts = 0;\n this.settleReconcileRetry();\n }\n\n /**\n * Schedule ONE bounded, exponentially-backed-off background retry of the\n * deferred reconcile save (PR #2016). Reentrant-safe: an already-armed timer\n * short-circuits, so successive timed-out saves never stack duplicate retries.\n * When attempts are exhausted the chain settles without publishing — the\n * durable fact `.md` is on disk and a process restart rebuilds the index from\n * the corpus, so this degrades to that safety net, never a fatal failure.\n */\n private scheduleReconcileRetry(): void {\n if (this.reconcileRetryTimer) return; // one retry in flight — no duplicate/reentrant retries\n const maxAttempts = this.lockOptions.retryMaxAttempts ?? CONTENT_HASH_INDEX_RETRY_MAX_ATTEMPTS;\n if (this.reconcileRetryAttempts >= maxAttempts) {\n log.warn(\n `content-hash index: exhausted ${maxAttempts} deferred reconcile-save retries for ${this.filePath}; ` +\n `${this.added.size} addition(s) remain dirty in-memory (a process restart rebuilds the index from the durable corpus)`\n );\n this.reconcileRetryAttempts = 0;\n this.settleReconcileRetry();\n return;\n }\n if (!this.reconcileRetryBarrier) {\n this.reconcileRetryBarrier = new Promise<void>((resolve) => {\n this.reconcileRetryResolve = resolve;\n });\n }\n const attempt = this.reconcileRetryAttempts + 1;\n const baseMs = this.lockOptions.retryBaseMs ?? CONTENT_HASH_INDEX_RETRY_BASE_MS;\n const delay = Math.min(baseMs * 2 ** (attempt - 1), CONTENT_HASH_INDEX_RETRY_MAX_DELAY_MS);\n this.reconcileRetryTimer = setTimeout(() => {\n this.reconcileRetryTimer = null;\n this.reconcileRetryAttempts = attempt;\n void this.saveMergingWithDisk()\n .catch((err) => {\n // A publish-time I/O/encryption error (not a lock timeout) is best-effort:\n // log and let the corpus-rebuild safety net cover it rather than loop.\n log.warn(`content-hash index: deferred reconcile-save retry failed for ${this.filePath}: ${err}`);\n })\n .finally(() => {\n // If the attempt neither published (dirty cleared → cancelReconcileRetry)\n // nor re-armed a further retry, the chain has ended — settle the barrier.\n if (this.dirty && !this.reconcileRetryTimer) this.settleReconcileRetry();\n });\n }, delay);\n this.reconcileRetryTimer.unref?.();\n }\n\n /** Cancel any armed reconcile-save retry and settle the barrier (a publish landed). */\n private cancelReconcileRetry(): void {\n if (this.reconcileRetryTimer) {\n clearTimeout(this.reconcileRetryTimer);\n this.reconcileRetryTimer = null;\n }\n this.reconcileRetryAttempts = 0;\n this.settleReconcileRetry();\n }\n\n /** Resolve and clear the retry barrier if one is outstanding. */\n private settleReconcileRetry(): void {\n const resolve = this.reconcileRetryResolve;\n this.reconcileRetryBarrier = null;\n this.reconcileRetryResolve = null;\n resolve?.();\n }\n\n /** Remove a hash from the index (used when archiving/deleting). */\n remove(content: string): void {\n const hash = ContentHashIndex.computeHash(content);\n // Record the removal (round 8 thread 3) even when the hash is not in our\n // in-memory set — a reconciling save must still drop it from the latest\n // on-disk state. A removal supersedes a pending add. Always mark dirty.\n this.added.delete(hash);\n this.removed.add(hash);\n this.hashes.delete(hash);\n this.dirty = true;\n }\n\n /**\n * Remove a pre-computed SHA-256 hash directly from the index without\n * re-hashing. Use this when the caller already holds the stored hash\n * (e.g. `memory.frontmatter.contentHash`) to avoid the double-hash bug\n * where `remove(hash)` would compute `hash(hash)` and never match the\n * entry.\n */\n removeByHash(hash: string): void {\n this.added.delete(hash);\n this.removed.add(hash);\n this.hashes.delete(hash);\n this.dirty = true;\n }\n\n /**\n * Add a pre-computed SHA-256 hash directly to the index without re-hashing.\n * Use this when the caller already holds the stored hash\n * (e.g. `memory.frontmatter.contentHash`) so that the index records the raw\n * content hash rather than re-hashing the citation-annotated body.\n *\n * @internal Only called from `StorageManager.ensureFactHashIndexAuthoritative`.\n * Not part of the public API — prefer `add(content)` for external callers.\n */\n addByHash(hash: string): void {\n // A re-add supersedes a pending removal of the same hash.\n this.removed.delete(hash);\n // Record OUR durable delta even when the local snapshot already holds the\n // hash (PR #2016 thread PRRT_kwDORJXyws6SEHve). Outside a rebuild\n // (StorageManager.addActiveFactContentHash on reactivation) local\n // membership can be STALE: a peer removed this hash on disk while this\n // instance kept it in memory. Skipping added/dirty on that path let the\n // reconciling save compute (on-disk \\ removed) ∪ added and silently drop\n // the reintroduced hash, so the peer never saw it again. Set semantics keep\n // this idempotent (no duplicate entries) and the removed.delete above\n // preserves remove/add ordering. Mirrors add().\n this.hashes.add(hash);\n this.added.add(hash);\n this.dirty = true;\n }\n\n /**\n * Resolve a pre-computed semantic hash to one deterministic corpus path.\n *\n * This lookup is separate from durable hash membership: `this.hashes` stays\n * one hash per line and `has(content)` keeps its existing raw-content contract.\n * Reconciliation supplies short-lived manifest rows where hash and path coexist.\n */\n static resolvePathByHash(hash: string, entries: Iterable<ContentHashPathEntry>): string | undefined {\n const canonicalHash = hash.toLowerCase();\n if (!/^[a-f0-9]{64}$/.test(canonicalHash)) return undefined;\n let canonicalPath: string | undefined;\n for (const entry of entries) {\n if (entry.contentHash.toLowerCase() !== canonicalHash || entry.path.length === 0) continue;\n if (canonicalPath === undefined || entry.path < canonicalPath) canonicalPath = entry.path;\n }\n return canonicalPath;\n }\n\n /** Normalize content (delegates to content-hash.ts for a single source of truth). */\n static normalizeContent(content: string): string {\n return normalizeContent(content);\n }\n\n /** Compute SHA-256 hash (delegates to content-hash.ts for a single source of truth). */\n static computeHash(content: string): string {\n return computeContentHash(content);\n }\n}\n"],"mappings":"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","names":[]}
@@ -6,14 +6,14 @@ import {
6
6
  loadSyncState,
7
7
  syncWearableSource,
8
8
  wearableSourceLabel
9
- } from "./chunk-IARXXZU4.js";
9
+ } from "./chunk-HOIRB77A.js";
10
10
  import {
11
11
  CompressionGuidelineCoordinator
12
12
  } from "./chunk-6LKEUCEM.js";
13
13
  import {
14
14
  ActivityStore,
15
15
  MaintenanceScheduler
16
- } from "./chunk-WLRD2TXF.js";
16
+ } from "./chunk-WOPA3SGI.js";
17
17
  import {
18
18
  runPeerProfileReasoner
19
19
  } from "./chunk-I74SUMNI.js";
@@ -32,7 +32,7 @@ import {
32
32
  import {
33
33
  CompoundingEngine,
34
34
  defaultTierMigrationCycleBudget
35
- } from "./chunk-7HXZJAID.js";
35
+ } from "./chunk-YGLY6QFV.js";
36
36
  import {
37
37
  SharedContextManager
38
38
  } from "./chunk-M23RF3LJ.js";
@@ -156,14 +156,14 @@ import {
156
156
  harmonicEntitySegment,
157
157
  normalizedHarmonicEntityIdentity,
158
158
  persistHarmonicRecords
159
- } from "./chunk-GXSOUIA4.js";
159
+ } from "./chunk-5WQMORU5.js";
160
160
  import {
161
161
  buildFocusedListRecallSection,
162
162
  shouldRecallFocusedListEvidence
163
163
  } from "./chunk-OH7QLI6W.js";
164
164
  import {
165
165
  ExtractionEngine
166
- } from "./chunk-AXIDQG5A.js";
166
+ } from "./chunk-G4T7L557.js";
167
167
  import {
168
168
  parseMemoryActionEligibilityContext
169
169
  } from "./chunk-WFLBP5GC.js";
@@ -190,7 +190,7 @@ import {
190
190
  buildEntityRecallSection,
191
191
  entityRecentTranscriptLookbackHours,
192
192
  readRecentEntityTranscriptEntries
193
- } from "./chunk-TEMSWHQD.js";
193
+ } from "./chunk-DZD576ZU.js";
194
194
  import {
195
195
  buildEventOrderRecallSection,
196
196
  shouldRecallEventOrderEvidence
@@ -207,7 +207,7 @@ import {
207
207
  } from "./chunk-YK6BDDHP.js";
208
208
  import {
209
209
  refreshConvergedNamespaces
210
- } from "./chunk-GXFSQ6SD.js";
210
+ } from "./chunk-C4ZNGVK3.js";
211
211
  import {
212
212
  formatDaySummaryMemories
213
213
  } from "./chunk-RPSYDM6C.js";
@@ -216,7 +216,7 @@ import {
216
216
  ensureBuiltInWearableConnectors,
217
217
  getWearableConnector,
218
218
  listWearableConnectors
219
- } from "./chunk-D5YOZ66N.js";
219
+ } from "./chunk-JV5YUBIZ.js";
220
220
  import {
221
221
  normalizeReplaySessionKey
222
222
  } from "./chunk-AJVLDJU6.js";
@@ -226,14 +226,14 @@ import {
226
226
  import {
227
227
  compareVerifiedEpisodeResults,
228
228
  searchVerifiedEpisodes
229
- } from "./chunk-J272WKX2.js";
229
+ } from "./chunk-6HPHEFXT.js";
230
230
  import {
231
231
  ThreadingManager
232
232
  } from "./chunk-OJP3N7UK.js";
233
233
  import {
234
234
  compareVerifiedSemanticRuleResults,
235
235
  searchVerifiedSemanticRules
236
- } from "./chunk-VFSAWRMZ.js";
236
+ } from "./chunk-LJS7KUPV.js";
237
237
  import {
238
238
  searchWorkProductLedgerEntries
239
239
  } from "./chunk-WT6UL3UA.js";
@@ -246,14 +246,14 @@ import {
246
246
  import {
247
247
  runNamespaceMaintenanceFanout,
248
248
  summarizeNamespaceMaintenanceHealth
249
- } from "./chunk-X7XEDOSL.js";
249
+ } from "./chunk-4IIFL7GC.js";
250
250
  import {
251
251
  NamespaceCatalog,
252
252
  planNamespaceMaintenance
253
- } from "./chunk-BKIFTXHR.js";
253
+ } from "./chunk-RZ4XGKOJ.js";
254
254
  import {
255
255
  searchHarmonicRetrieval
256
- } from "./chunk-W7Y5JDVB.js";
256
+ } from "./chunk-PDDTI7IC.js";
257
257
  import {
258
258
  isAboveImportanceThreshold,
259
259
  scoreImportance
@@ -285,7 +285,7 @@ import {
285
285
  materializeAfterSemanticConsolidation,
286
286
  parseConsolidationResponse,
287
287
  parseOperatorAwareConsolidationResponse
288
- } from "./chunk-BMEYMKWX.js";
288
+ } from "./chunk-WM65LU67.js";
289
289
  import {
290
290
  BootstrapEngine
291
291
  } from "./chunk-MYVPLJOO.js";
@@ -306,13 +306,13 @@ import {
306
306
  } from "./chunk-H3FZVNRN.js";
307
307
  import {
308
308
  detectMeetings
309
- } from "./chunk-O5FFBO2M.js";
309
+ } from "./chunk-47P3RYZP.js";
310
310
  import {
311
311
  compileCorrectionRule,
312
312
  correctionsFilePath,
313
313
  loadCorrectionsFile,
314
314
  saveCorrectionsFile
315
- } from "./chunk-NDAH7BJ5.js";
315
+ } from "./chunk-HVP33QVW.js";
316
316
  import {
317
317
  activityDayWindow,
318
318
  isValidActivityDate,
@@ -331,7 +331,7 @@ import {
331
331
  } from "./chunk-KD3QD3A5.js";
332
332
  import {
333
333
  MeetingsInputError
334
- } from "./chunk-HDIUYMSB.js";
334
+ } from "./chunk-QWGE2PUH.js";
335
335
  import {
336
336
  WearablesInputError,
337
337
  describeErrorForOperator
@@ -352,7 +352,7 @@ import {
352
352
  filterRecallCandidates,
353
353
  isGenericRecallExcludedPath,
354
354
  isTopLevelArchivePath
355
- } from "./chunk-BF6SXNQJ.js";
355
+ } from "./chunk-T2JHZWH6.js";
356
356
  import {
357
357
  importCapsule
358
358
  } from "./chunk-QYN5PXDZ.js";
@@ -396,7 +396,7 @@ import {
396
396
  } from "./chunk-QDW3E4RD.js";
397
397
  import {
398
398
  shouldSkipImplicitExtraction
399
- } from "./chunk-RYLEDKQ2.js";
399
+ } from "./chunk-RUMNY5DT.js";
400
400
  import {
401
401
  NamespaceSearchRouter,
402
402
  namespaceCollectionName
@@ -411,7 +411,7 @@ import {
411
411
  } from "./chunk-CYEPCZN5.js";
412
412
  import {
413
413
  NamespaceStorageRouter
414
- } from "./chunk-2LY6GIIE.js";
414
+ } from "./chunk-WDBX6VER.js";
415
415
  import {
416
416
  writeConversationChunks
417
417
  } from "./chunk-72A4L5JJ.js";
@@ -423,7 +423,7 @@ import {
423
423
  } from "./chunk-BIJAWZYW.js";
424
424
  import {
425
425
  buildChainFollowupGenerator
426
- } from "./chunk-F4EU6VUC.js";
426
+ } from "./chunk-JDZPNCMA.js";
427
427
  import {
428
428
  QmdResultResolver,
429
429
  StorageManager,
@@ -442,7 +442,7 @@ import {
442
442
  reconstructFusionInputs,
443
443
  selfDeps,
444
444
  serializeFusionDay
445
- } from "./chunk-WD5B5AIE.js";
445
+ } from "./chunk-6R4G7N4S.js";
446
446
  import {
447
447
  bodyIsEscaped,
448
448
  decodeTranscriptBody,
@@ -455,17 +455,12 @@ import {
455
455
  } from "./chunk-UHVXE24Y.js";
456
456
  import {
457
457
  buildRetiredFactTombstoneInputs
458
- } from "./chunk-JJRVPWFY.js";
458
+ } from "./chunk-MLPTFODV.js";
459
459
  import {
460
460
  canRecallToolScopedMemory,
461
461
  shouldPromoteGlobalFactToShared,
462
462
  withholdToolScopedFromSharedNamespace
463
463
  } from "./chunk-S2V7RUCL.js";
464
- import {
465
- attachCitation,
466
- hasCitationForTemplate,
467
- stripCitationForTemplate
468
- } from "./chunk-J6A3CX5N.js";
469
464
  import {
470
465
  confidenceTier
471
466
  } from "./chunk-UU3G6GUP.js";
@@ -482,14 +477,10 @@ import {
482
477
  TAG_LIMITS,
483
478
  composeMemoryEnvelope,
484
479
  isMemoryCategory
485
- } from "./chunk-5V6IXHPI.js";
480
+ } from "./chunk-NSVDUN76.js";
486
481
  import {
487
482
  normalizeTags
488
483
  } from "./chunk-BT7NVCML.js";
489
- import {
490
- normalizeAttributePairs,
491
- stripAttributesSuffix
492
- } from "./chunk-R3DJVOSM.js";
493
484
  import {
494
485
  checkCorpusReadAbort
495
486
  } from "./chunk-5GINB5LC.js";
@@ -578,22 +569,16 @@ import {
578
569
  import {
579
570
  assertExternalWikiRootOutsideMemoryDirCanonical
580
571
  } from "./chunk-JV3C2MNQ.js";
581
- import {
582
- sanitizeMemoryContent
583
- } from "./chunk-5GKPFL3S.js";
584
572
  import {
585
573
  coerceBool
586
574
  } from "./chunk-PQVCH2AE.js";
587
- import {
588
- MEMORY_ID_PATTERN,
589
- parseIdOrHandle,
590
- resolveHandle,
591
- stripHandles
592
- } from "./chunk-JAKIDQB2.js";
593
575
  import {
594
576
  createBoundedCoreSectionRunner,
595
577
  createRecallSectionMetricRecorder
596
578
  } from "./chunk-4O4TKIXQ.js";
579
+ import {
580
+ normalizeRecallTokenSet
581
+ } from "./chunk-ZBJMUXZH.js";
597
582
  import {
598
583
  decideLifecycleTransition,
599
584
  resolveLifecycleState
@@ -613,6 +598,11 @@ import {
613
598
  resolveNamespaceFromStorageDir,
614
599
  resolveScopePlan
615
600
  } from "./chunk-YN6ASZUG.js";
601
+ import {
602
+ attachCitation,
603
+ hasCitationForTemplate,
604
+ stripCitationForTemplate
605
+ } from "./chunk-J6A3CX5N.js";
616
606
  import {
617
607
  namespaceIdentityFromToken,
618
608
  namespaceIdentityToken,
@@ -628,7 +618,20 @@ import {
628
618
  } from "./chunk-7RJUVTVF.js";
629
619
  import {
630
620
  ContentHashIndex
631
- } from "./chunk-BQIFZ2MP.js";
621
+ } from "./chunk-CX5SW2EW.js";
622
+ import {
623
+ normalizeAttributePairs,
624
+ stripAttributesSuffix
625
+ } from "./chunk-JDSVLVCG.js";
626
+ import {
627
+ sanitizeMemoryContent
628
+ } from "./chunk-5GKPFL3S.js";
629
+ import {
630
+ MEMORY_ID_PATTERN,
631
+ parseIdOrHandle,
632
+ resolveHandle,
633
+ stripHandles
634
+ } from "./chunk-JAKIDQB2.js";
632
635
  import {
633
636
  assertIsDirectoryNotSymlink,
634
637
  assertRealpathInsideRoot
@@ -15039,7 +15042,7 @@ var OrchestratorInitCoordinator = class {
15039
15042
  if (signal.aborted) return;
15040
15043
  if (!this.deps.wearablesAutoSyncHandle && this.deps.config.wearables.enabled && this.deps.config.wearables.autoSyncEnabled && Object.values(this.deps.config.wearables.sources).some((source) => source.enabled)) {
15041
15044
  try {
15042
- const { startWearablesAutoSync } = await import("./auto-sync-QFQGOEO2.js");
15045
+ const { startWearablesAutoSync } = await import("./auto-sync-TDHLZPVP.js");
15043
15046
  if (signal.aborted) return;
15044
15047
  this.deps.wearablesAutoSyncHandle = startWearablesAutoSync(
15045
15048
  {
@@ -23676,9 +23679,9 @@ function walkFiles(dir, callback) {
23676
23679
  }
23677
23680
 
23678
23681
  // src/dedup/index.ts
23682
+ import crypto5 from "crypto";
23679
23683
  import fs4 from "fs";
23680
23684
  import path28 from "path";
23681
- import crypto5 from "crypto";
23682
23685
  var DEFAULT_DEDUP_THRESHOLD = 0.85;
23683
23686
  var DEFAULT_MAX_LOAD = 1e4;
23684
23687
  function normalizeThreshold(value, defaultValue) {
@@ -23736,6 +23739,9 @@ function findContradictions(options) {
23736
23739
  function computeSimilarity(a, b) {
23737
23740
  const normA = normalize(a);
23738
23741
  const normB = normalize(b);
23742
+ const punctuationBoundariesA = embeddedPunctuationSignature(a);
23743
+ const punctuationBoundariesB = embeddedPunctuationSignature(b);
23744
+ if (punctuationBoundariesA !== punctuationBoundariesB) return 0;
23739
23745
  if (normA === normB) return 1;
23740
23746
  if (hashContent2(normA) === hashContent2(normB)) return 0.99;
23741
23747
  if (normA.length > 50 && normB.length > 50) {
@@ -23743,15 +23749,65 @@ function computeSimilarity(a, b) {
23743
23749
  return 0.9;
23744
23750
  }
23745
23751
  }
23746
- const wordsA = new Set(normA.split(/\s+/));
23747
- const wordsB = new Set(normB.split(/\s+/));
23752
+ const wordsA = tokenizeForSimilarity(normA);
23753
+ const wordsB = tokenizeForSimilarity(normB);
23748
23754
  const intersection = new Set([...wordsA].filter((w) => wordsB.has(w)));
23749
23755
  const union = /* @__PURE__ */ new Set([...wordsA, ...wordsB]);
23750
23756
  if (union.size === 0) return 0;
23751
23757
  return intersection.size / union.size;
23752
23758
  }
23759
+ function embeddedPunctuationSignature(text) {
23760
+ const chars = [...text.normalize("NFC")];
23761
+ const significant = /[\p{L}\p{M}\p{N}]/u;
23762
+ const ignored = /[\s']/u;
23763
+ const boundaries = [];
23764
+ let position = 0;
23765
+ for (let index = 0; index < chars.length; ) {
23766
+ const char = chars[index];
23767
+ if (char === void 0) break;
23768
+ if (significant.test(char)) {
23769
+ position++;
23770
+ index++;
23771
+ continue;
23772
+ }
23773
+ if (ignored.test(char)) {
23774
+ index++;
23775
+ continue;
23776
+ }
23777
+ const start = index;
23778
+ while (index < chars.length) {
23779
+ const next = chars[index];
23780
+ if (next === void 0 || significant.test(next) || ignored.test(next)) break;
23781
+ index++;
23782
+ }
23783
+ const before = chars[start - 1];
23784
+ const after = chars[index];
23785
+ if (before && after && significant.test(before) && significant.test(after)) {
23786
+ boundaries.push(`${position}:${chars.slice(start, index).join("")}`);
23787
+ }
23788
+ }
23789
+ return boundaries.join("\0");
23790
+ }
23753
23791
  function normalize(text) {
23754
- return text.toLowerCase().replace(/[^\w\s']/g, "").replace(/\s+/g, " ").trim();
23792
+ return text.normalize("NFC").toLowerCase().replace(/[^\p{ASCII}\p{L}\p{M}\p{N}\s']/gu, " ").replace(/[^\p{L}\p{M}\p{N}\s']/gu, "").replace(/\s+/g, " ").trim();
23793
+ }
23794
+ function tokenizeForSimilarity(text) {
23795
+ if (/\p{Script=Hangul}/u.test(text)) {
23796
+ const tokens = normalizeRecallTokenSet(text);
23797
+ for (const segment of text.match(/\p{Script=Hangul}+/gu) ?? []) {
23798
+ const chars = [...segment];
23799
+ for (const size of [1, 2, 3, 4]) {
23800
+ for (let index = 0; index <= chars.length - size; index += 1) {
23801
+ tokens.add(chars.slice(index, index + size).join(""));
23802
+ }
23803
+ }
23804
+ }
23805
+ return tokens;
23806
+ }
23807
+ if (/[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}]/u.test(text)) {
23808
+ return normalizeRecallTokenSet(text);
23809
+ }
23810
+ return text.length === 0 ? /* @__PURE__ */ new Set() : new Set(text.split(/\s+/));
23755
23811
  }
23756
23812
  var NEGATION_WORDS = /* @__PURE__ */ new Set([
23757
23813
  "not",
@@ -26962,4 +27018,4 @@ export {
26962
27018
  blendGraphExpandedRecallScore,
26963
27019
  Orchestrator
26964
27020
  };
26965
- //# sourceMappingURL=chunk-RMHMUUBW.js.map
27021
+ //# sourceMappingURL=chunk-CYF6WVE7.js.map