@remnic/core 10.0.47 → 10.0.49

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 (335) hide show
  1. package/dist/access-admin-ops-surface.js +63 -61
  2. package/dist/access-audit.js +2 -2
  3. package/dist/access-authorization-probe.js +64 -62
  4. package/dist/access-boundary.js +63 -61
  5. package/dist/access-cli.js +144 -142
  6. package/dist/access-cli.js.map +1 -1
  7. package/dist/access-extraction-force-flush.js +63 -61
  8. package/dist/access-http-briefing.js +64 -62
  9. package/dist/access-http-query.js +65 -63
  10. package/dist/access-http.js +85 -83
  11. package/dist/access-identity-continuity-surface.js +63 -61
  12. package/dist/access-lcm-surface.js +63 -61
  13. package/dist/access-mcp.js +74 -72
  14. package/dist/access-namespace-preflight.js +63 -61
  15. package/dist/access-observe-write-category.js +11 -10
  16. package/dist/access-observe-write-surface.js +63 -61
  17. package/dist/access-offline-manifest.js +8 -7
  18. package/dist/access-operations-batch.js +66 -64
  19. package/dist/access-operations.js +73 -71
  20. package/dist/access-recall-concurrency.js +63 -61
  21. package/dist/access-recall-response.js +63 -61
  22. package/dist/access-recall-surface.js +63 -61
  23. package/dist/access-schema.js +10 -9
  24. package/dist/access-service.d.ts.map +1 -1
  25. package/dist/access-service.js +63 -61
  26. package/dist/access-surface-catalog.js +65 -63
  27. package/dist/access-surface-catalog.js.map +1 -1
  28. package/dist/active-recall.js +23 -21
  29. package/dist/active-recall.js.map +1 -1
  30. package/dist/adapters/index.js +4 -4
  31. package/dist/adapters/registry.js +2 -2
  32. package/dist/briefing.js +13 -12
  33. package/dist/buffer.js +5 -5
  34. package/dist/calibration.js +3 -3
  35. package/dist/{capsule-crypto-GWVG7LGC.js → capsule-crypto-7FJQINUR.js} +2 -2
  36. package/dist/capture-write-lock-scope.d.ts +7 -0
  37. package/dist/capture-write-lock-scope.d.ts.map +1 -0
  38. package/dist/capture-write-lock-scope.js +10 -0
  39. package/dist/causal-behavior.js +2 -2
  40. package/dist/causal-chain.js +2 -2
  41. package/dist/causal-consolidation.js +16 -15
  42. package/dist/causal-consolidation.js.map +1 -1
  43. package/dist/causal-retrieval.js +2 -2
  44. package/dist/causal-trajectory-graph.js +3 -3
  45. package/dist/causal-trajectory.js +1 -1
  46. package/dist/{chunk-J6B6FK2X.js → chunk-2BY56HE6.js} +43 -43
  47. package/dist/{chunk-ME5LVISI.js → chunk-2J6BIOVN.js} +2 -2
  48. package/dist/{chunk-EIYJK7OD.js → chunk-2M36PR7R.js} +2 -2
  49. package/dist/{chunk-OWHERGF2.js → chunk-2NLLXCJG.js} +2 -2
  50. package/dist/{chunk-WOPZ2P5Z.js → chunk-3INLTKTW.js} +2 -2
  51. package/dist/{chunk-6P6MZDBL.js → chunk-3NL4ALUP.js} +2 -2
  52. package/dist/{chunk-YUE7J2HZ.js → chunk-3NYIXVCT.js} +2 -2
  53. package/dist/{chunk-B44NFHWI.js → chunk-3PVKV3XL.js} +2 -2
  54. package/dist/{chunk-H7BZBSP6.js → chunk-52II7PB6.js} +4 -4
  55. package/dist/{chunk-5KGYR5VN.js → chunk-5DVOBBTV.js} +2 -2
  56. package/dist/{chunk-WCGJK4NQ.js → chunk-5FNZ3G6X.js} +10 -10
  57. package/dist/{chunk-IJH6METJ.js → chunk-5IDQVE4U.js} +5 -5
  58. package/dist/{chunk-OXSTKCYK.js → chunk-6AEKSOWV.js} +33 -5
  59. package/dist/chunk-6AEKSOWV.js.map +1 -0
  60. package/dist/{chunk-2DPJFJFH.js → chunk-6TIVVOVU.js} +10 -10
  61. package/dist/{chunk-L46MG2GE.js → chunk-6W3QH3QW.js} +17 -14
  62. package/dist/chunk-6W3QH3QW.js.map +1 -0
  63. package/dist/{chunk-BUKK5SWA.js → chunk-7LCGFUMB.js} +4 -4
  64. package/dist/chunk-7VLBZKNB.js +26 -0
  65. package/dist/chunk-7VLBZKNB.js.map +1 -0
  66. package/dist/{chunk-CHSRA76M.js → chunk-7XFQSQYS.js} +2 -2
  67. package/dist/{chunk-A45QXZMU.js → chunk-A3WXV7YU.js} +2 -2
  68. package/dist/{chunk-LXN737FX.js → chunk-AAANTXCQ.js} +2 -2
  69. package/dist/{chunk-JNLYHJG7.js → chunk-AF4UIHON.js} +9 -9
  70. package/dist/{chunk-JGMJZBFV.js → chunk-AGCEJDG2.js} +2 -2
  71. package/dist/{chunk-I3IPXGFQ.js → chunk-AJJPXUE6.js} +4 -4
  72. package/dist/{chunk-KAUCVTAW.js → chunk-BJTFLP3J.js} +2 -2
  73. package/dist/{chunk-QR6W3FSW.js → chunk-BMG3SAXA.js} +3 -3
  74. package/dist/{chunk-QE2XQM3S.js → chunk-BWF3KNSQ.js} +2 -2
  75. package/dist/{chunk-BCDECPVO.js → chunk-C3HRYVGD.js} +2 -2
  76. package/dist/{chunk-RQLTCHUL.js → chunk-C7WDWD35.js} +10 -10
  77. package/dist/{chunk-YL564QS2.js → chunk-CMOYD5CA.js} +3 -3
  78. package/dist/{chunk-4J7BNL7B.js → chunk-CPBYKOTC.js} +2 -2
  79. package/dist/{chunk-PPDNG7WC.js → chunk-CRJX4OMN.js} +2 -2
  80. package/dist/{chunk-YFJHFEET.js → chunk-D76AHITY.js} +2 -2
  81. package/dist/{chunk-ZX5N5D6M.js → chunk-DAOMWGO2.js} +4 -4
  82. package/dist/{chunk-2RQR4TXV.js → chunk-DM6SOROF.js} +2 -2
  83. package/dist/{chunk-VWJ56T63.js → chunk-E3DL3CAL.js} +2 -2
  84. package/dist/{chunk-M7LA4QBY.js → chunk-E47UQBYW.js} +3 -3
  85. package/dist/{chunk-23ZMQONL.js → chunk-ERMT5WQM.js} +2 -2
  86. package/dist/{chunk-FAKRTS3Y.js → chunk-ESDOQEJM.js} +2 -2
  87. package/dist/{chunk-VTCNVGM6.js → chunk-FOKTW6GY.js} +2 -2
  88. package/dist/{chunk-TF5NZGPS.js → chunk-FYZXZUGU.js} +2 -2
  89. package/dist/{chunk-XTN54NML.js → chunk-G3T6YMBO.js} +4 -4
  90. package/dist/{chunk-2JNBPOZ2.js → chunk-GDYLZ6FR.js} +3 -3
  91. package/dist/{chunk-DZPTR2XQ.js → chunk-GFAEKSFR.js} +2 -2
  92. package/dist/{chunk-GLZWOIU3.js → chunk-HCPVL6SF.js} +3 -3
  93. package/dist/{chunk-NDMPRT3Z.js → chunk-HDT3DMUF.js} +2 -2
  94. package/dist/{chunk-BWRX322G.js → chunk-HI53EK3Y.js} +2 -2
  95. package/dist/{chunk-BFPF5N3H.js → chunk-HXFIILGF.js} +4 -4
  96. package/dist/chunk-JNA7LFMQ.js +41 -0
  97. package/dist/chunk-JNA7LFMQ.js.map +1 -0
  98. package/dist/{chunk-2V664H6O.js → chunk-JS44PBCM.js} +5 -5
  99. package/dist/{chunk-XKTHJHSQ.js → chunk-JZCBMKR5.js} +3 -3
  100. package/dist/{chunk-KRACAE73.js → chunk-KMTMMBEB.js} +6 -6
  101. package/dist/{chunk-FJ264QBP.js → chunk-KNCR7APE.js} +5 -5
  102. package/dist/{chunk-WUBGMV3G.js → chunk-KRAMCBIW.js} +9 -9
  103. package/dist/{chunk-DRXTMDAG.js → chunk-LCHFINL4.js} +2 -2
  104. package/dist/{chunk-PJBYVJKO.js → chunk-LXXIV7Y2.js} +2 -2
  105. package/dist/{chunk-6CC2YCKG.js → chunk-MCS4LIXP.js} +2 -2
  106. package/dist/{chunk-2NX7JTST.js → chunk-MPWOAIIH.js} +2 -2
  107. package/dist/{chunk-CMNL3QSL.js → chunk-N5PISU26.js} +2 -2
  108. package/dist/{chunk-PKPOO6X5.js → chunk-N6EM7ESC.js} +16 -16
  109. package/dist/{chunk-FWV2SXSL.js → chunk-NH37SP6V.js} +64 -64
  110. package/dist/{chunk-MZCTS3ZG.js → chunk-NMOEOQV4.js} +2 -2
  111. package/dist/{chunk-VECRSYQG.js → chunk-NRGQ5HJO.js} +1 -1
  112. package/dist/{chunk-3DKKZVXS.js → chunk-NUK5XU3P.js} +5 -5
  113. package/dist/{chunk-YBKQAVPZ.js → chunk-O4CA53UY.js} +77 -63
  114. package/dist/chunk-O4CA53UY.js.map +1 -0
  115. package/dist/{chunk-FPANDKMQ.js → chunk-O7GNSHFF.js} +2 -2
  116. package/dist/{chunk-5R2IF2KI.js → chunk-OD7ZXCUF.js} +4 -4
  117. package/dist/{chunk-RT2GN6KQ.js → chunk-PBWJVRKE.js} +2 -2
  118. package/dist/{chunk-EX27VKU6.js → chunk-PDTNQLPC.js} +2 -2
  119. package/dist/{chunk-LJCHDFLP.js → chunk-Q6PYCPHO.js} +2 -2
  120. package/dist/{chunk-XTVH2NAW.js → chunk-QFTNWDJ6.js} +3 -3
  121. package/dist/{chunk-6CWAY4R7.js → chunk-QZK6HG4J.js} +2 -2
  122. package/dist/{chunk-Q6UZREJK.js → chunk-RKRX4C4H.js} +2 -2
  123. package/dist/{chunk-UXAF4RQM.js → chunk-RZDDNH63.js} +2 -2
  124. package/dist/{chunk-CCTLRRV6.js → chunk-SA6P2KS3.js} +24 -19
  125. package/dist/chunk-SA6P2KS3.js.map +1 -0
  126. package/dist/{chunk-QFQ4UG3I.js → chunk-SVJ5JVZO.js} +4 -4
  127. package/dist/{chunk-CTHYR4QK.js → chunk-SW3WHVKN.js} +2 -2
  128. package/dist/{chunk-Y57GJDG5.js → chunk-SWRRZNHM.js} +14 -17
  129. package/dist/chunk-SWRRZNHM.js.map +1 -0
  130. package/dist/{chunk-B4XSXFKI.js → chunk-V4GPFCJ7.js} +2 -2
  131. package/dist/{chunk-7AIPWNM7.js → chunk-VCBS5GRQ.js} +2 -2
  132. package/dist/{chunk-LU57EEJW.js → chunk-VGRBKEBH.js} +3 -3
  133. package/dist/{chunk-M7L5A2AT.js → chunk-VKUMKVEU.js} +3 -3
  134. package/dist/{chunk-3EGL7XZO.js → chunk-WIBWONL4.js} +2 -2
  135. package/dist/{chunk-BGK3SFCC.js → chunk-WJCAAVZX.js} +2 -2
  136. package/dist/{chunk-BMOJFGVX.js → chunk-WQFHHJWK.js} +2 -2
  137. package/dist/{chunk-6HVLHIAB.js → chunk-X52SXKVC.js} +2 -2
  138. package/dist/{chunk-UVYI6VIX.js → chunk-X7Y7WX73.js} +1 -1
  139. package/dist/{chunk-XM747YJF.js → chunk-XFND63OB.js} +2 -2
  140. package/dist/{chunk-RUAIO5UA.js → chunk-XSJL62LE.js} +2 -2
  141. package/dist/{chunk-3SL52JKD.js → chunk-XVZA6VXC.js} +4 -4
  142. package/dist/{chunk-MXPVNDGO.js → chunk-YB3WN6XA.js} +8 -8
  143. package/dist/{chunk-JCYEDMOY.js → chunk-YY6PWFUC.js} +2 -2
  144. package/dist/{chunk-6Q56WDHG.js → chunk-ZLCBLDJO.js} +2 -2
  145. package/dist/cli.js +104 -102
  146. package/dist/coding/export-okf-codegraph.js +12 -11
  147. package/dist/coding/export-okf-codegraph.js.map +1 -1
  148. package/dist/coding/pre-action-gate.js +2 -2
  149. package/dist/compounding/engine.js +14 -13
  150. package/dist/config.js +23 -21
  151. package/dist/connectors/codex-materialize-runner.js +13 -12
  152. package/dist/connectors/index.js +13 -12
  153. package/dist/convergence-refresh.js +15 -14
  154. package/dist/corpus-watermark.js +15 -14
  155. package/dist/deep-recall-http-glue.js +11 -10
  156. package/dist/deep-recall.js +2 -2
  157. package/dist/embedding-fallback.js +3 -2
  158. package/dist/embedding-generation-marker.d.ts +16 -0
  159. package/dist/embedding-generation-marker.d.ts.map +1 -0
  160. package/dist/embedding-generation-marker.js +19 -0
  161. package/dist/embedding-generation-marker.js.map +1 -0
  162. package/dist/embedding-index-storage.d.ts +2 -4
  163. package/dist/embedding-index-storage.d.ts.map +1 -1
  164. package/dist/embedding-index-storage.js +2 -1
  165. package/dist/entity-retrieval.js +14 -13
  166. package/dist/event-order-recall.js +2 -2
  167. package/dist/explicit-capture.js +1 -1
  168. package/dist/external-wiki-access.js +64 -62
  169. package/dist/extraction-span-materialize.js +2 -2
  170. package/dist/extraction.js +23 -22
  171. package/dist/{first-start-migration-A6PHIBUQ.js → first-start-migration-QVD22WWS.js} +4 -4
  172. package/dist/{graph-edge-decay-3HVLMT6U.js → graph-edge-decay-IU75NV42.js} +6 -6
  173. package/dist/graph-edge-decay-IU75NV42.js.map +1 -0
  174. package/dist/graph-jsonl.js +4 -4
  175. package/dist/graph-snapshot.js +4 -4
  176. package/dist/graph.js +5 -5
  177. package/dist/harmonic-retrieval.js +13 -12
  178. package/dist/index.d.ts +1 -1
  179. package/dist/index.d.ts.map +1 -1
  180. package/dist/index.js +192 -188
  181. package/dist/lcm/engine.js +4 -4
  182. package/dist/lcm/index.js +9 -9
  183. package/dist/local-llm.js +3 -3
  184. package/dist/location/index.js +15 -14
  185. package/dist/maintenance/memory-governance.js +13 -12
  186. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +13 -12
  187. package/dist/maintenance/rebuild-memory-projection-runner.js +15 -14
  188. package/dist/maintenance/rebuild-memory-projection.js +14 -13
  189. package/dist/memory-browse-operations.js +64 -62
  190. package/dist/memory-browse.js +5 -5
  191. package/dist/namespaces/migrate.js +14 -13
  192. package/dist/namespaces/search.js +6 -6
  193. package/dist/namespaces/storage.js +13 -12
  194. package/dist/offline-sync-changeset-generations.js +5 -4
  195. package/dist/offline-sync-embedding-generation.d.ts +12 -2
  196. package/dist/offline-sync-embedding-generation.d.ts.map +1 -1
  197. package/dist/offline-sync-embedding-generation.js +6 -3
  198. package/dist/offline-sync-snapshot-stream.js +8 -7
  199. package/dist/offline-sync.d.ts.map +1 -1
  200. package/dist/offline-sync.js +9 -8
  201. package/dist/operator-doctor-corpus.js +16 -15
  202. package/dist/operator-toolkit.js +35 -33
  203. package/dist/orchestration/maintenance.js +26 -25
  204. package/dist/orchestrator.js +146 -144
  205. package/dist/qmd.js +2 -2
  206. package/dist/recall-navigation-operations.js +64 -62
  207. package/dist/recall-navigation.js +63 -61
  208. package/dist/recall-state-view-admission.js +5 -5
  209. package/dist/recall-why-service.js +5 -5
  210. package/dist/resume-bundles.js +24 -22
  211. package/dist/search/factory.js +5 -5
  212. package/dist/search/index.js +9 -9
  213. package/dist/semantic-consolidation.js +14 -13
  214. package/dist/semantic-rule-promotion.js +13 -12
  215. package/dist/semantic-rule-verifier.js +13 -12
  216. package/dist/source-agent-qualifier.js +16 -15
  217. package/dist/standup/build.js +13 -12
  218. package/dist/storage.d.ts.map +1 -1
  219. package/dist/storage.js +12 -11
  220. package/dist/summarizer.js +4 -4
  221. package/dist/support-passport/index.js +66 -64
  222. package/dist/transfer/backup.js +2 -2
  223. package/dist/transfer/capsule-export.js +2 -2
  224. package/dist/transfer/capsule-import.js +2 -2
  225. package/dist/transfer/export-okf.js +13 -12
  226. package/dist/verified-recall.js +13 -12
  227. package/dist/who-knows-cli.js +14 -13
  228. package/dist/who-knows.js +13 -12
  229. package/package.json +2 -2
  230. package/src/access-service-peer-capture-backoff.test.ts +236 -0
  231. package/src/access-service.ts +6 -2
  232. package/src/capture-write-lock-scope.test.ts +32 -0
  233. package/src/capture-write-lock-scope.ts +30 -0
  234. package/src/embedding-generation-marker.ts +51 -0
  235. package/src/embedding-index-storage.ts +13 -29
  236. package/src/index.ts +1 -1
  237. package/src/offline-sync-embedding-delete-digest.test.ts +58 -0
  238. package/src/offline-sync-embedding-generation-marker.test.ts +245 -0
  239. package/src/offline-sync-embedding-generation.ts +47 -2
  240. package/src/offline-sync-embedding-lock-loss.test.ts +42 -0
  241. package/src/offline-sync.ts +4 -1
  242. package/src/storage.ts +2 -1
  243. package/dist/chunk-CCTLRRV6.js.map +0 -1
  244. package/dist/chunk-L46MG2GE.js.map +0 -1
  245. package/dist/chunk-OXSTKCYK.js.map +0 -1
  246. package/dist/chunk-Y57GJDG5.js.map +0 -1
  247. package/dist/chunk-YBKQAVPZ.js.map +0 -1
  248. /package/dist/{capsule-crypto-GWVG7LGC.js.map → capsule-crypto-7FJQINUR.js.map} +0 -0
  249. /package/dist/{graph-edge-decay-3HVLMT6U.js.map → capture-write-lock-scope.js.map} +0 -0
  250. /package/dist/{chunk-J6B6FK2X.js.map → chunk-2BY56HE6.js.map} +0 -0
  251. /package/dist/{chunk-ME5LVISI.js.map → chunk-2J6BIOVN.js.map} +0 -0
  252. /package/dist/{chunk-EIYJK7OD.js.map → chunk-2M36PR7R.js.map} +0 -0
  253. /package/dist/{chunk-OWHERGF2.js.map → chunk-2NLLXCJG.js.map} +0 -0
  254. /package/dist/{chunk-WOPZ2P5Z.js.map → chunk-3INLTKTW.js.map} +0 -0
  255. /package/dist/{chunk-6P6MZDBL.js.map → chunk-3NL4ALUP.js.map} +0 -0
  256. /package/dist/{chunk-YUE7J2HZ.js.map → chunk-3NYIXVCT.js.map} +0 -0
  257. /package/dist/{chunk-B44NFHWI.js.map → chunk-3PVKV3XL.js.map} +0 -0
  258. /package/dist/{chunk-H7BZBSP6.js.map → chunk-52II7PB6.js.map} +0 -0
  259. /package/dist/{chunk-5KGYR5VN.js.map → chunk-5DVOBBTV.js.map} +0 -0
  260. /package/dist/{chunk-WCGJK4NQ.js.map → chunk-5FNZ3G6X.js.map} +0 -0
  261. /package/dist/{chunk-IJH6METJ.js.map → chunk-5IDQVE4U.js.map} +0 -0
  262. /package/dist/{chunk-2DPJFJFH.js.map → chunk-6TIVVOVU.js.map} +0 -0
  263. /package/dist/{chunk-BUKK5SWA.js.map → chunk-7LCGFUMB.js.map} +0 -0
  264. /package/dist/{chunk-CHSRA76M.js.map → chunk-7XFQSQYS.js.map} +0 -0
  265. /package/dist/{chunk-A45QXZMU.js.map → chunk-A3WXV7YU.js.map} +0 -0
  266. /package/dist/{chunk-LXN737FX.js.map → chunk-AAANTXCQ.js.map} +0 -0
  267. /package/dist/{chunk-JNLYHJG7.js.map → chunk-AF4UIHON.js.map} +0 -0
  268. /package/dist/{chunk-JGMJZBFV.js.map → chunk-AGCEJDG2.js.map} +0 -0
  269. /package/dist/{chunk-I3IPXGFQ.js.map → chunk-AJJPXUE6.js.map} +0 -0
  270. /package/dist/{chunk-KAUCVTAW.js.map → chunk-BJTFLP3J.js.map} +0 -0
  271. /package/dist/{chunk-QR6W3FSW.js.map → chunk-BMG3SAXA.js.map} +0 -0
  272. /package/dist/{chunk-QE2XQM3S.js.map → chunk-BWF3KNSQ.js.map} +0 -0
  273. /package/dist/{chunk-BCDECPVO.js.map → chunk-C3HRYVGD.js.map} +0 -0
  274. /package/dist/{chunk-RQLTCHUL.js.map → chunk-C7WDWD35.js.map} +0 -0
  275. /package/dist/{chunk-YL564QS2.js.map → chunk-CMOYD5CA.js.map} +0 -0
  276. /package/dist/{chunk-4J7BNL7B.js.map → chunk-CPBYKOTC.js.map} +0 -0
  277. /package/dist/{chunk-PPDNG7WC.js.map → chunk-CRJX4OMN.js.map} +0 -0
  278. /package/dist/{chunk-YFJHFEET.js.map → chunk-D76AHITY.js.map} +0 -0
  279. /package/dist/{chunk-ZX5N5D6M.js.map → chunk-DAOMWGO2.js.map} +0 -0
  280. /package/dist/{chunk-2RQR4TXV.js.map → chunk-DM6SOROF.js.map} +0 -0
  281. /package/dist/{chunk-VWJ56T63.js.map → chunk-E3DL3CAL.js.map} +0 -0
  282. /package/dist/{chunk-M7LA4QBY.js.map → chunk-E47UQBYW.js.map} +0 -0
  283. /package/dist/{chunk-23ZMQONL.js.map → chunk-ERMT5WQM.js.map} +0 -0
  284. /package/dist/{chunk-FAKRTS3Y.js.map → chunk-ESDOQEJM.js.map} +0 -0
  285. /package/dist/{chunk-VTCNVGM6.js.map → chunk-FOKTW6GY.js.map} +0 -0
  286. /package/dist/{chunk-TF5NZGPS.js.map → chunk-FYZXZUGU.js.map} +0 -0
  287. /package/dist/{chunk-XTN54NML.js.map → chunk-G3T6YMBO.js.map} +0 -0
  288. /package/dist/{chunk-2JNBPOZ2.js.map → chunk-GDYLZ6FR.js.map} +0 -0
  289. /package/dist/{chunk-DZPTR2XQ.js.map → chunk-GFAEKSFR.js.map} +0 -0
  290. /package/dist/{chunk-GLZWOIU3.js.map → chunk-HCPVL6SF.js.map} +0 -0
  291. /package/dist/{chunk-NDMPRT3Z.js.map → chunk-HDT3DMUF.js.map} +0 -0
  292. /package/dist/{chunk-BWRX322G.js.map → chunk-HI53EK3Y.js.map} +0 -0
  293. /package/dist/{chunk-BFPF5N3H.js.map → chunk-HXFIILGF.js.map} +0 -0
  294. /package/dist/{chunk-2V664H6O.js.map → chunk-JS44PBCM.js.map} +0 -0
  295. /package/dist/{chunk-XKTHJHSQ.js.map → chunk-JZCBMKR5.js.map} +0 -0
  296. /package/dist/{chunk-KRACAE73.js.map → chunk-KMTMMBEB.js.map} +0 -0
  297. /package/dist/{chunk-FJ264QBP.js.map → chunk-KNCR7APE.js.map} +0 -0
  298. /package/dist/{chunk-WUBGMV3G.js.map → chunk-KRAMCBIW.js.map} +0 -0
  299. /package/dist/{chunk-DRXTMDAG.js.map → chunk-LCHFINL4.js.map} +0 -0
  300. /package/dist/{chunk-PJBYVJKO.js.map → chunk-LXXIV7Y2.js.map} +0 -0
  301. /package/dist/{chunk-6CC2YCKG.js.map → chunk-MCS4LIXP.js.map} +0 -0
  302. /package/dist/{chunk-2NX7JTST.js.map → chunk-MPWOAIIH.js.map} +0 -0
  303. /package/dist/{chunk-CMNL3QSL.js.map → chunk-N5PISU26.js.map} +0 -0
  304. /package/dist/{chunk-PKPOO6X5.js.map → chunk-N6EM7ESC.js.map} +0 -0
  305. /package/dist/{chunk-FWV2SXSL.js.map → chunk-NH37SP6V.js.map} +0 -0
  306. /package/dist/{chunk-MZCTS3ZG.js.map → chunk-NMOEOQV4.js.map} +0 -0
  307. /package/dist/{chunk-VECRSYQG.js.map → chunk-NRGQ5HJO.js.map} +0 -0
  308. /package/dist/{chunk-3DKKZVXS.js.map → chunk-NUK5XU3P.js.map} +0 -0
  309. /package/dist/{chunk-FPANDKMQ.js.map → chunk-O7GNSHFF.js.map} +0 -0
  310. /package/dist/{chunk-5R2IF2KI.js.map → chunk-OD7ZXCUF.js.map} +0 -0
  311. /package/dist/{chunk-RT2GN6KQ.js.map → chunk-PBWJVRKE.js.map} +0 -0
  312. /package/dist/{chunk-EX27VKU6.js.map → chunk-PDTNQLPC.js.map} +0 -0
  313. /package/dist/{chunk-LJCHDFLP.js.map → chunk-Q6PYCPHO.js.map} +0 -0
  314. /package/dist/{chunk-XTVH2NAW.js.map → chunk-QFTNWDJ6.js.map} +0 -0
  315. /package/dist/{chunk-6CWAY4R7.js.map → chunk-QZK6HG4J.js.map} +0 -0
  316. /package/dist/{chunk-Q6UZREJK.js.map → chunk-RKRX4C4H.js.map} +0 -0
  317. /package/dist/{chunk-UXAF4RQM.js.map → chunk-RZDDNH63.js.map} +0 -0
  318. /package/dist/{chunk-QFQ4UG3I.js.map → chunk-SVJ5JVZO.js.map} +0 -0
  319. /package/dist/{chunk-CTHYR4QK.js.map → chunk-SW3WHVKN.js.map} +0 -0
  320. /package/dist/{chunk-B4XSXFKI.js.map → chunk-V4GPFCJ7.js.map} +0 -0
  321. /package/dist/{chunk-7AIPWNM7.js.map → chunk-VCBS5GRQ.js.map} +0 -0
  322. /package/dist/{chunk-LU57EEJW.js.map → chunk-VGRBKEBH.js.map} +0 -0
  323. /package/dist/{chunk-M7L5A2AT.js.map → chunk-VKUMKVEU.js.map} +0 -0
  324. /package/dist/{chunk-3EGL7XZO.js.map → chunk-WIBWONL4.js.map} +0 -0
  325. /package/dist/{chunk-BGK3SFCC.js.map → chunk-WJCAAVZX.js.map} +0 -0
  326. /package/dist/{chunk-BMOJFGVX.js.map → chunk-WQFHHJWK.js.map} +0 -0
  327. /package/dist/{chunk-6HVLHIAB.js.map → chunk-X52SXKVC.js.map} +0 -0
  328. /package/dist/{chunk-UVYI6VIX.js.map → chunk-X7Y7WX73.js.map} +0 -0
  329. /package/dist/{chunk-XM747YJF.js.map → chunk-XFND63OB.js.map} +0 -0
  330. /package/dist/{chunk-RUAIO5UA.js.map → chunk-XSJL62LE.js.map} +0 -0
  331. /package/dist/{chunk-3SL52JKD.js.map → chunk-XVZA6VXC.js.map} +0 -0
  332. /package/dist/{chunk-MXPVNDGO.js.map → chunk-YB3WN6XA.js.map} +0 -0
  333. /package/dist/{chunk-JCYEDMOY.js.map → chunk-YY6PWFUC.js.map} +0 -0
  334. /package/dist/{chunk-6Q56WDHG.js.map → chunk-ZLCBLDJO.js.map} +0 -0
  335. /package/dist/{first-start-migration-A6PHIBUQ.js.map → first-start-migration-QVD22WWS.js.map} +0 -0
