@remnic/core 10.0.51 → 10.0.53

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 (266) hide show
  1. package/dist/access-admin-ops-surface.js +24 -24
  2. package/dist/access-authorization-probe.js +25 -25
  3. package/dist/access-boundary.js +24 -24
  4. package/dist/access-cli.js +65 -65
  5. package/dist/access-extraction-force-flush.js +24 -24
  6. package/dist/access-http-briefing.js +25 -25
  7. package/dist/access-http-query.js +26 -26
  8. package/dist/access-http.js +40 -40
  9. package/dist/access-identity-continuity-surface.js +24 -24
  10. package/dist/access-lcm-surface.js +24 -24
  11. package/dist/access-mcp.js +33 -33
  12. package/dist/access-namespace-preflight.js +24 -24
  13. package/dist/access-observe-write-surface.js +24 -24
  14. package/dist/access-operations-batch.js +25 -25
  15. package/dist/access-operations.js +32 -32
  16. package/dist/access-recall-concurrency.js +24 -24
  17. package/dist/access-recall-response.js +24 -24
  18. package/dist/access-recall-surface.js +24 -24
  19. package/dist/access-service.js +24 -24
  20. package/dist/access-surface-catalog.js +26 -26
  21. package/dist/active-recall.js +9 -9
  22. package/dist/briefing.js +10 -10
  23. package/dist/buffer.js +5 -5
  24. package/dist/causal-consolidation.js +11 -11
  25. package/dist/{chunk-3NL4ALUP.js → chunk-24SIB3EW.js} +3 -3
  26. package/dist/{chunk-Y3T5KQCR.js → chunk-2EYCW2ET.js} +2 -2
  27. package/dist/{chunk-AHGOOZUC.js → chunk-34UVJNSG.js} +2 -2
  28. package/dist/{chunk-2EXF6IIB.js → chunk-3632XJMR.js} +2 -2
  29. package/dist/{chunk-KETS5A62.js → chunk-3H3PNQEF.js} +2 -2
  30. package/dist/{chunk-SFRBUBUZ.js → chunk-3LNAQLW4.js} +3 -3
  31. package/dist/{chunk-75BK4XGV.js → chunk-4BUJICMI.js} +10 -10
  32. package/dist/{chunk-KIWO4327.js → chunk-4W5B5Z6P.js} +2 -2
  33. package/dist/{chunk-B35EQQ7L.js → chunk-53OFDW3P.js} +3 -3
  34. package/dist/{chunk-2ONKXEC7.js → chunk-5LBBXI2A.js} +2 -2
  35. package/dist/{chunk-UCLJTGP3.js → chunk-65B5RFKQ.js} +2 -2
  36. package/dist/{chunk-KAJYSO3U.js → chunk-6CDNOREO.js} +2 -2
  37. package/dist/{chunk-POJRFSJM.js → chunk-7XGNGLAN.js} +2 -2
  38. package/dist/{chunk-A6JDT6QF.js → chunk-AO5ZOD32.js} +2 -2
  39. package/dist/{chunk-RA7YRL6H.js → chunk-AOSCGNIC.js} +3 -3
  40. package/dist/{chunk-LWMLBVGB.js → chunk-B43P3DTC.js} +2 -2
  41. package/dist/{chunk-SJD334AG.js → chunk-CA6X37OB.js} +217 -173
  42. package/dist/chunk-CA6X37OB.js.map +1 -0
  43. package/dist/{chunk-VUMWVYMR.js → chunk-CIMD2MUR.js} +3 -3
  44. package/dist/{chunk-XRFLR3XF.js → chunk-DLZGSZVC.js} +22 -9
  45. package/dist/chunk-DLZGSZVC.js.map +1 -0
  46. package/dist/{chunk-5CWH2LKL.js → chunk-DOJBV6WR.js} +29 -14
  47. package/dist/chunk-DOJBV6WR.js.map +1 -0
  48. package/dist/{chunk-44EUCSG4.js → chunk-FFQNNFHX.js} +2 -2
  49. package/dist/{chunk-HEF4BRMT.js → chunk-FZLZUDJJ.js} +2 -2
  50. package/dist/{chunk-L3EFYRYK.js → chunk-GGFQAGOT.js} +7 -7
  51. package/dist/{chunk-ZLCBLDJO.js → chunk-GIRWNTMV.js} +2 -2
  52. package/dist/{chunk-EC2KVA27.js → chunk-H4DWSOBQ.js} +169 -105
  53. package/dist/chunk-H4DWSOBQ.js.map +1 -0
  54. package/dist/{chunk-SHNM7RIT.js → chunk-HJ4X4BGS.js} +2 -2
  55. package/dist/{chunk-MUNYUSBU.js → chunk-HJQ4NKKO.js} +2 -2
  56. package/dist/{chunk-V6Z4NAJZ.js → chunk-HM3ZTDAX.js} +2 -2
  57. package/dist/{chunk-EZS6QJNC.js → chunk-IFOCK3OJ.js} +2 -2
  58. package/dist/{chunk-LXXIV7Y2.js → chunk-JEX2JL3U.js} +7 -2
  59. package/dist/{chunk-LXXIV7Y2.js.map → chunk-JEX2JL3U.js.map} +1 -1
  60. package/dist/{chunk-DF6ZF2BN.js → chunk-LIVNX7WK.js} +2 -2
  61. package/dist/{chunk-WY66J4PI.js → chunk-LRVFS4KA.js} +2 -2
  62. package/dist/{chunk-LMB47UM6.js → chunk-LTDK6HBV.js} +2 -2
  63. package/dist/{chunk-HCIRR3BA.js → chunk-M4U25HLR.js} +2 -2
  64. package/dist/{chunk-YK7ZJPQM.js → chunk-MGN2RQRG.js} +2 -2
  65. package/dist/{chunk-G26YNEOC.js → chunk-NWA6IXR3.js} +1 -1
  66. package/dist/{chunk-G26YNEOC.js.map → chunk-NWA6IXR3.js.map} +1 -1
  67. package/dist/{chunk-JIJAWTRK.js → chunk-OCXDZJL4.js} +264 -194
  68. package/dist/chunk-OCXDZJL4.js.map +1 -0
  69. package/dist/{chunk-IUQXRRJB.js → chunk-OMWQO7H6.js} +2 -2
  70. package/dist/{chunk-7VO6E5UD.js → chunk-OVZIYLBZ.js} +6 -2
  71. package/dist/chunk-OVZIYLBZ.js.map +1 -0
  72. package/dist/{chunk-SPTPBKZX.js → chunk-OWNAWY6D.js} +2 -2
  73. package/dist/{chunk-XKDQTDXN.js → chunk-PFUXPTBT.js} +36 -15
  74. package/dist/chunk-PFUXPTBT.js.map +1 -0
  75. package/dist/{chunk-DQOGZZJA.js → chunk-QAHP5SBG.js} +3 -3
  76. package/dist/{chunk-GBGU5OZP.js → chunk-QF5EJ5VP.js} +13 -13
  77. package/dist/{chunk-FT75AQ74.js → chunk-QS5DUSBM.js} +2 -2
  78. package/dist/{chunk-72CBJ5VP.js → chunk-R3WZ74B2.js} +3 -3
  79. package/dist/{chunk-PDTNQLPC.js → chunk-RG3I2663.js} +2 -2
  80. package/dist/{chunk-CK6GCGMX.js → chunk-RTJJPW3C.js} +2 -2
  81. package/dist/{chunk-RJDYDF5K.js → chunk-TRAOZ2WP.js} +2 -2
  82. package/dist/{chunk-6ZAU7LAR.js → chunk-TTTPTQ6S.js} +2 -2
  83. package/dist/{chunk-JS44PBCM.js → chunk-U2A56LLF.js} +6 -6
  84. package/dist/{chunk-MC7PXJDP.js → chunk-UBOWDOL5.js} +5 -5
  85. package/dist/{chunk-4FM35YIA.js → chunk-UQYBPPVC.js} +2 -2
  86. package/dist/{chunk-OCRLJJOV.js → chunk-V4VCBFAL.js} +3 -3
  87. package/dist/{chunk-FNNGWN3O.js → chunk-VGE4PUY6.js} +2 -2
  88. package/dist/{chunk-5DVOBBTV.js → chunk-VV73XT3A.js} +2 -2
  89. package/dist/{chunk-GE3ZX6YK.js → chunk-W7NKMRAF.js} +2 -2
  90. package/dist/{chunk-AJJPXUE6.js → chunk-WBN66HPI.js} +2 -2
  91. package/dist/{chunk-XWJUFER3.js → chunk-WGFEGBFB.js} +2 -2
  92. package/dist/{chunk-43TUWQNR.js → chunk-XDKEHZUC.js} +2 -2
  93. package/dist/{chunk-ROAKLYOL.js → chunk-XHEKS4UN.js} +2 -2
  94. package/dist/{chunk-ZKK3VMWU.js → chunk-XVTB6BZS.js} +2 -2
  95. package/dist/{chunk-AZLD4CKG.js → chunk-Y56D5FSD.js} +17 -17
  96. package/dist/{chunk-MPWOAIIH.js → chunk-YDT3OEYF.js} +2 -2
  97. package/dist/{chunk-IN6U2BS5.js → chunk-YJHOVA42.js} +2 -2
  98. package/dist/{chunk-TC55M5PO.js → chunk-YLN4ZQV4.js} +2 -2
  99. package/dist/cli.js +50 -50
  100. package/dist/coding/export-okf-codegraph.js +9 -9
  101. package/dist/compounding/engine.js +11 -11
  102. package/dist/config.js +9 -9
  103. package/dist/connectors/codex-materialize-runner.js +10 -10
  104. package/dist/connectors/index.js +10 -10
  105. package/dist/convergence-refresh.js +12 -12
  106. package/dist/corpus-watermark.js +12 -12
  107. package/dist/entity-retrieval.js +10 -10
  108. package/dist/external-wiki-access.js +25 -25
  109. package/dist/extraction.js +14 -14
  110. package/dist/harmonic-retrieval.js +10 -10
  111. package/dist/index.js +65 -65
  112. package/dist/location/index.js +12 -12
  113. package/dist/maintenance/memory-governance.js +10 -10
  114. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +10 -10
  115. package/dist/maintenance/rebuild-memory-projection-runner.js +12 -12
  116. package/dist/maintenance/rebuild-memory-projection.js +11 -11
  117. package/dist/memory-browse-operations.js +25 -25
  118. package/dist/memory-browse.js +5 -5
  119. package/dist/namespaces/migrate.js +11 -11
  120. package/dist/namespaces/search.d.ts.map +1 -1
  121. package/dist/namespaces/search.js +8 -8
  122. package/dist/namespaces/storage.js +10 -10
  123. package/dist/operator-doctor-corpus.js +13 -13
  124. package/dist/operator-toolkit.js +18 -18
  125. package/dist/orchestration/extraction-persist-deps.d.ts +2 -0
  126. package/dist/orchestration/extraction-persist-deps.d.ts.map +1 -1
  127. package/dist/orchestration/extraction-persist-promotion.d.ts +40 -10
  128. package/dist/orchestration/extraction-persist-promotion.d.ts.map +1 -1
  129. package/dist/orchestration/extraction-persist.d.ts.map +1 -1
  130. package/dist/orchestration/lifecycle-pending-fallback-drain.d.ts +18 -0
  131. package/dist/orchestration/lifecycle-pending-fallback-drain.d.ts.map +1 -0
  132. package/dist/orchestration/maintenance.d.ts +11 -13
  133. package/dist/orchestration/maintenance.d.ts.map +1 -1
  134. package/dist/orchestration/maintenance.js +20 -20
  135. package/dist/orchestration/qmd-maintenance-completion.d.ts +20 -0
  136. package/dist/orchestration/qmd-maintenance-completion.d.ts.map +1 -0
  137. package/dist/orchestrator.d.ts.map +1 -1
  138. package/dist/orchestrator.js +65 -65
  139. package/dist/qmd.js +2 -2
  140. package/dist/recall-composition-decision.js +2 -2
  141. package/dist/recall-navigation-operations.js +25 -25
  142. package/dist/recall-navigation.js +24 -24
  143. package/dist/recall-state-view-admission.js +5 -5
  144. package/dist/recall-why-service.js +5 -5
  145. package/dist/resume-bundles.js +9 -9
  146. package/dist/search/factory.js +7 -7
  147. package/dist/search/index.js +7 -7
  148. package/dist/search/lancedb-backend.d.ts +3 -0
  149. package/dist/search/lancedb-backend.d.ts.map +1 -1
  150. package/dist/search/lancedb-backend.js +2 -2
  151. package/dist/search/meilisearch-backend.d.ts +3 -0
  152. package/dist/search/meilisearch-backend.d.ts.map +1 -1
  153. package/dist/search/meilisearch-backend.js +2 -2
  154. package/dist/search/orama-backend.d.ts +3 -0
  155. package/dist/search/orama-backend.d.ts.map +1 -1
  156. package/dist/search/orama-backend.js +2 -2
  157. package/dist/search/port.d.ts +7 -0
  158. package/dist/search/port.d.ts.map +1 -1
  159. package/dist/search/port.js +1 -1
  160. package/dist/search/remote-backend.d.ts +2 -0
  161. package/dist/search/remote-backend.d.ts.map +1 -1
  162. package/dist/search/remote-backend.js +2 -2
  163. package/dist/semantic-consolidation.js +11 -11
  164. package/dist/semantic-rule-promotion.js +10 -10
  165. package/dist/semantic-rule-verifier.js +10 -10
  166. package/dist/source-agent-qualifier.js +13 -13
  167. package/dist/standup/build.js +10 -10
  168. package/dist/storage/entity-canonical-id-migration-adapter.d.ts +7 -1
  169. package/dist/storage/entity-canonical-id-migration-adapter.d.ts.map +1 -1
  170. package/dist/storage/entity-migration-maintenance-pending.d.ts +31 -0
  171. package/dist/storage/entity-migration-maintenance-pending.d.ts.map +1 -0
  172. package/dist/storage.d.ts +2 -2
  173. package/dist/storage.d.ts.map +1 -1
  174. package/dist/storage.js +9 -9
  175. package/dist/support-passport/index.js +27 -27
  176. package/dist/transfer/export-okf.js +10 -10
  177. package/dist/verified-recall.js +10 -10
  178. package/dist/who-knows-cli.js +11 -11
  179. package/dist/who-knows.js +10 -10
  180. package/package.json +2 -2
  181. package/src/namespaces/search.test.ts +121 -0
  182. package/src/namespaces/search.ts +8 -0
  183. package/src/orchestration/extraction-persist-deps.ts +3 -0
  184. package/src/orchestration/extraction-persist-promotion.ts +104 -16
  185. package/src/orchestration/extraction-persist.ts +66 -77
  186. package/src/orchestration/lifecycle-pending-fallback-drain.ts +97 -0
  187. package/src/orchestration/maintenance.test.ts +443 -1
  188. package/src/orchestration/maintenance.ts +73 -95
  189. package/src/orchestration/qmd-maintenance-completion.ts +32 -0
  190. package/src/orchestrator-entity-write-failure.test.ts +370 -0
  191. package/src/orchestrator.ts +9 -1
  192. package/src/search/lancedb-backend.ts +29 -12
  193. package/src/search/meilisearch-backend.test.ts +148 -0
  194. package/src/search/meilisearch-backend.ts +41 -14
  195. package/src/search/orama-backend.test.ts +75 -1
  196. package/src/search/orama-backend.ts +22 -7
  197. package/src/search/port.ts +7 -0
  198. package/src/search/remote-backend.ts +4 -0
  199. package/src/storage/entity-canonical-id-migration-adapter.ts +44 -9
  200. package/src/storage/entity-migration-maintenance-pending-helpers.test.ts +87 -0
  201. package/src/storage/entity-migration-maintenance-pending.test.ts +242 -0
  202. package/src/storage/entity-migration-maintenance-pending.ts +89 -0
  203. package/src/storage.ts +2 -2
  204. package/dist/chunk-5CWH2LKL.js.map +0 -1
  205. package/dist/chunk-7VO6E5UD.js.map +0 -1
  206. package/dist/chunk-EC2KVA27.js.map +0 -1
  207. package/dist/chunk-JIJAWTRK.js.map +0 -1
  208. package/dist/chunk-SJD334AG.js.map +0 -1
  209. package/dist/chunk-XKDQTDXN.js.map +0 -1
  210. package/dist/chunk-XRFLR3XF.js.map +0 -1
  211. /package/dist/{chunk-3NL4ALUP.js.map → chunk-24SIB3EW.js.map} +0 -0
  212. /package/dist/{chunk-Y3T5KQCR.js.map → chunk-2EYCW2ET.js.map} +0 -0
  213. /package/dist/{chunk-AHGOOZUC.js.map → chunk-34UVJNSG.js.map} +0 -0
  214. /package/dist/{chunk-2EXF6IIB.js.map → chunk-3632XJMR.js.map} +0 -0
  215. /package/dist/{chunk-KETS5A62.js.map → chunk-3H3PNQEF.js.map} +0 -0
  216. /package/dist/{chunk-SFRBUBUZ.js.map → chunk-3LNAQLW4.js.map} +0 -0
  217. /package/dist/{chunk-75BK4XGV.js.map → chunk-4BUJICMI.js.map} +0 -0
  218. /package/dist/{chunk-KIWO4327.js.map → chunk-4W5B5Z6P.js.map} +0 -0
  219. /package/dist/{chunk-B35EQQ7L.js.map → chunk-53OFDW3P.js.map} +0 -0
  220. /package/dist/{chunk-2ONKXEC7.js.map → chunk-5LBBXI2A.js.map} +0 -0
  221. /package/dist/{chunk-UCLJTGP3.js.map → chunk-65B5RFKQ.js.map} +0 -0
  222. /package/dist/{chunk-KAJYSO3U.js.map → chunk-6CDNOREO.js.map} +0 -0
  223. /package/dist/{chunk-POJRFSJM.js.map → chunk-7XGNGLAN.js.map} +0 -0
  224. /package/dist/{chunk-A6JDT6QF.js.map → chunk-AO5ZOD32.js.map} +0 -0
  225. /package/dist/{chunk-RA7YRL6H.js.map → chunk-AOSCGNIC.js.map} +0 -0
  226. /package/dist/{chunk-LWMLBVGB.js.map → chunk-B43P3DTC.js.map} +0 -0
  227. /package/dist/{chunk-VUMWVYMR.js.map → chunk-CIMD2MUR.js.map} +0 -0
  228. /package/dist/{chunk-44EUCSG4.js.map → chunk-FFQNNFHX.js.map} +0 -0
  229. /package/dist/{chunk-HEF4BRMT.js.map → chunk-FZLZUDJJ.js.map} +0 -0
  230. /package/dist/{chunk-L3EFYRYK.js.map → chunk-GGFQAGOT.js.map} +0 -0
  231. /package/dist/{chunk-ZLCBLDJO.js.map → chunk-GIRWNTMV.js.map} +0 -0
  232. /package/dist/{chunk-SHNM7RIT.js.map → chunk-HJ4X4BGS.js.map} +0 -0
  233. /package/dist/{chunk-MUNYUSBU.js.map → chunk-HJQ4NKKO.js.map} +0 -0
  234. /package/dist/{chunk-V6Z4NAJZ.js.map → chunk-HM3ZTDAX.js.map} +0 -0
  235. /package/dist/{chunk-EZS6QJNC.js.map → chunk-IFOCK3OJ.js.map} +0 -0
  236. /package/dist/{chunk-DF6ZF2BN.js.map → chunk-LIVNX7WK.js.map} +0 -0
  237. /package/dist/{chunk-WY66J4PI.js.map → chunk-LRVFS4KA.js.map} +0 -0
  238. /package/dist/{chunk-LMB47UM6.js.map → chunk-LTDK6HBV.js.map} +0 -0
  239. /package/dist/{chunk-HCIRR3BA.js.map → chunk-M4U25HLR.js.map} +0 -0
  240. /package/dist/{chunk-YK7ZJPQM.js.map → chunk-MGN2RQRG.js.map} +0 -0
  241. /package/dist/{chunk-IUQXRRJB.js.map → chunk-OMWQO7H6.js.map} +0 -0
  242. /package/dist/{chunk-SPTPBKZX.js.map → chunk-OWNAWY6D.js.map} +0 -0
  243. /package/dist/{chunk-DQOGZZJA.js.map → chunk-QAHP5SBG.js.map} +0 -0
  244. /package/dist/{chunk-GBGU5OZP.js.map → chunk-QF5EJ5VP.js.map} +0 -0
  245. /package/dist/{chunk-FT75AQ74.js.map → chunk-QS5DUSBM.js.map} +0 -0
  246. /package/dist/{chunk-72CBJ5VP.js.map → chunk-R3WZ74B2.js.map} +0 -0
  247. /package/dist/{chunk-PDTNQLPC.js.map → chunk-RG3I2663.js.map} +0 -0
  248. /package/dist/{chunk-CK6GCGMX.js.map → chunk-RTJJPW3C.js.map} +0 -0
  249. /package/dist/{chunk-RJDYDF5K.js.map → chunk-TRAOZ2WP.js.map} +0 -0
  250. /package/dist/{chunk-6ZAU7LAR.js.map → chunk-TTTPTQ6S.js.map} +0 -0
  251. /package/dist/{chunk-JS44PBCM.js.map → chunk-U2A56LLF.js.map} +0 -0
  252. /package/dist/{chunk-MC7PXJDP.js.map → chunk-UBOWDOL5.js.map} +0 -0
  253. /package/dist/{chunk-4FM35YIA.js.map → chunk-UQYBPPVC.js.map} +0 -0
  254. /package/dist/{chunk-OCRLJJOV.js.map → chunk-V4VCBFAL.js.map} +0 -0
  255. /package/dist/{chunk-FNNGWN3O.js.map → chunk-VGE4PUY6.js.map} +0 -0
  256. /package/dist/{chunk-5DVOBBTV.js.map → chunk-VV73XT3A.js.map} +0 -0
  257. /package/dist/{chunk-GE3ZX6YK.js.map → chunk-W7NKMRAF.js.map} +0 -0
  258. /package/dist/{chunk-AJJPXUE6.js.map → chunk-WBN66HPI.js.map} +0 -0
  259. /package/dist/{chunk-XWJUFER3.js.map → chunk-WGFEGBFB.js.map} +0 -0
  260. /package/dist/{chunk-43TUWQNR.js.map → chunk-XDKEHZUC.js.map} +0 -0
  261. /package/dist/{chunk-ROAKLYOL.js.map → chunk-XHEKS4UN.js.map} +0 -0
  262. /package/dist/{chunk-ZKK3VMWU.js.map → chunk-XVTB6BZS.js.map} +0 -0
  263. /package/dist/{chunk-AZLD4CKG.js.map → chunk-Y56D5FSD.js.map} +0 -0
  264. /package/dist/{chunk-MPWOAIIH.js.map → chunk-YDT3OEYF.js.map} +0 -0
  265. /package/dist/{chunk-IN6U2BS5.js.map → chunk-YJHOVA42.js.map} +0 -0
  266. /package/dist/{chunk-TC55M5PO.js.map → chunk-YLN4ZQV4.js.map} +0 -0
