@remnic/core 9.63.4 → 9.63.5

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 (415) hide show
  1. package/dist/access-admin-ops-surface.d.ts +11 -11
  2. package/dist/access-admin-ops-surface.js +23 -23
  3. package/dist/access-authorization-probe.d.ts +11 -11
  4. package/dist/access-authorization-probe.js +24 -24
  5. package/dist/access-boundary.d.ts +11 -11
  6. package/dist/access-boundary.js +23 -23
  7. package/dist/access-cli.js +55 -55
  8. package/dist/access-coding-context-resolution.d.ts +1 -1
  9. package/dist/access-extraction-force-flush.d.ts +11 -11
  10. package/dist/access-extraction-force-flush.js +23 -23
  11. package/dist/access-health-types.d.ts +1 -1
  12. package/dist/access-http-lcm-compaction.d.ts +11 -11
  13. package/dist/access-http-lifecycle-flush.d.ts +11 -11
  14. package/dist/access-http-offline-stream.d.ts +11 -11
  15. package/dist/access-http-query.d.ts +2 -2
  16. package/dist/access-http-query.js +25 -25
  17. package/dist/access-http.d.ts +12 -12
  18. package/dist/access-http.js +34 -34
  19. package/dist/access-identity-continuity-surface.d.ts +9 -9
  20. package/dist/access-identity-continuity-surface.js +23 -23
  21. package/dist/access-lcm-surface.d.ts +11 -11
  22. package/dist/access-lcm-surface.js +23 -23
  23. package/dist/access-mcp.d.ts +11 -11
  24. package/dist/access-mcp.js +28 -28
  25. package/dist/access-memory-search-fanout.d.ts +2 -2
  26. package/dist/{access-namespace-preflight-yO4LMGFH.d.ts → access-namespace-preflight-DB0zXFek.d.ts} +1 -1
  27. package/dist/access-namespace-preflight.d.ts +3 -3
  28. package/dist/access-namespace-preflight.js +23 -23
  29. package/dist/access-observe-write-surface.d.ts +11 -11
  30. package/dist/access-observe-write-surface.js +23 -23
  31. package/dist/access-offline-manifest.d.ts +9 -9
  32. package/dist/access-offline-manifest.js +3 -3
  33. package/dist/access-operations-batch.js +24 -24
  34. package/dist/access-operations.d.ts +11 -11
  35. package/dist/access-operations.js +27 -27
  36. package/dist/access-recall-concurrency.d.ts +11 -11
  37. package/dist/access-recall-concurrency.js +23 -23
  38. package/dist/access-recall-response.d.ts +11 -11
  39. package/dist/access-recall-response.js +23 -23
  40. package/dist/access-recall-surface.d.ts +11 -11
  41. package/dist/access-recall-surface.js +23 -23
  42. package/dist/{access-service-D-bi3r01.d.ts → access-service-cKQrte9Z.d.ts} +7 -7
  43. package/dist/access-service-helpers.d.ts +11 -11
  44. package/dist/access-service.d.ts +11 -11
  45. package/dist/access-service.js +23 -23
  46. package/dist/access-surface-catalog.d.ts +11 -11
  47. package/dist/access-surface-catalog.js +25 -25
  48. package/dist/access-wearables-meetings-surface.d.ts +3 -3
  49. package/dist/action-confidence.d.ts +1 -1
  50. package/dist/active-memory-bridge.d.ts +1 -1
  51. package/dist/active-recall.d.ts +1 -1
  52. package/dist/ambient-provenance.d.ts +1 -1
  53. package/dist/artifact-search.d.ts +1 -1
  54. package/dist/behavior-learner.d.ts +1 -1
  55. package/dist/behavior-signals.d.ts +1 -1
  56. package/dist/bootstrap.d.ts +9 -9
  57. package/dist/briefing-window.d.ts +2 -2
  58. package/dist/briefing.d.ts +2 -2
  59. package/dist/briefing.js +11 -11
  60. package/dist/buffer-surprise-report.d.ts +1 -1
  61. package/dist/buffer-turn-helpers.d.ts +1 -1
  62. package/dist/buffer.d.ts +2 -2
  63. package/dist/buffer.js +4 -4
  64. package/dist/bulk-import/index.d.ts +3 -3
  65. package/dist/calibration.d.ts +1 -1
  66. package/dist/capabilities.d.ts +1 -1
  67. package/dist/{capsule-merge-HCJJMLPS.js → capsule-merge-SGIVB3WA.js} +5 -5
  68. package/dist/{catalog-BYIHQw1l.d.ts → catalog-CCzmf8IH.d.ts} +1 -1
  69. package/dist/causal-behavior.d.ts +1 -1
  70. package/dist/causal-consolidation.d.ts +1 -1
  71. package/dist/causal-consolidation.js +12 -12
  72. package/dist/causal-trajectory-graph.d.ts +1 -1
  73. package/dist/{chunk-XFCQIQQU.js → chunk-2UM6WHME.js} +3 -3
  74. package/dist/{chunk-CKWOMJDY.js → chunk-3Z5TGRFA.js} +8 -8
  75. package/dist/{chunk-JJX5XEIG.js → chunk-77QZW2D6.js} +4 -4
  76. package/dist/{chunk-X4MGNVOO.js → chunk-7AF243WZ.js} +1 -1
  77. package/dist/{chunk-2ASAS3CQ.js → chunk-7KQB4EBS.js} +2 -2
  78. package/dist/{chunk-3LJ2L3T3.js → chunk-7LF2OHIJ.js} +2 -2
  79. package/dist/{chunk-VAMQU4W7.js → chunk-AYVCKGA6.js} +2 -2
  80. package/dist/{chunk-GTRGH4ZT.js → chunk-BB2LH5JM.js} +2 -2
  81. package/dist/{chunk-XMMESCPD.js → chunk-C64XATK7.js} +17 -27
  82. package/dist/chunk-C64XATK7.js.map +1 -0
  83. package/dist/{chunk-DQV3LUQL.js → chunk-CUDSA46O.js} +2 -2
  84. package/dist/{chunk-PADG72LJ.js → chunk-DXDAQZ2K.js} +2 -2
  85. package/dist/{chunk-EJCN5ATI.js → chunk-DYZR3Z6D.js} +3 -3
  86. package/dist/{chunk-VN7IIQGS.js → chunk-E4KMY4KR.js} +2 -2
  87. package/dist/{chunk-ZQKXRKMR.js → chunk-EFKZT6AY.js} +2 -2
  88. package/dist/{chunk-DNRTKO2U.js → chunk-EJY3HJMT.js} +2 -2
  89. package/dist/{chunk-4EDAHS6D.js → chunk-ERPBRXVZ.js} +2 -2
  90. package/dist/{chunk-ZUZD2DRV.js → chunk-F6JYBVL6.js} +27 -57
  91. package/dist/{chunk-ZUZD2DRV.js.map → chunk-F6JYBVL6.js.map} +1 -1
  92. package/dist/{chunk-JWPG65LH.js → chunk-FHKXVTM5.js} +38 -39
  93. package/dist/chunk-FHKXVTM5.js.map +1 -0
  94. package/dist/{chunk-RPKJHYVE.js → chunk-FPEZ74F7.js} +2 -2
  95. package/dist/{chunk-Z334TJRB.js → chunk-GF7RQWXC.js} +2 -2
  96. package/dist/{chunk-6D7PZKCJ.js → chunk-GG4DN63W.js} +2 -2
  97. package/dist/{chunk-OR7KEGLR.js → chunk-GTD4Q62X.js} +2 -6
  98. package/dist/{chunk-QOMUE4FS.js → chunk-I5FLIB2J.js} +2 -2
  99. package/dist/{chunk-2JL7WPXL.js → chunk-IVXVLDNT.js} +12 -12
  100. package/dist/{chunk-NRFU5MVH.js → chunk-JOEJG4SD.js} +47 -1
  101. package/dist/chunk-JOEJG4SD.js.map +1 -0
  102. package/dist/{chunk-EJLTNPRY.js → chunk-KHCUVYCY.js} +3 -3
  103. package/dist/{chunk-QSIQVC32.js → chunk-KYTRF64R.js} +2 -2
  104. package/dist/{chunk-LNFYISZ6.js → chunk-LX4TNSAE.js} +4 -4
  105. package/dist/{chunk-H6ZXNH5I.js → chunk-MUJ4QFUQ.js} +3 -3
  106. package/dist/{chunk-JSH2TV34.js → chunk-NA56NSKL.js} +2 -2
  107. package/dist/{chunk-DFEYRCG2.js → chunk-NKB43PGI.js} +2 -2
  108. package/dist/{chunk-DLQQU4EG.js → chunk-NS5ETDYD.js} +2 -2
  109. package/dist/{chunk-VG6DC2GO.js → chunk-OETHJBAL.js} +53 -45
  110. package/dist/{chunk-VG6DC2GO.js.map → chunk-OETHJBAL.js.map} +1 -1
  111. package/dist/{chunk-BXOZALJ6.js → chunk-PB4WVYGC.js} +2 -2
  112. package/dist/{chunk-Q35XGIEM.js → chunk-PBRCYYO7.js} +2 -2
  113. package/dist/{chunk-QYN5PXDZ.js → chunk-PMVPCZJZ.js} +4 -4
  114. package/dist/{chunk-3USQWITL.js → chunk-QI5RDDEL.js} +3 -3
  115. package/dist/{chunk-I6OQCT3Y.js → chunk-QRWMS6SI.js} +2 -2
  116. package/dist/{chunk-ITYAXU4S.js → chunk-R6UMNP5C.js} +3 -3
  117. package/dist/{chunk-5W62VEFH.js → chunk-RWMSMTQP.js} +2 -2
  118. package/dist/{chunk-FKJVEW6O.js → chunk-SYVGVK4S.js} +2 -2
  119. package/dist/{chunk-GNKY5JEP.js → chunk-TSTI6A3A.js} +8 -8
  120. package/dist/{chunk-ISFUFLFM.js → chunk-UCLMKNHA.js} +2 -2
  121. package/dist/{chunk-ZMSZVISA.js → chunk-UFKPQBXH.js} +3 -3
  122. package/dist/{chunk-B2OOJCUX.js → chunk-UGHCZS6K.js} +2 -2
  123. package/dist/{chunk-RSLRGRBJ.js → chunk-V3KIRICY.js} +3 -3
  124. package/dist/{chunk-MRJ43KSG.js → chunk-VPHSMJ2E.js} +2 -2
  125. package/dist/{chunk-E2GYBTSP.js → chunk-VYEPACWY.js} +2 -2
  126. package/dist/{chunk-A4HXWNST.js → chunk-X7LEDA74.js} +2 -2
  127. package/dist/{chunk-KMAP7SNQ.js → chunk-XCB6QDL6.js} +2 -2
  128. package/dist/{chunk-WDUG2CH3.js → chunk-YEQCMA5L.js} +2 -2
  129. package/dist/{chunk-LZCSOUJ7.js → chunk-YFCEBB5P.js} +2 -2
  130. package/dist/{chunk-IKXUG6KC.js → chunk-YXMHUBN2.js} +2 -2
  131. package/dist/{chunk-GFNS3BHV.js → chunk-ZUPKNWRZ.js} +3 -3
  132. package/dist/{chunk-GSTIBXBW.js → chunk-ZVPVTPGI.js} +2 -2
  133. package/dist/{cli-DEoABKXH.d.ts → cli-BFBDYV0D.d.ts} +5 -5
  134. package/dist/cli.d.ts +13 -13
  135. package/dist/cli.js +45 -45
  136. package/dist/coding/pre-action-gate.d.ts +1 -1
  137. package/dist/compounding/engine.d.ts +2 -2
  138. package/dist/compounding/engine.js +11 -11
  139. package/dist/compounding/preference-consolidator.d.ts +1 -1
  140. package/dist/compression-optimizer.d.ts +1 -1
  141. package/dist/config.d.ts +1 -1
  142. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  143. package/dist/connectors/codex-materialize-runner.js +11 -11
  144. package/dist/connectors/codex-materialize.d.ts +1 -1
  145. package/dist/connectors/index.d.ts +1 -1
  146. package/dist/connectors/index.js +11 -11
  147. package/dist/consolidation-provenance-check.d.ts +2 -2
  148. package/dist/consolidation-provenance-check.js +5 -5
  149. package/dist/consolidation-undo.d.ts +2 -2
  150. package/dist/consolidation-undo.js +4 -4
  151. package/dist/contradiction/index.d.ts +2 -2
  152. package/dist/converge-config.d.ts +1 -1
  153. package/dist/convergence-refresh.d.ts +2 -2
  154. package/dist/convergence-refresh.js +13 -13
  155. package/dist/conversation-index/backend.d.ts +1 -1
  156. package/dist/conversation-index/chunker.d.ts +1 -1
  157. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  158. package/dist/conversation-index/indexer.d.ts +1 -1
  159. package/dist/conversation-index/search.d.ts +1 -1
  160. package/dist/corpus-watermark.d.ts +1 -1
  161. package/dist/corpus-watermark.js +13 -13
  162. package/dist/day-summary.d.ts +1 -1
  163. package/dist/delinearize.d.ts +1 -1
  164. package/dist/dependency-propagation-config.d.ts +1 -1
  165. package/dist/{dependency-propagation-delivery-BxhvAppj.d.ts → dependency-propagation-delivery-DiY5T63p.d.ts} +1 -1
  166. package/dist/direct-answer-wiring.d.ts +1 -1
  167. package/dist/direct-answer.d.ts +1 -1
  168. package/dist/embedding-fallback.d.ts +1 -1
  169. package/dist/enrichment/index.d.ts +1 -1
  170. package/dist/entity-origin-fields.d.ts +1 -1
  171. package/dist/entity-retrieval.d.ts +2 -2
  172. package/dist/entity-retrieval.js +11 -11
  173. package/dist/entity-schema.d.ts +1 -1
  174. package/dist/episodic-context.d.ts +1 -1
  175. package/dist/explicit-capture.d.ts +9 -9
  176. package/dist/explicit-capture.js +5 -5
  177. package/dist/external-wiki-access.d.ts +11 -11
  178. package/dist/external-wiki-access.js +24 -24
  179. package/dist/external-wiki-collection-registration.d.ts +1 -1
  180. package/dist/external-wiki-collection.d.ts +1 -1
  181. package/dist/external-wiki-mcp-tools.d.ts +11 -11
  182. package/dist/extraction-error-classification.d.ts +1 -1
  183. package/dist/extraction-faithfulness.d.ts +1 -1
  184. package/dist/extraction-judge-telemetry.d.ts +1 -1
  185. package/dist/extraction-judge-training.d.ts +1 -1
  186. package/dist/extraction-judge.d.ts +1 -1
  187. package/dist/extraction-liveness.d.ts +1 -1
  188. package/dist/extraction-normalization.d.ts +1 -1
  189. package/dist/extraction-prompt.d.ts +1 -1
  190. package/dist/extraction-source-grounding-rules.d.ts +1 -1
  191. package/dist/extraction-source-grounding.d.ts +1 -1
  192. package/dist/extraction.d.ts +1 -1
  193. package/dist/extraction.js +14 -14
  194. package/dist/fallback-llm.d.ts +1 -1
  195. package/dist/graph-dashboard-diff.d.ts +1 -1
  196. package/dist/graph-dashboard-key.d.ts +1 -1
  197. package/dist/graph-dashboard-parser.d.ts +1 -1
  198. package/dist/graph-edge-reinforcement.d.ts +1 -1
  199. package/dist/graph-path-reconstruction.d.ts +1 -1
  200. package/dist/graph-path-scoring.d.ts +1 -1
  201. package/dist/graph-snapshot.d.ts +1 -1
  202. package/dist/graph.d.ts +1 -1
  203. package/dist/harmonic-retrieval.js +1 -1
  204. package/dist/importance.d.ts +1 -1
  205. package/dist/importers/index.d.ts +1 -1
  206. package/dist/in-flight-reads.d.ts +1 -1
  207. package/dist/index.d.ts +21 -21
  208. package/dist/index.js +55 -55
  209. package/dist/intent.d.ts +1 -1
  210. package/dist/lcm/engine.d.ts +1 -1
  211. package/dist/lcm/index.d.ts +1 -1
  212. package/dist/lcm/tools.d.ts +1 -1
  213. package/dist/lifecycle.d.ts +1 -1
  214. package/dist/live-connectors-runner.d.ts +1 -1
  215. package/dist/local-llm.d.ts +1 -1
  216. package/dist/local-model-endpoint.d.ts +1 -1
  217. package/dist/maintenance/memory-governance.d.ts +1 -1
  218. package/dist/maintenance/memory-governance.js +11 -11
  219. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
  220. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +11 -11
  221. package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
  222. package/dist/maintenance/rebuild-memory-projection.js +12 -12
  223. package/dist/{maintenance-N5ur13Al.d.ts → maintenance-CaqA4z7V.d.ts} +3 -3
  224. package/dist/mcp-memory-inspector-app.d.ts +11 -11
  225. package/dist/memory-action-policy.d.ts +1 -1
  226. package/dist/memory-cache.d.ts +1 -1
  227. package/dist/memory-cache.js +1 -1
  228. package/dist/memory-corpus-version.js +2 -2
  229. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  230. package/dist/memory-projection-store.d.ts +1 -1
  231. package/dist/memory-provenance.d.ts +1 -1
  232. package/dist/memory-snapshot.d.ts +1 -1
  233. package/dist/memory-worth-outcomes.d.ts +2 -2
  234. package/dist/models-json.d.ts +1 -1
  235. package/dist/namespaces/migrate.d.ts +3 -3
  236. package/dist/namespaces/migrate.js +12 -12
  237. package/dist/namespaces/principal.d.ts +1 -1
  238. package/dist/namespaces/search.d.ts +1 -1
  239. package/dist/namespaces/search.js +4 -4
  240. package/dist/namespaces/storage.d.ts +3 -3
  241. package/dist/namespaces/storage.js +11 -11
  242. package/dist/native-knowledge.d.ts +1 -1
  243. package/dist/offline-sync-impression-drain.d.ts +1 -1
  244. package/dist/operator-doctor-corpus.d.ts +1 -1
  245. package/dist/operator-doctor-corpus.js +14 -14
  246. package/dist/operator-doctor-replica.d.ts +1 -1
  247. package/dist/operator-toolkit.d.ts +3 -3
  248. package/dist/operator-toolkit.js +20 -20
  249. package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
  250. package/dist/orchestration/maintenance.d.ts +4 -4
  251. package/dist/orchestration/maintenance.js +17 -17
  252. package/dist/{orchestrator-ByLrpav4.d.ts → orchestrator-CSc9GfQv.d.ts} +8 -8
  253. package/dist/orchestrator.d.ts +9 -9
  254. package/dist/orchestrator.js +55 -55
  255. package/dist/page-versioning.js +4 -4
  256. package/dist/patterns-cli.d.ts +1 -1
  257. package/dist/{pipeline-BdF3ferY.d.ts → pipeline-X606GdRJ.d.ts} +1 -1
  258. package/dist/policy-runtime.d.ts +1 -1
  259. package/dist/proactive-contention.d.ts +1 -1
  260. package/dist/provenance.d.ts +1 -1
  261. package/dist/{public-http-DusietP2.d.ts → public-http-8PcrDIYi.d.ts} +1 -1
  262. package/dist/{qmd-CBSxevyb.d.ts → qmd-DCKeR-GX.d.ts} +1 -1
  263. package/dist/qmd-preflight.d.ts +2 -2
  264. package/dist/qmd-recall-cache.d.ts +1 -1
  265. package/dist/qmd.d.ts +2 -2
  266. package/dist/qmd.js +2 -2
  267. package/dist/recall-concurrency-config.d.ts +1 -1
  268. package/dist/recall-disclosure-escalation.d.ts +1 -1
  269. package/dist/recall-explain-renderer.d.ts +1 -1
  270. package/dist/recall-memory-map.d.ts +1 -1
  271. package/dist/recall-planner-llm.d.ts +1 -1
  272. package/dist/recall-state.d.ts +1 -1
  273. package/dist/recall-tag-filter.d.ts +1 -1
  274. package/dist/recall-timings.d.ts +1 -1
  275. package/dist/recall-xray-cli.d.ts +1 -1
  276. package/dist/recall-xray-renderer.d.ts +1 -1
  277. package/dist/recall-xray.d.ts +1 -1
  278. package/dist/reconcile/cursor.d.ts +1 -1
  279. package/dist/reconcile/manifest.d.ts +1 -1
  280. package/dist/reconcile/manifest.js +2 -2
  281. package/dist/reconcile/plan.d.ts +1 -1
  282. package/dist/replay/normalizers/chatgpt.d.ts +1 -1
  283. package/dist/replay/normalizers/claude.d.ts +1 -1
  284. package/dist/replay/normalizers/openclaw.d.ts +1 -1
  285. package/dist/replay/normalizers/shared.d.ts +1 -1
  286. package/dist/replay/runner.d.ts +1 -1
  287. package/dist/replay/types.d.ts +1 -1
  288. package/dist/replica-divergence.d.ts +1 -1
  289. package/dist/replica-peers-config.d.ts +1 -1
  290. package/dist/resolve-auth-token.d.ts +1 -1
  291. package/dist/retrieval-agents.d.ts +2 -2
  292. package/dist/retrieval-tiers.d.ts +1 -1
  293. package/dist/routing/engine.d.ts +1 -1
  294. package/dist/routing/store.d.ts +1 -1
  295. package/dist/salvage-envelope.d.ts +1 -1
  296. package/dist/{scope-profiles-CeMv7pP0.d.ts → scope-profiles-_Y_RHCeE.d.ts} +1 -1
  297. package/dist/search/embed-helper.d.ts +1 -1
  298. package/dist/search/factory.d.ts +1 -1
  299. package/dist/search/factory.js +3 -3
  300. package/dist/search/index.d.ts +1 -1
  301. package/dist/search/index.js +3 -3
  302. package/dist/search/lancedb-backend.d.ts +1 -1
  303. package/dist/search/meilisearch-backend.d.ts +1 -1
  304. package/dist/search/noop-backend.d.ts +1 -1
  305. package/dist/search/orama-backend.d.ts +1 -1
  306. package/dist/search/port.d.ts +1 -1
  307. package/dist/search/remote-backend.d.ts +1 -1
  308. package/dist/{semantic-consolidation-B-85brYj.d.ts → semantic-consolidation-DT2VSrU0.d.ts} +1 -1
  309. package/dist/semantic-consolidation.d.ts +2 -2
  310. package/dist/semantic-consolidation.js +12 -12
  311. package/dist/semantic-rule-promotion.js +11 -11
  312. package/dist/semantic-rule-verifier.d.ts +1 -1
  313. package/dist/semantic-rule-verifier.js +11 -11
  314. package/dist/{service-CoO0HA2E.d.ts → service-BMo-gwDE.d.ts} +3 -3
  315. package/dist/session-observer-bands.d.ts +1 -1
  316. package/dist/session-observer-state.d.ts +1 -1
  317. package/dist/shared-context/manager.d.ts +1 -1
  318. package/dist/signal.d.ts +1 -1
  319. package/dist/source-agent-qualifier.d.ts +1 -1
  320. package/dist/source-agent-qualifier.js +13 -13
  321. package/dist/{storage-BVAVitkO.d.ts → storage-CGzJGUUu.d.ts} +49 -24
  322. package/dist/storage.d.ts +2 -2
  323. package/dist/storage.js +10 -10
  324. package/dist/summarizer.d.ts +1 -1
  325. package/dist/summary-snapshot.d.ts +1 -1
  326. package/dist/support-passport/index.d.ts +14 -14
  327. package/dist/support-passport/index.js +26 -26
  328. package/dist/temporal-supersession.d.ts +2 -2
  329. package/dist/temporal-timeline-recall.d.ts +1 -1
  330. package/dist/temporal-validity.d.ts +1 -1
  331. package/dist/threading.d.ts +1 -1
  332. package/dist/tier-migration.d.ts +2 -2
  333. package/dist/tier-routing.d.ts +1 -1
  334. package/dist/topics.d.ts +1 -1
  335. package/dist/transcript.d.ts +1 -1
  336. package/dist/transfer/capsule-import.js +5 -5
  337. package/dist/trust-score-stage.d.ts +1 -1
  338. package/dist/trust-score.d.ts +1 -1
  339. package/dist/{types-DWHOxlZP.d.ts → types-CBEAYU76.d.ts} +112 -128
  340. package/dist/types.d.ts +1 -1
  341. package/dist/utility-runtime.d.ts +1 -1
  342. package/dist/verified-recall.js +11 -11
  343. package/dist/write-envelope.d.ts +1 -1
  344. package/package.json +2 -2
  345. package/src/chat/chat-cli.test.ts +53 -0
  346. package/src/chat/chat-cli.ts +22 -58
  347. package/src/dedup/index.test.ts +65 -1
  348. package/src/dedup/index.ts +24 -2
  349. package/src/meetings/build.test.ts +20 -4
  350. package/src/meetings/build.ts +2 -2
  351. package/src/meetings/day-source.test.ts +3 -1
  352. package/src/meetings/day-source.ts +1 -12
  353. package/src/meetings/fuse.test.ts +64 -15
  354. package/src/meetings/fuse.ts +18 -12
  355. package/src/meetings/types.ts +4 -19
  356. package/src/memory-cache-derived.test.ts +90 -0
  357. package/src/memory-cache.ts +40 -42
  358. package/src/storage/content-hash-index.ts +54 -0
  359. package/src/storage-contract/content-hash.test.ts +59 -1
  360. package/src/storage-fact-hash-index-defer.test.ts +9 -9
  361. package/src/storage.ts +39 -40
  362. package/dist/chunk-JWPG65LH.js.map +0 -1
  363. package/dist/chunk-NRFU5MVH.js.map +0 -1
  364. package/dist/chunk-XMMESCPD.js.map +0 -1
  365. /package/dist/{capsule-merge-HCJJMLPS.js.map → capsule-merge-SGIVB3WA.js.map} +0 -0
  366. /package/dist/{chunk-XFCQIQQU.js.map → chunk-2UM6WHME.js.map} +0 -0
  367. /package/dist/{chunk-CKWOMJDY.js.map → chunk-3Z5TGRFA.js.map} +0 -0
  368. /package/dist/{chunk-JJX5XEIG.js.map → chunk-77QZW2D6.js.map} +0 -0
  369. /package/dist/{chunk-X4MGNVOO.js.map → chunk-7AF243WZ.js.map} +0 -0
  370. /package/dist/{chunk-2ASAS3CQ.js.map → chunk-7KQB4EBS.js.map} +0 -0
  371. /package/dist/{chunk-3LJ2L3T3.js.map → chunk-7LF2OHIJ.js.map} +0 -0
  372. /package/dist/{chunk-VAMQU4W7.js.map → chunk-AYVCKGA6.js.map} +0 -0
  373. /package/dist/{chunk-GTRGH4ZT.js.map → chunk-BB2LH5JM.js.map} +0 -0
  374. /package/dist/{chunk-DQV3LUQL.js.map → chunk-CUDSA46O.js.map} +0 -0
  375. /package/dist/{chunk-PADG72LJ.js.map → chunk-DXDAQZ2K.js.map} +0 -0
  376. /package/dist/{chunk-EJCN5ATI.js.map → chunk-DYZR3Z6D.js.map} +0 -0
  377. /package/dist/{chunk-VN7IIQGS.js.map → chunk-E4KMY4KR.js.map} +0 -0
  378. /package/dist/{chunk-ZQKXRKMR.js.map → chunk-EFKZT6AY.js.map} +0 -0
  379. /package/dist/{chunk-DNRTKO2U.js.map → chunk-EJY3HJMT.js.map} +0 -0
  380. /package/dist/{chunk-4EDAHS6D.js.map → chunk-ERPBRXVZ.js.map} +0 -0
  381. /package/dist/{chunk-RPKJHYVE.js.map → chunk-FPEZ74F7.js.map} +0 -0
  382. /package/dist/{chunk-Z334TJRB.js.map → chunk-GF7RQWXC.js.map} +0 -0
  383. /package/dist/{chunk-6D7PZKCJ.js.map → chunk-GG4DN63W.js.map} +0 -0
  384. /package/dist/{chunk-OR7KEGLR.js.map → chunk-GTD4Q62X.js.map} +0 -0
  385. /package/dist/{chunk-QOMUE4FS.js.map → chunk-I5FLIB2J.js.map} +0 -0
  386. /package/dist/{chunk-2JL7WPXL.js.map → chunk-IVXVLDNT.js.map} +0 -0
  387. /package/dist/{chunk-EJLTNPRY.js.map → chunk-KHCUVYCY.js.map} +0 -0
  388. /package/dist/{chunk-QSIQVC32.js.map → chunk-KYTRF64R.js.map} +0 -0
  389. /package/dist/{chunk-LNFYISZ6.js.map → chunk-LX4TNSAE.js.map} +0 -0
  390. /package/dist/{chunk-H6ZXNH5I.js.map → chunk-MUJ4QFUQ.js.map} +0 -0
  391. /package/dist/{chunk-JSH2TV34.js.map → chunk-NA56NSKL.js.map} +0 -0
  392. /package/dist/{chunk-DFEYRCG2.js.map → chunk-NKB43PGI.js.map} +0 -0
  393. /package/dist/{chunk-DLQQU4EG.js.map → chunk-NS5ETDYD.js.map} +0 -0
  394. /package/dist/{chunk-BXOZALJ6.js.map → chunk-PB4WVYGC.js.map} +0 -0
  395. /package/dist/{chunk-Q35XGIEM.js.map → chunk-PBRCYYO7.js.map} +0 -0
  396. /package/dist/{chunk-QYN5PXDZ.js.map → chunk-PMVPCZJZ.js.map} +0 -0
  397. /package/dist/{chunk-3USQWITL.js.map → chunk-QI5RDDEL.js.map} +0 -0
  398. /package/dist/{chunk-I6OQCT3Y.js.map → chunk-QRWMS6SI.js.map} +0 -0
  399. /package/dist/{chunk-ITYAXU4S.js.map → chunk-R6UMNP5C.js.map} +0 -0
  400. /package/dist/{chunk-5W62VEFH.js.map → chunk-RWMSMTQP.js.map} +0 -0
  401. /package/dist/{chunk-FKJVEW6O.js.map → chunk-SYVGVK4S.js.map} +0 -0
  402. /package/dist/{chunk-GNKY5JEP.js.map → chunk-TSTI6A3A.js.map} +0 -0
  403. /package/dist/{chunk-ISFUFLFM.js.map → chunk-UCLMKNHA.js.map} +0 -0
  404. /package/dist/{chunk-ZMSZVISA.js.map → chunk-UFKPQBXH.js.map} +0 -0
  405. /package/dist/{chunk-B2OOJCUX.js.map → chunk-UGHCZS6K.js.map} +0 -0
  406. /package/dist/{chunk-RSLRGRBJ.js.map → chunk-V3KIRICY.js.map} +0 -0
  407. /package/dist/{chunk-MRJ43KSG.js.map → chunk-VPHSMJ2E.js.map} +0 -0
  408. /package/dist/{chunk-E2GYBTSP.js.map → chunk-VYEPACWY.js.map} +0 -0
  409. /package/dist/{chunk-A4HXWNST.js.map → chunk-X7LEDA74.js.map} +0 -0
  410. /package/dist/{chunk-KMAP7SNQ.js.map → chunk-XCB6QDL6.js.map} +0 -0
  411. /package/dist/{chunk-WDUG2CH3.js.map → chunk-YEQCMA5L.js.map} +0 -0
  412. /package/dist/{chunk-LZCSOUJ7.js.map → chunk-YFCEBB5P.js.map} +0 -0
  413. /package/dist/{chunk-IKXUG6KC.js.map → chunk-YXMHUBN2.js.map} +0 -0
  414. /package/dist/{chunk-GFNS3BHV.js.map → chunk-ZUPKNWRZ.js.map} +0 -0
  415. /package/dist/{chunk-GSTIBXBW.js.map → chunk-ZVPVTPGI.js.map} +0 -0