@@ -1,22 +1,22 @@
1
1
  import {
2
2
  compareVerifiedEpisodeResults,
3
3
  searchVerifiedEpisodes
4
- } from "./chunk-VWJ56T63.js";
4
+ } from "./chunk-E3DL3CAL.js";
5
5
  import "./chunk-B7RWBZXW.js";
6
- import "./chunk-L46MG2GE.js";
6
+ import "./chunk-6W3QH3QW.js";
7
7
  import "./chunk-UHVXE24Y.js";
8
8
  import "./chunk-DM5QZ3YU.js";
9
9
  import "./chunk-VY6BD5KB.js";
10
10
  import "./chunk-G6OFEGUR.js";
11
- import "./chunk-PJBYVJKO.js";
12
- import "./chunk-2V664H6O.js";
11
+ import "./chunk-LXXIV7Y2.js";
12
+ import "./chunk-JS44PBCM.js";
13
+ import "./chunk-5CWH2LKL.js";
13
14
  import "./chunk-XKDQTDXN.js";
14
15
  import "./chunk-CYEPCZN5.js";
15
16
  import "./chunk-XRFLR3XF.js";
16
17
  import "./chunk-7VO6E5UD.js";
17
- import "./chunk-EXYT52NR.js";
18
- import "./chunk-5CWH2LKL.js";
19
18
  import "./chunk-WNEVEMJ3.js";