@@ -68,10 +68,7 @@ import {
68
68
  } from "../source-attribution.js";
69
69
  import { classifyMemoryKind } from "../himem.js";
70
70
  import { shouldPromoteGlobalFactToShared, withholdToolScopedFromSharedNamespace } from "../tool-scoped-memory.js";
71
- import {
72
- buildBehaviorSignalsForMemory,
73
- dedupeBehaviorSignalsByMemoryAndHash,
74
- } from "../behavior-signals.js";
71
+ import { buildBehaviorSignalsForMemory } from "../behavior-signals.js";
75
72
  import { buildProcedurePersistBody } from "../procedural/procedure-types.js";
76
73
  import { stripAttributesSuffix } from "../structured-attributes.js";
77
74
  import { resolveWriteSubject } from "../memory-subject.js";
@@ -103,7 +100,7 @@ import type {
103
100
  } from "../types.js";
104
101
  import {
105
102
  createBatchPromotedCopyProbe,
106
- flushDeferredFactHashOnFailure,
103
+ finalizeExtractionCommittedWrites,
107
104
  makeSubjectGuardAllows,
108
105
  profileAutoPromotionAllows,
109
106
  readActiveMemoriesBothTiers,
@@ -120,7 +117,7 @@ import {
120
117
  resolvePersistedMemoryRelativePath,
121
118
  } from "../orchestrator.js";
122
119
  import type { HarmonicConstructionInput } from "../harmonic-construction.js";
123
- import { enqueueMergedTargetForHarmonicConstruction, persistConstructedHarmonicRecords } from "./harmonic-construction-persist.js";
120
+ import { enqueueMergedTargetForHarmonicConstruction } from "./harmonic-construction-persist.js";
124
121
  import { applySemanticMergeAtPersist, runMergedTargetPostEffects, writeMergedVerbatimArtifact } from "./semantic-merge-persist.js";
125
122
  import { buildMergedTargetPromotionPayload } from "./semantic-merge-promotion-payload.js";
126
123
  import { persistMergedTargetThreadEpisode } from "./semantic-merge-commit-effects.js";
@@ -291,6 +288,7 @@ export class ExtractionPersistCoordinator {
291
288
  events: [...events],
292
289
  });