@@ -33,26 +33,41 @@ function sweepExpiredHotEntries(now: number): void {
33
33
  }
34
34
  }
35
35
 
36
- export function getCachedMemories(
37
- baseDir: string,
36
+ /**
37
+ * Shared read gate for every versioned cache layer (issue #2481): serve an
38
+ * entry only when its version and secure-store keyId match the caller.
39
+ * `currentVersion === 0` means version tracking is unavailable (tests, fresh
40
+ * installs) and always misses so disk is read. The TTL is a safety net for
41
+ * external filesystem edits that bypass the version sentinel (issue #1902):
42
+ * ttlMs <= 0 disables it, and on expiry the entry is evicted — not just
43
+ * skipped — so a stale dir releases its resident corpus instead of lingering
44
+ * until an explicit clear.
45
+ */
46
+ function getVersionedCacheEntry<K, E extends { version: number; keyId: string; loadedAt: number }>(
47
+ cache: Map<K, E>,
48
+ key: K,
38
49
  currentVersion: number,
39
- keyId = "",
40
- ttlMs = 0,
41
- ): MemoryFile[] | null {
42
- // Don't serve from cache when version tracking is unavailable (version=0).
43
- // This ensures tests and fresh installs without a version file always read disk.
50
+ keyId: string,
51
+ ttlMs: number,
52
+ ): E | null {
44
53
  if (currentVersion === 0) return null;
45
- const entry = hotCacheByDir.get(baseDir);
54
+ const entry = cache.get(key);
46
55
  if (!entry || entry.version !== currentVersion || entry.keyId !== keyId) return null;
47
- // TTL safety net (issue #1902): bound staleness from external filesystem edits
48
- // that bypass the version sentinel. ttlMs <= 0 disables the check. On expiry
49
- // evict the entry (not just return null) so a revisited-but-stale dir releases
50
- // its resident corpus instead of lingering until an explicit clear.
51
56
  if (ttlMs > 0 && Date.now() - entry.loadedAt > ttlMs) {
52
- hotCacheByDir.delete(baseDir);
57
+ cache.delete(key);
53
58
  return null;
54
59
  }
55
- return [...entry.memories.values()];
60
+ return entry;
61
+ }
62
+
63
+ export function getCachedMemories(
64
+ baseDir: string,
65
+ currentVersion: number,
66
+ keyId = "",
67
+ ttlMs = 0,
68
+ ): MemoryFile[] | null {
69
+ const entry = getVersionedCacheEntry(hotCacheByDir, baseDir, currentVersion, keyId, ttlMs);
70
+ return entry ? [...entry.memories.values()] : null;
56
71
  }
57
72
 
58
73
  export function setCachedMemories(
@@ -89,10 +104,10 @@ export function getCachedArchivedMemories(
89
104
  currentVersion: number,
90
105
  keyId = "",
91
106
  ): MemoryFile[] | null {
92
- if (currentVersion === 0) return null;
93
- const entry = archiveCacheByDir.get(baseDir);
94
- if (!entry || entry.version !== currentVersion || entry.keyId !== keyId) return null;
95
- return [...entry.memories.values()];
107
+ // ttlMs 0: the archive cache has no age TTL; it is version-keyed and cleared
108
+ // via invalidation.
109
+ const entry = getVersionedCacheEntry(archiveCacheByDir, baseDir, currentVersion, keyId, 0);
110
+ return entry ? [...entry.memories.values()] : null;
96
111
  }
97
112
 
98
113
  export function setCachedArchivedMemories(
@@ -165,7 +180,7 @@ export function invalidateCachedEntities(baseDir: string): void {
165
180
  // These avoid O(146K) filter+map on every verified recall/rules call.
166
181
  interface DerivedCacheEntry<T> {
167
182
  data: T;
168
- sourceVersion: number; // matches the hot cache version it was derived from
183
+ version: number; // matches the hot cache version it was derived from
169
184
  keyId: string; // secure-store key identity of the corpus it was derived from (#1902)
170
185
  loadedAt: number; // build time — bounds staleness from external edits via ttlMs (#1902)
171
186
  }
@@ -179,17 +194,8 @@ export function getCachedEpisodeMap(
179
194
  keyId = "",
180
195
  ttlMs = 0,
181
196
  ): Map<string, MemoryFile> | null {
182
- if (currentVersion === 0) return null;
183
- const entry = episodeMapByDir.get(baseDir);
184
- if (!entry || entry.sourceVersion !== currentVersion || entry.keyId !== keyId) return null;
185
- // TTL safety net (issue #1902): the version sentinel doesn't move on a direct
186
- // external edit, so bound how long a derived view is served before a rebuild
187
- // (which re-reads via readAllMemories, itself TTL-bounded). ttlMs <= 0 disables.
188
- if (ttlMs > 0 && Date.now() - entry.loadedAt > ttlMs) {
189
- episodeMapByDir.delete(baseDir);
190
- return null;
191
- }
192
- return entry.data;
197
+ const entry = getVersionedCacheEntry(episodeMapByDir, baseDir, currentVersion, keyId, ttlMs);
198
+ return entry ? entry.data : null;
193
199
  }
194
200
 
195
201
  /** Build and cache the episode memory map from the full memory list. */
@@ -206,7 +212,7 @@ export function setCachedEpisodeMap(
206
212
  if (m.frontmatter.memoryKind !== "episode") continue;
207
213
  map.set(m.frontmatter.id, m);
208
214
  }
209
- if (cache) episodeMapByDir.set(baseDir, { data: map, sourceVersion: version, keyId, loadedAt: Date.now() });
215
+ if (cache) episodeMapByDir.set(baseDir, { data: map, version, keyId, loadedAt: Date.now() });
210
216
  return map;
211
217
  }
212
218
 
@@ -217,16 +223,8 @@ export function getCachedRuleMemories(
217
223
  keyId = "",
218
224
  ttlMs = 0,
219
225
  ): { all: MemoryFile[]; byId: Map<string, MemoryFile> } | null {
220
- if (currentVersion === 0) return null;
221
- const entry = ruleMemoriesByDir.get(baseDir);
222
- if (!entry || entry.sourceVersion !== currentVersion || entry.keyId !== keyId) return null;
223
- // TTL safety net (issue #1902): bound staleness from direct external edits
224
- // that don't move the version sentinel. ttlMs <= 0 disables.
225
- if (ttlMs > 0 && Date.now() - entry.loadedAt > ttlMs) {
226
- ruleMemoriesByDir.delete(baseDir);
227
- return null;
228
- }
229
- return entry.data;
226
+ const entry = getVersionedCacheEntry(ruleMemoriesByDir, baseDir, currentVersion, keyId, ttlMs);
227
+ return entry ? entry.data : null;
230
228
  }
231
229
 
232
230
  /** Build and cache the rule memories from the full memory list. */
@@ -250,7 +248,7 @@ export function setCachedRuleMemories(
250
248
  }
251
249
  }
252
250
  const result = { all, byId };
253
- if (cache) ruleMemoriesByDir.set(baseDir, { data: result, sourceVersion: version, keyId, loadedAt: Date.now() });
251
+ if (cache) ruleMemoriesByDir.set(baseDir, { data: result, version, keyId, loadedAt: Date.now() });
254
252
  return result;
255
253
  }
256
254
 
@@ -110,6 +110,20 @@ export interface ContentHashPathEntry {
110
110
  */
111
111
  export class ContentHashIndex {
112
112
  private hashes: Set<string> = new Set();
113
+ /**
114
+ * Fact-ONLY hash partition (issue #2474). `hashes` above is category-blind
115
+ * (every write category registers there); this subset carries only
116
+ * `category === "fact"` hashes so fact-only membership checks
117
+ * (`hasFact*`) can never be satisfied by an unrelated decision/preference
118
+ * sharing the same normalized body. In-memory only — never serialized to
119
+ * fact-hashes.txt; `clear()` drops it and every authoritative rebuild
120
+ * repopulates it via `addFactByHash`. Subset invariant: `factHashes ⊆
121
+ * hashes` — `addFact*` registers in both, and the removal sites that drop
122
+ * a shared hash also drop the partition entry (removal stays caller-paired
123
+ * because shared-index removal is category-blind: archiving a non-fact
124
+ * must not evict an active fact's fact-only membership).
125
+ */
126
+ private factHashes: Set<string> = new Set();
113
127
  private dirty = false;
114
128
  /** True when load() found the pre-Unicode, markerless on-disk format. */
115
129
  private formatMigrationRequired = false;
@@ -290,6 +304,9 @@ export class ContentHashIndex {
290
304
  if (this.hashes.size > 0) {
291
305
  this.hashes.clear();
292
306
  }
307
+ // The fact-only partition is rebuilt with the shared set on every
308
+ // authoritative corpus rebuild, so it clears here too (issue #2474).
309
+ this.factHashes.clear();
293
310
  // A full clear is always paired with a plain overwrite save() (rebuild);
294
311
  // pending per-hash add/remove deltas are subsumed by writing the rebuilt set.
295
312
  // Cancel any armed deferred-reconcile retry (PR #2016) so it cannot fire in
@@ -693,6 +710,43 @@ export class ContentHashIndex {
693
710
  this.dirty = true;
694
711
  }
695
712
 
713
+ // ── Fact-only partition (issue #2474) ─────────────────────────────────
714
+ // Folded here from StorageManager's parallel `factOnlyHashes` set, which had
715
+ // to be kept in lockstep by hand on every add/remove/rebuild site. The
716
+ // partition lives on the index instance, so every path that mutates the
717
+ // shared set and needs fact-only truth mutates it in the same breath.
718
+
719
+ /** Register fact content in BOTH the shared index and the fact-only partition. */
720
+ addFact(content: string): void {
721
+ this.addFactByHash(ContentHashIndex.computeHash(content));
722
+ }
723
+
724
+ /** Register a pre-computed fact hash in both the shared index and the fact-only partition. */
725
+ addFactByHash(hash: string): void {
726
+ this.addByHash(hash);
727
+ this.factHashes.add(hash);
728
+ }
729
+
730
+ /** Fact-ONLY membership: has this content been registered as a fact? */
731
+ hasFact(content: string): boolean {
732
+ return this.factHashes.has(ContentHashIndex.computeHash(content));
733
+ }
734
+
735
+ /** Fact-ONLY membership for a pre-computed SHA-256 hash. */
736
+ hasFactByHash(hash: string): boolean {
737
+ return this.factHashes.has(hash);
738
+ }
739
+
740
+ /**
741
+ * Drop fact-only partition membership WITHOUT touching the shared index.
742
+ * The shared removal stays caller-owned: a shared hash is dropped only when
743
+ * no other active memory holds it, while fact-only membership follows the
744
+ * fact's own lifecycle (supersede/archive/promotion).
745
+ */
746
+ removeFactByHash(hash: string): void {
747
+ this.factHashes.delete(hash);
748
+ }
749
+
696
750
  /**
697
751
  * Resolve a pre-computed semantic hash to one deterministic corpus path.
698
752
  *
@@ -11,7 +11,7 @@
11
11
  import assert from "node:assert/strict";
12
12
  import test from "node:test";
13
13
 
14
- import { ContentHashIndex } from "../storage.js";
14
+ import { ContentHashIndex, StorageManager } from "../storage.js";
15
15
  import { makeStorage } from "./harness.js";
16
16
 
17
17
  test("content-hash: ContentHashIndex.computeHash is deterministic for the same input", () => {
@@ -158,3 +158,61 @@ test("content-hash: the frontmatter contentHash matches computeHash of the raw c
158
158
  await cleanup();
159
159
  }
160
160
  });
161
+
162
+ test("content-hash: fact-only membership across write, supersede, and rebuild — no stale true (#2474)", async () => {
163
+ const { storage, baseDir, cleanup } = await makeStorage();
164
+ try {
165
+ const supersededBody = "the staging region retires on friday";
166
+ const activeBody = "the production region stays";
167
+
168
+ // Write: both facts register fact-only membership on the shared index.
169
+ await storage.writeMemory("fact", supersededBody);
170
+ await storage.writeMemory("fact", activeBody);
171
+ assert.equal(
172
+ await storage.hasFactContentHash(supersededBody),
173
+ true,
174
+ "write registers the fact-only hash",
175
+ );
176
+ assert.equal(await storage.hasFactContentHash(activeBody), true);
177
+
178
+ // Supersede: the frontmatter rewrite runs syncFactHashIndexAfterRewrite →
179
+ // removeFactContentHashesForMemories, which must drop BOTH the shared hash
180
+ // and the fact-only partition. A stale partition entry is the PR #2016
181
+ // stale-true bug class: wearable / explicit-capture / promotion callers
182
+ // would skip a valid re-write.
183
+ const mem = (await storage.readAllMemories()).find((m) =>
184
+ (m.content ?? "").includes(supersededBody),
185
+ );
186
+ assert.ok(mem, "the fact to supersede must exist");
187
+ const ok = await storage.writeMemoryFrontmatter(mem!, { status: "superseded" });
188
+ assert.equal(ok, true, "frontmatter rewrite must succeed");
189
+ assert.equal(
190
+ await storage.hasFactContentHash(supersededBody),
191
+ false,
192
+ "no stale hasFactContentHash true after supersede",
193
+ );
194
+ assert.equal(
195
+ await storage.hasFactContentHash(activeBody),
196
+ true,
197
+ "the untouched fact keeps its fact-only membership",
198
+ );
199
+
200
+ // Rebuild: a fresh instance repopulates the index from the corpus. The
201
+ // superseded fact must stay out of the fact-only partition; the active
202
+ // fact must survive.
203
+ const reopened = new StorageManager(baseDir);
204
+ await reopened.ensureDirectories();
205
+ assert.equal(
206
+ await reopened.hasFactContentHash(supersededBody),
207
+ false,
208
+ "superseded fact stays out of fact-only membership after rebuild",
209
+ );
210
+ assert.equal(
211
+ await reopened.hasFactContentHash(activeBody),
212
+ true,
213
+ "active fact survives the rebuild",
214
+ );
215
+ } finally {
216
+ await cleanup();
217
+ }
218
+ });
@@ -308,10 +308,10 @@ test("direct writeMemory('fact') without the flag persists the hash via the LOCK
308
308
  });
309
309
 
310
310
  test("#2016 thread SDzOT: a fact hash added during the authoritative rebuild's corpus scan is not lost", async () => {
311
- // The rebuild used to build a fresh `factOnly` set and publish it with
312
- // `this.factOnlyHashes = factOnly`, dropping any concurrent in-process
313
- // writeMemory that added to the LIVE set during the readAllMemories /
314
- // readAllColdMemories awaits. The rebuild now repopulates the live set in place
311
+ // The rebuild used to build a fresh fact-only set and publish it with a
312
+ // reassignment, dropping any concurrent in-process writeMemory that added to
313
+ // the LIVE membership during the readAllMemories / readAllColdMemories
314
+ // awaits. The fact-only partition on ContentHashIndex repopulates in place
315
315
  // (clear + add), so a concurrent add survives publication — exactly as the
316
316
  // shared index preserves concurrent adds by mutating its `hashes` set in place.
317
317
  await withMemoryDir(async (dir) => {
@@ -320,7 +320,7 @@ test("#2016 thread SDzOT: a fact hash added during the authoritative rebuild's c
320
320
  await storage.writeMemory("fact", "alpha established fact", { source: "extraction" });
321
321
 
322
322
  const s = storage as unknown as {
323
- factOnlyHashes: Set<string>;
323
+ factHashIndex: ContentHashIndex | null;
324
324
  factHashIndexAuthoritative: boolean | null;
325
325
  readAllColdMemories: () => Promise<unknown[]>;
326
326
  ensureFactHashIndexAuthoritative: () => Promise<boolean>;
@@ -329,13 +329,13 @@ test("#2016 thread SDzOT: a fact hash added during the authoritative rebuild's c
329
329
  const realCold = s.readAllColdMemories.bind(storage);
330
330
  let injected = false;
331
331
  // Interpose on the SECOND corpus await inside the rebuild (after clear()):
332
- // simulate a concurrent writeMemory adding a fact hash to the live set while
333
- // the rebuild is mid-scan.
332
+ // simulate a concurrent writeMemory adding a fact hash to the live
333
+ // partition while the rebuild is mid-scan.
334
334
  s.readAllColdMemories = async () => {
335
335
  const res = await realCold();
336
336
  if (!injected) {
337
337
  injected = true;
338
- s.factOnlyHashes.add(sentinel);
338
+ s.factHashIndex?.addFactByHash(sentinel);
339
339
  }
340
340
  return res;
341
341
  };
@@ -345,7 +345,7 @@ test("#2016 thread SDzOT: a fact hash added during the authoritative rebuild's c
345
345
  assert.equal(await s.ensureFactHashIndexAuthoritative(), true, "rebuild published");
346
346
 
347
347
  assert.equal(
348
- s.factOnlyHashes.has(sentinel),
348
+ s.factHashIndex?.hasFactByHash(sentinel),
349
349
  true,
350
350
  "a fact hash added during the rebuild scan must survive publication (lost under reassign)"
351
351
  );
package/src/storage.ts CHANGED
@@ -1867,19 +1867,15 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
1867
1867
  private factHashIndexAuthoritative: boolean | null = null;
1868
1868
  private factHashIndexAuthoritativePromise: Promise<boolean> | null = null;
1869
1869
  /**
1870
- * Fact-ONLY hash membership (PR #2016). The shared `factHashIndex` above is
1871
- * category-agnostic (the round-15 corpus rebuild + addContentHashDedup index
1872
- * every category), so it cannot answer a fact-only question. This set carries
1873
- * only `category === "fact"` hashes and is the sole source for
1874
- * `hasFactContentHash`, so an over-included non-fact body can never suppress a
1875
- * real fact candidate. Kept in lockstep with the shared index on EVERY path:
1876
- * the authoritative corpus rebuild (repopulated in place), the write path
1877
- * (`writeMemory` / `addActiveFactContentHash`), the storage-owned removal
1878
- * (`removeFactContentHashesForMemories`), AND the orchestrator's archival /
1879
- * consolidation removal (`removeContentHashForMemory` ->
1880
- * `removeFactOnlyHashForMemory`). In-memory only; never persisted.
1870
+ * Fact-ONLY hash membership (PR #2016 / issue #2474) lives on the shared
1871
+ * `ContentHashIndex` fact-only partition (`addFact*` / `hasFact*` /
1872
+ * `removeFactByHash`), not a parallel set here. The partition carries only
1873
+ * `category === "fact"` hashes and is the sole source for
1874
+ * `hasFactContentHash`, so an over-included non-fact body can never
1875
+ * suppress a real fact candidate. In-memory only; never persisted every
1876
+ * authoritative corpus rebuild repopulates it via
1877
+ * `ContentHashIndex.clear()` + `addFactByHash`.
1881
1878
  */
1882
- private factOnlyHashes: Set<string> = new Set();
1883
1879
  /** Optional lock/retry tuning for the fact-hash index cross-process lock (PR #2016; tests inject tight budgets). */
1884
1880
  factHashIndexLockOptions: ContentHashIndexLockOptions = {};
1885
1881
  private readonly secureAppendChains = new Map<string, Promise<void>>();
@@ -3328,15 +3324,14 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
3328
3324
  */
3329
3325
  private async rebuildFactHashIndexFromCorpus(factHashIndex: ContentHashIndex): Promise<void> {
3330
3326
  factHashIndex.clear();
3331
- // Fact-ONLY membership rebuilt in lockstep (PR #2016): hasFactContentHash
3332
- // reads THIS set, never the category-agnostic shared index below, so an
3333
- // over-included non-fact body can never satisfy a fact-hash check. Repopulate
3334
- // the LIVE set in place (clear + add) rather than building a fresh set and
3335
- // reassigning: a concurrent in-process writeMemory that adds a fact hash
3336
- // during the corpus-read awaits below would be lost by a publish-time
3337
- // reassignment (PR #2016 thread SDzOT), exactly as the shared index avoids
3338
- // by mutating its `hashes` set in place.
3339
- this.factOnlyHashes.clear();
3327
+ // Fact-ONLY membership is rebuilt in lockstep (PR #2016 / issue #2474):
3328
+ // hasFactContentHash reads the index's fact-only partition, never the
3329
+ // category-agnostic shared set, so an over-included non-fact body can
3330
+ // never satisfy a fact-hash check. `factHashIndex.clear()` above cleared
3331
+ // the partition too, and it repopulates in place below a concurrent
3332
+ // in-process writeMemory that adds a fact hash during the corpus-read
3333
+ // awaits survives publication (PR #2016 thread SDzOT), exactly as the
3334
+ // shared index preserves by mutating its `hashes` set in place.
3340
3335
  // #1909 review round 14: index the HOT and COLD tiers together. A fact or
3341
3336
  // procedure demoted to cold/ is still active and its content-hash must
3342
3337
  // survive the corpus rebuild, or a restart would drop the hash and let the
@@ -3371,8 +3366,11 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
3371
3366
  continue;
3372
3367
  }
3373
3368
  for (const hash of hashes) {
3374
- factHashIndex.addByHash(hash);
3375
- if (memory.frontmatter.category === "fact") this.factOnlyHashes.add(hash);
3369
+ if (memory.frontmatter.category === "fact") {
3370
+ factHashIndex.addFactByHash(hash);
3371
+ } else {
3372
+ factHashIndex.addByHash(hash);
3373
+ }
3376
3374
  }
3377
3375
  }
3378
3376
  if (legacyRecovered > 0) {
@@ -3896,8 +3894,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
3896
3894
  options.contentHashSource !== undefined && options.contentHashSource.length > 0
3897
3895
  ? sanitizeMemoryContent(options.contentHashSource).text
3898
3896
  : sanitized.text;
3899
- factHashIndex.add(hashText);
3900
- this.factOnlyHashes.add(ContentHashIndex.computeHash(hashText));
3897
+ factHashIndex.addFact(hashText);
3901
3898
  // Gate only the flush (issue #1909): the `.add(...)` above already set
3902
3899
  // dirty=true. When the caller defers, it owns the batch save
3903
3900
  // (extraction persist -> saveContentHashIndexes()). Single-write callers
@@ -3973,7 +3970,8 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
3973
3970
  // upkeep); otherwise the snapshot may be stale, so verify against the durable
3974
3971
  // fact corpus (ground truth) so a lock-contended read never suppresses a fact.
3975
3972
  if (authoritative) {
3976
- return this.factOnlyHashes.has(hash);
3973
+ const factHashIndex = await this.getFactHashIndex();
3974
+ return factHashIndex.hasFact(sanitized.text);
3977
3975
  }
3978
3976
  return await this.factContentHashPresentInCorpus(hash);
3979
3977
  }
@@ -4002,8 +4000,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
4002
4000
  await this.ensureFactHashIndexAuthoritative();
4003
4001
  const factHashIndex = await this.getFactHashIndex();
4004
4002
  for (const hash of hashes) {
4005
- factHashIndex.addByHash(hash);
4006
- this.factOnlyHashes.add(hash);
4003
+ factHashIndex.addFactByHash(hash);
4007
4004
  }
4008
4005
  // PR #2016 thread SDzOP: flush through the SAME cross-process locked
4009
4006
  // reconcile the write/batch/rebuild paths use, never the unlocked whole-file
@@ -4089,7 +4086,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
4089
4086
  for (const hash of removedHashes) {
4090
4087
  if (!remainingActiveHashes.has(hash)) {
4091
4088
  factHashIndex.removeByHash(hash);
4092
- this.factOnlyHashes.delete(hash);
4089
+ factHashIndex.removeFactByHash(hash);
4093
4090
  }
4094
4091
  }
4095
4092
  // PR #2016 thread SDzOP: serialize the removal with the per-index lock via
@@ -4102,21 +4099,23 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
4102
4099
  }
4103
4100
 
4104
4101
  /**
4105
- * Remove a memory's fact-ONLY hash membership in lockstep with the shared,
4106
- * category-agnostic index removal the orchestrator's
4107
- * `removeContentHashForMemory` performs on archival / semantic consolidation
4108
- * (PR #2016 threads SDzOP / SDzOR). Without this, `factOnlyHashes` kept a
4109
- * removed/superseded fact's hash and `hasFactContentHash` returned a stale
4110
- * `true` until the next corpus rebuild, so wearable / explicit-capture /
4111
- * promotion callers skipped a valid write. In-memory only — `factOnlyHashes`
4112
- * is never persisted; it is rebuilt from the corpus. No-op for non-facts.
4113
- * Matches the shared index's unconditional per-hash removal so the two stay
4114
- * coherent.
4102
+ * Remove a memory's fact-ONLY partition membership in lockstep with the
4103
+ * shared, category-agnostic index removal the orchestrator's
4104
+ * `removeContentHashForMemory` performs on archival / semantic
4105
+ * consolidation (PR #2016 threads SDzOP / SDzOR). Without this, the
4106
+ * partition kept a removed/superseded fact's hash and `hasFactContentHash`
4107
+ * returned a stale `true` until the next corpus rebuild, so wearable /
4108
+ * explicit-capture / promotion callers skipped a valid write. No-op when
4109
+ * the fact-hash index has not been loaded in this process yet (the
4110
+ * partition is empty then and the corpus rebuild excludes the removed
4111
+ * memory). No-op for non-facts.
4115
4112
  */
4116
4113
  removeFactOnlyHashForMemory(memory: MemoryFile): void {
4117
4114
  if (memory.frontmatter.category !== "fact") return;
4115
+ const factHashIndex = this.factHashIndex;
4116
+ if (!factHashIndex) return;
4118
4117
  for (const hash of this.factContentHashesForRemoval(memory)) {
4119
- this.factOnlyHashes.delete(hash);
4118
+ factHashIndex.removeFactByHash(hash);
4120
4119
  }
4121
4120
  }
4122
4121