19
+ import "./chunk-EXYT52NR.js";
20
20
  import "./chunk-Y5NLBXPV.js";
21
21
  import "./chunk-TFA6HPOA.js";
22
22
  import "./chunk-F4TWWUMP.js";
@@ -27,17 +27,17 @@ import "./chunk-PPUNC7UX.js";
27
27
  import "./chunk-X3724WL4.js";
28
28
  import "./chunk-MRPOZBJC.js";
29
29
  import "./chunk-S2HLHAZ4.js";
30
- import "./chunk-LDXUBPMO.js";
31
30
  import "./chunk-DM2T26WE.js";
31
+ import "./chunk-LDXUBPMO.js";
32
32
  import "./chunk-FF6N7BXC.js";
33
33
  import "./chunk-WXPBDEMW.js";
34
34
  import "./chunk-AAD2ZS6P.js";
35
35
  import "./chunk-MPJDQC4G.js";
36
36
  import "./chunk-ZIKENA2C.js";
37
- import "./chunk-3ONXXHQO.js";
38
- import "./chunk-YXZG5TVN.js";
39
37
  import "./chunk-3OUGSOJP.js";
40
38
  import "./chunk-SCU65EZI.js";
39
+ import "./chunk-3ONXXHQO.js";
40
+ import "./chunk-YXZG5TVN.js";
41
41
  import "./chunk-P4GUQSK3.js";