293
290
  };
291
+
294
292
  const sharedProfileLayer = scopeProfileWritePlan?.layers.find(
295
293
  (layer) =>
296
294
  layer.id === "serverShared" &&
@@ -1106,6 +1104,32 @@ export class ExtractionPersistCoordinator {
1106
1104
  0,
1107
1105
  this.deps.config.extractionMaxProfileUpdatesPerRun,
1108
1106
  );
1107
+ const finalizeCommittedWrites = async (scheduleQmd: boolean): Promise<void> => {
1108
+ await finalizeExtractionCommittedWrites({
1109
+ saveContentHashIndexes: () => this.deps.saveContentHashIndexes(),
1110
+ behaviorSignalsByStorage: behaviorSignalsByStorage.values(),
1111
+ harmonic: {
1112
+ enabled: harmonicConstructionEnabled,
1113
+ entries: harmonicFactsByStorage.values(),
1114
+ baseStorageDir: storage.dir,
1115
+ abstractionNodeStoreDir:
1116
+ !scopeProfileWritePlan && harmonicBaseNamespace === this.deps.config.defaultNamespace
1117
+ ? this.deps.config.abstractionNodeStoreDir
1118
+ : undefined,
1119
+ sessionKey: sourceContext?.sessionKey,
1120
+ validAt: sourceContext?.validAt,
1121
+ episodeTitle: result.episodeTitle,
1122
+ anchorsEnabled: harmonicAnchorsEnabled,
1123
+ entityMentions: entities,
1124
+ },
1125
+ updateTemporalTagIndexes: (target, ids) =>
1126
+ this.deps.updateTemporalTagIndexes(target, ids),
1127
+ fallbackStorage: storage,
1128
+ persistedIdsByStorage,
1129
+ requestQmdMaintenance: () => this.deps.requestQmdMaintenance(),
1130
+ scheduleQmd,
1131
+ });
1132
+ };
1109
1133
 
1110
1134
  if (
1111
1135
  facts.length < result.facts.length ||
@@ -2583,6 +2607,25 @@ export class ExtractionPersistCoordinator {
2583
2607
  // so a blocked fact creates no active shared copy / supersession / graph entry.
2584
2608
  const tombstoneBlocked = factWrite.tombstoneBlocked;
2585
2609
  const postWriteGuard = faithfulnessEnforceStatus === "pending_review" || tombstoneBlocked;
2610
+ // #3231: the fact is durable now. Track it before any post-write step
2611
+ // that can throw, so the batch-end finalization on a failure path still
2612
+ // covers it (a retry exact-dedupes the fact and would not re-queue it).
2613
+ trackBehaviorSignals(
2614
+ targetStorage,
2615
+ buildBehaviorSignalsForMemory({
2616
+ memoryId,
2617
+ category: writeCategory,
2618
+ content: fact.content,
2619
+ namespace: this.deps.storageDirNamespace(targetStorage.dir),
2620
+ confidence: fact.confidence,
2621
+ source: "extraction",
2622
+ }),
2623
+ );
2624
+ trackPersistedId(targetStorage, memoryId, {
2625
+ pendingReview: postWriteGuard,
2626
+ category: writeCategory,
2627
+ harmonicFact,
2628
+ });
2586
2629
  // #1645: defer contradiction auto-resolve until tombstone status is
2587
2630
  // known (see applyDeferredContradictionResolve).
2588
2631
  try {
@@ -2596,7 +2639,9 @@ export class ExtractionPersistCoordinator {
2596
2639
  await anchorSnapshots.remove(targetStorage, contradiction!.supersededId);
2597
2640
  }
2598
2641
  } catch (err) {
2599
- await flushDeferredFactHashOnFailure(() => this.deps.saveContentHashIndexes(), factDedupEnabled);
2642
+ await finalizeCommittedWrites(true).catch((finalizeErr) =>
2643
+ log.warn(`committed-write finalization after post-write failure failed: ${finalizeErr}`),
2644
+ );
2600
2645
  throw err;
2601
2646
  }
2602
2647
  if (routedRuleId) {
@@ -2632,22 +2677,6 @@ export class ExtractionPersistCoordinator {
2632
2677
  }
2633
2678
  }
2634
2679
  try {
2635
- trackBehaviorSignals(
2636
- targetStorage,
2637
- buildBehaviorSignalsForMemory({
2638
- memoryId,
2639
- category: writeCategory,
2640
- content: fact.content,
2641
- namespace: this.deps.storageDirNamespace(targetStorage.dir),
2642
- confidence: fact.confidence,
2643
- source: "extraction",
2644
- }),
2645
- );
2646
- trackPersistedId(targetStorage, memoryId, {
2647
- pendingReview: postWriteGuard,
2648
- category: writeCategory,
2649
- harmonicFact,
2650
- });
2651
2680
  await anchorSnapshots.replace(targetStorage, memoryId, writeCategory, memoryPathById);
2652
2681
  if (
2653
2682
  !postWriteGuard &&
@@ -2782,9 +2811,12 @@ export class ExtractionPersistCoordinator {
2782
2811
  );
2783
2812
  }
2784
2813
  } catch (err) {
2785
- // PR #2016: flush the deferred fact-hash before propagating so a durable
2786
- // .md never outlives a missing shared fact-hash index entry.
2787
- await flushDeferredFactHashOnFailure(() => this.deps.saveContentHashIndexes(), factDedupEnabled);
2814
+ // PR #2016 / #3231: finalize deferred side effects for facts already
2815
+ // durable before propagating so hash/behavior/harmonic/temporal/QMD
2816
+ // still land on a partial batch.
2817
+ await finalizeCommittedWrites(true).catch((finalizeErr) =>
2818
+ log.warn(`committed-write finalization after post-write failure failed: ${finalizeErr}`),
2819
+ );
2788
2820
  throw err;
2789
2821
  }
2790
2822
  }
@@ -2807,7 +2839,6 @@ export class ExtractionPersistCoordinator {
2807
2839
  durableNonFactTouchRecorded = true;
2808
2840
  touchBaseNonFactNamespace();
2809
2841
  };
2810
- // #1955 review: entity fields are screened before entering the index (screenEntityForIndex).
2811
2842
  const entityScreenOn = resolveSecurityCapabilities(this.deps.config).injectionScreen;
2812
2843
  const entityScreenProfile = resolveSecurityCapabilities(this.deps.config).injectionScreenProfile;
2813
2844
  for (const entity of entities) {
@@ -2829,7 +2860,10 @@ export class ExtractionPersistCoordinator {
2829
2860
  recordDurableNonFactWrite();
2830
2861
  }
2831
2862
  } catch (err) {
2832
- log.warn(`persistExtraction: entity write failed: ${err}`);
2863
+ await finalizeCommittedWrites(true).catch((finalizeErr) =>
2864
+ log.warn(`committed-write finalization after entity failure failed: ${finalizeErr}`),
2865
+ );
2866
+ throw err;
2833
2867
  }
2834
2868
  }
2835
2869
  // Persist entity relationships (v7.0). #1955 review: source/label/target are screened.
@@ -2929,28 +2963,9 @@ export class ExtractionPersistCoordinator {
2929
2963
  touchBaseNonFactNamespace();
2930
2964
  }
2931
2965
 
2932
- // Save any content-hash indexes touched during the batch via the removal-
2933
- // aware, lock-held reconciling save (issue #1909). Round 11: the fact-hash
2934
- // index is rebuilt from the corpus on every restart (no ready marker), so
2935
- // this on-disk write is the in-process persisted view — never a cross-restart
2936
- // trust anchor. A deferred write whose addContentHashDedup threw is still
2937
- // safe: the fact .md is durable and the next restart's rebuild includes it.
2938
- await this.deps.saveContentHashIndexes().catch((err) => {
2939
- log.warn(`content-hash index save failed: ${err}`);
2940
- });
2941
-
2942
- for (const {
2943
- storage: targetStorage,
2944
- events,
2945
- } of behaviorSignalsByStorage.values()) {
2946
- const dedupedSignals = dedupeBehaviorSignalsByMemoryAndHash(events);
2947
- if (dedupedSignals.length === 0) continue;
2948
- await targetStorage
2949
- .appendBehaviorSignals(dedupedSignals)
2950
- .catch((err) =>
2951
- log.warn(`appendBehaviorSignals failed (non-fatal): ${err}`),
2952
- );
2953
- }
2966
+ // Shared batch-end finalization (hash, behavior, harmonic, temporal).
2967
+ // Failure paths call the same helper with scheduleQmd=true (#3231).
2968
+ await finalizeCommittedWrites(false);
2954
2969
 
2955
2970
  const dedupSuffix = `${dedupedCount > 0 ? ` (${dedupedCount} deduped)` : ""}${semanticMergedCount > 0 ? ` (${semanticMergedCount} merged)` : ""}`;
2956
2971
  const gatedSuffix =
@@ -2962,33 +2977,7 @@ export class ExtractionPersistCoordinator {
2962
2977
  log.info(
2963
2978
  `persisted: ${facts.length - dedupedCount - importanceGatedCount - judgeGatedCount - redactionGatedCount - semanticMergedCount} facts${dedupSuffix}${gatedSuffix}${judgeSuffix}${redactionSuffix}, ${entities.length} entities, ${questions.length} questions, ${profileUpdates.length} profile updates`,
2964
2979
  );
2965
- if (harmonicConstructionEnabled && harmonicFactsByStorage.size > 0) {
2966
- await persistConstructedHarmonicRecords({
2967
- entries: harmonicFactsByStorage.values(),
2968
- baseStorageDir: storage.dir,
2969
- abstractionNodeStoreDir:
2970
- !scopeProfileWritePlan && harmonicBaseNamespace === this.deps.config.defaultNamespace
2971
- ? this.deps.config.abstractionNodeStoreDir
2972
- : undefined,
2973
- sessionKey: sourceContext?.sessionKey,
2974
- validAt: sourceContext?.validAt,
2975
- episodeTitle: result.episodeTitle,
2976
- anchorsEnabled: harmonicAnchorsEnabled,
2977
- entityMentions: entities,
2978
- });
2979
- }
2980
- // Update temporal + tag indexes (v8.1) — fire-and-forget, fail-open
2981
- void (async () => {
2982
- if (persistedIdsByStorage.size === 0) {
2983
- await this.deps.updateTemporalTagIndexes(storage, []);
2984
- return;
2985
- }
2986
- for (const entry of persistedIdsByStorage.values()) {
2987
- await this.deps.updateTemporalTagIndexes(entry.storage, entry.ids);
2988
- }
2989
- })().catch((err) =>
2990
- log.debug(`temporal-index update error (non-fatal): ${err}`),
2991
- );
2980
+
2992
2981
  // #1635: surface pending_review ids so the thread episode set excludes them.
2993
2982
  this.deps.setLastPersistExtractionPendingReviewIds(pendingReviewPersistedIds);
2994
2983
  // Return the persisted fact IDs for threading
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Fallback lifecycle pending-append drain for targets with no secure
3
+ * StorageManager. Moved verbatim out of maintenance.ts (issue #2033) so that
4
+ * file stays under the structural size ceiling; behavior is unchanged.
5
+ */
6
+
7
+ import { appendFile, mkdir, readFile, writeFile } from "node:fs/promises";
8
+ import path from "node:path";
9
+
10
+ import { log } from "../logger.js";
11
+ import {
12
+ drainPendingLifecycleLedgerIfAny,
13
+ pendingLifecycleLedgerDir,
14
+ type LifecyclePendingIo,
15
+ } from "../storage/memory-lifecycle-ledger-access.js";
16
+ import { probeEncryptedRegularFileHeader } from "../secure-store/secure-fs.js";
17
+ import { listContainedSpillFiles } from "../utils/path-containment.js";
18
+
19
+ /**
20
+ * Drain a filesystem-fallback target's pending lifecycle-append spill when no
21
+ * secure StorageManager is available (catalog-disabled namespace; issue
22
+ * #2033). Uses the safe path-scoped PLAINTEXT context this fallback already
23
+ * operates in: a keyless drain can only fold plaintext spills into a plaintext
24
+ * ledger, so it refuses when the ledger or ANY spill is encrypted at rest,
25
+ * leaving those pending for a keyed (catalog-path) drain — exactly mirroring
26
+ * the fallback compaction's encrypted-ledger deferral. Non-fatal; a fast
27
+ * no-op when nothing is pending. The shared spill lister enforces the symlink/
28
+ * containment guard on every spill file it reads or deletes.
29
+ */
30
+ export async function drainPendingLifecycleAppendsForPath(memoryDir: string): Promise<void> {
31
+ const ledgerPath = path.join(memoryDir, "state", "memory-lifecycle-ledger.jsonl");
32
+ const spillDir = pendingLifecycleLedgerDir(ledgerPath);
33
+ // Enumerate spills through the SAME guarded lister the actual drain uses
34
+ // (listContainedSpillFiles): it rejects a symlinked/non-directory spill dir
35
+ // and skips any symlink/FIFO/device/escaping entry, returning only regular
36
+ // files contained in the dir. Never raw-readdir + open() an untrusted name:
37
+ // opening a FIFO would block until a writer appears and a symlink would
38
+ // redirect the probe outside the dir (#2033). Enumerate BOTH live `*.jsonl`
39
+ // spills and crash-orphaned `*.jsonl.claimed` files: a drain that died
40
+ // between claiming a spill (rename to `.claimed`) and committing it leaves
41
+ // the ONLY copy of those rows as a claimed orphan. Gating solely on live
42
+ // spills would early-return here whenever the pending dir holds nothing but
43
+ // orphans, stranding those rows forever; proceeding lets
44
+ // drainPendingLifecycleLedgerIfAny -> recoverOrphanedClaims restore and
45
+ // re-commit them under the ledger lock (#2033).
46
+ let spillFiles: string[];
47
+ let claimedOrphans: string[];
48
+ try {
49
+ spillFiles = await listContainedSpillFiles(spillDir);
50
+ claimedOrphans = await listContainedSpillFiles(spillDir, ".jsonl.claimed");
51
+ } catch (err) {
52
+ log.debug(`fallback lifecycle pending scan failed (non-fatal) for ${memoryDir}: ${err}`);
53
+ return;
54
+ }
55
+ if (spillFiles.length === 0 && claimedOrphans.length === 0) return;
56
+ // The pending encryption state is authoritative only UNDER the ledger lock:
57
+ // drainPendingLifecycleLedgerIfAny waits for the lock and re-enumerates the
58
+ // pending dir, so a secure-store writer that spills an encrypted file — or a
59
+ // keyed compaction that rewrites the ledger encrypted — while this fallback
60
+ // waits would defeat any pre-lock probe (#2033). Probe each file at the
61
+ // moment of use inside the held lock instead: readSecure refuses an
62
+ // encrypted spill (the fold reads each spill lazily and propagates the throw
63
+ // BEFORE claiming that spill, leaving it intact) and the append refuses a
64
+ // ledger that became encrypted (the fold rolls the claims back). Either way
65
+ // the plaintext IO
66
+ // never reads or writes ciphertext; the keyed catalog-path drain handles the
67
+ // deferred rows.
68
+ const io: LifecyclePendingIo = {
69
+ writeSecure: async (filePath, payload) => {
70
+ await mkdir(path.dirname(filePath), { recursive: true });
71
+ await writeFile(filePath, payload, "utf-8");
72
+ },
73
+ readSecure: async (filePath) => {
74
+ if (await probeEncryptedRegularFileHeader(filePath)) {
75
+ throw new Error(`fallback lifecycle drain deferred: encrypted spill at ${filePath}`);
76
+ }
77
+ return readFile(filePath, "utf-8");
78
+ },
79
+ };
80
+ try {
81
+ await drainPendingLifecycleLedgerIfAny(
82
+ ledgerPath,
83
+ io,
84
+ async (payload) => {
85
+ if (await probeEncryptedRegularFileHeader(ledgerPath)) {
86
+ throw new Error(`fallback lifecycle drain deferred: ledger became encrypted at ${ledgerPath}`);
87
+ }
88
+ await appendFile(ledgerPath, payload, "utf-8");
89
+ },
90
+ async () => {
91
+ await mkdir(path.dirname(ledgerPath), { recursive: true });
92
+ },
93
+ );
94
+ } catch (err) {
95
+ log.debug(`fallback lifecycle pending drain failed (non-fatal) for ${memoryDir}: ${err}`);
96
+ }
97
+ }