@remnic/core 9.52.1 → 9.53.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 (253) hide show
  1. package/dist/access-admin-ops-surface.d.ts +5 -5
  2. package/dist/access-admin-ops-surface.js +22 -22
  3. package/dist/access-authorization-probe.d.ts +5 -5
  4. package/dist/access-authorization-probe.js +23 -23
  5. package/dist/access-boundary.d.ts +5 -5
  6. package/dist/access-boundary.js +22 -22
  7. package/dist/access-cli.js +54 -54
  8. package/dist/access-extraction-force-flush.d.ts +5 -5
  9. package/dist/access-extraction-force-flush.js +22 -22
  10. package/dist/access-http-lcm-compaction.d.ts +5 -5
  11. package/dist/access-http-lifecycle-flush.d.ts +5 -5
  12. package/dist/access-http-offline-stream.d.ts +5 -5
  13. package/dist/access-http-query.js +22 -22
  14. package/dist/access-http.d.ts +5 -5
  15. package/dist/access-http.js +29 -29
  16. package/dist/access-identity-continuity-surface.d.ts +4 -4
  17. package/dist/access-identity-continuity-surface.js +22 -22
  18. package/dist/access-lcm-surface.d.ts +5 -5
  19. package/dist/access-lcm-surface.js +22 -22
  20. package/dist/access-mcp.d.ts +5 -5
  21. package/dist/access-mcp.js +27 -27
  22. package/dist/access-namespace-preflight.js +22 -22
  23. package/dist/access-observe-write-surface.d.ts +5 -5
  24. package/dist/access-observe-write-surface.js +22 -22
  25. package/dist/access-offline-manifest.d.ts +4 -4
  26. package/dist/access-offline-manifest.js +8 -4
  27. package/dist/access-operations-batch.js +24 -24
  28. package/dist/access-operations.d.ts +5 -5
  29. package/dist/access-operations.js +26 -26
  30. package/dist/access-recall-concurrency.d.ts +5 -5
  31. package/dist/access-recall-concurrency.js +22 -22
  32. package/dist/access-recall-response.d.ts +5 -5
  33. package/dist/access-recall-response.js +22 -22
  34. package/dist/access-recall-surface.d.ts +5 -5
  35. package/dist/access-recall-surface.js +22 -22
  36. package/dist/{access-service-Cbk3bNbD.d.ts → access-service-CgCjvbQu.d.ts} +3 -3
  37. package/dist/access-service-helpers.d.ts +5 -5
  38. package/dist/access-service.d.ts +5 -5
  39. package/dist/access-service.js +22 -22
  40. package/dist/access-surface-catalog.d.ts +5 -5
  41. package/dist/access-wearables-meetings-surface.d.ts +2 -2
  42. package/dist/active-recall.js +4 -4
  43. package/dist/{auto-sync-QFQGOEO2.js → auto-sync-JXEW7444.js} +6 -6
  44. package/dist/bootstrap.d.ts +4 -4
  45. package/dist/briefing.d.ts +1 -1
  46. package/dist/briefing.js +12 -12
  47. package/dist/buffer.d.ts +1 -1
  48. package/dist/causal-consolidation.js +13 -13
  49. package/dist/{chunk-MLXZD4WM.js → chunk-2GFK22OZ.js} +2 -2
  50. package/dist/{chunk-D5YOZ66N.js → chunk-3DWTDC54.js} +20 -20
  51. package/dist/{chunk-RANKJI5T.js → chunk-3JLPGJ43.js} +2 -2
  52. package/dist/chunk-5FVVY2EB.js +27 -0
  53. package/dist/chunk-5FVVY2EB.js.map +1 -0
  54. package/dist/{chunk-GXSOUIA4.js → chunk-5WQMORU5.js} +4 -4
  55. package/dist/{chunk-J272WKX2.js → chunk-6HPHEFXT.js} +2 -2
  56. package/dist/{chunk-B6LZ4IBH.js → chunk-6LAPLZOS.js} +2 -2
  57. package/dist/{chunk-WD5B5AIE.js → chunk-6R4G7N4S.js} +118 -173
  58. package/dist/chunk-6R4G7N4S.js.map +1 -0
  59. package/dist/{chunk-VXCNQYTC.js → chunk-APPFNGX6.js} +2 -2
  60. package/dist/{chunk-RMHMUUBW.js → chunk-AY43LBE4.js} +104 -48
  61. package/dist/{chunk-RMHMUUBW.js.map → chunk-AY43LBE4.js.map} +1 -1
  62. package/dist/{chunk-GXFSQ6SD.js → chunk-C4ZNGVK3.js} +2 -2
  63. package/dist/{chunk-JSEJH2YQ.js → chunk-CGVHPCP2.js} +2 -2
  64. package/dist/{chunk-BQIFZ2MP.js → chunk-CX5SW2EW.js} +41 -24
  65. package/dist/chunk-CX5SW2EW.js.map +1 -0
  66. package/dist/{chunk-TEMSWHQD.js → chunk-DZD576ZU.js} +5 -5
  67. package/dist/{chunk-AMTEYNYK.js → chunk-EVWWT3KE.js} +4 -4
  68. package/dist/{chunk-XAPMEU3K.js → chunk-FHFERRYE.js} +2 -2
  69. package/dist/{chunk-P2KBDJJ6.js → chunk-G2LUMAUF.js} +4 -3
  70. package/dist/{chunk-P2KBDJJ6.js.map → chunk-G2LUMAUF.js.map} +1 -1
  71. package/dist/{chunk-AXIDQG5A.js → chunk-G4T7L557.js} +5 -5
  72. package/dist/{chunk-7M6NYQWB.js → chunk-G7Z6EENO.js} +4 -4
  73. package/dist/{chunk-YXKVLYXU.js → chunk-HWRD23DW.js} +2 -2
  74. package/dist/{chunk-SOEN6KCF.js → chunk-IBKR2TFR.js} +2 -2
  75. package/dist/{chunk-R3DJVOSM.js → chunk-JDSVLVCG.js} +8 -1
  76. package/dist/chunk-JDSVLVCG.js.map +1 -0
  77. package/dist/{chunk-F4EU6VUC.js → chunk-JDZPNCMA.js} +2 -2
  78. package/dist/{chunk-DLG5V6ND.js → chunk-K4QS7LXU.js} +4 -7
  79. package/dist/chunk-K4QS7LXU.js.map +1 -0
  80. package/dist/{chunk-BAKXNQ3C.js → chunk-KRTY3ENI.js} +2 -2
  81. package/dist/{chunk-NK5RGJ65.js → chunk-L4DLLKPN.js} +2 -2
  82. package/dist/{chunk-VFSAWRMZ.js → chunk-LJS7KUPV.js} +2 -2
  83. package/dist/{chunk-JJRVPWFY.js → chunk-MLPTFODV.js} +166 -37
  84. package/dist/chunk-MLPTFODV.js.map +1 -0
  85. package/dist/{chunk-NOEMGE56.js → chunk-NH5IR2WM.js} +2 -2
  86. package/dist/{chunk-5V6IXHPI.js → chunk-NSVDUN76.js} +2 -2
  87. package/dist/{chunk-IARXXZU4.js → chunk-P7XI2AQ3.js} +2 -2
  88. package/dist/{chunk-W7Y5JDVB.js → chunk-PDDTI7IC.js} +4 -4
  89. package/dist/{chunk-QINJITDS.js → chunk-PX2LSHYM.js} +2 -2
  90. package/dist/{chunk-O5FFBO2M.js → chunk-QAVH6X2A.js} +2 -2
  91. package/dist/{chunk-HDIUYMSB.js → chunk-QWGE2PUH.js} +6 -6
  92. package/dist/{chunk-X57M2Q4I.js → chunk-RDJRFDJY.js} +3 -3
  93. package/dist/{chunk-RYLEDKQ2.js → chunk-RUMNY5DT.js} +3 -3
  94. package/dist/{chunk-BKIFTXHR.js → chunk-RZ4XGKOJ.js} +2 -2
  95. package/dist/{chunk-66SE3BNH.js → chunk-SUPEYLH2.js} +2 -2
  96. package/dist/{chunk-BF6SXNQJ.js → chunk-T2JHZWH6.js} +20 -20
  97. package/dist/{chunk-VHFXP27N.js → chunk-THPPCISA.js} +60 -23
  98. package/dist/chunk-THPPCISA.js.map +1 -0
  99. package/dist/{chunk-QPOHMO6M.js → chunk-UES4BHA2.js} +2 -2
  100. package/dist/{chunk-X7XEDOSL.js → chunk-VLL43QEQ.js} +8 -8
  101. package/dist/{chunk-QBSFOKY6.js → chunk-VOELBUS4.js} +4 -4
  102. package/dist/{chunk-2LY6GIIE.js → chunk-WDBX6VER.js} +2 -2
  103. package/dist/{chunk-BMEYMKWX.js → chunk-WM65LU67.js} +2 -2
  104. package/dist/{chunk-WLRD2TXF.js → chunk-WOPA3SGI.js} +4 -4
  105. package/dist/{chunk-5UZ6UCOZ.js → chunk-XUAMCLY4.js} +3 -3
  106. package/dist/{chunk-7HXZJAID.js → chunk-YGLY6QFV.js} +3 -3
  107. package/dist/{chunk-2OIQDTDC.js → chunk-ZPJ4QSGP.js} +2 -2
  108. package/dist/{chunk-3OY7KXHM.js → chunk-ZYLC7NFO.js} +3 -3
  109. package/dist/{cli-DMAFI0qt.d.ts → cli-D-HiEYhl.d.ts} +3 -3
  110. package/dist/cli.d.ts +6 -6
  111. package/dist/cli.js +41 -41
  112. package/dist/compounding/engine.d.ts +1 -1
  113. package/dist/compounding/engine.js +13 -13
  114. package/dist/config.js +4 -4
  115. package/dist/connectors/codex-materialize-runner.js +12 -12
  116. package/dist/connectors/index.js +12 -12
  117. package/dist/consolidation-provenance-check.d.ts +1 -1
  118. package/dist/consolidation-undo.d.ts +1 -1
  119. package/dist/content-hash.d.ts +12 -2
  120. package/dist/content-hash.js +9 -3
  121. package/dist/contradiction/index.d.ts +1 -1
  122. package/dist/contradiction/index.js +3 -3
  123. package/dist/convergence-refresh.d.ts +1 -1
  124. package/dist/convergence-refresh.js +14 -14
  125. package/dist/corpus-watermark.js +14 -14
  126. package/dist/entity-retrieval.d.ts +1 -1
  127. package/dist/entity-retrieval.js +12 -12
  128. package/dist/explicit-capture.d.ts +4 -4
  129. package/dist/explicit-capture.js +8 -8
  130. package/dist/external-wiki-access.d.ts +5 -5
  131. package/dist/external-wiki-access.js +23 -23
  132. package/dist/external-wiki-mcp-tools.d.ts +5 -5
  133. package/dist/extraction-normalization.js +2 -2
  134. package/dist/extraction-source-grounding.js +3 -3
  135. package/dist/extraction.js +16 -16
  136. package/dist/{forget-HDS4N6CG.js → forget-EHGGJZLX.js} +3 -2
  137. package/dist/{forget-HDS4N6CG.js.map → forget-EHGGJZLX.js.map} +1 -1
  138. package/dist/harmonic-construction.js +2 -2
  139. package/dist/harmonic-retrieval.js +4 -4
  140. package/dist/index.d.ts +12 -12
  141. package/dist/index.js +66 -66
  142. package/dist/maintenance/memory-governance.js +12 -12
  143. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +1 -1
  144. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +12 -12
  145. package/dist/maintenance/rebuild-memory-projection.d.ts +1 -1
  146. package/dist/maintenance/rebuild-memory-projection.js +13 -13
  147. package/dist/{maintenance-kBII2qUI.d.ts → maintenance-CN_Ct-Hr.d.ts} +1 -1
  148. package/dist/mcp-memory-inspector-app.d.ts +5 -5
  149. package/dist/memory-worth-outcomes.d.ts +1 -1
  150. package/dist/namespaces/migrate.d.ts +1 -1
  151. package/dist/namespaces/migrate.js +13 -13
  152. package/dist/namespaces/storage.d.ts +1 -1
  153. package/dist/namespaces/storage.js +12 -12
  154. package/dist/operator-doctor-corpus.js +15 -15
  155. package/dist/operator-toolkit.d.ts +1 -1
  156. package/dist/operator-toolkit.js +20 -20
  157. package/dist/orchestration/compression-guideline-coordinator.d.ts +1 -1
  158. package/dist/orchestration/maintenance.d.ts +2 -2
  159. package/dist/orchestration/maintenance.js +17 -17
  160. package/dist/{orchestrator-DHy5LtTy.d.ts → orchestrator-B3Xe8qu0.d.ts} +3 -3
  161. package/dist/orchestrator.d.ts +4 -4
  162. package/dist/orchestrator.js +54 -54
  163. package/dist/provenance.js +2 -2
  164. package/dist/reconcile/manifest.d.ts +3 -1
  165. package/dist/reconcile/manifest.js +7 -3
  166. package/dist/{resolution-MDPNOEG6.js → resolution-MMOD5WC4.js} +4 -4
  167. package/dist/resume-bundles.js +5 -5
  168. package/dist/salvage-envelope.js +3 -3
  169. package/dist/schemas.d.ts +38 -38
  170. package/dist/semantic-consolidation.js +13 -13
  171. package/dist/semantic-rule-promotion.js +12 -12
  172. package/dist/semantic-rule-verifier.js +12 -12
  173. package/dist/{service-PT2_z7xm.d.ts → service-CQGEqL1g.d.ts} +1 -1
  174. package/dist/source-agent-qualifier.js +14 -14
  175. package/dist/{storage-BmVudhk4.d.ts → storage-DmkCjo0l.d.ts} +36 -32
  176. package/dist/storage.d.ts +1 -1
  177. package/dist/storage.js +14 -14
  178. package/dist/structured-attributes.d.ts +3 -1
  179. package/dist/structured-attributes.js +3 -1
  180. package/dist/tier-migration.d.ts +1 -1
  181. package/dist/transfer/types.d.ts +12 -12
  182. package/dist/verified-recall.js +12 -12
  183. package/dist/write-envelope.js +2 -2
  184. package/package.json +2 -2
  185. package/src/access-offline-manifest.ts +1 -0
  186. package/src/access-service-offline-file-content.test.ts +1 -0
  187. package/src/content-hash.ts +34 -1
  188. package/src/dedup/index.test.ts +56 -38
  189. package/src/dedup/index.ts +85 -38
  190. package/src/lifecycle/tombstones.test.ts +763 -16
  191. package/src/lifecycle/tombstones.ts +217 -50
  192. package/src/reconcile/manifest.test.ts +158 -1
  193. package/src/reconcile/manifest.ts +76 -22
  194. package/src/storage/content-hash-index.ts +56 -40
  195. package/src/storage/entity-ref-repair.ts +3 -3
  196. package/src/storage/memory-read-store.ts +9 -0
  197. package/src/storage/tombstone-blocked-capture-index.ts +4 -9
  198. package/src/storage-contract/content-hash.test.ts +13 -0
  199. package/src/storage-fact-hash-index-defer.test.ts +1 -1
  200. package/src/storage.ts +107 -93
  201. package/src/structured-attributes.ts +11 -0
  202. package/dist/chunk-BQIFZ2MP.js.map +0 -1
  203. package/dist/chunk-DLG5V6ND.js.map +0 -1
  204. package/dist/chunk-JJRVPWFY.js.map +0 -1
  205. package/dist/chunk-R3DJVOSM.js.map +0 -1
  206. package/dist/chunk-VHFXP27N.js.map +0 -1
  207. package/dist/chunk-W5H6ZRPT.js +0 -14
  208. package/dist/chunk-W5H6ZRPT.js.map +0 -1
  209. package/dist/chunk-WD5B5AIE.js.map +0 -1
  210. /package/dist/{auto-sync-QFQGOEO2.js.map → auto-sync-JXEW7444.js.map} +0 -0
  211. /package/dist/{chunk-MLXZD4WM.js.map → chunk-2GFK22OZ.js.map} +0 -0
  212. /package/dist/{chunk-D5YOZ66N.js.map → chunk-3DWTDC54.js.map} +0 -0
  213. /package/dist/{chunk-RANKJI5T.js.map → chunk-3JLPGJ43.js.map} +0 -0
  214. /package/dist/{chunk-GXSOUIA4.js.map → chunk-5WQMORU5.js.map} +0 -0
  215. /package/dist/{chunk-J272WKX2.js.map → chunk-6HPHEFXT.js.map} +0 -0
  216. /package/dist/{chunk-B6LZ4IBH.js.map → chunk-6LAPLZOS.js.map} +0 -0
  217. /package/dist/{chunk-VXCNQYTC.js.map → chunk-APPFNGX6.js.map} +0 -0
  218. /package/dist/{chunk-GXFSQ6SD.js.map → chunk-C4ZNGVK3.js.map} +0 -0
  219. /package/dist/{chunk-JSEJH2YQ.js.map → chunk-CGVHPCP2.js.map} +0 -0
  220. /package/dist/{chunk-TEMSWHQD.js.map → chunk-DZD576ZU.js.map} +0 -0
  221. /package/dist/{chunk-AMTEYNYK.js.map → chunk-EVWWT3KE.js.map} +0 -0
  222. /package/dist/{chunk-XAPMEU3K.js.map → chunk-FHFERRYE.js.map} +0 -0
  223. /package/dist/{chunk-AXIDQG5A.js.map → chunk-G4T7L557.js.map} +0 -0
  224. /package/dist/{chunk-7M6NYQWB.js.map → chunk-G7Z6EENO.js.map} +0 -0
  225. /package/dist/{chunk-YXKVLYXU.js.map → chunk-HWRD23DW.js.map} +0 -0
  226. /package/dist/{chunk-SOEN6KCF.js.map → chunk-IBKR2TFR.js.map} +0 -0
  227. /package/dist/{chunk-F4EU6VUC.js.map → chunk-JDZPNCMA.js.map} +0 -0
  228. /package/dist/{chunk-BAKXNQ3C.js.map → chunk-KRTY3ENI.js.map} +0 -0
  229. /package/dist/{chunk-NK5RGJ65.js.map → chunk-L4DLLKPN.js.map} +0 -0
  230. /package/dist/{chunk-VFSAWRMZ.js.map → chunk-LJS7KUPV.js.map} +0 -0
  231. /package/dist/{chunk-NOEMGE56.js.map → chunk-NH5IR2WM.js.map} +0 -0
  232. /package/dist/{chunk-5V6IXHPI.js.map → chunk-NSVDUN76.js.map} +0 -0
  233. /package/dist/{chunk-IARXXZU4.js.map → chunk-P7XI2AQ3.js.map} +0 -0
  234. /package/dist/{chunk-W7Y5JDVB.js.map → chunk-PDDTI7IC.js.map} +0 -0
  235. /package/dist/{chunk-QINJITDS.js.map → chunk-PX2LSHYM.js.map} +0 -0
  236. /package/dist/{chunk-O5FFBO2M.js.map → chunk-QAVH6X2A.js.map} +0 -0
  237. /package/dist/{chunk-HDIUYMSB.js.map → chunk-QWGE2PUH.js.map} +0 -0
  238. /package/dist/{chunk-X57M2Q4I.js.map → chunk-RDJRFDJY.js.map} +0 -0
  239. /package/dist/{chunk-RYLEDKQ2.js.map → chunk-RUMNY5DT.js.map} +0 -0
  240. /package/dist/{chunk-BKIFTXHR.js.map → chunk-RZ4XGKOJ.js.map} +0 -0
  241. /package/dist/{chunk-66SE3BNH.js.map → chunk-SUPEYLH2.js.map} +0 -0
  242. /package/dist/{chunk-BF6SXNQJ.js.map → chunk-T2JHZWH6.js.map} +0 -0
  243. /package/dist/{chunk-QPOHMO6M.js.map → chunk-UES4BHA2.js.map} +0 -0
  244. /package/dist/{chunk-X7XEDOSL.js.map → chunk-VLL43QEQ.js.map} +0 -0
  245. /package/dist/{chunk-QBSFOKY6.js.map → chunk-VOELBUS4.js.map} +0 -0
  246. /package/dist/{chunk-2LY6GIIE.js.map → chunk-WDBX6VER.js.map} +0 -0
  247. /package/dist/{chunk-BMEYMKWX.js.map → chunk-WM65LU67.js.map} +0 -0
  248. /package/dist/{chunk-WLRD2TXF.js.map → chunk-WOPA3SGI.js.map} +0 -0
  249. /package/dist/{chunk-5UZ6UCOZ.js.map → chunk-XUAMCLY4.js.map} +0 -0
  250. /package/dist/{chunk-7HXZJAID.js.map → chunk-YGLY6QFV.js.map} +0 -0
  251. /package/dist/{chunk-2OIQDTDC.js.map → chunk-ZPJ4QSGP.js.map} +0 -0
  252. /package/dist/{chunk-3OY7KXHM.js.map → chunk-ZYLC7NFO.js.map} +0 -0
  253. /package/dist/{resolution-MDPNOEG6.js.map → resolution-MMOD5WC4.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/storage/tombstone-blocked-capture-mutation.ts","../src/storage/tombstone-blocked-capture-sync.ts","../src/storage/tombstone-blocked-capture-index.ts"],"sourcesContent":["import { AsyncLocalStorage } from \"node:async_hooks\";\nimport { createHash } from \"node:crypto\";\nimport { mkdir } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { withHeldFileLock } from \"../utils/serialize-mutations.js\";\nimport type { MemoryFile, MemoryFrontmatter } from \"../types.js\";\nconst TOMBSTONE_CAPTURE_WRITE_LOCK_STALE_MS = 60_000;\nconst CAPTURE_WRITE_LOCK_MAX_ATTEMPTS = 3;\nconst CAPTURE_WRITE_LOCK_RETRY_BASE_MS = 25;\nconst CAPTURE_WRITE_LOCK_BUSY_MESSAGE = \"tombstone-blocked capture write lock remained busy\";\n\nexport function isTombstoneBlockedCaptureWriteLockBusy(error: unknown): boolean {\n return error instanceof Error && error.message === CAPTURE_WRITE_LOCK_BUSY_MESSAGE;\n}\n\nexport function normalizeExplicitCaptureContent(value: string): string {\n return value.toLowerCase().replace(/\\s+/g, \" \").trim();\n}\n\nexport function buildExplicitCaptureDedupKey(\n content: string,\n category: string,\n sourceConnector: string | undefined\n): string {\n const encode = (label: string, value: string): string => `${label} ${value.length} ${value}`;\n return [\n encode(\"category\", category),\n encode(\"connector\", sourceConnector?.trim() ?? \"\"),\n encode(\"content\", normalizeExplicitCaptureContent(content)),\n ].join(\" \");\n}\n\nexport function buildCapturePathLockIdentity(pathname: string): string {\n return `path ${pathname.length} ${pathname}`;\n}\n\nexport function captureIdentityHash(memory: MemoryFile): string {\n return createHash(\"sha256\")\n .update(\n buildExplicitCaptureDedupKey(memory.content, memory.frontmatter.category, memory.frontmatter.sourceConnector)\n )\n .digest(\"hex\");\n}\n\nexport type TombstoneBlockedCaptureWriteLockOptions = {\n readonly stateDir: string;\n readonly withHeldFileLock?: typeof withHeldFileLock;\n};\n\nexport class TombstoneBlockedCaptureWriteLock {\n private readonly context = new AsyncLocalStorage<ReadonlySet<string>>();\n\n constructor(private readonly options: TombstoneBlockedCaptureWriteLockOptions) {}\n\n private captureWriteLockPathForHash(identityHash: string): string {\n const filename =\n identityHash.length === 0 ? \"explicit-capture-write.lock\" : `explicit-capture-write-${identityHash}.lock`;\n return path.join(this.options.stateDir, \"tombstone-blocked-capture\", filename);\n }\n\n private async withSingleCaptureWriteLock<T>(lockPath: string, task: () => Promise<T>): Promise<T> {\n await mkdir(path.dirname(lockPath), { recursive: true });\n const retry = Symbol(\"retry\");\n const permanentFailure = Symbol(\"permanent-failure\");\n const runWithHeldFileLock = this.options.withHeldFileLock ?? withHeldFileLock;\n for (let attempt = 0; attempt < CAPTURE_WRITE_LOCK_MAX_ATTEMPTS; attempt += 1) {\n const result = await runWithHeldFileLock<T | typeof retry | typeof permanentFailure>(\n lockPath,\n {\n staleMs: TOMBSTONE_CAPTURE_WRITE_LOCK_STALE_MS,\n maxWaitMs: 1_000,\n pollMs: 25,\n },\n async (acquired, controller) => {\n if (acquired) return await task();\n return controller.failure === \"error\" ? permanentFailure : retry;\n }\n );\n if (result === permanentFailure) {\n throw new Error(\"tombstone-blocked capture write lock acquisition failed\");\n }\n if (result !== retry) return result;\n if (attempt === CAPTURE_WRITE_LOCK_MAX_ATTEMPTS - 1) break;\n const delayState = Promise.withResolvers<void>();\n setTimeout(delayState.resolve, CAPTURE_WRITE_LOCK_RETRY_BASE_MS * 2 ** attempt);\n await delayState.promise;\n }\n throw new Error(CAPTURE_WRITE_LOCK_BUSY_MESSAGE);\n }\n private async withPhysicalCaptureWriteLocks<T>(\n task: () => Promise<T>,\n identityHashes: readonly string[]\n ): Promise<T> {\n const lockPaths = [...new Set(identityHashes.map((hash) => this.captureWriteLockPathForHash(hash)))];\n const acquire = async (index: number): Promise<T> => {\n if (index === lockPaths.length) return await task();\n return await this.withSingleCaptureWriteLock(lockPaths[index], () => acquire(index + 1));\n };\n return await acquire(0);\n }\n\n async withCaptureWriteLock<T>(task: () => Promise<T>, identity?: string | readonly string[]): Promise<T> {\n const identities =\n Array.isArray(identity) && identity.length > 0 ? identity : [typeof identity === \"string\" ? identity : \"\"];\n return await this.withCaptureWriteLocks(task, identities, []);\n }\n\n async withCaptureWriteLockHashes<T>(task: () => Promise<T>, identityHashes: readonly string[]): Promise<T> {\n return await this.withCaptureWriteLocks(task, [], identityHashes);\n }\n\n async withCaptureWriteLockAndHashes<T>(\n task: () => Promise<T>,\n identity: string | readonly string[] | undefined,\n identityHashes: readonly string[]\n ): Promise<T> {\n const identities =\n Array.isArray(identity) && identity.length > 0 ? identity : [typeof identity === \"string\" ? identity : \"\"];\n return await this.withCaptureWriteLocks(task, identities, identityHashes);\n }\n\n private async withCaptureWriteLocks<T>(\n task: () => Promise<T>,\n identities: readonly string[],\n identityHashes: readonly string[]\n ): Promise<T> {\n const current = this.context.getStore();\n const hashToken = (key: string): string =>\n `\\u0000${key.length === 0 ? \"\" : createHash(\"sha256\").update(key).digest(\"hex\")}`;\n const identityHash = (key: string): string =>\n key.length === 0 ? \"\" : createHash(\"sha256\").update(key).digest(\"hex\");\n const identityKeys = [...new Set(identities)];\n const hashes = [...new Set(identityHashes)];\n const requested = [\n ...identityKeys\n .filter((key) => !current || (!current.has(key) && !current.has(hashToken(key))))\n .map((key) => ({ hash: identityHash(key), pathLock: key.startsWith(\"path \") })),\n ...hashes.filter((hash) => !current || !current.has(`\\u0000${hash}`)).map((hash) => ({ hash, pathLock: false })),\n ]\n .filter((entry, index, entries) => entries.findIndex((candidate) => candidate.hash === entry.hash) === index)\n .sort(\n (left, right) =>\n Number(left.pathLock) - Number(right.pathLock) ||\n this.captureWriteLockPathForHash(left.hash).localeCompare(this.captureWriteLockPathForHash(right.hash))\n );\n const physicalMissing = requested.map((entry) => entry.hash);\n if (current && requested.length > 0) {\n const held = [...current]\n .filter((token) => token.startsWith(\"\\u0000\"))\n .map((token) => {\n const hash = token.slice(1);\n const pathLock = [...current].some(\n (key) => !key.startsWith(\"\\u0000\") && key.startsWith(\"path \") && hashToken(key) === token\n );\n return { hash, pathLock };\n });\n const requestedFirst = requested[0];\n const heldLast = held\n .sort(\n (left, right) =>\n Number(left.pathLock) - Number(right.pathLock) ||\n this.captureWriteLockPathForHash(left.hash).localeCompare(this.captureWriteLockPathForHash(right.hash))\n )\n .at(-1);\n if (\n heldLast &&\n requestedFirst &&\n (Number(requestedFirst.pathLock) < Number(heldLast.pathLock) ||\n (requestedFirst.pathLock === heldLast.pathLock &&\n this.captureWriteLockPathForHash(requestedFirst.hash) < this.captureWriteLockPathForHash(heldLast.hash)))\n ) {\n throw new Error(CAPTURE_WRITE_LOCK_BUSY_MESSAGE);\n }\n }\n const next = new Set(current);\n for (const key of identityKeys) {\n next.add(key);\n next.add(hashToken(key));\n }\n for (const hash of hashes) next.add(`\\u0000${hash}`);\n const run = () => this.context.run(next, task);\n if (physicalMissing.length === 0) return await run();\n return await this.withPhysicalCaptureWriteLocks(run, physicalMissing);\n }\n}\n\nexport type TombstoneBlockedMutationHost = {\n readCurrent: () => Promise<MemoryFile | null>;\n isBlocked: (memory: MemoryFile | null) => boolean;\n isQueuedReview: (memory: MemoryFile | null) => boolean;\n memoryIdentity: (memory: MemoryFile) => string;\n prepareWrite: () => Promise<string>;\n commitWrite: (marker: string) => Promise<void>;\n discardWrite: (marker: string) => Promise<void>;\n markUntrusted: () => void;\n writeStorageSecureFile: (pathname: string, fileContent: string) => Promise<void>;\n withCaptureWriteLock: (task: () => Promise<void>, identity: string | readonly string[]) => Promise<void>;\n logWarning: (message: string) => void;\n};\n\nexport type TombstoneBlockedMutation = {\n blocked: boolean;\n pathname: string;\n fileContent: string;\n identity: string | readonly string[];\n updateIndex: (rebuildMarker?: string, current?: MemoryFile | null) => Promise<void>;\n beforeIndexUpdate?: () => Promise<void>;\n coordinate?: boolean;\n};\n\nexport async function runTombstoneBlockedMutation(\n host: TombstoneBlockedMutationHost,\n mutation: TombstoneBlockedMutation\n): Promise<void> {\n let lockIdentity: string | readonly string[] = mutation.identity;\n for (;;) {\n let retryIdentity: string | undefined;\n const mutate = async (): Promise<void> => {\n const current = await host.readCurrent();\n const currentBlocked = host.isBlocked(current);\n const currentQueuedReview = host.isQueuedReview(current);\n if (current !== null && (mutation.coordinate === true || currentBlocked || currentQueuedReview)) {\n const currentIdentity = host.memoryIdentity(current);\n const heldIdentities = Array.isArray(lockIdentity) ? lockIdentity : [lockIdentity];\n if (!heldIdentities.includes(currentIdentity)) {\n retryIdentity = currentIdentity;\n return;\n }\n }\n const rebuildMarker = mutation.blocked || currentBlocked ? await host.prepareWrite() : undefined;\n try {\n await host.writeStorageSecureFile(mutation.pathname, mutation.fileContent);\n } catch (err) {\n if (rebuildMarker) {\n try {\n await host.discardWrite(rebuildMarker);\n } catch (cleanupError) {\n host.markUntrusted();\n host.logWarning(`storage.tombstoneBlocked failed to clear write marker: ${cleanupError}`);\n }\n }\n throw err;\n }\n if (rebuildMarker) {\n try {\n await host.commitWrite(rebuildMarker);\n } catch (err) {\n host.markUntrusted();\n host.logWarning(`storage.tombstoneBlocked committed write marker failed: ${err}`);\n }\n }\n if (rebuildMarker) await mutation.beforeIndexUpdate?.();\n await mutation.updateIndex(rebuildMarker, currentBlocked && current !== null ? current : undefined);\n };\n await host.withCaptureWriteLock(mutate, lockIdentity);\n if (retryIdentity === undefined) return;\n const identities = Array.isArray(lockIdentity) ? [...lockIdentity, retryIdentity] : [lockIdentity, retryIdentity];\n lockIdentity = [...new Set(identities)];\n }\n}\n\nexport function tombstoneBlocked(frontmatter: MemoryFrontmatter): boolean {\n return frontmatter.status === \"pending_review\" && Boolean(frontmatter.blockedBy);\n}\n\nexport function isQueuedReviewFrontmatter(frontmatter: MemoryFrontmatter): boolean {\n return frontmatter.status === \"pending_review\" && (frontmatter.tags ?? []).includes(\"queued-review\");\n}\n\nexport function isQueuedReviewMemory(memory: MemoryFile | null): memory is MemoryFile {\n return memory !== null && isQueuedReviewFrontmatter(memory.frontmatter);\n}\n","import { createHash, randomUUID, type Hash } from \"node:crypto\";\nimport { unlink } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { isDeepStrictEqual } from \"node:util\";\nimport { log } from \"../logger.js\";\nimport type { MemoryFile, MemoryFrontmatter } from \"../types.js\";\nimport { markProjectedMemoryPathInvalid } from \"../memory-projection-store.js\";\nimport { RECALL_FALLBACK_DIRS } from \"../utils/category-dir.js\";\nimport { isErrnoCode } from \"../utils/errno.js\";\nimport { pathMayCarryEntityRefs, requestEntityCanonicalIdReconcile } from \"./entity-canonical-id-references.js\";\nimport { withRawEntityPageMutation } from \"./entity-canonical-id-lock.js\";\nimport { readMaybeEncryptedFileFromChunks, writeMaybeEncryptedFileFromChunks } from \"../secure-store/secure-fs.js\";\nimport * as archiveMutation from \"../archive-mutation-version.js\";\nimport {\n buildExplicitCaptureDedupKey,\n buildCapturePathLockIdentity,\n captureIdentityHash,\n tombstoneBlocked,\n isQueuedReviewMemory,\n runTombstoneBlockedMutation,\n type TombstoneBlockedMutationHost,\n} from \"./tombstone-blocked-capture-mutation.js\";\nimport { TombstoneBlockedCaptureIndex } from \"./tombstone-blocked-capture-index.js\";\nimport type { TombstoneBlockedCaptureIndexOptions } from \"./tombstone-blocked-capture-index.js\";\n\nconst OFFLINE_SYNC_BUFFER_LIMIT_BYTES = 1_048_576;\nconst OFFLINE_SYNC_STAGE_READ_BYTES = 64 * 1024;\nconst OFFLINE_SYNC_FRONTMATTER_DELIMITER = Buffer.from(\"\\n---\\n\", \"utf8\");\n\nconst CASED_CHARACTER = /\\p{Cased}/u;\nconst CASE_IGNORABLE_CHARACTER = /\\p{Case_Ignorable}/u;\n\ntype StreamedOfflineSyncIdentity = {\n identityHash: string;\n};\n\ntype PreparedOfflineSyncChunks = {\n after: MemoryFile | null;\n chunks: AsyncIterable<Buffer>;\n stagePath?: string;\n streamedIdentity?: StreamedOfflineSyncIdentity;\n};\n\ntype ExplicitContentNormalizerSink = {\n write: (chunk: string) => void;\n beginConditionalSigma: () => void;\n resolveConditionalSigma: (useFinalSigma: boolean) => void;\n};\n\nfunction createExplicitContentNormalizer(sink: ExplicitContentNormalizerSink): {\n push: (text: string) => void;\n finish: () => void;\n} {\n let started = false;\n let pendingSpace = false;\n let output = \"\";\n let precededByCased = false;\n let pendingSigma = false;\n const flush = () => {\n if (output.length > 0) {\n sink.write(output);\n output = \"\";\n }\n };\n const emit = (text: string) => {\n for (const character of text) {\n if (/\\s/u.test(character)) {\n if (started) pendingSpace = true;\n continue;\n }\n if (pendingSpace) {\n output += \" \";\n pendingSpace = false;\n }\n output += character;\n started = true;\n if (output.length >= OFFLINE_SYNC_STAGE_READ_BYTES) flush();\n }\n };\n const resolveSigma = (followedByCased: boolean) => {\n flush();\n sink.resolveConditionalSigma(!followedByCased);\n pendingSigma = false;\n };\n const push = (text: string) => {\n for (const character of text) {\n const caseIgnorable = CASE_IGNORABLE_CHARACTER.test(character);\n const cased = CASED_CHARACTER.test(character);\n if (pendingSigma) {\n if (caseIgnorable) {\n emit(character.toLowerCase());\n continue;\n }\n resolveSigma(cased);\n }\n if (character === \"Σ\" && precededByCased) {\n flush();\n sink.beginConditionalSigma();\n pendingSigma = true;\n precededByCased = true;\n continue;\n }\n emit(character.toLowerCase());\n if (!caseIgnorable) precededByCased = cased;\n }\n };\n return {\n push,\n finish() {\n if (pendingSigma) resolveSigma(false);\n flush();\n },\n };\n}\n\nasync function forEachStagedTextChunk(\n stagePath: string,\n offset: number,\n onText: (text: string) => void,\n key: Buffer | null,\n memoryDir: string\n): Promise<void> {\n const decoder = new TextDecoder(\"utf-8\");\n let remaining = offset;\n for await (const chunk of readMaybeEncryptedFileFromChunks(stagePath, key, memoryDir)) {\n const textChunk = remaining >= chunk.length ? null : chunk.subarray(remaining);\n remaining = Math.max(0, remaining - chunk.length);\n if (textChunk === null || textChunk.length === 0) continue;\n const text = decoder.decode(textChunk, { stream: true });\n if (text.length > 0) onText(text);\n }\n const finalText = decoder.decode();\n if (finalText.length > 0) onText(finalText);\n}\n\nasync function findStagedBodyOffset(stagePath: string, key: Buffer | null, memoryDir: string): Promise<number | null> {\n let scannedBytes = 0;\n let tail = Buffer.alloc(0);\n for await (const chunk of readMaybeEncryptedFileFromChunks(stagePath, key, memoryDir)) {\n const window = tail.length > 0 ? Buffer.concat([tail, chunk]) : chunk;\n const windowStart = scannedBytes - tail.length;\n for (let searchFrom = 0; ; ) {\n const delimiterStart = window.indexOf(OFFLINE_SYNC_FRONTMATTER_DELIMITER, searchFrom);\n if (delimiterStart < 0) break;\n if (windowStart + delimiterStart >= 4) {\n return windowStart + delimiterStart + OFFLINE_SYNC_FRONTMATTER_DELIMITER.length;\n }\n searchFrom = delimiterStart + 1;\n }\n scannedBytes += chunk.length;\n const tailLength = Math.min(OFFLINE_SYNC_FRONTMATTER_DELIMITER.length - 1, window.length);\n tail = Buffer.from(window.subarray(window.length - tailLength));\n }\n return null;\n}\n\nasync function readStagedPrefix(\n stagePath: string,\n byteLimit: number,\n key: Buffer | null,\n memoryDir: string\n): Promise<Buffer> {\n const chunks: Buffer[] = [];\n let bytesRead = 0;\n for await (const chunk of readMaybeEncryptedFileFromChunks(stagePath, key, memoryDir)) {\n const length = Math.min(chunk.length, byteLimit - bytesRead);\n if (length > 0) chunks.push(chunk.subarray(0, length));\n bytesRead += length;\n if (bytesRead >= byteLimit) break;\n }\n return Buffer.concat(chunks, bytesRead);\n}\n\nexport type OfflineSyncMemoryParser = (filePath: string, content: Buffer) => MemoryFile | null;\n\nexport function parseTombstoneBlockedOfflineSyncMemory(\n filePath: string,\n content: Buffer,\n memoryDir: string,\n parseFrontmatter: (raw: string) => { frontmatter: MemoryFrontmatter; content: string } | null,\n normalizeFrontmatterForPath: (frontmatter: MemoryFrontmatter, pathRel: string, content?: string) => MemoryFrontmatter,\n toMemoryPathRel: (baseDir: string, filePath: string) => string\n): MemoryFile | null {\n const parsed = parseFrontmatter(content.toString(\"utf8\"));\n if (!parsed) return null;\n return {\n path: filePath,\n frontmatter: normalizeFrontmatterForPath(parsed.frontmatter, toMemoryPathRel(memoryDir, filePath), parsed.content),\n content: parsed.content,\n };\n}\n\nexport abstract class TombstoneBlockedCaptureIndexHost {\n private tombstoneBlockedCaptureIndex: TombstoneBlockedCaptureIndex | null = null;\n protected abstract tombstoneBlockedCaptureIndexOptions(): TombstoneBlockedCaptureIndexOptions;\n protected abstract writeStorageSecureFile(\n filePath: string,\n content: string | Buffer,\n forceEncrypt?: boolean\n ): Promise<void>;\n protected abstract assertManagedStoragePath(filePath: string, method: string): string;\n protected abstract notifyCatalogWriteForPath(filePath: string): void;\n protected abstract readMemoryByPath(filePath: string): Promise<MemoryFile | null>;\n protected abstract invalidateAllMemoriesCache(): void;\n protected abstract invalidateKnowledgeIndexCache(): void;\n protected abstract invalidateColdMemoriesCache(): void;\n protected abstract bumpArtifactWriteVersion(): number;\n protected abstract bumpMemoryStatusVersion(): void;\n protected abstract bumpMemoryCorpusVersion(): void;\n protected abstract markFactHashIndexNotAuthoritative(): void;\n protected abstract deleteManagedStorageFile(filePath: string, deletionMtimeMs?: number | null): Promise<boolean>;\n protected abstract writeManagedStorageFile(filePath: string, write: () => Promise<void>): Promise<void>;\n\n private async writeStorageSecureFileChunks(filePath: string, chunks: AsyncIterable<Buffer>): Promise<void> {\n const options = this.tombstoneBlockedCaptureIndexOptions();\n await writeMaybeEncryptedFileFromChunks(\n filePath,\n chunks,\n options.secureStoreWriteKeyProvider(),\n {},\n options.memoryDir\n );\n this.notifyCatalogWriteForPath(filePath);\n }\n\n protected getTombstoneBlockedCaptureIndex(): TombstoneBlockedCaptureIndex {\n if (this.tombstoneBlockedCaptureIndex === null) {\n this.tombstoneBlockedCaptureIndex = new TombstoneBlockedCaptureIndex(this.tombstoneBlockedCaptureIndexOptions());\n }\n return this.tombstoneBlockedCaptureIndex;\n }\n async withTombstoneBlockedCaptureWriteLock<T>(\n task: () => Promise<T>,\n identity?: string | readonly string[]\n ): Promise<T> {\n return await this.getTombstoneBlockedCaptureIndex().withCaptureWriteLock(task, identity);\n }\n\n protected async withTombstoneBlockedCaptureWriteLockAndHashes<T>(\n task: () => Promise<T>,\n identity: string | readonly string[] | undefined,\n identityHashes: readonly string[]\n ): Promise<T> {\n return await this.getTombstoneBlockedCaptureIndex().withCaptureWriteLockAndHashes(task, identity, identityHashes);\n }\n\n private async writeTombstoneBlockedMutation(\n blocked: boolean,\n pathname: string,\n fileContent: string,\n identity: string | readonly string[],\n updateIndex: (rebuildMarker?: string, current?: MemoryFile | null) => Promise<void>,\n beforeIndexUpdate?: () => Promise<void>,\n coordinate = false\n ): Promise<void> {\n const host: TombstoneBlockedMutationHost = {\n readCurrent: () => this.readMemoryByPath(pathname),\n isBlocked: (memory) => this.isTombstoneBlockedMemory(memory),\n isQueuedReview: (memory) => isQueuedReviewMemory(memory),\n memoryIdentity: (memory) => this.offlineSyncMemoryIdentity(memory),\n prepareWrite: () => this.getTombstoneBlockedCaptureIndex().prepareWrite(),\n commitWrite: (marker) => this.getTombstoneBlockedCaptureIndex().commitWrite(marker),\n discardWrite: (marker) => this.getTombstoneBlockedCaptureIndex().discardWrite(marker),\n markUntrusted: () => this.getTombstoneBlockedCaptureIndex().markUntrusted(),\n writeStorageSecureFile: (target, content) => this.writeStorageSecureFile(target, content),\n withCaptureWriteLock: (task, lockIdentity) => this.withTombstoneBlockedCaptureWriteLock(task, lockIdentity),\n logWarning: (message) => log.warn(message),\n };\n await runTombstoneBlockedMutation(host, {\n blocked,\n pathname,\n fileContent,\n identity,\n updateIndex,\n beforeIndexUpdate,\n coordinate,\n });\n }\n\n protected async writeTombstoneBlockedMemory(\n pathname: string,\n fileContent: string,\n frontmatter: MemoryFrontmatter,\n content: string,\n beforeIndexUpdate?: () => Promise<void>\n ): Promise<void> {\n await this.writeTombstoneBlockedMutation(\n tombstoneBlocked(frontmatter),\n pathname,\n fileContent,\n [\n buildCapturePathLockIdentity(pathname),\n buildExplicitCaptureDedupKey(content, frontmatter.category, frontmatter.sourceConnector),\n ],\n (rebuildMarker) =>\n this.getTombstoneBlockedCaptureIndex().addWrittenMemory(pathname, frontmatter, content, rebuildMarker),\n beforeIndexUpdate\n );\n }\n\n protected async withTombstoneBlockedMemoryPathLock<T>(\n pathname: string,\n task: (current: MemoryFile | null) => Promise<T>,\n additionalPathnames: readonly string[] = []\n ): Promise<T> {\n let lockIdentities = [pathname, ...additionalPathnames].map(buildCapturePathLockIdentity);\n for (;;) {\n let retryIdentity: string | undefined;\n let result: T | undefined;\n await this.withTombstoneBlockedCaptureWriteLock(async () => {\n const current = await this.readMemoryByPath(pathname);\n if (current !== null) {\n const currentIdentity = this.offlineSyncMemoryIdentity(current);\n if (!lockIdentities.includes(currentIdentity)) {\n retryIdentity = currentIdentity;\n return;\n }\n }\n result = await task(current);\n }, lockIdentities);\n if (retryIdentity !== undefined) {\n lockIdentities = [...new Set([...lockIdentities, retryIdentity])];\n continue;\n }\n return result!;\n }\n }\n\n protected async writeTombstoneBlockedChunk(\n pathname: string,\n fileContent: string,\n frontmatter: MemoryFrontmatter,\n content: string,\n findDuplicate: () => Promise<MemoryFile | null>,\n afterWrite: (current: MemoryFile | null) => Promise<void>\n ): Promise<string> {\n const incomingIdentity = buildExplicitCaptureDedupKey(content, frontmatter.category, frontmatter.sourceConnector);\n let lockIdentities = [buildCapturePathLockIdentity(pathname), incomingIdentity];\n for (;;) {\n let retryIdentity: string | undefined;\n let result = frontmatter.id;\n await this.withTombstoneBlockedCaptureWriteLock(async () => {\n const current = await this.readMemoryByPath(pathname);\n if (current !== null) {\n const currentIdentity = this.offlineSyncMemoryIdentity(current);\n if (!lockIdentities.includes(currentIdentity)) {\n retryIdentity = currentIdentity;\n return;\n }\n }\n if (tombstoneBlocked(frontmatter)) {\n const duplicate = await findDuplicate();\n if (duplicate) {\n result = duplicate.frontmatter.id;\n return;\n }\n }\n await this.writeTombstoneBlockedMemory(pathname, fileContent, frontmatter, content);\n await afterWrite(current);\n }, lockIdentities);\n if (retryIdentity === undefined) return result;\n lockIdentities = [...new Set([...lockIdentities, retryIdentity])];\n }\n }\n\n protected async writeTombstoneBlockedUpdate(\n before: MemoryFile,\n fileContent: string,\n frontmatter: MemoryFrontmatter,\n content: string,\n beforeIndexUpdate?: () => Promise<void>\n ): Promise<void> {\n await this.writeTombstoneBlockedMutation(\n tombstoneBlocked(before.frontmatter) || tombstoneBlocked(frontmatter),\n before.path,\n fileContent,\n [\n buildCapturePathLockIdentity(before.path),\n this.offlineSyncMemoryIdentity(before),\n buildExplicitCaptureDedupKey(content, frontmatter.category, frontmatter.sourceConnector),\n ],\n (rebuildMarker, current) =>\n this.getTombstoneBlockedCaptureIndex().syncUpdatedMemory(\n current ?? before,\n frontmatter,\n content,\n rebuildMarker\n ),\n beforeIndexUpdate,\n true\n );\n }\n\n protected async writeTombstoneBlockedFrontmatter(\n before: MemoryFile,\n fileContent: string,\n frontmatter: MemoryFrontmatter,\n beforeIndexUpdate?: () => Promise<void>\n ): Promise<void> {\n await this.writeTombstoneBlockedMutation(\n tombstoneBlocked(before.frontmatter) || tombstoneBlocked(frontmatter),\n before.path,\n fileContent,\n [\n buildCapturePathLockIdentity(before.path),\n this.offlineSyncMemoryIdentity(before),\n buildExplicitCaptureDedupKey(before.content, frontmatter.category, frontmatter.sourceConnector),\n ],\n (rebuildMarker, current) =>\n this.getTombstoneBlockedCaptureIndex().syncUpdatedFrontmatter(current ?? before, frontmatter, rebuildMarker),\n beforeIndexUpdate,\n true\n );\n }\n\n private isTombstoneBlockedMemory(memory: MemoryFile | null): memory is MemoryFile {\n return memory !== null && memory.frontmatter.status === \"pending_review\" && Boolean(memory.frontmatter.blockedBy);\n }\n\n private offlineSyncMemoryIdentity(memory: MemoryFile): string {\n return buildExplicitCaptureDedupKey(\n memory.content,\n memory.frontmatter.category,\n memory.frontmatter.sourceConnector\n );\n }\n private async isDuplicateTombstoneBlockedOfflineSync(\n target: string,\n incoming: MemoryFile,\n streamedIdentity?: StreamedOfflineSyncIdentity\n ): Promise<boolean> {\n const before = await this.readMemoryByPath(target);\n const duplicate = streamedIdentity\n ? true\n : await this.getTombstoneBlockedCaptureIndex().has(\n incoming.content,\n incoming.frontmatter.category,\n incoming.frontmatter.sourceConnector\n );\n if (!duplicate) return false;\n const incomingIdentity = streamedIdentity?.identityHash ?? this.offlineSyncMemoryIdentity(incoming);\n const options = this.tombstoneBlockedCaptureIndexOptions();\n const existing = [...(await options.readAllMemories()), ...(await options.readAllColdMemories())];\n const exactMatch = existing.some(\n (memory) =>\n this.isTombstoneBlockedMemory(memory) &&\n (streamedIdentity ? captureIdentityHash(memory) : this.offlineSyncMemoryIdentity(memory)) === incomingIdentity\n );\n if (!exactMatch) return false;\n if (before === null) return true;\n if (!this.isTombstoneBlockedMemory(before)) return false;\n const beforeIdentity = streamedIdentity ? captureIdentityHash(before) : this.offlineSyncMemoryIdentity(before);\n if (beforeIdentity !== incomingIdentity) return false;\n return streamedIdentity\n ? isDeepStrictEqual(before.frontmatter, incoming.frontmatter)\n : before.content === incoming.content && isDeepStrictEqual(before.frontmatter, incoming.frontmatter);\n }\n\n private async invalidateAfterOfflineSyncMutation(\n filePath: string,\n ownedMarker?: string,\n archiveChanged = true\n ): Promise<void> {\n this.invalidateAllMemoriesCache();\n this.invalidateKnowledgeIndexCache();\n this.markFactHashIndexNotAuthoritative();\n if (filePath.includes(`${path.sep}cold${path.sep}`)) {\n this.invalidateColdMemoriesCache();\n }\n await this.rebuildTombstoneBlockedCaptureAfterInvalidationForPath(filePath, ownedMarker);\n if (filePath.includes(`${path.sep}artifacts${path.sep}`)) {\n this.bumpArtifactWriteVersion();\n }\n const memoryDir = this.tombstoneBlockedCaptureIndexOptions().memoryDir;\n archiveMutation.bumpArchiveMutationForPath(memoryDir, archiveChanged, filePath);\n this.bumpMemoryStatusVersion();\n }\n\n protected async runTombstoneBlockedArchive(\n memory: MemoryFile,\n task: (current: MemoryFile, markDurable: () => void) => Promise<string | null>\n ): Promise<string | null> {\n let archivedPath: string | null = null;\n const archived = await this.runTombstoneBlockedInvalidation(memory, async (current, rebuildMarker, markDurable) => {\n let archiveDurable = false;\n const markArchiveDurable = () => {\n archiveDurable = true;\n markDurable();\n };\n archivedPath = await task(current, markArchiveDurable);\n if (rebuildMarker !== undefined && (archivedPath !== null || archiveDurable)) {\n await this.rebuildTombstoneBlockedCaptureAfterInvalidation(rebuildMarker);\n } else if (rebuildMarker !== undefined) {\n const index = this.getTombstoneBlockedCaptureIndex();\n try {\n await index.discardWrite(rebuildMarker);\n } catch {\n index.markUntrusted();\n }\n }\n return archivedPath !== null;\n });\n return archived ? archivedPath : null;\n }\n\n protected async runTombstoneBlockedInvalidation(\n memory: MemoryFile,\n task: (current: MemoryFile, rebuildMarker: string | undefined, markDurable: () => void) => Promise<boolean>,\n propagateErrors = false,\n coordinate = false\n ): Promise<boolean> {\n let lockIdentities = [\n buildCapturePathLockIdentity(memory.path),\n ...(coordinate || this.isTombstoneBlockedMemory(memory) || isQueuedReviewMemory(memory)\n ? [this.offlineSyncMemoryIdentity(memory)]\n : []),\n ];\n for (;;) {\n const attempt = async () => {\n const options = this.tombstoneBlockedCaptureIndexOptions();\n const current =\n (await this.readMemoryByPath(memory.path)) ??\n (await options.readAllMemories()).find((candidate) => candidate.frontmatter.id === memory.frontmatter.id) ??\n (await options.readAllColdMemories()).find((candidate) => candidate.frontmatter.id === memory.frontmatter.id);\n if (!current) return { result: false };\n const blocked = this.isTombstoneBlockedMemory(current);\n const queuedReview = isQueuedReviewMemory(current);\n if (blocked || queuedReview) {\n const currentIdentity = this.offlineSyncMemoryIdentity(current);\n if (!lockIdentities.includes(currentIdentity)) return { retryIdentity: currentIdentity };\n }\n const blockedIndex = blocked ? this.getTombstoneBlockedCaptureIndex() : null;\n let rebuildMarker: string | undefined;\n let durable = false;\n try {\n if (blockedIndex) rebuildMarker = await blockedIndex.prepareWrite();\n const result = await task(current, rebuildMarker, () => {\n durable = true;\n });\n if (!result && rebuildMarker && !durable && blockedIndex) {\n try {\n await blockedIndex.discardWrite(rebuildMarker);\n } catch {\n blockedIndex.markUntrusted();\n }\n }\n return { result };\n } catch (error) {\n if (rebuildMarker && !durable && blockedIndex) {\n try {\n await blockedIndex.discardWrite(rebuildMarker);\n } catch {\n blockedIndex.markUntrusted();\n }\n }\n if (propagateErrors) throw error;\n return { result: false };\n }\n };\n const result = await this.withTombstoneBlockedCaptureWriteLock(attempt, lockIdentities);\n if (result.retryIdentity !== undefined) {\n lockIdentities = [...new Set([...lockIdentities, result.retryIdentity])];\n continue;\n }\n return result.result;\n }\n }\n async deleteMemoryForMaintenance(\n memory: MemoryFile,\n shouldDelete: (current: MemoryFile) => boolean = () => true\n ): Promise<MemoryFile | null> {\n let deleted: MemoryFile | null = null;\n const removed = await this.runTombstoneBlockedInvalidation(\n memory,\n async (current, rebuildMarker, markDurable) => {\n if (!shouldDelete(current)) return false;\n if (!(await this.deleteManagedStorageFile(current.path))) return false;\n markDurable();\n deleted = current;\n const memoryDir = this.tombstoneBlockedCaptureIndexOptions().memoryDir;\n archiveMutation.bumpArchiveMutationForPath(memoryDir, true, current.path);\n markProjectedMemoryPathInvalid(memoryDir, current.frontmatter.id);\n this.invalidateAllMemoriesCache();\n if (current.path.includes(`${path.sep}cold${path.sep}`)) {\n this.invalidateColdMemoriesCache();\n }\n await this.rebuildTombstoneBlockedCaptureAfterInvalidation(rebuildMarker);\n this.bumpMemoryCorpusVersion();\n this.bumpMemoryStatusVersion();\n return true;\n },\n true,\n true\n );\n return removed ? deleted : null;\n }\n\n protected async runTombstoneBlockedOfflineSyncMutation(\n target: string,\n after: MemoryFile | null,\n write: () => Promise<boolean | void>,\n coordinate = false,\n streamedIdentity?: StreamedOfflineSyncIdentity\n ): Promise<void> {\n for (;;) {\n const before = await this.readMemoryByPath(target);\n const targetIdentity = before === null ? undefined : this.offlineSyncMemoryIdentity(before);\n const afterIdentity = after === null || streamedIdentity ? undefined : this.offlineSyncMemoryIdentity(after);\n const mustCoordinate =\n coordinate || targetIdentity !== undefined || afterIdentity !== undefined || streamedIdentity !== undefined;\n const identities = [\n ...(mustCoordinate ? [buildCapturePathLockIdentity(target)] : []),\n ...(targetIdentity === undefined ? [] : [targetIdentity]),\n ...(afterIdentity === undefined ? [] : [afterIdentity]),\n ];\n let retryIdentity: string | undefined;\n const mutate = async (): Promise<void> => {\n const current = await this.readMemoryByPath(target);\n if (current !== null) {\n const currentIdentity = this.offlineSyncMemoryIdentity(current);\n if (currentIdentity !== targetIdentity) {\n retryIdentity = currentIdentity;\n return;\n }\n }\n if (\n this.isTombstoneBlockedMemory(after) &&\n (await this.isDuplicateTombstoneBlockedOfflineSync(target, after, streamedIdentity))\n ) {\n return;\n }\n const affectsBlockedIndex =\n coordinate || this.isTombstoneBlockedMemory(current) || this.isTombstoneBlockedMemory(after);\n const marker = affectsBlockedIndex ? await this.getTombstoneBlockedCaptureIndex().prepareWrite() : undefined;\n let durable = false;\n try {\n const changed = await write();\n durable = true;\n if (marker) {\n try {\n await this.getTombstoneBlockedCaptureIndex().commitWrite(marker);\n } catch (err) {\n this.getTombstoneBlockedCaptureIndex().markUntrusted();\n log.warn(`storage.offlineSyncFile committed write marker failed: ${err}`);\n }\n }\n await this.invalidateAfterOfflineSyncMutation(target, marker, changed !== false);\n } catch (err) {\n if (marker && !durable) {\n try {\n await this.getTombstoneBlockedCaptureIndex().discardWrite(marker);\n } catch (cleanupError) {\n this.getTombstoneBlockedCaptureIndex().markUntrusted();\n log.warn(`storage.offlineSyncFile failed to clear write marker: ${cleanupError}`);\n }\n }\n throw err;\n }\n };\n if (!mustCoordinate) {\n await mutate();\n } else if (streamedIdentity) {\n await this.withTombstoneBlockedCaptureWriteLockAndHashes(mutate, identities, [streamedIdentity.identityHash]);\n } else {\n await this.withTombstoneBlockedCaptureWriteLock(mutate, identities);\n }\n if (retryIdentity !== undefined) continue;\n return;\n }\n }\n\n protected async writeTombstoneBlockedOfflineSyncFile(target: string, content: Buffer): Promise<void> {\n const options = this.tombstoneBlockedCaptureIndexOptions();\n const after = options.parseMemory?.(target, content) ?? null;\n await withRawEntityPageMutation(path.dirname(options.stateDir), target, async () => {\n await this.runTombstoneBlockedOfflineSyncMutation(\n target,\n after,\n () => this.writeManagedStorageFile(target, () => this.writeStorageSecureFile(target, content))\n );\n });\n }\n\n private async prepareTombstoneBlockedOfflineSyncChunks(\n target: string,\n chunks: AsyncIterable<Buffer>\n ): Promise<PreparedOfflineSyncChunks> {\n const parseMemory = this.tombstoneBlockedCaptureIndexOptions().parseMemory;\n if (!parseMemory) return { after: null, chunks };\n\n const iterator = chunks[Symbol.asyncIterator]();\n const buffered: Buffer[] = [];\n let bufferedBytes = 0;\n let firstOverflow: Buffer | undefined;\n for (;;) {\n const next = await iterator.next();\n if (next.done) break;\n if (bufferedBytes + next.value.length > OFFLINE_SYNC_BUFFER_LIMIT_BYTES) {\n firstOverflow = next.value;\n break;\n }\n bufferedBytes += next.value.length;\n buffered.push(next.value);\n }\n const overflow = firstOverflow;\n if (overflow === undefined) {\n let after: MemoryFile | null = null;\n try {\n after = parseMemory(target, Buffer.concat(buffered));\n } catch {\n after = null;\n }\n const replay = (async function* (): AsyncIterable<Buffer> {\n for (const chunk of buffered) yield chunk;\n })();\n return { after, chunks: replay };\n }\n\n const options = this.tombstoneBlockedCaptureIndexOptions();\n const stagePath = path.join(\n options.stateDir,\n \"tombstone-blocked-capture\",\n \"offline-sync-staging\",\n `${randomUUID()}.stage`\n );\n const stagedChunks = (async function* (): AsyncIterable<Buffer> {\n for (const chunk of buffered) yield chunk;\n yield overflow;\n for (;;) {\n const next = await iterator.next();\n if (next.done) break;\n yield next.value;\n }\n })();\n try {\n await writeMaybeEncryptedFileFromChunks(\n stagePath,\n stagedChunks,\n options.secureStoreWriteKeyProvider(),\n { atomic: false },\n options.memoryDir\n );\n return await this.describeStagedOfflineSyncChunks(target, stagePath, parseMemory);\n } catch (err) {\n await unlink(stagePath).catch(() => {});\n throw err;\n }\n }\n\n private async describeStagedOfflineSyncChunks(\n target: string,\n stagePath: string,\n parseMemory: OfflineSyncMemoryParser\n ): Promise<PreparedOfflineSyncChunks> {\n const options = this.tombstoneBlockedCaptureIndexOptions();\n const key = options.secureStoreKeyProvider();\n const bodyOffset = await findStagedBodyOffset(stagePath, key, options.memoryDir);\n if (bodyOffset === null) {\n return { after: null, chunks: this.readStagedOfflineSyncChunks(stagePath), stagePath };\n }\n const prefix = await readStagedPrefix(stagePath, bodyOffset, key, options.memoryDir);\n let after: MemoryFile | null = null;\n try {\n after = parseMemory(target, prefix.subarray(0, bodyOffset));\n } catch {\n after = null;\n }\n if (after === null) {\n return { after: null, chunks: this.readStagedOfflineSyncChunks(stagePath), stagePath };\n }\n const streamedIdentity = await this.computeStagedOfflineSyncIdentity(stagePath, bodyOffset, after);\n return {\n after,\n chunks: this.readStagedOfflineSyncChunks(stagePath),\n stagePath,\n streamedIdentity,\n };\n }\n\n private async computeStagedOfflineSyncIdentity(\n stagePath: string,\n bodyOffset: number,\n after: MemoryFile\n ): Promise<StreamedOfflineSyncIdentity> {\n let normalizedLength = 0;\n const countNormalizer = createExplicitContentNormalizer({\n write: (chunk) => {\n normalizedLength += chunk.length;\n },\n beginConditionalSigma: () => {\n normalizedLength += 1;\n },\n resolveConditionalSigma: () => {},\n });\n const options = this.tombstoneBlockedCaptureIndexOptions();\n const key = options.secureStoreKeyProvider();\n await forEachStagedTextChunk(stagePath, bodyOffset, (text) => countNormalizer.push(text), key, options.memoryDir);\n countNormalizer.finish();\n\n const category = after.frontmatter.category;\n const connector = after.frontmatter.sourceConnector?.trim() ?? \"\";\n const encode = (label: string, value: string): string => `${label} ${value.length} ${value}`;\n const identityPrefix = [\n encode(\"category\", category),\n encode(\"connector\", connector),\n `content ${normalizedLength} `,\n ].join(\" \");\n let identityHash = createHash(\"sha256\");\n let normalSigmaIdentityHash: Hash | undefined;\n identityHash.update(identityPrefix);\n const identityNormalizer = createExplicitContentNormalizer({\n write: (chunk) => {\n identityHash.update(chunk);\n normalSigmaIdentityHash?.update(chunk);\n },\n beginConditionalSigma: () => {\n normalSigmaIdentityHash = identityHash.copy().update(\"σ\");\n identityHash.update(\"ς\");\n },\n resolveConditionalSigma: (useFinalSigma) => {\n if (!useFinalSigma) {\n if (normalSigmaIdentityHash === undefined) throw new Error(\"conditional sigma hash state is missing\");\n identityHash = normalSigmaIdentityHash;\n }\n normalSigmaIdentityHash = undefined;\n },\n });\n await forEachStagedTextChunk(\n stagePath,\n bodyOffset,\n (text) => identityNormalizer.push(text),\n key,\n options.memoryDir\n );\n identityNormalizer.finish();\n return {\n identityHash: identityHash.digest(\"hex\"),\n };\n }\n\n private async *readStagedOfflineSyncChunks(stagePath: string): AsyncIterable<Buffer> {\n const options = this.tombstoneBlockedCaptureIndexOptions();\n for await (const chunk of readMaybeEncryptedFileFromChunks(\n stagePath,\n options.secureStoreKeyProvider(),\n options.memoryDir\n )) {\n yield chunk;\n }\n }\n\n protected async writeTombstoneBlockedOfflineSyncFileChunks(\n target: string,\n chunks: AsyncIterable<Buffer>\n ): Promise<void> {\n const coordinate = this.getTombstoneBlockedCaptureIndex().shouldRebuildAfterInvalidationForPath(target);\n const prepared: PreparedOfflineSyncChunks = coordinate\n ? await this.prepareTombstoneBlockedOfflineSyncChunks(target, chunks)\n : { after: null, chunks };\n const streamedIdentity = prepared.streamedIdentity;\n const baseDir = path.dirname(this.tombstoneBlockedCaptureIndexOptions().stateDir);\n try {\n await withRawEntityPageMutation(baseDir, target, async () => {\n await this.runTombstoneBlockedOfflineSyncMutation(\n target,\n prepared.after,\n () => this.writeManagedStorageFile(target, () => this.writeStorageSecureFileChunks(target, prepared.chunks)),\n coordinate,\n streamedIdentity\n );\n });\n } finally {\n if (prepared.stagePath !== undefined) await unlink(prepared.stagePath).catch(() => {});\n }\n }\n\n async writeOfflineSyncFile(filePath: string, content: Buffer): Promise<void> {\n const target = this.assertManagedStoragePath(filePath, \"storage.writeOfflineSyncFile\");\n await this.writeTombstoneBlockedOfflineSyncFile(target, content);\n await this.requestSyncReconcileIfMigrationPath(target);\n }\n\n async writeOfflineSyncFileChunks(filePath: string, chunks: AsyncIterable<Buffer>): Promise<void> {\n const target = this.assertManagedStoragePath(filePath, \"storage.writeOfflineSyncFileChunks\");\n await this.writeTombstoneBlockedOfflineSyncFileChunks(target, chunks);\n await this.requestSyncReconcileIfMigrationPath(target);\n }\n\n /**\n * Opaque replicated bytes can restore legacy memory references or entity\n * relationship targets. Other sync traffic must not request reconciliation.\n */\n private async requestSyncReconcileIfMigrationPath(target: string): Promise<void> {\n const stateDir = this.tombstoneBlockedCaptureIndexOptions().stateDir;\n if (!pathMayCarryEntityRefs(path.dirname(stateDir), target)) return;\n await requestEntityCanonicalIdReconcile(stateDir);\n }\n\n async deleteOfflineSyncFile(filePath: string, deletionMtimeMs?: number | null): Promise<void> {\n const target = this.assertManagedStoragePath(filePath, \"storage.deleteOfflineSyncFile\");\n await this.deleteTombstoneBlockedOfflineSyncFile(target, deletionMtimeMs);\n await this.requestSyncReconcileIfMigrationPath(target);\n }\n\n protected async deleteTombstoneBlockedOfflineSyncFile(\n target: string,\n deletionMtimeMs?: number | null\n ): Promise<void> {\n const stateDir = this.tombstoneBlockedCaptureIndexOptions().stateDir;\n await withRawEntityPageMutation(path.dirname(stateDir), target, async () => {\n await this.runTombstoneBlockedOfflineSyncMutation(target, null, async () => {\n return await this.deleteManagedStorageFile(target, deletionMtimeMs);\n });\n });\n }\n\n async checkTombstoneBlockedExplicitCapture(\n ...args: [string, string, string?]\n ): Promise<{ has: boolean; authoritative: boolean }> {\n return this.getTombstoneBlockedCaptureIndex().check(...args);\n }\n\n async hasTombstoneBlockedExplicitCapture(...args: [string, string, string?]): Promise<boolean> {\n return this.getTombstoneBlockedCaptureIndex().has(...args);\n }\n\n async isTombstoneBlockedExplicitCaptureIndexAuthoritative(): Promise<boolean> {\n return this.getTombstoneBlockedCaptureIndex().isAuthoritative();\n }\n\n protected async rebuildTombstoneBlockedCaptureAfterInvalidationForPath(\n filePath: string,\n ownedMarker?: string\n ): Promise<void> {\n const index = this.getTombstoneBlockedCaptureIndex();\n if (index.shouldRebuildAfterInvalidationForPath(filePath)) {\n await this.rebuildTombstoneBlockedCaptureAfterInvalidation(ownedMarker);\n }\n }\n protected async rebuildTombstoneBlockedCaptureAfterInvalidation(ownedMarker?: string): Promise<void> {\n await this.getTombstoneBlockedCaptureIndex().rebuildAfterInvalidation(ownedMarker);\n }\n}\n","import { execFile } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport { mkdir, readFile, readdir, rename, stat, unlink, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { promisify } from \"node:util\";\nimport { log } from \"../logger.js\";\nimport type { MemoryFile, MemoryFrontmatter } from \"../types.js\";\nimport { RECALL_FALLBACK_DIRS } from \"../utils/category-dir.js\";\nimport { isErrnoCode } from \"../utils/errno.js\";\nimport { withHeldFileLock } from \"../utils/serialize-mutations.js\";\nimport {\n CONTENT_HASH_INDEX_RETRY_MAX_DELAY_MS,\n ContentHashIndex,\n type ContentHashIndexLockOptions,\n} from \"./content-hash-index.js\";\nimport {\n buildExplicitCaptureDedupKey,\n TombstoneBlockedCaptureWriteLock,\n} from \"./tombstone-blocked-capture-mutation.js\";\nimport type { OfflineSyncMemoryParser } from \"./tombstone-blocked-capture-sync.js\";\nexport {\n buildExplicitCaptureDedupKey,\n isTombstoneBlockedCaptureWriteLockBusy,\n normalizeExplicitCaptureContent,\n} from \"./tombstone-blocked-capture-mutation.js\";\nexport {\n parseTombstoneBlockedOfflineSyncMemory,\n type OfflineSyncMemoryParser,\n TombstoneBlockedCaptureIndexHost,\n} from \"./tombstone-blocked-capture-sync.js\";\n\nconst REBUILD_MAX_ATTEMPTS = 3;\nconst execFileAsync = promisify(execFile);\nconst REBUILD_RETRY_BASE_MS = 50;\n\nconst ABANDONED_MARKER_MIN_AGE_MS = 60_000;\nconst MARKER_PROCESS_START_TOLERANCE_MS = 2_000;\nconst DOTNET_UNIX_EPOCH_TICKS = 621_355_968_000_000_000;\nconst MARKER_PROCESS_STARTED_AT_MS = Date.now() - process.uptime() * 1000;\n\n\ntype RebuildMarker = {\n path: string;\n committed: boolean;\n pid?: number;\n ownerId?: string;\n createdAt?: number;\n processStartedAtMs?: number;\n malformed?: boolean;\n};\n\n\nexport type TombstoneBlockedCaptureIndexOptions = {\n readonly stateDir: string;\n readonly memoryDir: string;\n readonly secureStoreKeyProvider: () => Buffer | null;\n readonly secureStoreWriteKeyProvider: () => Buffer | null;\n readonly lockOptions: () => ContentHashIndexLockOptions;\n readonly readAllMemories: () => Promise<MemoryFile[]>;\n readonly readAllColdMemories: () => Promise<MemoryFile[]>;\n readonly parseMemory?: OfflineSyncMemoryParser;\n readonly withHeldFileLock?: typeof withHeldFileLock;\n};\n\n/**\n * Durable targeted deduplication for tombstone-blocked explicit captures.\n *\n * The active fact-hash index intentionally excludes blocked rows. This small\n * companion index keeps the blocked identity visible without making every\n * authoritative active-index miss scan the full corpus.\n */\nexport class TombstoneBlockedCaptureIndex {\n private readonly options: TombstoneBlockedCaptureIndexOptions;\n private index: ContentHashIndex | null = null;\n private loadPromise: Promise<ContentHashIndex> | null = null;\n private refreshPromise: Promise<ContentHashIndex> | null = null;\n private authoritative = false;\n private readonly captureWriteLock: TombstoneBlockedCaptureWriteLock;\n\n constructor(options: TombstoneBlockedCaptureIndexOptions) {\n this.options = options;\n this.captureWriteLock = new TombstoneBlockedCaptureWriteLock(options);\n }\n\n private createIndex(): ContentHashIndex {\n return new ContentHashIndex(\n path.join(this.options.stateDir, \"tombstone-blocked-capture\"),\n this.options.secureStoreKeyProvider,\n this.options.secureStoreWriteKeyProvider,\n this.options.memoryDir,\n this.options.lockOptions()\n );\n }\n\n private indexPath(): string {\n return path.join(this.options.stateDir, \"tombstone-blocked-capture\", \"fact-hashes.txt\");\n }\n\n private rebuildMarkerPath(): string {\n return path.join(this.options.stateDir, \"tombstone-blocked-capture\", \"rebuild-required\");\n }\n\n private async readRebuildMarkers(): Promise<RebuildMarker[]> {\n try {\n const entries = (await readdir(this.rebuildMarkerPath())).filter((entry) => !entry.startsWith(\".\"));\n return (\n await Promise.all(\n entries.map(async (entry) => {\n const markerPath = path.join(this.rebuildMarkerPath(), entry);\n try {\n const raw = (await readFile(markerPath, \"utf8\")).trim();\n if (raw === \"committed\") return { path: markerPath, committed: true };\n let value: Record<string, unknown>;\n let malformed = false;\n try {\n const parsed = JSON.parse(raw) as unknown;\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n malformed = true;\n value = {};\n } else {\n value = parsed as Record<string, unknown>;\n }\n } catch {\n malformed = true;\n value = {};\n }\n const state = value.state;\n if (state !== \"pending\" && state !== \"committed\") malformed = true;\n const markerStat = await stat(markerPath).catch(() => null);\n // A torn payload can lose its JSON metadata, but the atomic\n // marker filename and filesystem mtime still identify its owner\n // and age. Preserve both so stale malformed markers can be\n // reaped without treating a fresh pre-commit gap as abandoned.\n const createdAt =\n typeof value.createdAt === \"number\" && Number.isFinite(value.createdAt)\n ? value.createdAt\n : markerStat?.mtimeMs;\n if (typeof value.pid !== \"number\" || !Number.isInteger(value.pid)) malformed = true;\n const ownerId =\n typeof value.ownerId === \"string\" && value.ownerId.length > 0\n ? value.ownerId\n : path.basename(markerPath);\n if (typeof value.ownerId !== \"string\" || value.ownerId.length === 0) malformed = true;\n const processStartedAtMs =\n typeof value.processStartedAtMs === \"number\" &&\n Number.isFinite(value.processStartedAtMs) &&\n value.processStartedAtMs > 0\n ? value.processStartedAtMs\n : undefined;\n return {\n path: markerPath,\n committed: state === \"committed\",\n ...(typeof value.pid === \"number\" && Number.isInteger(value.pid) ? { pid: value.pid } : {}),\n ...(ownerId.length > 0 ? { ownerId } : {}),\n ...(typeof createdAt === \"number\" && Number.isFinite(createdAt) ? { createdAt } : {}),\n ...(processStartedAtMs === undefined ? {} : { processStartedAtMs }),\n ...(malformed ? { malformed: true } : {}),\n };\n } catch (err) {\n if (isErrnoCode(err, \"ENOENT\")) return null;\n throw err;\n }\n })\n )\n ).filter((marker): marker is RebuildMarker => marker !== null);\n } catch (err) {\n if (isErrnoCode(err, \"ENOENT\")) return [];\n throw err;\n }\n }\n private async isAbandonedMarker(marker: RebuildMarker): Promise<boolean> {\n if (marker.committed || marker.createdAt === undefined) return false;\n if (Date.now() - marker.createdAt < ABANDONED_MARKER_MIN_AGE_MS) return false;\n if (marker.malformed) return true;\n return marker.pid !== undefined && !(await this.isProcessAlive(marker.pid, marker.processStartedAtMs));\n }\n\n private async isProcessAlive(pid: number, processStartedAtMs?: number): Promise<boolean> {\n try {\n process.kill(pid, 0);\n } catch (err) {\n return !isErrnoCode(err, \"ESRCH\");\n }\n if (processStartedAtMs === undefined) return true;\n const runningStartedAtMs = await this.readProcessStartedAtMs(pid);\n if (runningStartedAtMs === null) return true;\n return runningStartedAtMs <= processStartedAtMs + MARKER_PROCESS_START_TOLERANCE_MS;\n }\n private async readProcessStartedAtMs(pid: number): Promise<number | null> {\n try {\n if (process.platform === \"win32\") {\n const { stdout } = await execFileAsync(\n \"powershell.exe\",\n [\n \"-NoLogo\",\n \"-NoProfile\",\n \"-NonInteractive\",\n \"-Command\",\n `(Get-Process -Id ${pid} -ErrorAction Stop).StartTime.ToUniversalTime().Ticks`,\n ],\n { encoding: \"utf8\", timeout: 1_000 }\n );\n const ticks = Number(stdout.trim());\n return Number.isFinite(ticks) ? (ticks - DOTNET_UNIX_EPOCH_TICKS) / 10_000 : null;\n }\n const { stdout } = await execFileAsync(\"ps\", [\"-p\", String(pid), \"-o\", \"lstart=\"], {\n encoding: \"utf8\",\n timeout: 1_000,\n });\n const output = stdout.trim();\n if (!output) return null;\n const startedAtMs = Date.parse(output);\n return Number.isFinite(startedAtMs) ? startedAtMs : null;\n } catch {\n return null;\n }\n }\n\n private async getClearableRebuildMarkerPaths(markers: readonly RebuildMarker[]): Promise<string[]> {\n const paths = await Promise.all(\n markers.map(async (marker) => (marker.committed || (await this.isAbandonedMarker(marker)) ? marker.path : null))\n );\n return paths.filter((markerPath): markerPath is string => markerPath !== null);\n }\n\n private async getRebuildMarkers(): Promise<RebuildMarker[]> {\n return await this.readRebuildMarkers();\n }\n\n // A pending marker protects the pre-commit gap; only committed markers are safe for another writer to clear.\n private async writeMarkerAtomically(markerPath: string, payload: string): Promise<void> {\n const temporaryPath = `${markerPath}.tmp-${process.pid}-${randomUUID()}`;\n try {\n await writeFile(temporaryPath, payload, \"utf8\");\n await rename(temporaryPath, markerPath);\n } finally {\n await unlink(temporaryPath).catch((err: unknown) => {\n if (!isErrnoCode(err, \"ENOENT\")) throw err;\n });\n }\n }\n\n private async markRebuildRequired(committed = false): Promise<string> {\n const markerDir = this.rebuildMarkerPath();\n await mkdir(markerDir, { recursive: true });\n const ownerId = randomUUID();\n const markerPath = path.join(markerDir, ownerId);\n await this.writeMarkerAtomically(\n markerPath,\n `${JSON.stringify({\n state: committed ? \"committed\" : \"pending\",\n pid: process.pid,\n ownerId,\n createdAt: Date.now(),\n processStartedAtMs: MARKER_PROCESS_STARTED_AT_MS,\n })}\\n`\n );\n return markerPath;\n }\n\n private async markRebuildCommitted(markerPath: string): Promise<void> {\n await this.writeMarkerAtomically(\n markerPath,\n `${JSON.stringify({\n state: \"committed\",\n pid: process.pid,\n ownerId: path.basename(markerPath),\n createdAt: Date.now(),\n processStartedAtMs: MARKER_PROCESS_STARTED_AT_MS,\n })}\\n`\n );\n }\n\n private async clearRebuildRequired(markerPaths: readonly string[]): Promise<void> {\n await Promise.all(\n markerPaths.map(async (markerPath) => {\n try {\n await unlink(markerPath);\n } catch (err) {\n if (!isErrnoCode(err, \"ENOENT\")) throw err;\n }\n })\n );\n }\n\n private async hasRebuildRequired(excludedMarkers: readonly string[] = []): Promise<boolean> {\n const excluded = new Set(excludedMarkers);\n return (await this.getRebuildMarkers()).some((marker) => !excluded.has(marker.path));\n }\n\n private async setAuthoritative(rebuilt: boolean): Promise<void> {\n this.authoritative = rebuilt && !(await this.getRebuildMarkers()).some((marker) => !marker.committed);\n }\n private isBlocked(memory: MemoryFile): boolean {\n return memory.frontmatter.status === \"pending_review\" && Boolean(memory.frontmatter.blockedBy);\n }\n\n private async rebuild(index: ContentHashIndex): Promise<boolean> {\n return await index.rebuildUnderLock(async () => {\n index.clear();\n const existing = [...(await this.options.readAllMemories()), ...(await this.options.readAllColdMemories())];\n for (const memory of existing) {\n if (!this.isBlocked(memory)) continue;\n index.add(\n buildExplicitCaptureDedupKey(memory.content, memory.frontmatter.category, memory.frontmatter.sourceConnector)\n );\n }\n });\n }\n\n private async hasPersistedIndexOrMarkers(): Promise<boolean> {\n try {\n await stat(this.indexPath());\n return true;\n } catch (err) {\n if (!isErrnoCode(err, \"ENOENT\")) throw err;\n return (await this.readRebuildMarkers()).length > 0;\n }\n }\n\n private async getIndex(): Promise<ContentHashIndex> {\n if (this.index) return this.index;\n if (!this.loadPromise) {\n const index = this.createIndex();\n this.loadPromise = (async () => {\n await index.load();\n const rebuildMarkers = await this.getRebuildMarkers();\n const clearableRebuildMarkers = await this.getClearableRebuildMarkerPaths(rebuildMarkers);\n let persisted = true;\n try {\n await stat(this.indexPath());\n if (rebuildMarkers.length > 0) persisted = false;\n } catch (err) {\n if (isErrnoCode(err, \"ENOENT\")) persisted = false;\n else throw err;\n }\n if (!persisted) {\n const lockOptions = this.options.lockOptions();\n const maxAttempts = lockOptions.retryMaxAttempts ?? REBUILD_MAX_ATTEMPTS;\n const baseMs = lockOptions.retryBaseMs ?? REBUILD_RETRY_BASE_MS;\n let rebuilt = false;\n for (let attempt = 0; attempt < maxAttempts; attempt += 1) {\n rebuilt = await this.rebuild(index);\n if (rebuilt || attempt === maxAttempts - 1) break;\n const wait = Math.min(baseMs * 2 ** attempt, CONTENT_HASH_INDEX_RETRY_MAX_DELAY_MS);\n const delayState = Promise.withResolvers<void>();\n setTimeout(delayState.resolve, wait);\n await delayState.promise;\n }\n if (!rebuilt) {\n throw new Error(\"tombstone-blocked capture index rebuild lock unavailable\");\n }\n await this.clearRebuildRequired(clearableRebuildMarkers);\n }\n await this.setAuthoritative(true);\n this.index = index;\n return index;\n })().catch((err) => {\n this.loadPromise = null;\n throw err;\n });\n }\n return this.loadPromise;\n }\n\n async withCaptureWriteLock<T>(task: () => Promise<T>, identity?: string | readonly string[]): Promise<T> {\n return await this.captureWriteLock.withCaptureWriteLock(task, identity);\n }\n\n async withCaptureWriteLockHashes<T>(task: () => Promise<T>, identityHashes: readonly string[]): Promise<T> {\n return await this.captureWriteLock.withCaptureWriteLockHashes(task, identityHashes);\n }\n async withCaptureWriteLockAndHashes<T>(\n task: () => Promise<T>,\n identity: string | readonly string[] | undefined,\n identityHashes: readonly string[]\n ): Promise<T> {\n return await this.captureWriteLock.withCaptureWriteLockAndHashes(task, identity, identityHashes);\n }\n\n private async reload(): Promise<ContentHashIndex> {\n if (!this.refreshPromise) {\n this.refreshPromise = (async () => {\n this.index = null;\n this.loadPromise = null;\n return await this.getIndex();\n })().finally(() => {\n this.refreshPromise = null;\n });\n }\n return this.refreshPromise;\n }\n\n /** Return blocked-row membership and authority from one index snapshot. */\n async check(\n content: string,\n category: string,\n sourceConnector?: string\n ): Promise<{ has: boolean; authoritative: boolean }> {\n const key = buildExplicitCaptureDedupKey(content, category, sourceConnector);\n let index = await this.getIndex();\n if ((await this.hasRebuildRequired()) || !(await index.isDiskFingerprintCurrent())) {\n index = await this.reload();\n }\n return { has: index.has(key), authoritative: this.authoritative };\n }\n\n /** Return whether a blocked row matches this explicit-capture identity. */\n async has(content: string, category: string, sourceConnector?: string): Promise<boolean> {\n return (await this.check(content, category, sourceConnector)).has;\n }\n\n /** Return whether the in-memory index is safe to answer an authoritative miss. */\n async isAuthoritative(): Promise<boolean> {\n const index = await this.getIndex();\n if ((await this.hasRebuildRequired()) || !(await index.isDiskFingerprintCurrent())) {\n await this.reload();\n }\n return this.authoritative;\n }\n\n /** Reserve durable rebuild intent before a blocked memory file is committed. */\n async prepareWrite(): Promise<string> {\n return this.markRebuildRequired();\n }\n\n /** Mark a prepared write committed once its memory file is durable. */\n async commitWrite(rebuildMarker: string): Promise<void> {\n await this.markRebuildCommitted(rebuildMarker);\n }\n\n /** Drop a pending marker when the protected memory write never commits. */\n async discardWrite(rebuildMarker: string): Promise<void> {\n await this.clearRebuildRequired([rebuildMarker]);\n }\n\n /** Add a newly persisted blocked row to the durable targeted index. */\n async add(memory: MemoryFile, rebuildMarker?: string): Promise<void> {\n if (!this.isBlocked(memory)) return;\n let index = await this.getIndex();\n if (\n (await this.hasRebuildRequired(rebuildMarker ? [rebuildMarker] : [])) ||\n !(await index.isDiskFingerprintCurrent())\n ) {\n index = await this.reload();\n }\n index.add(\n buildExplicitCaptureDedupKey(memory.content, memory.frontmatter.category, memory.frontmatter.sourceConnector)\n );\n const marker = rebuildMarker ?? (await this.markRebuildRequired(true));\n if (rebuildMarker) await this.markRebuildCommitted(rebuildMarker);\n await index.saveMergingWithDisk();\n await index.flushReconcileRetry();\n if (index.hasPendingChanges) {\n this.markUntrusted();\n return;\n }\n await this.clearRebuildRequired([marker]);\n await this.setAuthoritative(true);\n }\n\n /** Rebuild the index after a blocked row changes or is removed. */\n async rebuildIfLoaded(ownedMarker?: string): Promise<void> {\n const index = this.index ?? ((await this.hasPersistedIndexOrMarkers()) ? this.getIndex() : null);\n if (!index) return;\n const rebuildMarkers = await this.getRebuildMarkers();\n const rebuildMarker = await this.markRebuildRequired(true);\n const clearableRebuildMarkers = await this.getClearableRebuildMarkerPaths(rebuildMarkers);\n const rebuilt = await this.rebuild(await index);\n if (rebuilt) {\n await this.clearRebuildRequired([\n ...clearableRebuildMarkers,\n ...(ownedMarker === undefined || clearableRebuildMarkers.includes(ownedMarker) ? [] : [ownedMarker]),\n rebuildMarker,\n ]);\n }\n await this.setAuthoritative(rebuilt);\n }\n\n /** Rebuild when either side of a write is blocked and its identity changed. */\n async sync(before: MemoryFile, after: MemoryFile, rebuildMarker?: string): Promise<void> {\n const beforeBlocked = this.isBlocked(before);\n const afterBlocked = this.isBlocked(after);\n if (!beforeBlocked && !afterBlocked) return;\n const beforeKey = buildExplicitCaptureDedupKey(\n before.content,\n before.frontmatter.category,\n before.frontmatter.sourceConnector\n );\n const afterKey = buildExplicitCaptureDedupKey(\n after.content,\n after.frontmatter.category,\n after.frontmatter.sourceConnector\n );\n if (beforeBlocked && afterBlocked && beforeKey === afterKey) {\n if (rebuildMarker) {\n await this.markRebuildCommitted(rebuildMarker);\n await this.clearRebuildRequired([rebuildMarker]);\n }\n return;\n }\n const existingMarkers = await this.getRebuildMarkers();\n const marker = rebuildMarker ?? (await this.markRebuildRequired(true));\n const clearableExistingMarkers = await this.getClearableRebuildMarkerPaths(existingMarkers);\n if (rebuildMarker) await this.markRebuildCommitted(rebuildMarker);\n const rebuilt = await this.rebuild(await this.getIndex());\n if (rebuilt) {\n await this.clearRebuildRequired([\n ...clearableExistingMarkers,\n marker,\n ]);\n }\n await this.setAuthoritative(rebuilt);\n }\n markUntrusted(): void {\n this.authoritative = false;\n }\n\n private async failOpen(operation: string, action: () => Promise<void>): Promise<void> {\n try {\n await action();\n } catch (err) {\n this.markUntrusted();\n log.warn(`storage.${operation} completed but failed to update tombstone-blocked capture index: ${err}`);\n }\n }\n\n async addWrittenMemory(\n pathname: string,\n frontmatter: MemoryFrontmatter,\n content: string,\n rebuildMarker?: string\n ): Promise<void> {\n await this.failOpen(\"writeMemory\", () => this.add({ path: pathname, frontmatter, content }, rebuildMarker));\n }\n\n async rebuildAfterInvalidation(ownedMarker?: string): Promise<void> {\n await this.failOpen(\"invalidateMemory\", () => this.rebuildIfLoaded(ownedMarker));\n }\n\n async syncUpdatedMemory(\n before: MemoryFile,\n frontmatter: MemoryFrontmatter,\n content: string,\n rebuildMarker?: string\n ): Promise<void> {\n await this.failOpen(\"updateMemory\", () => this.sync(before, { ...before, frontmatter, content }, rebuildMarker));\n }\n\n async syncUpdatedFrontmatter(\n before: MemoryFile,\n frontmatter: MemoryFrontmatter,\n rebuildMarker?: string\n ): Promise<void> {\n await this.failOpen(\"writeMemoryFrontmatter\", () => this.sync(before, { ...before, frontmatter }, rebuildMarker));\n }\n shouldRebuildAfterInvalidationForPath(filePath: string): boolean {\n const relative = path.relative(path.resolve(this.options.memoryDir), path.resolve(filePath));\n const category = relative.split(path.sep)[0];\n return category === \"cold\" || RECALL_FALLBACK_DIRS.includes(category);\n }\n}\n"],"mappings":"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","names":["createHash","randomUUID","unlink","path","mkdir","path","path","stdout","mkdir","path","result","randomUUID","unlink","createHash"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lifecycle/tombstones.ts"],"sourcesContent":["// ---------------------------------------------------------------------------\n// lifecycle/tombstones.ts — Tombstone store + non-resurrection invariant\n// (issue #1579)\n//\n// A \"tombstone\" records that a fact has been retired (corrected, superseded,\n// or retracted) so that the SAME fact cannot silently come back to life through\n// any of the five resurrection paths:\n//\n// 1. Re-extraction (session replay, re-observation)\n// 2. Importers (capsule / import-* payloads)\n// 3. Consolidation merges\n// 4. Dreams (REM re-derivation)\n// 5. Pattern reinforcement (duplicate promotion)\n//\n// The invariant is enforced at the SINGLE storage persist path\n// (`StorageManager.writeMemory` — the same chokepoint that records catalog\n// writes, issue #1522). Every write path funnels through it, so paths (a)–(e)\n// are blocked WITHOUT per-path code.\n//\n// File-first / rebuildable (the repo's storage philosophy): the JSONL at\n// `<stateDir>/tombstones.jsonl` is a cache of truth. The authoritative sources\n// are the memory files themselves (status: superseded/retracted) and the\n// `corrections/` records. `rebuildTombstonesFromStorage` reconstructs the\n// JSONL from those sources.\n//\n// Design rules honored (issue #1579 design section):\n// - Hash `rawContent` exactly as the dedup index does — one helper\n// (`ContentHashIndex.computeHash` / `normalizeContent`), never a second\n// (checklist §13; rule 23).\n// - Append-only log — never rewrite history; a later `kind: \"revocation\"`\n// entry re-allows (rule 25).\n// - Instance-scoped, never module-level (rule 11).\n// - Namespace-scoped — a tombstone in namespace A never blocks namespace B\n// (rule 42).\n// - Serialized appends with rejection recovery (rule 40).\n// - Never silent drop — a blocked write lands as pending_review + blockedBy\n// (rule 34).\n// - Do NOT register a blocked fact as an active dedup/index entry (rule 44).\n// - Off = pre-feature behavior for rollback safety (rule 30).\n// - Semantic tier (4) ships dark, off by default (rule 48).\n// ---------------------------------------------------------------------------\n\nimport { serializeMutations, withHeldFileLock } from \"../utils/serialize-mutations.js\";\n\n/** Why a tombstone was emitted. */\nexport type TombstoneReason =\n | \"correction\"\n | \"supersession\"\n | \"retraction\"\n | \"contradiction_resolution\";\n\n/** Who emitted the tombstone. */\nexport type TombstoneCreatedBy =\n | \"user_correction\"\n | \"contradiction_resolution\"\n | \"supersession\"\n | \"chat\";\n\n/** Tier that matched on lookup. */\nexport type TombstoneMatchTier = \"exact\" | \"normalized\" | \"keyed\" | \"semantic\";\n\n/**\n * A single append-only tombstone log entry.\n *\n * `kind: \"tombstone\"` blocks; `kind: \"revocation\"` re-allows. The log is\n * never rewritten — the NEWEST matching entry wins at lookup (rule 25).\n */\nexport interface TombstoneEntry {\n /** Stable tombstone id (`tomb-<ts>-<rand>`). */\n id: string;\n kind: \"tombstone\" | \"revocation\";\n reason: TombstoneReason;\n /** The memory that was retired. */\n sourceMemoryId: string;\n /** sha256 of the retired memory's rawContent (rule 23). */\n contentHash: string;\n /** `ContentHashIndex.normalizeContent(rawContent)` — the pre-hash form. */\n normalizedText: string;\n entityRef?: string;\n /** Structured-attribute supersession key when one existed. */\n supersessionKey?: string;\n /** Stable operation identity for crash-recovery replay. */\n operationKey?: string;\n /** Namespace scope (rule 42). */\n namespace: string;\n createdAt: string;\n createdBy: TombstoneCreatedBy;\n /** For `kind: \"revocation\"`: the tombstone id being revoked. */\n revokes?: string;\n}\n\n/** A positive block decision returned by `TombstoneStore.lookup`. */\nexport interface TombstoneMatch {\n tombstoneId: string;\n matchedTier: TombstoneMatchTier;\n reason: TombstoneReason;\n}\n\n/** Inputs to a lookup. At least one discriminator must be present.\n *\n * Issue #1579 thread Ociag/Oci-W: `supersessionKeys` (plural) lets the write\n * chokepoint check EVERY derived key, not just the first. Emitters register\n * one tombstone per matched key (temporal-supersession, rebuild), so a block\n * can live on any later key; querying only `supersessionKeys[0]` missed it\n * and the retired fact resurrected as active. `supersessionKey` (singular)\n * remains for direct/unit callers; `lookup` checks the union of both. */\nexport interface TombstoneLookupQuery {\n contentHash?: string;\n normalizedText?: string;\n entityRef?: string;\n /** Single supersession key (direct/unit callers). */\n supersessionKey?: string;\n /** All derived supersession keys (write chokepoint). The keyed tier is\n * checked for each; the first active match wins. */\n supersessionKeys?: string[];\n namespace: string;\n}\n\n/** Configuration for a tombstone store instance. */\nexport interface TombstoneStoreOptions {\n enabled: boolean;\n semanticMatch: boolean;\n semanticThreshold: number;\n /** sha256 of raw content — wired to `ContentHashIndex.computeHash`. */\n hashContent: (raw: string) => string;\n /** Normalize raw content — wired to `ContentHashIndex.normalizeContent`. */\n normalizeText: (raw: string) => string;\n /**\n * Optional cosine similarity in [0, 1] for the semantic tier. When\n * undefined or when `semanticMatch` is false, the semantic tier is\n * skipped entirely.\n */\n semanticSimilarity?: (a: string, b: string) => number;\n /**\n * Cross-process write-lock timings for the tombstone JSONL mutation lock\n * (issue #1639). The secure-store append is a read-merge-write (read\n * encrypted → decrypt → concat → re-encrypt → atomic rename), so two\n * Remnic processes appending concurrently can each read the same contents\n * and the last writer drops the other's entry — breaking the\n * non-resurrection invariant. The lock serializes the mutation across\n * processes. When omitted, defaults that fit the short tombstone critical\n * section (mirroring the summary-snapshot lock): staleMs 30s, maxWaitMs 5s,\n * heartbeatMs floor(staleMs/3).\n */\n readonly lockStaleMs?: number;\n readonly lockMaxWaitMs?: number;\n readonly lockHeartbeatMs?: number;\n}\n\n/** Injected file I/O — the StorageManager wires its secure-store-aware\n * implementations so tombstones are encrypted at rest alongside other state.\n * `stat` is optional; when provided the store tracks the file mtime itself and\n * runs a cross-process staleness probe on each access (#1579). */\nexport interface TombstoneFileIo {\n read: (filePath: string) => Promise<string>;\n append: (filePath: string, content: string) => Promise<void>;\n write: (filePath: string, content: string) => Promise<void>;\n stat?: (filePath: string) => { mtimeMs: number };\n}\n\n/** Aggregate stats for `remnic doctor`. */\nexport interface TombstoneStats {\n count: number;\n revoked: number;\n lastAppendAt: string | null;\n corruptedLines: number;\n /** Whether the in-memory index matches the on-disk file (rebuild check). */\n loaded: boolean;\n}\n\nconst TOMBSTONE_PREFIX = \"tomb\";\n\nfunction newTombstoneId(): string {\n return `${TOMBSTONE_PREFIX}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;\n}\n\n/** Deterministic key for the keyed tier (namespace + entityRef + supersessionKey).\n *\n * The namespace is part of the discriminator so two namespace-scoped stores\n * that share the same backing `tombstones.jsonl` (namespaces disabled, or the\n * same directory used with different namespace configs) cannot overwrite each\n * other's index entries — a later tombstone for namespace B with the same\n * entity/key no longer evicts namespace A's entry (issue #1579 thread Ocs-O). */\nfunction keyedTierKey(namespace: string, entityRef: string, supersessionKey: string): string {\n return `${namespace}\\0${entityRef}\\0${supersessionKey}`;\n}\n\n/**\n * Parse one JSONL line into a TombstoneEntry, validating the discriminated\n * union. Returns `null` for malformed lines (rule 34 — skip with a counter,\n * never crash).\n */\nexport function parseTombstoneLine(line: string): TombstoneEntry | null {\n const trimmed = line.trim();\n if (trimmed.length === 0) return null;\n let parsed: unknown;\n try {\n parsed = JSON.parse(trimmed);\n } catch {\n return null;\n }\n if (!parsed || typeof parsed !== \"object\") return null;\n const e = parsed as Record<string, unknown>;\n if (typeof e.id !== \"string\" || e.id.length === 0) return null;\n if (e.kind !== \"tombstone\" && e.kind !== \"revocation\") return null;\n if (\n e.reason !== \"correction\" &&\n e.reason !== \"supersession\" &&\n e.reason !== \"retraction\" &&\n e.reason !== \"contradiction_resolution\"\n ) {\n return null;\n }\n if (typeof e.sourceMemoryId !== \"string\") return null;\n if (typeof e.contentHash !== \"string\") return null;\n if (typeof e.normalizedText !== \"string\") return null;\n if (typeof e.namespace !== \"string\") return null;\n if (typeof e.createdAt !== \"string\") return null;\n if (\n e.createdBy !== \"user_correction\" &&\n e.createdBy !== \"contradiction_resolution\" &&\n e.createdBy !== \"supersession\" &&\n e.createdBy !== \"chat\"\n ) {\n return null;\n }\n const out: TombstoneEntry = {\n id: e.id,\n kind: e.kind,\n reason: e.reason,\n sourceMemoryId: e.sourceMemoryId,\n contentHash: e.contentHash,\n normalizedText: e.normalizedText,\n namespace: e.namespace,\n createdAt: e.createdAt,\n createdBy: e.createdBy,\n };\n if (typeof e.operationKey === \"string\") out.operationKey = e.operationKey;\n if (typeof e.entityRef === \"string\") out.entityRef = e.entityRef;\n if (typeof e.supersessionKey === \"string\") out.supersessionKey = e.supersessionKey;\n if (typeof e.revokes === \"string\") out.revokes = e.revokes;\n return out;\n}\n\n/**\n * The instance-scoped tombstone store. One per StorageManager (rule 11),\n * namespace-scoped via `namespace` + the on-disk path (rule 42).\n *\n * The in-memory index is built lazily on first access and invalidated on\n * append + by the StorageManager's cache-invalidation chokepoint (rule 25).\n */\nexport class TombstoneStore {\n private entries: TombstoneEntry[] = [];\n /** contentHash → tombstone id (newest) — exact tier. */\n private readonly byHash = new Map<string, string>();\n /** normalizedText → tombstone id (newest) — normalized tier. */\n private readonly byNormalized = new Map<string, string>();\n /** entityRef\\0supersessionKey → tombstone id (newest) — keyed tier. */\n private readonly byKey = new Map<string, string>();\n /** Tombstone ids that have a later revocation entry. */\n private readonly revokedIds = new Set<string>();\n /** id → entry index (newest only, for revocation lookups). */\n private readonly byId = new Map<string, TombstoneEntry>();\n private loaded = false;\n private loadPromise: Promise<void> | null = null;\n private corruptedLines = 0;\n private lastAppendAt: string | null = null;\n /**\n * Last-seen mtime of the JSONL file (cross-process staleness probe, #1579).\n * Tracked inside the store so the StorageManager wiring stays thin. When the\n * file's mtime advances past this value between accesses, the in-memory index\n * is stale (a peer process appended) and is reloaded before the next lookup.\n */\n private fileMtimeMs = 0;\n\n constructor(\n private readonly filePath: string,\n private readonly namespace: string,\n private readonly options: TombstoneStoreOptions,\n private readonly io: TombstoneFileIo,\n ) {\n this.lockStaleMs = this.options.lockStaleMs ?? 30_000;\n this.lockMaxWaitMs = this.options.lockMaxWaitMs ?? 5_000;\n this.lockHeartbeatMs =\n this.options.lockHeartbeatMs ?? Math.max(100, Math.floor(this.lockStaleMs / 3));\n }\n\n /**\n * Resolved cross-process write-lock timings (issue #1639). Defaults mirror\n * the summary-snapshot lock: a tombstone append critical section is\n * sub-second, so a stale lock older than 30s is a crashed holder; bounded\n * acquisition gives up after 5s and strict-fails rather than clobbering a\n * concurrent writer (which would reintroduce the lost-write race this lock\n * closes).\n */\n private readonly lockStaleMs: number;\n private readonly lockMaxWaitMs: number;\n private readonly lockHeartbeatMs: number;\n\n /**\n * Sibling advisory lockfile: `<tombstones>.jsonl` → `<tombstones>.lock`.\n * Shared by append, revoke, and rebuild so every JSONL mutation serializes\n * against the others across processes (issue #1639: \"shared with rebuilds\").\n */\n private get lockPath(): string {\n return this.filePath.replace(/\\.jsonl$/i, \"\") + \".lock\";\n }\n\n /** Lazy load + build the in-memory index. Idempotent. */\n async load(): Promise<void> {\n if (this.loaded) return;\n if (this.loadPromise) return this.loadPromise;\n this.loadPromise = this.loadInternal();\n try {\n await this.loadPromise;\n } finally {\n this.loadPromise = null;\n }\n }\n\n private async loadInternal(): Promise<void> {\n // Record the file's mtime so the staleness probe does not immediately\n // invalidate on the next access (fileMtimeMs starts at 0; without this,\n // any non-zero mtime would trigger a spurious reload). Done before the\n // read so an ENOENT still records 0.\n this.recordFileMtime();\n let raw: string;\n try {\n raw = await this.io.read(this.filePath);\n } catch (err) {\n // ENOENT is fine — fresh store. Other errors leave the store empty\n // rather than crashing the write path (rule 34 spirit: degrade to\n // \"no tombstones known\" rather than blocking all writes).\n const code = (err as NodeJS.ErrnoException)?.code;\n if (code !== \"ENOENT\") {\n // Swallow — the write path must not crash on a corrupt tombstone file.\n // Rebuild will repair on the next doctor/maintenance run.\n }\n this.loaded = true;\n return;\n }\n this.resetIndex();\n let corrupted = 0;\n for (const line of raw.split(\"\\n\")) {\n const entry = parseTombstoneLine(line);\n if (!entry) {\n if (line.trim().length > 0) corrupted += 1;\n continue;\n }\n this.indexEntry(entry);\n }\n this.corruptedLines = corrupted;\n this.loaded = true;\n }\n\n private resetIndex(): void {\n this.entries = [];\n this.byHash.clear();\n this.byNormalized.clear();\n this.byKey.clear();\n this.revokedIds.clear();\n this.byId.clear();\n }\n\n /**\n * Index an entry. Later entries (higher array index = newer createdAt)\n * OVERRIDE earlier ones at each tier key — the newest matching entry wins\n * (rule 25). Revocation entries mark their target as revoked.\n */\n private indexEntry(entry: TombstoneEntry): void {\n this.entries.push(entry);\n this.byId.set(entry.id, entry);\n if (entry.createdAt > (this.lastAppendAt ?? \"\")) {\n this.lastAppendAt = entry.createdAt;\n }\n if (entry.kind === \"revocation\") {\n if (entry.revokes) this.revokedIds.add(entry.revokes);\n return;\n }\n // Tombstone entries populate the lookup maps. The namespace is part of\n // every discriminator key (issue #1579 thread Ocs-O): when two\n // namespace-scoped stores share the same backing file, a later tombstone\n // for namespace B with identical content must NOT evict namespace A's map\n // entry — otherwise A's lookup finds B's id, rejects it on namespace\n // mismatch, and misses its own still-active tombstone (resurrection).\n const ns = entry.namespace;\n if (entry.contentHash) this.byHash.set(`${ns}\\0${entry.contentHash}`, entry.id);\n if (entry.normalizedText) this.byNormalized.set(`${ns}\\0${entry.normalizedText}`, entry.id);\n if (entry.entityRef && entry.supersessionKey) {\n this.byKey.set(keyedTierKey(ns, entry.entityRef, entry.supersessionKey), entry.id);\n }\n }\n\n /** Invalidate the in-memory cache (rule 25). The next access reloads. */\n invalidate(): void {\n this.loaded = false;\n this.loadPromise = null;\n this.resetIndex();\n }\n\n /**\n * Cross-process staleness probe (#1579). If the file's mtime advanced since\n * the last load/own-write, a peer process appended and our in-memory index is\n * stale — invalidate AND reload in place so the next lookup sees the new\n * entries. Best-effort: a stat error is swallowed (the loaded index is\n * retained rather than crashing the write path). No-op when no `stat` was\n * injected or when the mtime is unchanged. After our own append/revoke/rebuild\n * `markWritten` records the new mtime, so this probe does not fire for our\n * own writes (only for peer-process appends).\n */\n async ensureFreshAgainstDisk(): Promise<void> {\n if (!this.io.stat) return;\n let mtimeMs: number;\n try {\n mtimeMs = Math.floor(this.io.stat(this.filePath).mtimeMs);\n } catch {\n return; // ENOENT / permission — keep the loaded index (fail-open).\n }\n if (mtimeMs === this.fileMtimeMs && this.loaded) return;\n this.fileMtimeMs = mtimeMs;\n this.invalidate();\n await this.load();\n }\n\n /**\n * Record the file mtime after THIS process writes (append / revoke / rebuild)\n * so `ensureFreshAgainstDisk` does not treat our own write as a peer append\n * and throw away the just-updated in-memory index (#1579 — avoids a needless\n * invalidate+reload in the hot write path).\n */\n private markWritten(): void {\n this.recordFileMtime();\n }\n\n private recordFileMtime(): void {\n if (!this.io.stat) return;\n try {\n this.fileMtimeMs = Math.floor(this.io.stat(this.filePath).mtimeMs);\n } catch {\n // ENOENT — fresh store with no file yet; mtime stays at its current value.\n }\n }\n\n /**\n * Append a tombstone entry. Serialized via `serializeMutations` keyed by\n * file path so concurrent appends do not interleave, with rejection recovery\n * (rule 40 — a single failed append never poisons the chain). The in-memory\n * index is updated AFTER the durable append succeeds.\n *\n * Returns the new tombstone id.\n */\n async appendTombstone(input: {\n reason: TombstoneReason;\n createdBy: TombstoneCreatedBy;\n sourceMemoryId: string;\n rawContent: string;\n entityRef?: string;\n supersessionKey?: string;\n operationKey?: string;\n createdAt?: string;\n /**\n * Pre-computed canonical contentHash from the retired memory's frontmatter.\n * When provided, used directly so the tombstone's exact tier matches the\n * hash writeMemory computes on re-extraction (issue #1579 review: cited\n * facts must not slip past the chokepoint because the emitter hashed the\n * citation-annotated body instead of the canonical source).\n */\n contentHash?: string;\n }): Promise<string> {\n await this.load();\n const createdAt = input.createdAt ?? new Date().toISOString();\n const id = newTombstoneId();\n const entry: TombstoneEntry = {\n id,\n kind: \"tombstone\",\n reason: input.reason,\n sourceMemoryId: input.sourceMemoryId,\n contentHash: input.contentHash ?? this.options.hashContent(input.rawContent),\n normalizedText: this.options.normalizeText(input.rawContent),\n ...(input.entityRef ? { entityRef: input.entityRef } : {}),\n ...(input.supersessionKey ? { supersessionKey: input.supersessionKey } : {}),\n ...(input.operationKey ? { operationKey: input.operationKey } : {}),\n namespace: this.namespace,\n createdAt,\n createdBy: input.createdBy,\n };\n await this.serializeAppend(entry);\n this.indexEntry(entry);\n this.markWritten();\n return id;\n }\n\n /**\n * Append a revocation entry referencing `tombstoneId`. The log is\n * append-only; lookup treats a revoked tombstone as re-allowed (rule 25).\n */\n async revoke(tombstoneId: string, createdBy: TombstoneCreatedBy): Promise<string> {\n await this.load();\n const createdAt = new Date().toISOString();\n const id = newTombstoneId();\n const entry: TombstoneEntry = {\n id,\n kind: \"revocation\",\n reason: \"correction\",\n sourceMemoryId: \"\",\n contentHash: \"\",\n normalizedText: \"\",\n namespace: this.namespace,\n createdAt,\n createdBy,\n revokes: tombstoneId,\n };\n await this.serializeAppend(entry);\n this.indexEntry(entry);\n this.markWritten();\n return id;\n }\n\n private serializeAppend(entry: TombstoneEntry): Promise<void> {\n const line = JSON.stringify(entry) + \"\\n\";\n // serializeMutations (in-process, rule 40 rejection recovery) wraps the\n // cross-process lock: within one process appends are queued, and across\n // processes the advisory lockfile serializes the read-merge-write so two\n // Remnic processes appending concurrently cannot drop each other's entry\n // (issue #1639). Under the lock we re-sync the in-memory index against\n // disk first, so indexEntry builds on the peer's just-appended entries.\n return serializeMutations(`tombstone:${this.filePath}`, () =>\n this.withWriteLock(async () => {\n await this.ensureFreshAgainstDisk();\n await this.io.append(this.filePath, line);\n }),\n );\n }\n\n /**\n * Acquire the cross-process tombstone write lock and run `task` under it\n * (issue #1639). Strict-fail on acquisition timeout: the secure-store append\n * is a read-merge-write, so a best-effort unlocked run would clobber a\n * concurrent writer — reintroducing the lost-write race this lock closes.\n * The thrown error surfaces to the caller (rule 34: never silently drop);\n * rebuild recovers the tombstone on the next maintenance cycle.\n *\n * In-process callers are already serialized by serializeMutations (one key\n * for append/revoke/rebuild), so this lock only contends across processes —\n * the single-process daemon (default deployment) acquires it immediately.\n */\n private withWriteLock<T>(task: () => Promise<T>): Promise<T> {\n return withHeldFileLock(\n this.lockPath,\n {\n staleMs: this.lockStaleMs,\n maxWaitMs: this.lockMaxWaitMs,\n heartbeatMs: this.lockHeartbeatMs,\n },\n async (acquired) => {\n if (!acquired) {\n throw new Error(\n \"could not acquire tombstone write lock (contention timeout or filesystem error)\",\n );\n }\n return task();\n },\n );\n }\n\n /**\n * Look up whether `query` is blocked by an active (non-revoked) tombstone.\n * Tiers are checked in order: exact (contentHash) → normalized → keyed →\n * semantic (off by default). Returns the first active match, or `null`.\n *\n * Namespace isolation (rule 42): only entries with `namespace === query.namespace`\n * match. The store is per-namespace, so this is belt-and-suspenders.\n */\n lookup(query: TombstoneLookupQuery): TombstoneMatch | null {\n // We intentionally do NOT await load() here — lookup is called from the\n // hot write path. Callers MUST ensure the store is loaded before lookup\n // (StorageManager does this in ensureTombstoneStoreLoaded). If not loaded,\n // lookup returns null (fail-open: a missing tombstone check is preferable\n // to crashing every write — see rule 34 / the \"degrade gracefully\" note).\n if (!this.options.enabled) return null;\n if (!this.loaded) return null;\n\n // Tier 1: exact contentHash. Namespace is part of the map key (thread\n // Ocs-O), so the lookup finds only this namespace's tombstone even when\n // the backing file is shared. The namespace equality check below is kept\n // as defense-in-depth.\n const ns = query.namespace;\n if (query.contentHash) {\n const id = this.byHash.get(`${ns}\\0${query.contentHash}`);\n if (id && !this.revokedIds.has(id)) {\n const entry = this.byId.get(id);\n if (entry && entry.namespace === ns) {\n return { tombstoneId: id, matchedTier: \"exact\", reason: entry.reason };\n }\n }\n }\n // Tier 2: normalized text.\n if (query.normalizedText) {\n const id = this.byNormalized.get(`${ns}\\0${query.normalizedText}`);\n if (id && !this.revokedIds.has(id)) {\n const entry = this.byId.get(id);\n if (entry && entry.namespace === ns) {\n return { tombstoneId: id, matchedTier: \"normalized\", reason: entry.reason };\n }\n }\n }\n // Tier 3: keyed (entityRef + supersessionKey). Issue #1579 thread\n // Ociag/Oci-W: check EVERY supplied key, not just the first — emitters\n // append one tombstone per matched supersession key, so the active block\n // can live on any later key. The union of `supersessionKey` (singular,\n // direct callers) and `supersessionKeys` (array, write chokepoint) is\n // checked; the first active match wins (tiers are equality-based, so\n // ordering across keys does not affect correctness).\n if (query.entityRef) {\n const keysToCheck: string[] = [];\n if (query.supersessionKey) keysToCheck.push(query.supersessionKey);\n if (query.supersessionKeys) {\n for (const k of query.supersessionKeys) {\n if (!keysToCheck.includes(k)) keysToCheck.push(k);\n }\n }\n for (const key of keysToCheck) {\n const id = this.byKey.get(keyedTierKey(ns, query.entityRef, key));\n if (id && !this.revokedIds.has(id)) {\n const entry = this.byId.get(id);\n if (entry && entry.namespace === ns) {\n return { tombstoneId: id, matchedTier: \"keyed\", reason: entry.reason };\n }\n }\n }\n }\n // Tier 4: semantic (off by default, rule 48).\n if (this.options.semanticMatch && this.options.semanticSimilarity && query.normalizedText) {\n const threshold = this.options.semanticThreshold;\n let best: { id: string; reason: TombstoneReason; score: number } | null = null;\n for (const entry of this.entries) {\n if (entry.kind !== \"tombstone\") continue;\n if (entry.namespace !== query.namespace) continue;\n if (this.revokedIds.has(entry.id)) continue;\n if (!entry.normalizedText) continue;\n const score = this.options.semanticSimilarity(query.normalizedText, entry.normalizedText);\n if (score >= threshold && (!best || score > best.score)) {\n best = { id: entry.id, reason: entry.reason, score };\n }\n }\n if (best) {\n return { tombstoneId: best.id, matchedTier: \"semantic\", reason: best.reason };\n }\n }\n return null;\n }\n async hasExactEntry(input: {\n sourceMemoryId: string;\n contentHash?: string;\n entityRef?: string;\n supersessionKey?: string;\n createdAt?: string;\n operationKey?: string;\n }): Promise<boolean> {\n if (!this.options.enabled) return false;\n await this.ensureFreshAgainstDisk();\n await this.load();\n return this.entries.some(\n (entry) =>\n entry.kind === \"tombstone\" &&\n !this.revokedIds.has(entry.id) &&\n entry.namespace === this.namespace &&\n entry.sourceMemoryId === input.sourceMemoryId &&\n (input.contentHash === undefined || entry.contentHash === input.contentHash) &&\n (input.entityRef === undefined || entry.entityRef === input.entityRef) &&\n (input.supersessionKey === undefined || entry.supersessionKey === input.supersessionKey) &&\n (input.createdAt === undefined || entry.createdAt === input.createdAt) &&\n (input.operationKey === undefined || entry.operationKey === input.operationKey),\n );\n }\n\n\n /** Aggregate stats for the doctor / x-ray surfaces. */\n stats(): TombstoneStats {\n let active = 0;\n for (const entry of this.entries) {\n if (entry.kind === \"tombstone\" && !this.revokedIds.has(entry.id)) active += 1;\n }\n return {\n count: active,\n revoked: this.revokedIds.size,\n lastAppendAt: this.lastAppendAt,\n corruptedLines: this.corruptedLines,\n loaded: this.loaded,\n };\n }\n\n /** Read-only snapshot of all entries (for rebuild + tests). */\n snapshot(): readonly TombstoneEntry[] {\n return this.entries;\n }\n\n /**\n * Rebuild the in-memory index + JSONL from the supplied retired-memory\n * records + existing entries (preserving revocations). Byte-stable: entries\n * are sorted by (createdAt, id) before write (rule 38).\n *\n * Returns the count of tombstone entries written.\n */\n async rebuild(retiredMemories: ReadonlyArray<RetiredMemoryRecord>): Promise<number> {\n // The full read-merge-write runs UNDER the cross-process lock (issue #1639,\n // cursor/codex review): we ensureFreshAgainstDisk() first so the in-memory\n // index reflects any peer append/revoke that landed while we waited for the\n // lock, THEN compute the payload. Rebuild rewrites the entire JSONL, so a\n // payload built from a stale this.entries would overwrite a peer's just-\n // written entry and resurrect a retired fact — the exact invariant this\n // store exists to enforce. serializeMutations (in-process) wraps the\n // cross-process lock; the key is unified with append/revoke so they cannot\n // interleave in-process either.\n const rebuiltCount = await serializeMutations(`tombstone:${this.filePath}`, () =>\n this.withWriteLock(async () => {\n await this.ensureFreshAgainstDisk();\n // Preserve existing revocations (all namespaces — ids are globally\n // unique) so a rebuild does not silently un-revoke.\n const existingRevocations = this.entries.filter((e) => e.kind === \"revocation\");\n // Preserve tombstone entries from OTHER namespaces when the backing\n // file is shared (issue #1579 thread Oc2MJ). rebuild rewrites the\n // entire file; without preserving foreign entries, rebuilding\n // namespace A would silently delete namespace B's tombstones, allowing\n // resurrection in B.\n const foreignTombstones = this.entries.filter(\n (e) => e.kind === \"tombstone\" && e.namespace !== this.namespace,\n );\n // Reuse existing tombstone ids for source-equivalent entries so a prior\n // revocation (which references the tombstone id) survives rebuild —\n // minting fresh ids would orphan the revocation and silently un-revoke.\n // Issue #1579 thread Oci-T: key the reuse map by (sourceMemoryId,\n // supersessionKey). See the append path above for the full rationale.\n const existingBySource = new Map<string, string>();\n for (const e of this.entries) {\n if (e.kind === \"tombstone\") {\n existingBySource.set(`${e.sourceMemoryId}\\u{0000}${e.supersessionKey ?? \"\"}`, e.id);\n }\n }\n const rebuilt: TombstoneEntry[] = retiredMemories.map((m) => ({\n id:\n existingBySource.get(`${m.memoryId}\\u{0000}${m.supersessionKey ?? \"\"}`) ??\n newTombstoneId(),\n kind: \"tombstone\" as const,\n reason: m.reason,\n sourceMemoryId: m.memoryId,\n contentHash: m.contentHash ?? this.options.hashContent(m.rawContent),\n normalizedText: this.options.normalizeText(m.rawContent),\n ...(m.entityRef ? { entityRef: m.entityRef } : {}),\n ...(m.supersessionKey ? { supersessionKey: m.supersessionKey } : {}),\n namespace: this.namespace,\n createdAt: m.createdAt,\n createdBy: m.createdBy,\n }));\n // Sort deterministically (rule 38): createdAt, then id for stability.\n rebuilt.sort((a, b) =>\n a.createdAt === b.createdAt\n ? a.id < b.id ? -1 : a.id > b.id ? 1 : 0\n : a.createdAt < b.createdAt ? -1 : 1,\n );\n const all = [...rebuilt, ...existingRevocations, ...foreignTombstones].sort((a, b) =>\n a.createdAt === b.createdAt\n ? a.id < b.id ? -1 : a.id > b.id ? 1 : 0\n : a.createdAt < b.createdAt ? -1 : 1,\n );\n const serialized =\n all.map((e) => JSON.stringify(e)).join(\"\\n\") + (all.length > 0 ? \"\\n\" : \"\");\n await this.io.write(this.filePath, serialized);\n // Update the in-memory index under the same lock so it stays consistent\n // with the file we just wrote (no window for a lookup to see a stale\n // index that misses a just-rebuilt entry).\n this.resetIndex();\n for (const entry of all) this.indexEntry(entry);\n this.corruptedLines = 0;\n this.loaded = true;\n this.markWritten();\n return rebuilt.length;\n }),\n );\n return rebuiltCount;\n }\n}\n\n/** A retired memory projected into the shape `TombstoneStore.rebuild` consumes. */\nexport interface RetiredMemoryRecord {\n memoryId: string;\n rawContent: string;\n entityRef?: string;\n supersessionKey?: string;\n reason: TombstoneReason;\n createdBy: TombstoneCreatedBy;\n createdAt: string;\n /** Canonical contentHash from the retired memory's frontmatter (#1579). */\n contentHash?: string;\n}\n\n/**\n * Project a corpus of memories into the retired-memory records `rebuild`\n * consumes. Pure (no I/O) so the StorageManager wiring stays thin (#1579,\n * #1520 god-file ratchet). Only superseded / forgotten / rejected FACTS\n * participate — entities, questions, and artifacts have their own lifecycle\n * (issue pitfall). The supersession key is derived from structured attributes\n * via the injected helper so there is one keyed-tier definition (rule 23).\n */\nexport function collectRetiredMemoriesForRebuild(\n memories: ReadonlyArray<{\n frontmatter: {\n id: string;\n status?: string;\n category?: string;\n contentHash?: string;\n entityRef?: string;\n structuredAttributes?: Record<string, string>;\n updated?: string;\n created?: string;\n };\n content: string;\n }>,\n deps: {\n /** Strip citation annotations from the body before hashing/normalizing. */\n stripCitation: (text: string) => string;\n /** Derive the keyed-tier supersession key (one helper, rule 23). */\n supersessionKeysForFact: (spec: {\n entityRef?: string;\n structuredAttributes?: Record<string, string>;\n }) => string[];\n },\n): RetiredMemoryRecord[] {\n const retired: RetiredMemoryRecord[] = [];\n for (const m of memories) {\n const status = m.frontmatter.status;\n if (status !== \"superseded\" && status !== \"rejected\" && status !== \"forgotten\") continue;\n if (m.frontmatter.category !== \"fact\") continue;\n const reason: TombstoneReason =\n status === \"superseded\" ? \"supersession\" : status === \"forgotten\" ? \"retraction\" : \"correction\";\n const createdBy: TombstoneCreatedBy =\n reason === \"supersession\" ? \"supersession\" : \"user_correction\";\n const entityRef = m.frontmatter.entityRef;\n const keys =\n entityRef && m.frontmatter.structuredAttributes\n ? deps.supersessionKeysForFact({\n entityRef,\n structuredAttributes: m.frontmatter.structuredAttributes,\n })\n : [];\n // Issue #1579 thread Ocgjz: emit one record per matched supersession key\n // (not just keys[0]) so rebuild reproduces the same keyed tombstones as\n // live temporal-supersession (which now appends one per key — thread ObteS).\n // Without this, a rebuild would under-rebuild the JSONL and keyed-tier\n // blocks would disappear until rediscovered.\n const keysToEmit = keys.length > 0 ? keys : [undefined];\n for (const key of keysToEmit) {\n retired.push({\n memoryId: m.frontmatter.id,\n rawContent: deps.stripCitation(m.content),\n contentHash: m.frontmatter.contentHash,\n ...(entityRef ? { entityRef } : {}),\n ...(key ? { supersessionKey: key } : {}),\n reason,\n createdBy,\n createdAt: m.frontmatter.updated || m.frontmatter.created || new Date().toISOString(),\n });\n }\n }\n return retired;\n}\n\n/**\n * One-shot write-time resurrection gate (issue #1579 / #2213). Looks up the\n * fact's identity in the tombstone store and, on a match, downgrades the\n * frontmatter to `pending_review` + `blockedBy` IN PLACE. ADD-ONLY: an\n * already-blocked or terminal-status record is left untouched. Pure over its\n * inputs (no I/O beyond the injected store) so both `writeMemory`'s gate and\n * the chunk-repair re-gate share one lookup + apply.\n */\nexport function applyTombstoneResurrectionGate(\n store: Pick<TombstoneStore, \"lookup\">,\n fm: {\n id: string;\n status?: string;\n blockedBy?: string;\n tombstoneBlockTier?: TombstoneMatchTier;\n entityRef?: string;\n contentHash?: string;\n },\n query: {\n normalizedText: string;\n supersessionKeys: string[];\n namespace: string;\n },\n): TombstoneMatch | null {\n if (fm.status === \"pending_review\" && fm.blockedBy) return null;\n if (!(fm.status === undefined || fm.status === \"active\" || fm.status === \"pending_review\")) return null;\n const match = store.lookup({\n contentHash: fm.contentHash,\n normalizedText: query.normalizedText,\n ...(fm.entityRef ? { entityRef: fm.entityRef } : {}),\n ...(query.supersessionKeys.length > 0 ? { supersessionKeys: query.supersessionKeys } : {}),\n namespace: query.namespace,\n });\n if (!match) return null;\n fm.status = \"pending_review\";\n fm.blockedBy = match.tombstoneId;\n fm.tombstoneBlockTier = match.matchedTier;\n return match;\n}\n\n/**\n * Build the live-emission tombstone inputs for a single retired FACT — one\n * input per derived supersession key (or a single keyless record when no\n * structured attributes are present). Pure (no I/O) so the emitters in\n * `StorageManager.supersedeMemory` (contradiction) and `forgetMemory`\n * (retraction) stay thin (#1579, #1520 god-file ratchet). Mirrors the\n * temporal-supersession emitter and `collectRetiredMemoriesForRebuild` so\n * every retire path emits the same keyed-tombstone shape (issue #1579\n * threads Oci-Y / OchiF: without per-key tombstones, a paraphrased\n * re-observation missed the keyed tier and the fact resurrected active).\n */\nexport function buildRetiredFactTombstoneInputs(\n memory: {\n id: string;\n content: string;\n contentHash?: string;\n entityRef?: string;\n structuredAttributes?: Record<string, string>;\n },\n opts: {\n reason: TombstoneReason;\n createdBy: TombstoneCreatedBy;\n createdAt: string;\n supersessionKeysForFact: (spec: {\n entityRef?: string;\n structuredAttributes?: Record<string, string>;\n }) => string[];\n },\n): Array<{\n reason: TombstoneReason;\n createdBy: TombstoneCreatedBy;\n sourceMemoryId: string;\n rawContent: string;\n contentHash?: string;\n entityRef?: string;\n supersessionKey?: string;\n createdAt: string;\n}> {\n const keys =\n memory.entityRef && memory.structuredAttributes\n ? opts.supersessionKeysForFact({\n entityRef: memory.entityRef,\n structuredAttributes: memory.structuredAttributes,\n })\n : [];\n const keysToEmit = keys.length > 0 ? keys : [undefined];\n return keysToEmit.map((key) => ({\n reason: opts.reason,\n createdBy: opts.createdBy,\n sourceMemoryId: memory.id,\n rawContent: memory.content,\n ...(memory.contentHash ? { contentHash: memory.contentHash } : {}),\n ...(memory.entityRef ? { entityRef: memory.entityRef } : {}),\n ...(key ? { supersessionKey: key } : {}),\n createdAt: opts.createdAt,\n }));\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/structured-attributes.ts"],"sourcesContent":["/**\n * Shared helpers for the `\\n[Attributes: …]` enrichment suffix that\n * `writeMemory` appends to a stored body when `structuredAttributes` are\n * present.\n *\n * Extracted here (out of `storage.ts`) so every reader — the storage\n * manager, the wearable service, and the coding surfaces — strips the suffix\n * with ONE definition. Previously `coding/architecture-surfaces.ts` carried a\n * weaker local copy that only checked the trailing `]`, which could truncate\n * card markdown that legitimately ends in a `[Attributes: …]` line (cursor\n * review: duplicate attribute suffix stripper).\n *\n * String operations, not regex — CodeQL `js/polynomial-redos` flags\n * suffix-anchored patterns over library-supplied content.\n */\n\nimport { sanitizeMemoryContent } from \"./sanitize.js\";\n\n/**\n * Remove the `[Attributes: …]` suffix `writeMemory` appends to the stored\n * body when structuredAttributes are present, yielding the raw fact/card text\n * for content comparison or client display. Inverse companion of\n * `normalizeAttributePairs` enrichment in `storage.ts`.\n *\n * Returns the stripped (trimmed) body when the marker opens the final\n * non-empty line and its inner payload contains no premature `]` or newline\n * (mirrors the exact shape `normalizeAttributePairs` emits). Otherwise\n * returns the trimmed input unchanged — never truncates legitimate content.\n */\nexport function stripAttributesSuffix(content: string): string {\n const trimmed = content.trimEnd();\n if (!trimmed.endsWith(\"]\")) return content.trim();\n const marker = \"\\n[Attributes: \";\n const markerIndex = trimmed.lastIndexOf(marker);\n if (markerIndex === -1) return content.trim();\n // The block must be the FINAL line and contain no \"]\" before the\n // closing bracket (mirrors the shape normalizeAttributePairs emits).\n const inner = trimmed.slice(markerIndex + marker.length, -1);\n if (inner.includes(\"]\") || inner.includes(\"\\n\")) return content.trim();\n return trimmed.slice(0, markerIndex).trim();\n}\n// ---------------------------------------------------------------------------\n// Persisted-body assembly (issue #1989 PR2)\n// ---------------------------------------------------------------------------\n//\n// `writeMemory` historically enriched content with the attribute suffix and\n// then sanitized the COMBINED body inline. That assembly is the persisted\n// form both the file body and write-idempotency fingerprints must agree on\n// (AGENTS.md §13), so it lives here — shared by `StorageManager.writeMemory`\n// and `composeMemoryEnvelope` — instead of existing twice.\n\n/**\n * Canonical `key: value; …` rendering of structured attributes. Keys are\n * trimmed + lowercased, values trimmed, pairs sorted by normalized key.\n * Moved verbatim from `storage.ts` (which re-exports it for API stability);\n * used at the write path, the dedup-lookup path, and envelope assembly.\n */\nexport function normalizeAttributePairs(pairs: Record<string, string>): string {\n return Object.entries(pairs)\n .map(([k, v]) => [k.trim().toLowerCase(), v.trim()] as [string, string])\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([k, v]) => `${k}: ${v}`)\n .join(\"; \");\n}\n\nexport interface AssembledPersistBody {\n /** The exact body persistence writes: enriched then sanitized. */\n text: string;\n /** False when sanitization redacted injection-bearing text. */\n clean: boolean;\n /** Matched injection pattern sources (for the storage warn log). */\n violations: string[];\n}\n\n/**\n * Assemble the persisted body exactly as `writeMemory` does: append the\n * normalized attribute suffix when attributes are present, then sanitize the\n * combined result. ONE definition — byte-identity between the legacy write\n * path and the sealed-envelope path is structural, not tested-by-hope.\n */\nexport function assemblePersistedBody(\n content: string,\n structuredAttributes?: Record<string, string>,\n): AssembledPersistBody {\n let enriched = content;\n if (structuredAttributes && Object.keys(structuredAttributes).length > 0) {\n enriched = `${content}\\n[Attributes: ${normalizeAttributePairs(structuredAttributes)}]`;\n }\n const sanitized = sanitizeMemoryContent(enriched);\n return { text: sanitized.text, clean: sanitized.clean, violations: sanitized.violations };\n}\n"],"mappings":";;;;;AA6BO,SAAS,sBAAsB,SAAyB;AAC7D,QAAM,UAAU,QAAQ,QAAQ;AAChC,MAAI,CAAC,QAAQ,SAAS,GAAG,EAAG,QAAO,QAAQ,KAAK;AAChD,QAAM,SAAS;AACf,QAAM,cAAc,QAAQ,YAAY,MAAM;AAC9C,MAAI,gBAAgB,GAAI,QAAO,QAAQ,KAAK;AAG5C,QAAM,QAAQ,QAAQ,MAAM,cAAc,OAAO,QAAQ,EAAE;AAC3D,MAAI,MAAM,SAAS,GAAG,KAAK,MAAM,SAAS,IAAI,EAAG,QAAO,QAAQ,KAAK;AACrE,SAAO,QAAQ,MAAM,GAAG,WAAW,EAAE,KAAK;AAC5C;AAiBO,SAAS,wBAAwB,OAAuC;AAC7E,SAAO,OAAO,QAAQ,KAAK,EACxB,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,YAAY,GAAG,EAAE,KAAK,CAAC,CAAqB,EACtE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,EACrC,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,EAAE,EAC5B,KAAK,IAAI;AACd;AAiBO,SAAS,sBACd,SACA,sBACsB;AACtB,MAAI,WAAW;AACf,MAAI,wBAAwB,OAAO,KAAK,oBAAoB,EAAE,SAAS,GAAG;AACxE,eAAW,GAAG,OAAO;AAAA,eAAkB,wBAAwB,oBAAoB,CAAC;AAAA,EACtF;AACA,QAAM,YAAY,sBAAsB,QAAQ;AAChD,SAAO,EAAE,MAAM,UAAU,MAAM,OAAO,UAAU,OAAO,YAAY,UAAU,WAAW;AAC1F;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/reconcile/manifest.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { inferMemoryStatus } from \"../memory-lifecycle-ledger-utils.js\";\nimport { ContentHashIndex, type ContentHashPathEntry } from \"../storage/content-hash-index.js\";\nimport type { MemoryFrontmatter, MemoryStatus } from \"../types.js\";\nimport { RECALL_FALLBACK_DIRS } from \"../utils/category-dir.js\";\nimport {\n type ReconcileFileState,\n type ReconcilePlan,\n type ReconcilePlanEntry,\n type ReconcileSemanticAgreement,\n type ReconcileSemanticChange,\n summarizeReconcilePlan,\n} from \"./plan.js\";\n\nexport const RECONCILE_MANIFEST_FORMAT = \"remnic-reconcile-manifest\";\nexport const RECONCILE_MANIFEST_SCHEMA_VERSION = 1;\n\nexport interface ReconcileMemoryIdentity {\n id: string;\n category: string;\n contentHash: string;\n status: MemoryStatus;\n}\n\nexport interface ReconcileManifestFile extends ReconcileFileState {\n memory?: ReconcileMemoryIdentity;\n}\n\ntype ActiveFactManifestFile = ReconcileManifestFile & { memory: ReconcileMemoryIdentity };\n\nexport interface ReconcileManifest {\n format: typeof RECONCILE_MANIFEST_FORMAT;\n schemaVersion: typeof RECONCILE_MANIFEST_SCHEMA_VERSION;\n files: ReconcileManifestFile[];\n}\n\nexport type ReconcileMemoryParser = (\n raw: string,\n) => { frontmatter: MemoryFrontmatter; content: string } | null;\n\nexport interface BuildReconcileManifestOptions {\n files: Iterable<ReconcileFileState>;\n readFile: (file: ReconcileFileState) => Promise<Buffer | string | null>;\n parseMemory: ReconcileMemoryParser;\n cachedFiles?: Iterable<ReconcileManifestFile>;\n}\n\nconst SHA256_PATTERN = /^[a-f0-9]{64}$/i;\nconst MEMORY_DIRS = new Set(RECALL_FALLBACK_DIRS);\n\nfunction isMemoryPath(filePath: string): boolean {\n if (!filePath.endsWith(\".md\")) return false;\n const segments = filePath.split(\"/\");\n let index = 0;\n if (segments[index] === \"cold\" || segments[index] === \"archive\") index += 1;\n return MEMORY_DIRS.has(segments[index] ?? \"\");\n}\n\n\nfunction parsedMemoryIdentity(\n filePath: string,\n raw: Buffer | string,\n parseMemory: ReconcileMemoryParser,\n): ReconcileMemoryIdentity | undefined {\n if (!isMemoryPath(filePath)) return undefined;\n const parsed = parseMemory(Buffer.isBuffer(raw) ? raw.toString(\"utf8\") : raw);\n if (!parsed?.frontmatter.id) return undefined;\n const storedHash = parsed.frontmatter.contentHash;\n const contentHash =\n storedHash && SHA256_PATTERN.test(storedHash)\n ? storedHash.toLowerCase()\n : ContentHashIndex.computeHash(parsed.content);\n return {\n id: parsed.frontmatter.id,\n category: parsed.frontmatter.category,\n contentHash,\n status: inferMemoryStatus(parsed.frontmatter, filePath),\n };\n}\n\nexport async function buildReconcileManifestFile(\n file: ReconcileFileState,\n readFile: (file: ReconcileFileState) => Promise<Buffer | string | null>,\n parseMemory: ReconcileMemoryParser,\n): Promise<ReconcileManifestFile> {\n let raw: Buffer | string | null = null;\n if (isMemoryPath(file.path)) {\n try {\n raw = await readFile(file);\n } catch {\n raw = null;\n }\n }\n if (raw !== null && createHash(\"sha256\").update(raw).digest(\"hex\") !== file.sha256.toLowerCase()) {\n raw = null;\n }\n const memory = raw === null ? undefined : parsedMemoryIdentity(file.path, raw, parseMemory);\n return { ...file, ...(memory ? { memory } : {}) };\n}\n\nexport async function buildReconcileManifest(options: BuildReconcileManifestOptions): Promise<ReconcileManifest> {\n const cachedByPath = new Map<string, ReconcileManifestFile>();\n for (const cached of options.cachedFiles ?? []) {\n cachedByPath.set(cached.path, cached);\n }\n\n const files: ReconcileManifestFile[] = [];\n for (const file of options.files) {\n const cached = cachedByPath.get(file.path);\n if (cached?.sha256.toLowerCase() === file.sha256.toLowerCase()) {\n files.push({ ...file, ...(cached.memory ? { memory: cached.memory } : {}) });\n continue;\n }\n\n files.push(await buildReconcileManifestFile(file, options.readFile, options.parseMemory));\n }\n files.sort((left, right) => (left.path < right.path ? -1 : left.path > right.path ? 1 : 0));\n return {\n format: RECONCILE_MANIFEST_FORMAT,\n schemaVersion: RECONCILE_MANIFEST_SCHEMA_VERSION,\n files,\n };\n}\n\nfunction activeFactByPath(manifest: ReconcileManifest | undefined): Map<string, ActiveFactManifestFile> {\n const result = new Map<string, ActiveFactManifestFile>();\n for (const file of manifest?.files ?? []) {\n if (file.memory?.category === \"fact\" && file.memory.status === \"active\") {\n result.set(file.path, file as ActiveFactManifestFile);\n }\n }\n return result;\n}\n\nfunction contentHashRows(files: Iterable<ActiveFactManifestFile>): ContentHashPathEntry[] {\n const rows: ContentHashPathEntry[] = [];\n for (const file of files) {\n rows.push({ path: file.path, contentHash: file.memory.contentHash });\n }\n return rows;\n}\n\nfunction comparePlanEntries(left: ReconcilePlanEntry, right: ReconcilePlanEntry): number {\n if (left.namespace !== right.namespace) return left.namespace < right.namespace ? -1 : 1;\n return left.path < right.path ? -1 : left.path > right.path ? 1 : 0;\n}\n\nfunction semanticAgreementKey(agreement: ReconcileSemanticAgreement): string {\n return `${agreement.local.path}\\0${agreement.peer.path}`;\n}\n\nfunction classifySemanticChange(\n current: ReconcileSemanticAgreement,\n prior: ReconcileSemanticAgreement | undefined\n): ReconcileSemanticChange {\n if (!prior) return \"unchanged\";\n const localChanged = current.local.sha256 !== prior.local.sha256;\n const peerChanged = current.peer.sha256 !== prior.peer.sha256;\n if (localChanged && peerChanged) return \"both_modified\";\n if (localChanged) return \"local_changed\";\n if (peerChanged) return \"peer_changed\";\n return \"unchanged\";\n}\n\nexport function collapseActiveFactDuplicates(\n plan: ReconcilePlan,\n localManifests: ReadonlyMap<string, ReconcileManifest>,\n peerManifests: ReadonlyMap<string, ReconcileManifest>,\n priorSemanticAgreements?: ReadonlyMap<string, readonly ReconcileSemanticAgreement[]>,\n): ReconcilePlan {\n const entriesByNamespace = new Map<string, ReconcilePlanEntry[]>();\n for (const entry of plan.entries) {\n const entries = entriesByNamespace.get(entry.namespace) ?? [];\n entries.push({ ...entry });\n entriesByNamespace.set(entry.namespace, entries);\n }\n\n let changed = false;\n for (const namespace of new Set([...localManifests.keys(), ...peerManifests.keys()])) {\n const entries = entriesByNamespace.get(namespace) ?? [];\n const localManifest = localManifests.get(namespace);\n const peerManifest = peerManifests.get(namespace);\n const localByPath = activeFactByPath(localManifest);\n const peerByPath = activeFactByPath(peerManifest);\n const localFilesByPath = new Map((localManifest?.files ?? []).map((file) => [file.path, file]));\n const peerFilesByPath = new Map((peerManifest?.files ?? []).map((file) => [file.path, file]));\n const priorSemanticByPathPair = new Map(\n (priorSemanticAgreements?.get(namespace) ?? []).map((agreement) => [\n semanticAgreementKey(agreement),\n agreement,\n ])\n );\n const localByHash = new Map<string, ActiveFactManifestFile[]>();\n const peerByHash = new Map<string, ActiveFactManifestFile[]>();\n\n for (const file of localByPath.values()) {\n const hash = file.memory.contentHash;\n const bucket = localByHash.get(hash) ?? [];\n bucket.push(file);\n localByHash.set(hash, bucket);\n }\n for (const file of peerByPath.values()) {\n const hash = file.memory.contentHash;\n const bucket = peerByHash.get(hash) ?? [];\n bucket.push(file);\n peerByHash.set(hash, bucket);\n }\n\n const removed = new Set<ReconcilePlanEntry>();\n const replacements: ReconcilePlanEntry[] = [];\n for (const hash of new Set([...localByHash.keys(), ...peerByHash.keys()])) {\n const localCandidates = (localByHash.get(hash) ?? []).filter((file) => {\n const opposite = peerFilesByPath.get(file.path);\n const activeOpposite = peerByPath.get(file.path);\n return opposite === undefined || activeOpposite?.memory.contentHash === hash;\n });\n const peerCandidates = (peerByHash.get(hash) ?? []).filter((file) => {\n const opposite = localFilesByPath.get(file.path);\n const activeOpposite = localByPath.get(file.path);\n return opposite === undefined || activeOpposite?.memory.contentHash === hash;\n });\n const localPath = ContentHashIndex.resolvePathByHash(hash, contentHashRows(localCandidates));\n const peerPath = ContentHashIndex.resolvePathByHash(hash, contentHashRows(peerCandidates));\n\n if (localPath && peerPath && localPath !== peerPath) {\n const localFile = localByPath.get(localPath);\n const peerFile = peerByPath.get(peerPath);\n if (!localFile || !peerFile) continue;\n const duplicatePaths = new Set([\n ...localCandidates.map((file) => file.path),\n ...peerCandidates.map((file) => file.path),\n ]);\n const authoritativeSamePathEntries = new Set(entries.filter(\n (entry) =>\n duplicatePaths.has(entry.path)\n && localFilesByPath.has(entry.path)\n && peerFilesByPath.has(entry.path)\n && entry.action !== \"identical\"\n ));\n if (authoritativeSamePathEntries.size > 0) {\n for (const entry of entries) {\n if (\n duplicatePaths.has(entry.path)\n && !authoritativeSamePathEntries.has(entry)\n && (entry.action === \"pull\" || entry.action === \"push\" || entry.action === \"identical\")\n ) {\n removed.add(entry);\n changed = true;\n }\n }\n continue;\n }\n const unsafeEntry = entries.some(\n (entry) => duplicatePaths.has(entry.path) && (entry.action === \"suppress\" || entry.action === \"conflict\")\n );\n if (unsafeEntry) continue;\n for (const entry of entries) {\n if (\n duplicatePaths.has(entry.path) &&\n (entry.action === \"pull\" || entry.action === \"push\" || entry.action === \"identical\")\n ) {\n removed.add(entry);\n }\n }\n const semanticAgreement: ReconcileSemanticAgreement = {\n local: { path: localPath, sha256: localFile.sha256 },\n peer: { path: peerPath, sha256: peerFile.sha256 },\n };\n replacements.push({\n path: localPath < peerPath ? localPath : peerPath,\n namespace,\n action: \"identical\",\n reason: \"semantic_duplicate\",\n semanticAgreement,\n semanticChange: classifySemanticChange(\n semanticAgreement,\n priorSemanticByPathPair.get(semanticAgreementKey(semanticAgreement))\n ),\n });\n changed = true;\n continue;\n }\n\n const sameSideEntries = entries.filter((entry) => {\n if (localPath && entry.reason === \"local_only\") {\n return localCandidates.some((file) => file.path === entry.path);\n }\n if (peerPath && entry.reason === \"peer_only\") {\n return peerCandidates.some((file) => file.path === entry.path);\n }\n return false;\n });\n const canonicalPath = localPath ?? peerPath;\n const hasSharedCanonical = localPath !== undefined && localPath === peerPath;\n if (!canonicalPath || sameSideEntries.length === 0 || (!hasSharedCanonical && sameSideEntries.length < 2)) {\n continue;\n }\n for (const entry of sameSideEntries) {\n if (entry.path !== canonicalPath) {\n removed.add(entry);\n changed = true;\n }\n }\n }\n\n if (removed.size > 0 || replacements.length > 0) {\n entriesByNamespace.set(\n namespace,\n [...entries.filter((entry) => !removed.has(entry)), ...replacements].sort(comparePlanEntries)\n );\n }\n }\n\n if (!changed) return plan;\n const entries = [...entriesByNamespace.values()].flat().sort(comparePlanEntries);\n return {\n entries,\n byNamespace: summarizeReconcilePlan(entries),\n converged: entries.every((entry) => entry.action === \"identical\"),\n };\n}\n"],"mappings":"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","names":["entries"]}
@@ -1,14 +0,0 @@
1
- // src/content-hash.ts
2
- import { createHash } from "crypto";
3
- function normalizeContent(content) {
4
- return content.toLowerCase().replace(/[^a-z0-9\s]/g, " ").replace(/\s+/g, " ").trim();
5
- }
6
- function computeContentHash(content) {
7
- return createHash("sha256").update(normalizeContent(content)).digest("hex");
8
- }
9
-
10
- export {
11
- normalizeContent,
12
- computeContentHash
13
- };
14
- //# sourceMappingURL=chunk-W5H6ZRPT.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/content-hash.ts"],"sourcesContent":["/**\n * content-hash.ts — standalone content normalization + SHA-256 hashing.\n *\n * Extracted from `ContentHashIndex` (storage.ts) so correction modules and\n * other consumers can hash content WITHOUT importing the storage god file\n * (issue #1533 directStorageImports ratchet). The static methods on\n * `ContentHashIndex` delegate here to guarantee identical results.\n */\n\nimport { createHash } from \"node:crypto\";\n\n/** Normalize content: lowercase, strip non-alphanumerics, collapse whitespace. */\nexport function normalizeContent(content: string): string {\n return content\n .toLowerCase()\n .replace(/[^a-z0-9\\s]/g, \" \")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\n/** Normalize content and compute SHA-256 hash. */\nexport function computeContentHash(content: string): string {\n return createHash(\"sha256\").update(normalizeContent(content)).digest(\"hex\");\n}\n"],"mappings":";AASA,SAAS,kBAAkB;AAGpB,SAAS,iBAAiB,SAAyB;AACxD,SAAO,QACJ,YAAY,EACZ,QAAQ,gBAAgB,GAAG,EAC3B,QAAQ,QAAQ,GAAG,EACnB,KAAK;AACV;AAGO,SAAS,mBAAmB,SAAyB;AAC1D,SAAO,WAAW,QAAQ,EAAE,OAAO,iBAAiB,OAAO,CAAC,EAAE,OAAO,KAAK;AAC5E;","names":[]}