42
42
  import "./chunk-3WU7XOFN.js";
43
43
  import "./chunk-G7D6GZ5J.js";
@@ -48,12 +48,13 @@ import "./chunk-LWRIGKFM.js";
48
48
  import "./chunk-5WITETWU.js";
49
49
  import "./chunk-6CIAGZ6X.js";
50
50
  import "./chunk-7CT3AI52.js";
51
- import "./chunk-I3IPXGFQ.js";
51
+ import "./chunk-UUZ7KZAO.js";
52
+ import "./chunk-AJJPXUE6.js";
52
53
  import "./chunk-G26YNEOC.js";
54
+ import "./chunk-VILPVT4S.js";
53
55
  import "./chunk-AF2XMJKD.js";
54
56
  import "./chunk-OR42ZI54.js";
55
57
  import "./chunk-IUM3VSHI.js";
56
- import "./chunk-VILPVT4S.js";
57
58
  import "./chunk-23G5P7TA.js";
58
59
  import "./chunk-C64XATK7.js";
59
60
  import "./chunk-42JKGUFJ.js";
@@ -63,7 +64,7 @@ import "./chunk-L2EXJQJP.js";
63
64
  import "./chunk-45GF7Y3V.js";
64
65
  import "./chunk-YIJECSIX.js";
65
66
  import "./chunk-E2AWJ7KQ.js";
66
- import "./chunk-UUZ7KZAO.js";
67
+ import "./chunk-7VLBZKNB.js";
67
68
  import "./chunk-HADD45AR.js";
68
69
  import "./chunk-RNFMFC37.js";
69
70
  import "./chunk-YCVB7X56.js";
@@ -4,22 +4,22 @@ import {
4
4
  renderWhoKnows,
5
5
  renderWhoKnowsJson,
6
6
  renderWhoKnowsText
7
- } from "./chunk-BWRX322G.js";
8
- import "./chunk-JGMJZBFV.js";
9
- import "./chunk-L46MG2GE.js";
7
+ } from "./chunk-HI53EK3Y.js";
8
+ import "./chunk-AGCEJDG2.js";
9
+ import "./chunk-6W3QH3QW.js";
10
10
  import "./chunk-UHVXE24Y.js";
11
11
  import "./chunk-DM5QZ3YU.js";
12
12
  import "./chunk-VY6BD5KB.js";
13
13
  import "./chunk-G6OFEGUR.js";
14
- import "./chunk-PJBYVJKO.js";
15
- import "./chunk-2V664H6O.js";
14
+ import "./chunk-LXXIV7Y2.js";
15
+ import "./chunk-JS44PBCM.js";
16
+ import "./chunk-5CWH2LKL.js";
16
17
  import "./chunk-XKDQTDXN.js";
17
18
  import "./chunk-CYEPCZN5.js";
18
19
  import "./chunk-XRFLR3XF.js";
19
20
  import "./chunk-7VO6E5UD.js";
20
- import "./chunk-EXYT52NR.js";
21
- import "./chunk-5CWH2LKL.js";
22
21
  import "./chunk-WNEVEMJ3.js";
22
+ import "./chunk-EXYT52NR.js";
23
23
  import "./chunk-Y5NLBXPV.js";
24
24
  import "./chunk-TFA6HPOA.js";
25
25
  import "./chunk-F4TWWUMP.js";
@@ -30,17 +30,17 @@ import "./chunk-PPUNC7UX.js";
30
30
  import "./chunk-X3724WL4.js";
31
31
  import "./chunk-MRPOZBJC.js";
32
32
  import "./chunk-S2HLHAZ4.js";
33
- import "./chunk-LDXUBPMO.js";
34
33
  import "./chunk-DM2T26WE.js";
34
+ import "./chunk-LDXUBPMO.js";
35
35
  import "./chunk-FF6N7BXC.js";
36
36
  import "./chunk-WXPBDEMW.js";
37
37
  import "./chunk-AAD2ZS6P.js";
38
38
  import "./chunk-MPJDQC4G.js";
39
39
  import "./chunk-ZIKENA2C.js";
40
- import "./chunk-3ONXXHQO.js";
41
- import "./chunk-YXZG5TVN.js";
42
40
  import "./chunk-3OUGSOJP.js";
43
41
  import "./chunk-SCU65EZI.js";
42
+ import "./chunk-3ONXXHQO.js";
43
+ import "./chunk-YXZG5TVN.js";
44
44
  import "./chunk-P4GUQSK3.js";
45
45
  import "./chunk-3WU7XOFN.js";
46
46
  import "./chunk-G7D6GZ5J.js";
@@ -51,12 +51,13 @@ import "./chunk-LWRIGKFM.js";
51
51
  import "./chunk-5WITETWU.js";
52
52
  import "./chunk-6CIAGZ6X.js";
53
53
  import "./chunk-7CT3AI52.js";
54
- import "./chunk-I3IPXGFQ.js";
54
+ import "./chunk-UUZ7KZAO.js";
55
+ import "./chunk-AJJPXUE6.js";
55
56
  import "./chunk-G26YNEOC.js";
57
+ import "./chunk-VILPVT4S.js";
56
58
  import "./chunk-AF2XMJKD.js";
57
59
  import "./chunk-OR42ZI54.js";
58
60
  import "./chunk-IUM3VSHI.js";
59
- import "./chunk-VILPVT4S.js";
60
61
  import "./chunk-23G5P7TA.js";
61
62
  import "./chunk-C64XATK7.js";
62
63
  import "./chunk-42JKGUFJ.js";
@@ -66,7 +67,7 @@ import "./chunk-L2EXJQJP.js";
66
67
  import "./chunk-45GF7Y3V.js";
67
68
  import "./chunk-YIJECSIX.js";
68
69
  import "./chunk-E2AWJ7KQ.js";
69
- import "./chunk-UUZ7KZAO.js";
70
+ import "./chunk-7VLBZKNB.js";
70
71
  import "./chunk-HADD45AR.js";
71
72
  import "./chunk-RNFMFC37.js";
72
73
  import "./chunk-YCVB7X56.js";
package/dist/who-knows.js CHANGED
@@ -9,21 +9,21 @@ import {
9
9
  loadWhoKnowsEntities,
10
10
  tokenizeTopic,
11
11
  validateWhoKnowsInput
12
- } from "./chunk-JGMJZBFV.js";
13
- import "./chunk-L46MG2GE.js";
12
+ } from "./chunk-AGCEJDG2.js";
13
+ import "./chunk-6W3QH3QW.js";
14
14
  import "./chunk-UHVXE24Y.js";
15
15
  import "./chunk-DM5QZ3YU.js";
16
16
  import "./chunk-VY6BD5KB.js";
17
17
  import "./chunk-G6OFEGUR.js";
18
- import "./chunk-PJBYVJKO.js";
19
- import "./chunk-2V664H6O.js";
18
+ import "./chunk-LXXIV7Y2.js";
19
+ import "./chunk-JS44PBCM.js";
20
+ import "./chunk-5CWH2LKL.js";
20
21
  import "./chunk-XKDQTDXN.js";
21
22
  import "./chunk-CYEPCZN5.js";
22
23
  import "./chunk-XRFLR3XF.js";
23
24
  import "./chunk-7VO6E5UD.js";
24
- import "./chunk-EXYT52NR.js";
25
- import "./chunk-5CWH2LKL.js";
26
25
  import "./chunk-WNEVEMJ3.js";
26
+ import "./chunk-EXYT52NR.js";
27
27
  import "./chunk-Y5NLBXPV.js";
28
28
  import "./chunk-TFA6HPOA.js";
29
29
  import "./chunk-F4TWWUMP.js";
@@ -34,17 +34,17 @@ import "./chunk-PPUNC7UX.js";
34
34
  import "./chunk-X3724WL4.js";
35
35
  import "./chunk-MRPOZBJC.js";
36
36
  import "./chunk-S2HLHAZ4.js";
37
- import "./chunk-LDXUBPMO.js";
38
37
  import "./chunk-DM2T26WE.js";
38
+ import "./chunk-LDXUBPMO.js";
39
39
  import "./chunk-FF6N7BXC.js";
40
40
  import "./chunk-WXPBDEMW.js";
41
41
  import "./chunk-AAD2ZS6P.js";
42
42
  import "./chunk-MPJDQC4G.js";
43
43
  import "./chunk-ZIKENA2C.js";
44
- import "./chunk-3ONXXHQO.js";
45
- import "./chunk-YXZG5TVN.js";
46
44
  import "./chunk-3OUGSOJP.js";
47
45
  import "./chunk-SCU65EZI.js";
46
+ import "./chunk-3ONXXHQO.js";
47
+ import "./chunk-YXZG5TVN.js";
48
48
  import "./chunk-P4GUQSK3.js";
49
49
  import "./chunk-3WU7XOFN.js";
50
50
  import "./chunk-G7D6GZ5J.js";
@@ -55,12 +55,13 @@ import "./chunk-LWRIGKFM.js";
55
55
  import "./chunk-5WITETWU.js";
56
56
  import "./chunk-6CIAGZ6X.js";
57
57
  import "./chunk-7CT3AI52.js";
58
- import "./chunk-I3IPXGFQ.js";
58
+ import "./chunk-UUZ7KZAO.js";
59
+ import "./chunk-AJJPXUE6.js";
59
60
  import "./chunk-G26YNEOC.js";
61
+ import "./chunk-VILPVT4S.js";
60
62
  import "./chunk-AF2XMJKD.js";
61
63
  import "./chunk-OR42ZI54.js";
62
64
  import "./chunk-IUM3VSHI.js";
63
- import "./chunk-VILPVT4S.js";
64
65
  import "./chunk-23G5P7TA.js";
65
66
  import "./chunk-C64XATK7.js";
66
67
  import "./chunk-42JKGUFJ.js";
@@ -70,7 +71,7 @@ import "./chunk-L2EXJQJP.js";
70
71
  import "./chunk-45GF7Y3V.js";
71
72
  import "./chunk-YIJECSIX.js";
72
73
  import "./chunk-E2AWJ7KQ.js";
73
- import "./chunk-UUZ7KZAO.js";
74
+ import "./chunk-7VLBZKNB.js";
74
75
  import "./chunk-HADD45AR.js";
75
76
  import "./chunk-RNFMFC37.js";
76
77
  import "./chunk-YCVB7X56.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remnic/core",
3
- "version": "10.0.47",
3
+ "version": "10.0.49",
4
4
  "description": "Framework-agnostic Remnic memory engine — orchestrator, storage, extraction, search, trust zones",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -3347,7 +3347,7 @@
3347
3347
  "core"
3348
3348
  ],
3349
3349
  "peerDependencies": {
3350
- "@remnic/coding-graph": "^10.0.47"
3350
+ "@remnic/coding-graph": "^10.0.49"
3351
3351
  },
3352
3352
  "peerDependenciesMeta": {
3353
3353
  "@remnic/coding-graph": {
@@ -0,0 +1,236 @@
1
+ import assert from "node:assert/strict";
2
+ import { createHash } from "node:crypto";
3
+ import { mkdtemp, readFile, rm } from "node:fs/promises";
4
+ import os from "node:os";
5
+ import path from "node:path";
6
+ import test from "node:test";
7
+
8
+ import { EngramAccessService } from "./access-service.js";
9
+ import { CAPTURE_WRITE_LOCK_BUSY_MESSAGE } from "./capture-write-lock-backoff.js";
10
+ import { buildCapturePathLockIdentity, TombstoneBlockedCaptureWriteLock } from "./capture-write-lock.js";
11
+ import { parseConfig } from "./config.js";
12
+ import { Orchestrator } from "./orchestrator.js";
13
+ import { buildExplicitCaptureDedupKey } from "./storage/tombstone-blocked-capture-index.js";
14
+ import { OFFLINE_SYNC_CHANGESET_FORMAT } from "./offline-sync.js";
15
+
16
+ // Real contention exceeds the legacy deadline but fits inside the configured peer budget.
17
+
18
+ /** Longer than the legacy 3s capture-lock deadline, shorter than the converge deadline. */
19
+ const CONTENTION_HOLD_MS = 3_600;
20
+ /** The converge deadline a peer apply is scoped to. */
21
+ const CONVERGE_DEADLINE_MS = 8_000;
22
+ /** An ordinary capture must still give up near the legacy 3s bound. */
23
+ const LEGACY_BOUND_MS = 4_500;
24
+
25
+ const PEER_REL_PATH = "facts/2026-08-13/peer-apply-target.md";
26
+ const ORDINARY_CONTENT = "ordinary capture body";
27
+
28
+ function peerContent(): Buffer {
29
+ return Buffer.from(
30
+ [
31
+ "---",
32
+ "id: peer-apply-target",
33
+ "category: fact",
34
+ "created: 2026-08-13T00:00:00.000Z",
35
+ "---",
36
+ "",
37
+ "Peer applied body",
38
+ "",
39
+ ].join("\n")
40
+ );
41
+ }
42
+
43
+ async function createPeerService(root: string) {
44
+ const orchestrator = new Orchestrator(
45
+ parseConfig({
46
+ memoryDir: root,
47
+ namespacesEnabled: false,
48
+ defaultNamespace: "global",
49
+ converge: {
50
+ conflictPolicy: "newest-wins",
51
+ captureWriteLockInitialDelayMs: 20,
52
+ captureWriteLockMaxDelayMs: 50,
53
+ captureWriteLockDeadlineMs: CONVERGE_DEADLINE_MS,
54
+ },
55
+ })
56
+ );
57
+ const storage = await orchestrator.getStorage();
58
+ await storage.ensureDirectories();
59
+ assert.equal(storage.dir, root, "the fixture uses one cached flat-root storage");
60
+ return { storage, service: new EngramAccessService(orchestrator) };
61
+ }
62
+
63
+ /** Hold a capture lock and release it after `holdMs`. */
64
+ function holdCaptureLock(stateDir: string, identity: string, holdMs: number) {
65
+ const holder = new TombstoneBlockedCaptureWriteLock({ stateDir });
66
+ const released = Promise.withResolvers<void>();
67
+ const acquired = Promise.withResolvers<void>();
68
+ let timer: NodeJS.Timeout | undefined;
69
+ const holding = holder.withCaptureWriteLock(async () => {
70
+ acquired.resolve();
71
+ timer = setTimeout(() => released.resolve(), holdMs);
72
+ await released.promise;
73
+ }, identity);
74
+ return {
75
+ acquired: acquired.promise,
76
+ release: (): void => {
77
+ clearTimeout(timer);
78
+ released.resolve();
79
+ },
80
+ done: holding,
81
+ };
82
+ }
83
+
84
+ function peerApplyRequest(content: Buffer) {
85
+ return {
86
+ sourceId: "remnic-converge",
87
+ path: PEER_REL_PATH,
88
+ sha256: createHash("sha256").update(content).digest("hex"),
89
+ bytes: content.length,
90
+ mtimeMs: 1_700_000_000_000,
91
+ offset: 0,
92
+ content,
93
+ };
94
+ }
95
+
96
+ for (const kind of ["chunk", "changeset"] as const) {
97
+ test(
98
+ `peer ${kind} apply waits out a busy capture lock instead of the legacy deadline`,
99
+ { timeout: 30_000 },
100
+ async () => {
101
+ const root = await mkdtemp(path.join(os.tmpdir(), "remnic-peer-capture-backoff-"));
102
+ const { service } = await createPeerService(root);
103
+ const content = peerContent();
104
+ const holder = holdCaptureLock(
105
+ path.join(root, "state"),
106
+ buildCapturePathLockIdentity(path.resolve(root, PEER_REL_PATH)),
107
+ CONTENTION_HOLD_MS
108
+ );
109
+ try {
110
+ await holder.acquired;
111
+ const startedAt = Date.now();
112
+ const apply =
113
+ kind === "chunk"
114
+ ? service.offlineSyncApplyFileContent(peerApplyRequest(content))
115
+ : service.offlineSyncApply({
116
+ returnCurrentFiles: false,
117
+ changeset: {
118
+ format: OFFLINE_SYNC_CHANGESET_FORMAT,
119
+ schemaVersion: 1,
120
+ createdAt: "2026-08-13T00:00:00.000Z",
121
+ sourceId: "remnic-converge",
122
+ includeTranscripts: false,
123
+ changes: [
124
+ {
125
+ type: "upsert",
126
+ path: PEER_REL_PATH,
127
+ file: {
128
+ path: PEER_REL_PATH,
129
+ sha256: createHash("sha256").update(content).digest("hex"),
130
+ bytes: content.length,
131
+ mtimeMs: 1_700_000_000_000,
132
+ contentBase64: content.toString("base64"),
133
+ },
134
+ },
135
+ ],
136
+ },
137
+ });
138
+ const outcome = await apply.then(
139
+ () => ({ ok: true as const }),
140
+ (error) => ({ ok: false as const, error })
141
+ );
142
+ assert.equal(
143
+ outcome.ok,
144
+ true,
145
+ outcome.ok
146
+ ? ""
147
+ : `peer apply failed: ${outcome.error instanceof Error ? outcome.error.message : String(outcome.error)}`
148
+ );
149
+ assert.ok(Date.now() - startedAt >= 2_500, "peer apply must wait out the capture-lock contention");
150
+ assert.equal(await readFile(path.join(root, PEER_REL_PATH), "utf8"), content.toString("utf8"));
151
+ } finally {
152
+ holder.release();
153
+ await holder.done.catch(() => undefined);
154
+ await rm(root, { recursive: true, force: true });
155
+ }
156
+ }
157
+ );
158
+ }
159
+
160
+ test(
161
+ "an ordinary capture keeps the legacy capture-lock bound while a peer apply is in flight",
162
+ { timeout: 30_000 },
163
+ async () => {
164
+ const root = await mkdtemp(path.join(os.tmpdir(), "remnic-peer-capture-isolation-"));
165
+ const { storage, service } = await createPeerService(root);
166
+ const content = peerContent();
167
+ const stateDir = path.join(root, "state");
168
+ const peerHolder = holdCaptureLock(
169
+ stateDir,
170
+ buildCapturePathLockIdentity(path.resolve(root, PEER_REL_PATH)),
171
+ CONTENTION_HOLD_MS
172
+ );
173
+ const ordinaryHolder = holdCaptureLock(
174
+ stateDir,
175
+ buildExplicitCaptureDedupKey(ORDINARY_CONTENT, "fact", undefined),
176
+ CONTENTION_HOLD_MS
177
+ );
178
+ let peerApply: Promise<{ ok: true; value: unknown } | { ok: false; error: unknown }> | undefined;
179
+ try {
180
+ await Promise.all([peerHolder.acquired, ordinaryHolder.acquired]);
181
+ peerApply = service.offlineSyncApplyFileContent(peerApplyRequest(content)).then(
182
+ (value) => ({ ok: true as const, value }),
183
+ (error) => ({ ok: false as const, error })
184
+ );
185
+ const startedAt = Date.now();
186
+ const outcome = await storage.writeMemory("fact", ORDINARY_CONTENT).then(
187
+ () => ({ ok: true as const }),
188
+ (error) => ({ ok: false as const, error })
189
+ );
190
+ assert.equal(outcome.ok, false, "ordinary capture must not succeed while the capture lock is held");
191
+ assert.equal(
192
+ outcome.ok ? "" : outcome.error instanceof Error ? outcome.error.message : String(outcome.error),
193
+ CAPTURE_WRITE_LOCK_BUSY_MESSAGE
194
+ );
195
+ assert.ok(
196
+ Date.now() - startedAt < LEGACY_BOUND_MS,
197
+ "ordinary capture must keep the legacy capture-lock bound, not the converge deadline"
198
+ );
199
+ } finally {
200
+ peerHolder.release();
201
+ ordinaryHolder.release();
202
+ await Promise.all([peerHolder.done.catch(() => undefined), ordinaryHolder.done.catch(() => undefined)]);
203
+ await peerApply;
204
+ await rm(root, { recursive: true, force: true });
205
+ }
206
+ }
207
+ );
208
+ test("a failed peer apply does not leak converge capture-lock limits", { timeout: 30_000 }, async () => {
209
+ const root = await mkdtemp(path.join(os.tmpdir(), "remnic-peer-capture-error-scope-"));
210
+ const { storage, service } = await createPeerService(root);
211
+ const content = peerContent();
212
+ const holder = holdCaptureLock(
213
+ path.join(root, "state"),
214
+ buildExplicitCaptureDedupKey(ORDINARY_CONTENT, "fact", undefined),
215
+ CONTENTION_HOLD_MS
216
+ );
217
+ try {
218
+ await assert.rejects(
219
+ service.offlineSyncApplyFileContent({
220
+ ...peerApplyRequest(content),
221
+ sha256: "0".repeat(64),
222
+ })
223
+ );
224
+ await holder.acquired;
225
+ const startedAt = Date.now();
226
+ await assert.rejects(storage.writeMemory("fact", ORDINARY_CONTENT), new RegExp(CAPTURE_WRITE_LOCK_BUSY_MESSAGE));
227
+ assert.ok(
228
+ Date.now() - startedAt < LEGACY_BOUND_MS,
229
+ "ordinary capture after a failed peer apply must keep the legacy lock bound"
230
+ );
231
+ } finally {
232
+ holder.release();
233
+ await holder.done.catch(() => undefined);
234
+ await rm(root, { recursive: true, force: true });
235
+ }
236
+ });
@@ -136,6 +136,8 @@ import {
136
136
  applySupportPassportOfflineSyncChangeset,
137
137
  applySupportPassportOfflineSyncFileContent,
138
138
  } from "./support-passport/offline-sync-guard.js";
139
+ import { withCaptureWriteLockBackoff } from "./capture-write-lock-scope.js";
140
+ import { resolveConvergeCaptureWriteLockBackoff } from "./converge-config.js";
139
141
  import type { WearablesService } from "./wearables/service.js";
140
142
  import { exportWorkBoardMarkdown, exportWorkBoardSnapshot, importWorkBoardSnapshot } from "./work/board.js";
141
143
  import { wrapWorkLayerContext } from "./work/boundary.js";
@@ -5623,7 +5625,8 @@ export class EngramAccessService extends SupportPassportAccessServiceBase {
5623
5625
  const resolvedNamespace = this.writableNamespaceFor(options.namespace, undefined, options.principal);
5624
5626
  const storage = await this.orchestrator.getStorage(resolvedNamespace);
5625
5627
  try {
5626
- const result = await applySupportPassportOfflineSyncFileContent(storage, options);
5628
+ const result = await withCaptureWriteLockBackoff(storage, resolveConvergeCaptureWriteLockBackoff(this.orchestrator.config.converge),
5629
+ () => applySupportPassportOfflineSyncFileContent(storage, options));
5627
5630
  return {
5628
5631
  namespace: resolvedNamespace,
5629
5632
  ...result,
@@ -5671,7 +5674,8 @@ export class EngramAccessService extends SupportPassportAccessServiceBase {
5671
5674
  const resolvedNamespace = this.writableNamespaceFor(options.namespace, undefined, options.principal);
5672
5675
  const storage = await this.orchestrator.getStorage(resolvedNamespace);
5673
5676
  try {
5674
- const result = await applySupportPassportOfflineSyncChangeset(storage, options);
5677
+ const result = await withCaptureWriteLockBackoff(storage, resolveConvergeCaptureWriteLockBackoff(this.orchestrator.config.converge),
5678
+ () => applySupportPassportOfflineSyncChangeset(storage, options));
5675
5679
  return {
5676
5680
  namespace: resolvedNamespace,
5677
5681
  ...result,
@@ -0,0 +1,32 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+ import { scopedCaptureWriteLockLimits, withCaptureWriteLockBackoff } from "./capture-write-lock-scope.js";
4
+
5
+ const limits = { initialDelayMs: 20, maxDelayMs: 50, deadlineMs: 8_000 };
6
+ const expected = {
7
+ captureWriteLockInitialDelayMs: 20,
8
+ captureWriteLockMaxDelayMs: 50,
9
+ captureWriteLockDeadlineMs: 8_000,
10
+ };
11
+
12
+ test("capture backoff scope belongs only to its storage and restores nested state after rejection", async () => {
13
+ const storage = { dir: "synthetic-shared-root" };
14
+ const other = { dir: storage.dir };
15
+ const result = await withCaptureWriteLockBackoff(storage, limits, async () => {
16
+ await Promise.resolve();
17
+ assert.deepEqual(scopedCaptureWriteLockLimits(storage), expected);
18
+ assert.equal(scopedCaptureWriteLockLimits(other), undefined);
19
+ await assert.rejects(
20
+ withCaptureWriteLockBackoff(other, { ...limits, deadlineMs: 4_000 }, async () => {
21
+ assert.equal(scopedCaptureWriteLockLimits(other)?.captureWriteLockDeadlineMs, 4_000);
22
+ assert.equal(scopedCaptureWriteLockLimits(storage), undefined);
23
+ throw new Error("peer apply failed");
24
+ }),
25
+ /peer apply failed/
26
+ );
27
+ return scopedCaptureWriteLockLimits(storage);
28
+ });
29
+ assert.deepEqual(result, expected);
30
+ assert.equal(scopedCaptureWriteLockLimits(storage), undefined);
31
+ assert.equal(scopedCaptureWriteLockLimits(other), undefined);
32
+ });
@@ -0,0 +1,30 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ import type { CaptureWriteLockBackoffLimits, CaptureWriteLockLimitSource } from "./capture-write-lock-backoff.js";
3
+ import type { StorageManager } from "./storage.js";
4
+
5
+ type CaptureLockOwner = Pick<StorageManager, "dir">;
6
+
7
+ const captureScope = new AsyncLocalStorage<{ storage: CaptureLockOwner; limits: CaptureWriteLockLimitSource }>();
8
+
9
+ export function withCaptureWriteLockBackoff<T>(
10
+ storage: CaptureLockOwner,
11
+ limits: CaptureWriteLockBackoffLimits,
12
+ run: () => Promise<T>
13
+ ): Promise<T> {
14
+ return captureScope.run(
15
+ {
16
+ storage,
17
+ limits: {
18
+ captureWriteLockInitialDelayMs: limits.initialDelayMs,
19
+ captureWriteLockMaxDelayMs: limits.maxDelayMs,
20
+ captureWriteLockDeadlineMs: limits.deadlineMs,
21
+ },
22
+ },
23
+ run
24
+ );
25
+ }
26
+
27
+ export function scopedCaptureWriteLockLimits(storage: CaptureLockOwner): CaptureWriteLockLimitSource | undefined {
28
+ const scope = captureScope.getStore();
29
+ return scope?.storage === storage ? scope.limits : undefined;
30
+ }
@@ -0,0 +1,51 @@
1
+ // Node-local warm-cache generation marker (`<stateDir>/embeddings.generation`).
2
+ // Two-phase publication barrier: in-flight before a publication's first
3
+ // destructive write, fresh unique value after its last write (PR #3176), so a
4
+ // completed stamp is only ever stable while generation bytes are unchanged.
5
+ // Single owner of the atomic protocol and logging — the store's own mutations
6
+ // and the offline-sync direct write/delete paths (issue #3182) share it.
7
+ // Plain fs always (tmp + rename): the marker is node-local raw bytes, never
8
+ // sync traffic or secure-store content.
9
+ import { randomUUID } from "node:crypto";
10
+ import { rename, rm, writeFile } from "node:fs/promises";
11
+ import path from "node:path";
12
+
13
+ import { log } from "./logger.js";
14
+
15
+ export const GENERATION_MARKER_BASENAME = "embeddings.generation";
16
+
17
+ /** Reserved in-flight marker value; never equals a completion marker. */
18
+ export const GENERATION_MARKER_IN_FLIGHT = "in-flight";
19
+
20
+ export function generationMarkerPath(stateDirAbs: string): string {
21
+ return path.join(stateDirAbs, GENERATION_MARKER_BASENAME);
22
+ }
23
+
24
+ /** Strict atomic marker write; recovery uses it for a fresh completed value. */
25
+ export async function writeGenerationMarkerRaw(markerAbs: string, value: string): Promise<void> {
26
+ const tempPath = `${markerAbs}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}`;
27
+ try {
28
+ await writeFile(tempPath, value, "utf-8");
29
+ await rename(tempPath, markerAbs);
30
+ } catch (err) {
31
+ await rm(tempPath, { force: true }).catch(() => undefined);
32
+ throw err;
33
+ }
34
+ }
35
+
36
+ /** Barrier first half: strict, so bytes can never change under a stable stamp. */
37
+ export async function beginGenerationMarker(markerAbs: string): Promise<void> {
38
+ await writeGenerationMarkerRaw(markerAbs, GENERATION_MARKER_IN_FLIGHT);
39
+ }
40
+
41
+ /**
42
+ * Barrier second half: written after the last content write. Best-effort:
43
+ * a failure leaves the in-flight marker, whose stamp identityStamp()
44
+ * never repeats, so cached probes revalidate on every search until a
45
+ * publication completes.
46
+ */
47
+ export async function completeGenerationMarker(markerAbs: string): Promise<void> {
48
+ await writeGenerationMarkerRaw(markerAbs, randomUUID()).catch((err) => {
49
+ log.warn(`embedding index: could not write generation completion marker: ${err instanceof Error ? err.message : String(err)}`);
50
+ });
51
+ }