@remnic/core 9.69.101 → 9.69.103
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.
- package/dist/access-admin-ops-surface.js +52 -51
- package/dist/access-authorization-probe.js +53 -52
- package/dist/access-boundary.js +52 -51
- package/dist/access-cli.js +151 -148
- package/dist/access-cli.js.map +1 -1
- package/dist/access-extraction-force-flush.js +52 -51
- package/dist/access-http-briefing.js +53 -52
- package/dist/access-http-query.js +54 -53
- package/dist/access-http.js +76 -75
- package/dist/access-identity-continuity-surface.js +52 -51
- package/dist/access-lcm-surface.js +52 -51
- package/dist/access-mcp.js +65 -64
- package/dist/access-namespace-preflight.js +52 -51
- package/dist/access-observe-write-category.js +8 -8
- package/dist/access-observe-write-surface.js +52 -51
- package/dist/access-offline-manifest.js +5 -5
- package/dist/access-operations-batch.js +56 -55
- package/dist/access-operations.js +63 -62
- package/dist/access-recall-concurrency.js +52 -51
- package/dist/access-recall-response.js +52 -51
- package/dist/access-recall-surface.js +52 -51
- package/dist/access-schema.js +7 -7
- package/dist/access-service.js +52 -51
- package/dist/access-surface-catalog.js +54 -53
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/active-recall.js +20 -19
- package/dist/active-recall.js.map +1 -1
- package/dist/adapters/index.js +4 -4
- package/dist/adapters/registry.js +2 -2
- package/dist/briefing.js +14 -13
- package/dist/buffer.js +5 -5
- package/dist/{capsule-crypto-7FJQINUR.js → capsule-crypto-YO5QJ6L3.js} +2 -2
- package/dist/{capsule-merge-ZCXUPLNJ.js → capsule-merge-42GJGDUC.js} +4 -3
- package/dist/{capsule-merge-ZCXUPLNJ.js.map → capsule-merge-42GJGDUC.js.map} +1 -1
- package/dist/causal-behavior.js +2 -2
- package/dist/causal-chain.js +2 -2
- package/dist/causal-consolidation.js +17 -16
- package/dist/causal-consolidation.js.map +1 -1
- package/dist/causal-retrieval.js +2 -2
- package/dist/causal-trajectory-graph.js +3 -3
- package/dist/causal-trajectory.js +1 -1
- package/dist/{chunk-UL7KDVLC.js → chunk-26DJ7FG6.js} +11 -11
- package/dist/{chunk-QCYUIZK2.js → chunk-2GSO4FEC.js} +7 -7
- package/dist/{chunk-533RHNHB.js → chunk-2JJD7GIW.js} +2 -2
- package/dist/{chunk-IOYY6ROU.js → chunk-2MMBJE53.js} +7 -7
- package/dist/{chunk-QSXEQPC4.js → chunk-2OFDC3AK.js} +2 -2
- package/dist/{chunk-5FAGCOZD.js → chunk-2U3R3DDH.js} +9 -9
- package/dist/{chunk-SCXURCVT.js → chunk-2UPTRDGM.js} +3 -3
- package/dist/{chunk-XVZA6VXC.js → chunk-3SL52JKD.js} +4 -4
- package/dist/{chunk-XEATJBNB.js → chunk-4QHWRWCF.js} +70 -70
- package/dist/{chunk-SBOCJ47I.js → chunk-5FHH4NJR.js} +6 -6
- package/dist/{chunk-V3I4NLZP.js → chunk-5GKRQBPQ.js} +2 -2
- package/dist/{chunk-PYYQCHJC.js → chunk-5PEBJUYD.js} +2 -2
- package/dist/{chunk-PEZAHDDU.js → chunk-6RWPKWCZ.js} +4 -4
- package/dist/{chunk-DSPWVQZ6.js → chunk-73R4HOOK.js} +3 -3
- package/dist/chunk-7CT3AI52.js +84 -0
- package/dist/chunk-7CT3AI52.js.map +1 -0
- package/dist/{chunk-S533KGX6.js → chunk-7X7A7KVN.js} +2 -2
- package/dist/{chunk-F5MINS3R.js → chunk-A6WNTVA7.js} +3 -3
- package/dist/{chunk-F5MINS3R.js.map → chunk-A6WNTVA7.js.map} +1 -1
- package/dist/{chunk-JZ66PN72.js → chunk-AWSP3WNM.js} +2 -2
- package/dist/{chunk-IY47KPML.js → chunk-B3OFQP5Y.js} +6 -6
- package/dist/{chunk-GNBZB43J.js → chunk-B44TVSEI.js} +2 -2
- package/dist/{chunk-4DXNOVNW.js → chunk-B454SHPU.js} +6 -6
- package/dist/{chunk-3LMOJXZR.js → chunk-BKVCTTEN.js} +2 -2
- package/dist/{chunk-2NLLXCJG.js → chunk-BXLOS5AJ.js} +2 -2
- package/dist/{chunk-HWLIMQE2.js → chunk-CHDGJJV6.js} +2 -2
- package/dist/{chunk-UYPQOASU.js → chunk-CNBGAFDY.js} +2 -2
- package/dist/{chunk-CYG3K2T2.js → chunk-D42DLA4D.js} +6 -6
- package/dist/{chunk-X5TAWDRO.js → chunk-D4MXH276.js} +2 -2
- package/dist/{chunk-X7Y7WX73.js → chunk-DQEMWVMT.js} +1 -1
- package/dist/{chunk-UFIZRMQZ.js → chunk-E4XLFYHV.js} +61 -29
- package/dist/chunk-E4XLFYHV.js.map +1 -0
- package/dist/{chunk-4OXXDL3X.js → chunk-EWWK65CI.js} +2 -2
- package/dist/{chunk-DFPG47ET.js → chunk-EZ3F4YIN.js} +11 -11
- package/dist/{chunk-PNVOKGAX.js → chunk-G5I5ZT6O.js} +2 -2
- package/dist/{chunk-7Z2UKRNJ.js → chunk-GQ6ZF4LD.js} +2 -2
- package/dist/{chunk-7OA4JWP5.js → chunk-GWWHV7F3.js} +2 -2
- package/dist/chunk-H6Z3RNW3.js +330 -0
- package/dist/chunk-H6Z3RNW3.js.map +1 -0
- package/dist/{chunk-645WOU5I.js → chunk-H7BZBSP6.js} +4 -4
- package/dist/{chunk-PHBH74Q6.js → chunk-HTXTVY64.js} +2 -2
- package/dist/{chunk-AXHU56C3.js → chunk-HWGFTTPS.js} +2 -2
- package/dist/{chunk-ARY6O3JN.js → chunk-HYFVZJLX.js} +2 -2
- package/dist/{chunk-2SGLMP2E.js → chunk-IDSZNHIP.js} +2 -2
- package/dist/{chunk-LO4UKPKX.js → chunk-IFCKHPY4.js} +2 -2
- package/dist/{chunk-ZHXSOMYH.js → chunk-IOMLGJHG.js} +4 -4
- package/dist/{chunk-YRULQW5J.js → chunk-ISX7GVZE.js} +4 -4
- package/dist/{chunk-5PHZSD75.js → chunk-J3ZJBX7I.js} +2 -2
- package/dist/{chunk-DINOVGA5.js → chunk-JHZOY4CJ.js} +48 -48
- package/dist/chunk-JHZOY4CJ.js.map +1 -0
- package/dist/{chunk-RFQT7IZO.js → chunk-JRDL3FGM.js} +3 -3
- package/dist/{chunk-OGZC2WUX.js → chunk-JWFTPRYD.js} +2 -2
- package/dist/{chunk-VPOAMPDD.js → chunk-K5ABKRXK.js} +59 -59
- package/dist/{chunk-P3WRFSYF.js → chunk-KMN2JE4D.js} +2 -2
- package/dist/{chunk-4MP2Q2EI.js → chunk-KN4GNQH7.js} +3 -3
- package/dist/{chunk-L6YCGS7I.js → chunk-KYUVFCT2.js} +2 -2
- package/dist/{chunk-5BVL2XUD.js → chunk-L6BUCPGI.js} +17 -17
- package/dist/{chunk-55NZVUNI.js → chunk-LP4UW5WI.js} +2 -2
- package/dist/{chunk-SF7CWSR6.js → chunk-LXJZUNLX.js} +2 -2
- package/dist/{chunk-XCB6QDL6.js → chunk-M5GVCJSJ.js} +8 -2
- package/dist/chunk-M5GVCJSJ.js.map +1 -0
- package/dist/{chunk-DGS34QSY.js → chunk-MFZACYZ6.js} +2 -2
- package/dist/{chunk-G3BW6SDE.js → chunk-NBYSCXOY.js} +3 -3
- package/dist/{chunk-KYLYXGKD.js → chunk-NIGZ3LE7.js} +2 -2
- package/dist/{chunk-JTC3PBNH.js → chunk-NN62MUZA.js} +2 -2
- package/dist/{chunk-R2TVWQLR.js → chunk-NT2Q6AHC.js} +2 -2
- package/dist/{chunk-ABGM2BN4.js → chunk-O43AAJFQ.js} +2 -2
- package/dist/{chunk-CZN53OT5.js → chunk-OC6ATPIP.js} +2 -2
- package/dist/{chunk-6Z263Z3E.js → chunk-OWV6LKNZ.js} +2 -2
- package/dist/{chunk-NM3BT2OH.js → chunk-PNZAFABF.js} +2 -2
- package/dist/{chunk-HIHN4XHL.js → chunk-PQ7EB5AD.js} +3 -3
- package/dist/{chunk-VVYLVE6R.js → chunk-PQKZLBCJ.js} +1 -1
- package/dist/{chunk-OFFW73OZ.js → chunk-PRNR47DI.js} +2 -2
- package/dist/{chunk-RZXFXKWY.js → chunk-Q3LWW7WS.js} +2 -2
- package/dist/{chunk-M7T2NKET.js → chunk-QKCGOECM.js} +2 -2
- package/dist/{chunk-Z3O53WZR.js → chunk-QWUJWBZ5.js} +2 -2
- package/dist/{chunk-HFOY2SBG.js → chunk-RYN4AIRM.js} +7 -5
- package/dist/chunk-RYN4AIRM.js.map +1 -0
- package/dist/{chunk-4LNCLZNK.js → chunk-S2GR3T7W.js} +2 -2
- package/dist/{chunk-2IWBHZ3H.js → chunk-SIGDETMB.js} +2 -2
- package/dist/{chunk-7AUIGOH4.js → chunk-SOVRTUD3.js} +2 -2
- package/dist/chunk-SP4DB6SX.js +19 -0
- package/dist/chunk-SP4DB6SX.js.map +1 -0
- package/dist/{chunk-S5R77WHV.js → chunk-SWXPR5SE.js} +2 -2
- package/dist/{chunk-3DNTFZAT.js → chunk-T32YYUT2.js} +2 -2
- package/dist/{chunk-W5JQSVPZ.js → chunk-T6RQNV7E.js} +2 -2
- package/dist/{chunk-O23QMYN4.js → chunk-TRN56SPQ.js} +2 -2
- package/dist/{chunk-KQAFEZQX.js → chunk-VDX2J7OX.js} +2 -2
- package/dist/{chunk-ZGYLPCWN.js → chunk-VO2BNAA2.js} +3 -3
- package/dist/{chunk-WVEECBCG.js → chunk-VV2MVHCJ.js} +2 -2
- package/dist/{chunk-HVDEKJJR.js → chunk-VYIBRCVW.js} +70 -61
- package/dist/chunk-VYIBRCVW.js.map +1 -0
- package/dist/{chunk-B3O3IRZN.js → chunk-VZBW6CDG.js} +1 -1
- package/dist/{chunk-JPKK466T.js → chunk-W5XWHTDO.js} +2 -2
- package/dist/{chunk-JNAOTN7B.js → chunk-XLWMNDQR.js} +4 -4
- package/dist/chunk-XLWMNDQR.js.map +1 -0
- package/dist/{chunk-DBWNTLLI.js → chunk-XM32D6YZ.js} +6 -6
- package/dist/{chunk-RP7RSENW.js → chunk-XQWKB6PY.js} +2 -2
- package/dist/{chunk-64S6X4IU.js → chunk-XTN54NML.js} +4 -4
- package/dist/{chunk-EZ25VE3G.js → chunk-YNDLCWXS.js} +4 -4
- package/dist/{chunk-Y7427SL7.js → chunk-Z6EZCN6Z.js} +10 -10
- package/dist/{chunk-5K2ALMSZ.js → chunk-ZRUC7FD3.js} +2 -2
- package/dist/cli.js +102 -101
- package/dist/coding/export-okf-codegraph.js +13 -12
- package/dist/coding/export-okf-codegraph.js.map +1 -1
- package/dist/coding/pre-action-gate.js +2 -2
- package/dist/compounding/engine.js +14 -13
- package/dist/config.js +20 -19
- package/dist/connectors/codex-materialize-runner.js +14 -13
- package/dist/connectors/index.js +14 -13
- package/dist/consolidation-provenance-check.js +4 -3
- package/dist/consolidation-undo.js +3 -2
- package/dist/consolidation-undo.js.map +1 -1
- package/dist/contradiction/index.js +3 -2
- package/dist/convergence-refresh.js +16 -15
- package/dist/corpus-watermark.js +16 -15
- package/dist/dashboard-runtime.js +2 -2
- package/dist/deep-recall-http-glue.js +8 -8
- package/dist/deep-recall.js +2 -2
- package/dist/entity-mention-carry.d.ts +16 -0
- package/dist/entity-mention-carry.d.ts.map +1 -0
- package/dist/entity-mention-carry.js +8 -0
- package/dist/entity-mention-epoch.d.ts +22 -0
- package/dist/entity-mention-epoch.d.ts.map +1 -0
- package/dist/entity-mention-epoch.js +8 -0
- package/dist/entity-mention-index-cache.d.ts +28 -0
- package/dist/entity-mention-index-cache.d.ts.map +1 -0
- package/dist/entity-mention-index-cache.js +29 -0
- package/dist/entity-mention-index-cache.js.map +1 -0
- package/dist/entity-retrieval.d.ts.map +1 -1
- package/dist/entity-retrieval.js +18 -15
- package/dist/event-order-recall.js +2 -2
- package/dist/external-wiki-access.js +53 -52
- package/dist/extraction-span-materialize.js +2 -2
- package/dist/extraction.js +21 -20
- package/dist/{graph-edge-decay-MKIRZ762.js → graph-edge-decay-PVKDKLQK.js} +6 -6
- package/dist/graph-edge-decay-PVKDKLQK.js.map +1 -0
- package/dist/graph-jsonl.js +4 -4
- package/dist/graph-snapshot.js +4 -4
- package/dist/graph.js +5 -5
- package/dist/harmonic-retrieval.js +1 -1
- package/dist/index.js +186 -183
- package/dist/lcm/engine.js +4 -4
- package/dist/lcm/index.js +13 -13
- package/dist/location/index.js +16 -15
- package/dist/maintenance/memory-governance.js +14 -13
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +14 -13
- package/dist/maintenance/rebuild-memory-projection.js +15 -14
- package/dist/memory-browse-operations.js +53 -52
- package/dist/memory-browse.js +5 -5
- package/dist/memory-corpus-version.d.ts +8 -3
- package/dist/memory-corpus-version.d.ts.map +1 -1
- package/dist/memory-corpus-version.js +2 -1
- package/dist/namespaces/migrate.js +15 -14
- package/dist/namespaces/search.js +7 -7
- package/dist/namespaces/storage.js +14 -13
- package/dist/offline-sync-changeset-generations.js +3 -3
- package/dist/offline-sync-embedding-generation.js +2 -2
- package/dist/offline-sync-snapshot-stream.js +5 -5
- package/dist/offline-sync.js +7 -7
- package/dist/operator-doctor-corpus.js +17 -16
- package/dist/operator-toolkit.js +33 -32
- package/dist/orchestration/maintenance.js +22 -21
- package/dist/orchestrator.js +151 -148
- package/dist/page-versioning.js +3 -2
- package/dist/preferences/preference-drift.d.ts.map +1 -1
- package/dist/procedural/library-maintenance.d.ts.map +1 -1
- package/dist/qmd.js +4 -4
- package/dist/recall-navigation-operations.js +53 -52
- package/dist/recall-navigation.js +52 -51
- package/dist/recall-state-view-admission.js +5 -5
- package/dist/recall-why-service.js +5 -5
- package/dist/{resolution-BROE3TRO.js → resolution-RSG4HZTL.js} +4 -3
- package/dist/resolution-RSG4HZTL.js.map +1 -0
- package/dist/resume-bundles.js +21 -20
- package/dist/search/factory.js +6 -6
- package/dist/search/index.js +12 -12
- package/dist/semantic-consolidation.js +15 -14
- package/dist/semantic-rule-promotion.js +14 -13
- package/dist/semantic-rule-verifier.js +14 -13
- package/dist/source-agent-qualifier.js +17 -16
- package/dist/standup/build.js +14 -13
- package/dist/storage/entity-mention-frontmatter-hold.d.ts +14 -0
- package/dist/storage/entity-mention-frontmatter-hold.d.ts.map +1 -0
- package/dist/storage.d.ts +13 -9
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +13 -12
- package/dist/support-passport/index.js +55 -54
- package/dist/transfer/backup.js +2 -2
- package/dist/transfer/capsule-export.js +2 -2
- package/dist/transfer/capsule-import.js +5 -4
- package/dist/transfer/export-okf.js +14 -13
- package/dist/verified-recall.js +14 -13
- package/dist/who-knows-cli.js +15 -14
- package/dist/who-knows.js +14 -13
- package/package.json +2 -2
- package/src/entity-mention-carry.ts +31 -0
- package/src/entity-mention-epoch.ts +120 -0
- package/src/entity-mention-index-cache.ts +443 -0
- package/src/entity-retrieval.ts +72 -71
- package/src/maintenance/rebuild-memory-projection.ts +1 -1
- package/src/memory-corpus-version.ts +13 -3
- package/src/preferences/preference-drift.ts +5 -3
- package/src/procedural/library-maintenance.ts +4 -3
- package/src/semantic-rule-promotion.ts +1 -1
- package/src/storage/entity-mention-frontmatter-hold.ts +44 -0
- package/src/storage.ts +40 -38
- package/dist/chunk-DINOVGA5.js.map +0 -1
- package/dist/chunk-HFOY2SBG.js.map +0 -1
- package/dist/chunk-HVDEKJJR.js.map +0 -1
- package/dist/chunk-JNAOTN7B.js.map +0 -1
- package/dist/chunk-UFIZRMQZ.js.map +0 -1
- package/dist/chunk-XCB6QDL6.js.map +0 -1
- /package/dist/{capsule-crypto-7FJQINUR.js.map → capsule-crypto-YO5QJ6L3.js.map} +0 -0
- /package/dist/{chunk-UL7KDVLC.js.map → chunk-26DJ7FG6.js.map} +0 -0
- /package/dist/{chunk-QCYUIZK2.js.map → chunk-2GSO4FEC.js.map} +0 -0
- /package/dist/{chunk-533RHNHB.js.map → chunk-2JJD7GIW.js.map} +0 -0
- /package/dist/{chunk-IOYY6ROU.js.map → chunk-2MMBJE53.js.map} +0 -0
- /package/dist/{chunk-QSXEQPC4.js.map → chunk-2OFDC3AK.js.map} +0 -0
- /package/dist/{chunk-5FAGCOZD.js.map → chunk-2U3R3DDH.js.map} +0 -0
- /package/dist/{chunk-SCXURCVT.js.map → chunk-2UPTRDGM.js.map} +0 -0
- /package/dist/{chunk-XVZA6VXC.js.map → chunk-3SL52JKD.js.map} +0 -0
- /package/dist/{chunk-XEATJBNB.js.map → chunk-4QHWRWCF.js.map} +0 -0
- /package/dist/{chunk-SBOCJ47I.js.map → chunk-5FHH4NJR.js.map} +0 -0
- /package/dist/{chunk-V3I4NLZP.js.map → chunk-5GKRQBPQ.js.map} +0 -0
- /package/dist/{chunk-PYYQCHJC.js.map → chunk-5PEBJUYD.js.map} +0 -0
- /package/dist/{chunk-PEZAHDDU.js.map → chunk-6RWPKWCZ.js.map} +0 -0
- /package/dist/{chunk-DSPWVQZ6.js.map → chunk-73R4HOOK.js.map} +0 -0
- /package/dist/{chunk-S533KGX6.js.map → chunk-7X7A7KVN.js.map} +0 -0
- /package/dist/{chunk-JZ66PN72.js.map → chunk-AWSP3WNM.js.map} +0 -0
- /package/dist/{chunk-IY47KPML.js.map → chunk-B3OFQP5Y.js.map} +0 -0
- /package/dist/{chunk-GNBZB43J.js.map → chunk-B44TVSEI.js.map} +0 -0
- /package/dist/{chunk-4DXNOVNW.js.map → chunk-B454SHPU.js.map} +0 -0
- /package/dist/{chunk-3LMOJXZR.js.map → chunk-BKVCTTEN.js.map} +0 -0
- /package/dist/{chunk-2NLLXCJG.js.map → chunk-BXLOS5AJ.js.map} +0 -0
- /package/dist/{chunk-HWLIMQE2.js.map → chunk-CHDGJJV6.js.map} +0 -0
- /package/dist/{chunk-UYPQOASU.js.map → chunk-CNBGAFDY.js.map} +0 -0
- /package/dist/{chunk-CYG3K2T2.js.map → chunk-D42DLA4D.js.map} +0 -0
- /package/dist/{chunk-X5TAWDRO.js.map → chunk-D4MXH276.js.map} +0 -0
- /package/dist/{chunk-X7Y7WX73.js.map → chunk-DQEMWVMT.js.map} +0 -0
- /package/dist/{chunk-4OXXDL3X.js.map → chunk-EWWK65CI.js.map} +0 -0
- /package/dist/{chunk-DFPG47ET.js.map → chunk-EZ3F4YIN.js.map} +0 -0
- /package/dist/{chunk-PNVOKGAX.js.map → chunk-G5I5ZT6O.js.map} +0 -0
- /package/dist/{chunk-7Z2UKRNJ.js.map → chunk-GQ6ZF4LD.js.map} +0 -0
- /package/dist/{chunk-7OA4JWP5.js.map → chunk-GWWHV7F3.js.map} +0 -0
- /package/dist/{chunk-645WOU5I.js.map → chunk-H7BZBSP6.js.map} +0 -0
- /package/dist/{chunk-PHBH74Q6.js.map → chunk-HTXTVY64.js.map} +0 -0
- /package/dist/{chunk-AXHU56C3.js.map → chunk-HWGFTTPS.js.map} +0 -0
- /package/dist/{chunk-ARY6O3JN.js.map → chunk-HYFVZJLX.js.map} +0 -0
- /package/dist/{chunk-2SGLMP2E.js.map → chunk-IDSZNHIP.js.map} +0 -0
- /package/dist/{chunk-LO4UKPKX.js.map → chunk-IFCKHPY4.js.map} +0 -0
- /package/dist/{chunk-ZHXSOMYH.js.map → chunk-IOMLGJHG.js.map} +0 -0
- /package/dist/{chunk-YRULQW5J.js.map → chunk-ISX7GVZE.js.map} +0 -0
- /package/dist/{chunk-5PHZSD75.js.map → chunk-J3ZJBX7I.js.map} +0 -0
- /package/dist/{chunk-RFQT7IZO.js.map → chunk-JRDL3FGM.js.map} +0 -0
- /package/dist/{chunk-OGZC2WUX.js.map → chunk-JWFTPRYD.js.map} +0 -0
- /package/dist/{chunk-VPOAMPDD.js.map → chunk-K5ABKRXK.js.map} +0 -0
- /package/dist/{chunk-P3WRFSYF.js.map → chunk-KMN2JE4D.js.map} +0 -0
- /package/dist/{chunk-4MP2Q2EI.js.map → chunk-KN4GNQH7.js.map} +0 -0
- /package/dist/{chunk-L6YCGS7I.js.map → chunk-KYUVFCT2.js.map} +0 -0
- /package/dist/{chunk-5BVL2XUD.js.map → chunk-L6BUCPGI.js.map} +0 -0
- /package/dist/{chunk-55NZVUNI.js.map → chunk-LP4UW5WI.js.map} +0 -0
- /package/dist/{chunk-SF7CWSR6.js.map → chunk-LXJZUNLX.js.map} +0 -0
- /package/dist/{chunk-DGS34QSY.js.map → chunk-MFZACYZ6.js.map} +0 -0
- /package/dist/{chunk-G3BW6SDE.js.map → chunk-NBYSCXOY.js.map} +0 -0
- /package/dist/{chunk-KYLYXGKD.js.map → chunk-NIGZ3LE7.js.map} +0 -0
- /package/dist/{chunk-JTC3PBNH.js.map → chunk-NN62MUZA.js.map} +0 -0
- /package/dist/{chunk-R2TVWQLR.js.map → chunk-NT2Q6AHC.js.map} +0 -0
- /package/dist/{chunk-ABGM2BN4.js.map → chunk-O43AAJFQ.js.map} +0 -0
- /package/dist/{chunk-CZN53OT5.js.map → chunk-OC6ATPIP.js.map} +0 -0
- /package/dist/{chunk-6Z263Z3E.js.map → chunk-OWV6LKNZ.js.map} +0 -0
- /package/dist/{chunk-NM3BT2OH.js.map → chunk-PNZAFABF.js.map} +0 -0
- /package/dist/{chunk-HIHN4XHL.js.map → chunk-PQ7EB5AD.js.map} +0 -0
- /package/dist/{chunk-VVYLVE6R.js.map → chunk-PQKZLBCJ.js.map} +0 -0
- /package/dist/{chunk-OFFW73OZ.js.map → chunk-PRNR47DI.js.map} +0 -0
- /package/dist/{chunk-RZXFXKWY.js.map → chunk-Q3LWW7WS.js.map} +0 -0
- /package/dist/{chunk-M7T2NKET.js.map → chunk-QKCGOECM.js.map} +0 -0
- /package/dist/{chunk-Z3O53WZR.js.map → chunk-QWUJWBZ5.js.map} +0 -0
- /package/dist/{chunk-4LNCLZNK.js.map → chunk-S2GR3T7W.js.map} +0 -0
- /package/dist/{chunk-2IWBHZ3H.js.map → chunk-SIGDETMB.js.map} +0 -0
- /package/dist/{chunk-7AUIGOH4.js.map → chunk-SOVRTUD3.js.map} +0 -0
- /package/dist/{chunk-S5R77WHV.js.map → chunk-SWXPR5SE.js.map} +0 -0
- /package/dist/{chunk-3DNTFZAT.js.map → chunk-T32YYUT2.js.map} +0 -0
- /package/dist/{chunk-W5JQSVPZ.js.map → chunk-T6RQNV7E.js.map} +0 -0
- /package/dist/{chunk-O23QMYN4.js.map → chunk-TRN56SPQ.js.map} +0 -0
- /package/dist/{chunk-KQAFEZQX.js.map → chunk-VDX2J7OX.js.map} +0 -0
- /package/dist/{chunk-ZGYLPCWN.js.map → chunk-VO2BNAA2.js.map} +0 -0
- /package/dist/{chunk-WVEECBCG.js.map → chunk-VV2MVHCJ.js.map} +0 -0
- /package/dist/{chunk-B3O3IRZN.js.map → chunk-VZBW6CDG.js.map} +0 -0
- /package/dist/{chunk-JPKK466T.js.map → chunk-W5XWHTDO.js.map} +0 -0
- /package/dist/{chunk-DBWNTLLI.js.map → chunk-XM32D6YZ.js.map} +0 -0
- /package/dist/{chunk-RP7RSENW.js.map → chunk-XQWKB6PY.js.map} +0 -0
- /package/dist/{chunk-64S6X4IU.js.map → chunk-XTN54NML.js.map} +0 -0
- /package/dist/{chunk-EZ25VE3G.js.map → chunk-YNDLCWXS.js.map} +0 -0
- /package/dist/{chunk-Y7427SL7.js.map → chunk-Z6EZCN6Z.js.map} +0 -0
- /package/dist/{chunk-5K2ALMSZ.js.map → chunk-ZRUC7FD3.js.map} +0 -0
- /package/dist/{graph-edge-decay-MKIRZ762.js.map → entity-mention-carry.js.map} +0 -0
- /package/dist/{resolution-BROE3TRO.js.map → entity-mention-epoch.js.map} +0 -0
package/src/entity-retrieval.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { resolveNamespaceCapabilities } from "./capabilities.js";
|
|
|
2
2
|
import { renderAuthorityBoundContent } from "./recall-context-composition.js";
|
|
3
3
|
import { createHash } from "node:crypto";
|
|
4
4
|
import { sanitizeMemoryContent } from "./sanitize.js";
|
|
5
|
-
import {
|
|
5
|
+
import { readFile } from "node:fs/promises";
|
|
6
6
|
import path from "node:path";
|
|
7
7
|
import { collectNativeKnowledgeChunks, type NativeKnowledgeChunk } from "./native-knowledge.js";
|
|
8
8
|
import { compareEntityTimestamps, normalizeEntityName, type StorageManager } from "./storage.js";
|
|
@@ -22,6 +22,15 @@ import {
|
|
|
22
22
|
yieldEntityRecallScan,
|
|
23
23
|
yieldEntityRecallScanEvery,
|
|
24
24
|
} from "./entity-recall-cancellation.js";
|
|
25
|
+
import { applyCarriedMemorySnippets } from "./entity-mention-carry.js";
|
|
26
|
+
import {
|
|
27
|
+
entityMentionCacheGeneration,
|
|
28
|
+
entityMentionIdentity,
|
|
29
|
+
entityMentionPersistedIndexReadable,
|
|
30
|
+
entityMentionScopeKey,
|
|
31
|
+
resolveEntityMentionIndex,
|
|
32
|
+
writePersistedEntityMentionIndex,
|
|
33
|
+
} from "./entity-mention-index-cache.js";
|
|
25
34
|
const ENTITY_INDEX_VERSION = 3;
|
|
26
35
|
const RECENT_TRANSCRIPT_LOOKBACK_HOURS = 24;
|
|
27
36
|
const INSTRUCTION_LIKE_RE = /\b(always|never|must|should|remember to|do not|don't|process|workflow|template|checklist|instruction)\b/i;
|
|
@@ -64,6 +73,8 @@ type EntityMentionIndex = {
|
|
|
64
73
|
updatedAt: string;
|
|
65
74
|
entityStatusVersion?: number;
|
|
66
75
|
entities: EntityMentionIndexEntry[];
|
|
76
|
+
/** In-memory only. A new canonical id had no snippets to carry. */
|
|
77
|
+
pendingSnippetReconcile?: boolean;
|
|
67
78
|
};
|
|
68
79
|
type EntityCandidate = {
|
|
69
80
|
entry: EntityMentionIndexEntry;
|
|
@@ -356,13 +367,19 @@ async function readCurrentPersistedEntityIndex(
|
|
|
356
367
|
return null;
|
|
357
368
|
}
|
|
358
369
|
const index = await readEntityIndexState(storage);
|
|
359
|
-
if (!index || index.entityStatusVersion !== storage.getMemoryStatusVersion()) {
|
|
370
|
+
if (!entityMentionPersistedIndexReadable(storage.dir) || !index || index.entityStatusVersion !== storage.getMemoryStatusVersion()) {
|
|
360
371
|
return null;
|
|
361
372
|
}
|
|
362
373
|
return index;
|
|
363
374
|
}
|
|
364
|
-
|
|
365
|
-
|
|
375
|
+
type CarriedMemorySnippets = Map<string, { memorySnippets: string[]; memorySnippetOrigins?: (string | undefined)[] }>;
|
|
376
|
+
|
|
377
|
+
function carriedMemorySnippets(index: EntityMentionIndex): CarriedMemorySnippets {
|
|
378
|
+
return new Map(index.entities.map((entry) => [entry.canonicalId, {
|
|
379
|
+
memorySnippets: entry.memorySnippets.slice(),
|
|
380
|
+
memorySnippetOrigins: entry.memorySnippetOrigins?.slice(),
|
|
381
|
+
}]));
|
|
382
|
+
}
|
|
366
383
|
|
|
367
384
|
function nativeEntityIndexRevision(chunks: NativeKnowledgeChunk[]): string {
|
|
368
385
|
const projection = chunks.map((chunk) => [
|
|
@@ -376,40 +393,13 @@ function nativeEntityIndexRevision(chunks: NativeKnowledgeChunk[]): string {
|
|
|
376
393
|
]);
|
|
377
394
|
return createHash("sha256").update(JSON.stringify(projection)).digest("hex");
|
|
378
395
|
}
|
|
379
|
-
function namespaceEntityIndexCacheKey(
|
|
380
|
-
storages: StorageManager[],
|
|
381
|
-
recallNamespaces: string[],
|
|
382
|
-
nativeRevision: string,
|
|
383
|
-
): string {
|
|
384
|
-
const namespaceKey = uniqueStrings(recallNamespaces).join("\u001f");
|
|
385
|
-
const storageKey = storages
|
|
386
|
-
.map((scopedStorage) => {
|
|
387
|
-
const aliases = Object.entries(scopedStorage.entityAliases)
|
|
388
|
-
.sort(([left], [right]) => left.localeCompare(right));
|
|
389
|
-
return (
|
|
390
|
-
`${path.resolve(scopedStorage.dir)}@${scopedStorage.getMemoryStatusVersion()}` +
|
|
391
|
-
`:${scopedStorage.getMemoryCorpusVersion()}:${scopedStorage.getEntityMutationVersion()}` +
|
|
392
|
-
`:${scopedStorage.hotCacheKeyId()}:${JSON.stringify(aliases)}`
|
|
393
|
-
);
|
|
394
|
-
})
|
|
395
|
-
.join("\u001f");
|
|
396
|
-
return `${namespaceKey}\u001e${storageKey}\u001e${nativeRevision}`;
|
|
397
|
-
}
|
|
398
|
-
function rememberNamespaceEntityIndex(key: string, index: EntityMentionIndex): void {
|
|
399
|
-
if (namespaceEntityIndexCache.size >= MAX_NAMESPACE_ENTITY_INDEX_CACHE_ENTRIES) {
|
|
400
|
-
const oldestKey = namespaceEntityIndexCache.keys().next().value;
|
|
401
|
-
if (typeof oldestKey === "string") namespaceEntityIndexCache.delete(oldestKey);
|
|
402
|
-
}
|
|
403
|
-
namespaceEntityIndexCache.set(key, index);
|
|
404
|
-
}
|
|
405
396
|
|
|
406
|
-
async function writeEntityIndexState(
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
await writeFile(statePath, nextContent, "utf-8");
|
|
397
|
+
async function writeEntityIndexState(
|
|
398
|
+
storage: StorageManager,
|
|
399
|
+
index: EntityMentionIndex,
|
|
400
|
+
persistGeneration: number,
|
|
401
|
+
): Promise<void> {
|
|
402
|
+
await writePersistedEntityMentionIndex(storage.dir, persistGeneration, JSON.stringify(index, null, 2) + "\n");
|
|
413
403
|
}
|
|
414
404
|
|
|
415
405
|
function nativePseudoCanonicalId(chunk: NativeKnowledgeChunk): string {
|
|
@@ -483,6 +473,7 @@ async function buildEntityMentionIndex(
|
|
|
483
473
|
nativeChunksOverride?: NativeKnowledgeChunk[],
|
|
484
474
|
resolvedStorages?: StorageManager[],
|
|
485
475
|
abortSignal?: AbortSignal,
|
|
476
|
+
carrySnippets?: CarriedMemorySnippets,
|
|
486
477
|
): Promise<EntityMentionIndex> {
|
|
487
478
|
checkEntityRecallAbort(abortSignal);
|
|
488
479
|
const storages = resolvedStorages ?? await resolveEntityIndexStorages(
|
|
@@ -493,11 +484,14 @@ async function buildEntityMentionIndex(
|
|
|
493
484
|
);
|
|
494
485
|
const shouldPersistIndex =
|
|
495
486
|
storages.length === 1 && path.resolve(storages[0]!.dir) === path.resolve(storage.dir);
|
|
487
|
+
const persistGeneration = entityMentionCacheGeneration(storage.dir);
|
|
496
488
|
const entityStatusVersionBefore = shouldPersistIndex ? storage.getMemoryStatusVersion() : undefined;
|
|
497
489
|
const [previousIndex, entityFileSets, memorySets, nativeChunks] = await Promise.all([
|
|
498
490
|
shouldPersistIndex ? readEntityIndexState(storage) : Promise.resolve(null),
|
|
499
491
|
Promise.all(storages.map((scopedStorage) => scopedStorage.readAllEntityFiles({ abortSignal }))),
|
|
500
|
-
|
|
492
|
+
carrySnippets
|
|
493
|
+
? Promise.resolve([])
|
|
494
|
+
: Promise.all(storages.map((scopedStorage) => scopedStorage.readAllMemories({ abortSignal }))),
|
|
501
495
|
nativeChunksOverride ? Promise.resolve(nativeChunksOverride) : readNativeChunks(config, recallNamespaces),
|
|
502
496
|
]);
|
|
503
497
|
// The bulk reads now stop at their own scan boundaries (issue #2307); this
|
|
@@ -562,15 +556,20 @@ async function buildEntityMentionIndex(
|
|
|
562
556
|
}
|
|
563
557
|
|
|
564
558
|
scanned = 0;
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
559
|
+
const pendingSnippetReconcile = carrySnippets
|
|
560
|
+
? applyCarriedMemorySnippets(entities.values(), carrySnippets)
|
|
561
|
+
: false;
|
|
562
|
+
if (!carrySnippets) {
|
|
563
|
+
for (const memory of memories) {
|
|
564
|
+
scanned += 1;
|
|
565
|
+
await yieldEntityRecallScanEvery(scanned, abortSignal);
|
|
566
|
+
const entry = typeof memory.frontmatter.entityRef === "string" ? entities.get(memory.frontmatter.entityRef) : undefined;
|
|
567
|
+
if (!entry) continue;
|
|
568
|
+
const snippet = await readMemorySnippet(memory);
|
|
569
|
+
if (entry.memorySnippets.includes(snippet)) continue;
|
|
570
|
+
entry.memorySnippets.push(snippet);
|
|
571
|
+
entry.memorySnippetOrigins = [...(entry.memorySnippetOrigins ?? []), memory.frontmatter.origin];
|
|
572
|
+
}
|
|
574
573
|
}
|
|
575
574
|
// Each remaining phase is another synchronous pass over the whole index
|
|
576
575
|
// (alias map, native-chunk merge, sort, two full serializations). Yield between
|
|
@@ -604,7 +603,7 @@ async function buildEntityMentionIndex(
|
|
|
604
603
|
await yieldEntityRecallScan(abortSignal);
|
|
605
604
|
const nextEntities = JSON.stringify(sortedEntities);
|
|
606
605
|
const entityStatusVersionAfter = shouldPersistIndex ? storage.getMemoryStatusVersion() : undefined;
|
|
607
|
-
const canPersistIndex = shouldPersistIndex && entityStatusVersionBefore === entityStatusVersionAfter;
|
|
606
|
+
const canPersistIndex = shouldPersistIndex && entityStatusVersionBefore === entityStatusVersionAfter && persistGeneration === entityMentionCacheGeneration(storage.dir);
|
|
608
607
|
const index: EntityMentionIndex = {
|
|
609
608
|
version: ENTITY_INDEX_VERSION,
|
|
610
609
|
updatedAt:
|
|
@@ -615,12 +614,10 @@ async function buildEntityMentionIndex(
|
|
|
615
614
|
entities: sortedEntities,
|
|
616
615
|
};
|
|
617
616
|
if (canPersistIndex) {
|
|
618
|
-
// A build the caller has abandoned must not leave a persisted index behind:
|
|
619
|
-
// the write is I/O the timed-out recall no longer needs, and the next recall
|
|
620
|
-
// is already competing for the same disk.
|
|
621
617
|
checkEntityRecallAbort(abortSignal);
|
|
622
|
-
await writeEntityIndexState(storage, index);
|
|
618
|
+
await writeEntityIndexState(storage, index, persistGeneration);
|
|
623
619
|
}
|
|
620
|
+
if (pendingSnippetReconcile) index.pendingSnippetReconcile = true;
|
|
624
621
|
return index;
|
|
625
622
|
}
|
|
626
623
|
|
|
@@ -1081,30 +1078,34 @@ export async function buildEntityRecallSection(options: BuildEntityRecallSection
|
|
|
1081
1078
|
options.namespaceStorage,
|
|
1082
1079
|
)
|
|
1083
1080
|
: undefined;
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
? namespaceEntityIndexCache.get(namespaceCacheKey)
|
|
1094
|
-
: undefined;
|
|
1095
|
-
checkEntityRecallAbort(options.abortSignal);
|
|
1096
|
-
if (!index) {
|
|
1097
|
-
index = await buildEntityMentionIndex(
|
|
1081
|
+
if (!nativeChunks) {
|
|
1082
|
+
nativeChunks = await readNativeChunks(options.config, options.recallNamespaces);
|
|
1083
|
+
}
|
|
1084
|
+
const indexStorages = resolvedStorages ?? [options.storage];
|
|
1085
|
+
const index = await resolveEntityMentionIndex({
|
|
1086
|
+
scopeKey: entityMentionScopeKey(options.recallNamespaces, indexStorages, nativeEntityIndexRevision(nativeChunks)),
|
|
1087
|
+
currentIdentity: () => entityMentionIdentity(indexStorages),
|
|
1088
|
+
abortSignal: options.abortSignal,
|
|
1089
|
+
buildFull: (signal) => buildEntityMentionIndex(
|
|
1098
1090
|
options.storage,
|
|
1099
1091
|
options.config,
|
|
1100
1092
|
options.recallNamespaces,
|
|
1101
1093
|
options.namespaceStorage,
|
|
1102
1094
|
nativeChunks,
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
)
|
|
1106
|
-
|
|
1107
|
-
|
|
1095
|
+
indexStorages,
|
|
1096
|
+
signal,
|
|
1097
|
+
),
|
|
1098
|
+
rebuildEntities: (previous, signal) => buildEntityMentionIndex(
|
|
1099
|
+
options.storage,
|
|
1100
|
+
options.config,
|
|
1101
|
+
options.recallNamespaces,
|
|
1102
|
+
options.namespaceStorage,
|
|
1103
|
+
nativeChunks,
|
|
1104
|
+
indexStorages,
|
|
1105
|
+
signal,
|
|
1106
|
+
carriedMemorySnippets(previous),
|
|
1107
|
+
),
|
|
1108
|
+
});
|
|
1108
1109
|
// Candidate resolution is another synchronous pass over every entity and alias,
|
|
1109
1110
|
// reached even on a cache hit that did no I/O at all — so yield here too, or a
|
|
1110
1111
|
// cached corpus could still hold the loop past the section budget (issue #2291).
|
|
@@ -589,7 +589,7 @@ async function loadAuthoritativeProjectionSnapshot(options: {
|
|
|
589
589
|
const storage = assertInjectedStorageRooted("rebuildMemoryProjection", options.memoryDir, options.storage) ?? new StorageManager(options.memoryDir);
|
|
590
590
|
// Force a fresh disk read — projection verify/rebuild must see the true
|
|
591
591
|
// on-disk state, not a potentially stale in-process cache.
|
|
592
|
-
storage.invalidateAllMemoriesCacheForDir();
|
|
592
|
+
storage.invalidateAllMemoriesCacheForDir({ indexedText: false });
|
|
593
593
|
const selected = selectProjectionMemories([
|
|
594
594
|
await storage.readAllMemories(),
|
|
595
595
|
await storage.readAllColdMemories(),
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { appendFileSync, mkdirSync } from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import { entityMentionEpoch } from "./entity-mention-epoch.js";
|
|
3
4
|
import { deleteInFlightReadsForDir } from "./in-flight-reads.js";
|
|
4
5
|
import { invalidateDerivedAndGlobalForDir } from "./memory-cache.js";
|
|
5
6
|
|
|
@@ -17,10 +18,16 @@ export const MEMORY_CORPUS_VERSION_SENTINEL = ".memory-corpus-version.log";
|
|
|
17
18
|
* — review approval, governance restore, migration. Appends one byte to the
|
|
18
19
|
* on-disk sentinel so any process's version-keyed hot-memories cache rescans
|
|
19
20
|
* on its next read (StorageManager.readSharedVersion reads the file size, so
|
|
20
|
-
* the growth is observed immediately).
|
|
21
|
-
*
|
|
21
|
+
* the growth is observed immediately). The same call moves the entity-mention
|
|
22
|
+
* epoch, unless the caller passes `{ indexedText: false }` for a metadata
|
|
23
|
+
* stamp that cannot change snippet text, entityRef, or origin. Fail-open: a
|
|
24
|
+
* bump failure must never crash the caller — a stale-cache window self-heals
|
|
25
|
+
* on the next real write.
|
|
22
26
|
*/
|
|
23
|
-
export function bumpMemoryCorpusVersionForDir(
|
|
27
|
+
export function bumpMemoryCorpusVersionForDir(
|
|
28
|
+
memoryDir: string,
|
|
29
|
+
options?: { indexedText?: boolean },
|
|
30
|
+
): void {
|
|
24
31
|
try {
|
|
25
32
|
const stateDir = path.join(memoryDir, "state");
|
|
26
33
|
mkdirSync(stateDir, { recursive: true });
|
|
@@ -28,6 +35,9 @@ export function bumpMemoryCorpusVersionForDir(memoryDir: string): void {
|
|
|
28
35
|
} catch {
|
|
29
36
|
/* fail-open: never let a cache-coherence bump crash the primary operation */
|
|
30
37
|
}
|
|
38
|
+
if (options?.indexedText !== false && !entityMentionEpoch.suppressed()) {
|
|
39
|
+
entityMentionEpoch.bump(memoryDir);
|
|
40
|
+
}
|
|
31
41
|
// Drop any in-flight readAllMemories scan for this dir (Cursor Medium, #1902):
|
|
32
42
|
// after the sentinel advances, a concurrent read that missed the version-keyed
|
|
33
43
|
// hot entry must not attach to a scan that began BEFORE this out-of-band write
|
|
@@ -558,8 +558,10 @@ export async function runPreferenceDriftScan(
|
|
|
558
558
|
// shared corpus version out of band — otherwise hot recall caches keep
|
|
559
559
|
// serving pre-stamp frontmatter and the damping stage never sees the new
|
|
560
560
|
// `driftState` (§25/§31).
|
|
561
|
-
bumpMemoryCorpusVersionForDir(storage.dir);
|
|
562
|
-
if (storage.dir !== deps.memoryDir)
|
|
561
|
+
bumpMemoryCorpusVersionForDir(storage.dir, { indexedText: false });
|
|
562
|
+
if (storage.dir !== deps.memoryDir) {
|
|
563
|
+
bumpMemoryCorpusVersionForDir(deps.memoryDir, { indexedText: false });
|
|
564
|
+
}
|
|
563
565
|
}
|
|
564
566
|
try {
|
|
565
567
|
await writeJsonFileAtomic(driftMarkerPath(deps.memoryDir), {
|
|
@@ -640,7 +642,7 @@ export async function resolvePreferenceDrift(
|
|
|
640
642
|
{ lastCorroborated: nowIso, driftState: undefined, updated: nowIso },
|
|
641
643
|
{ at: now, actor: DRIFT_ACTOR, reasonCode: "drift_kept", ruleVersion: DRIFT_RULE_VERSION },
|
|
642
644
|
);
|
|
643
|
-
bumpMemoryCorpusVersionForDir(storage.dir);
|
|
645
|
+
bumpMemoryCorpusVersionForDir(storage.dir, { indexedText: false });
|
|
644
646
|
touched();
|
|
645
647
|
return { affectedIds: [preferenceId], message: `Preference ${preferenceId} confirmed still current` };
|
|
646
648
|
}
|
|
@@ -526,9 +526,10 @@ export async function runProcedureLibraryMaintenance(options: {
|
|
|
526
526
|
report.appliedCount = report.applied.length;
|
|
527
527
|
|
|
528
528
|
if (writes > 0) {
|
|
529
|
-
//
|
|
530
|
-
//
|
|
531
|
-
|
|
529
|
+
// Corpus bump so hot caches observe the pass. Archive already moved the
|
|
530
|
+
// mention epoch when it removed the live file. Merge-supersede and repair
|
|
531
|
+
// stamps are metadata-only, so this bump must not move the epoch.
|
|
532
|
+
bumpMemoryCorpusVersionForDir(options.memoryDir, { indexedText: false });
|
|
532
533
|
}
|
|
533
534
|
try {
|
|
534
535
|
await writeJsonFileAtomic(maintenanceMarkerPath(options.memoryDir), {
|
|
@@ -610,7 +610,7 @@ export async function promoteSemanticRuleFromMemory(options: {
|
|
|
610
610
|
};
|
|
611
611
|
|
|
612
612
|
return withPromotionLock(options.memoryDir, ruleKey, async (lock) => {
|
|
613
|
-
storage.invalidateAllMemoriesCacheForDir();
|
|
613
|
+
storage.invalidateAllMemoriesCacheForDir({ indexedText: false });
|
|
614
614
|
const existingRule = (await storage.readAllMemories()).find(
|
|
615
615
|
(memory) =>
|
|
616
616
|
memory.frontmatter.category === "rule" &&
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { entityMentionEpoch } from "../entity-mention-epoch.js";
|
|
2
|
+
import type { MemoryFile, MemoryFrontmatter } from "../types.js";
|
|
3
|
+
import {
|
|
4
|
+
buildCapturePathLockIdentity,
|
|
5
|
+
buildExplicitCaptureDedupKey,
|
|
6
|
+
} from "./tombstone-blocked-capture-mutation.js";
|
|
7
|
+
|
|
8
|
+
type MentionHoldStorage = {
|
|
9
|
+
withTombstoneBlockedCaptureWriteLock<T>(
|
|
10
|
+
task: () => Promise<T>,
|
|
11
|
+
identity?: readonly string[],
|
|
12
|
+
): Promise<T>;
|
|
13
|
+
readMemoryByPath(pathname: string): Promise<MemoryFile | null>;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Metadata frontmatter writes may suppress the mention epoch only when the
|
|
18
|
+
* file still has the same body, entityRef, and origin while the path lock is
|
|
19
|
+
* held. The write runs in that same lock so a concurrent body or entityRef
|
|
20
|
+
* change cannot be overwritten under suppression.
|
|
21
|
+
*/
|
|
22
|
+
export async function holdMentionNeutralFrontmatter<T>(
|
|
23
|
+
storage: MentionHoldStorage,
|
|
24
|
+
memory: MemoryFile,
|
|
25
|
+
updated: MemoryFrontmatter,
|
|
26
|
+
write: () => Promise<T>,
|
|
27
|
+
): Promise<T | undefined> {
|
|
28
|
+
const identities = [
|
|
29
|
+
buildCapturePathLockIdentity(memory.path),
|
|
30
|
+
buildExplicitCaptureDedupKey(memory.content, memory.frontmatter.category, memory.frontmatter.sourceConnector),
|
|
31
|
+
buildExplicitCaptureDedupKey(memory.content, updated.category, updated.sourceConnector),
|
|
32
|
+
];
|
|
33
|
+
return storage.withTombstoneBlockedCaptureWriteLock(async () => {
|
|
34
|
+
const persisted = await storage.readMemoryByPath(memory.path);
|
|
35
|
+
if (
|
|
36
|
+
!persisted ||
|
|
37
|
+
persisted.content !== memory.content ||
|
|
38
|
+
!entityMentionEpoch.neutral(persisted.frontmatter, updated)
|
|
39
|
+
) {
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
return write();
|
|
43
|
+
}, identities);
|
|
44
|
+
}
|
package/src/storage.ts
CHANGED
|
@@ -87,6 +87,8 @@ import {
|
|
|
87
87
|
deleteInFlightReadsForDir,
|
|
88
88
|
clearInFlightReads,
|
|
89
89
|
} from "./in-flight-reads.js";
|
|
90
|
+
import { entityMentionEpoch } from "./entity-mention-epoch.js";
|
|
91
|
+
import { holdMentionNeutralFrontmatter } from "./storage/entity-mention-frontmatter-hold.js";
|
|
90
92
|
import * as archive from "./archive-mutation-version.js";
|
|
91
93
|
import { rotateMarkdownFileToArchive } from "./hygiene.js";
|
|
92
94
|
import { sanitizeMemoryContent } from "./sanitize.js";
|
|
@@ -2419,11 +2421,9 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
2419
2421
|
* Bump only — NOT invalidateAllForDir (that would drop the very hot
|
|
2420
2422
|
* entry the write path just patched).
|
|
2421
2423
|
*/
|
|
2422
|
-
protected bumpMemoryCorpusVersion(): void {
|
|
2424
|
+
protected bumpMemoryCorpusVersion(opts?: { indexedText?: boolean }): void {
|
|
2423
2425
|
this.bumpSharedVersion("memory-corpus", StorageManager.memoryCorpusVersionByDir);
|
|
2424
|
-
|
|
2425
|
-
// must not attach to a scan that began BEFORE this mutation. (The patch
|
|
2426
|
-
// path uses bumpMemoryCorpusVersionExclusive and clears the slot itself.)
|
|
2426
|
+
if (opts?.indexedText !== false && !entityMentionEpoch.suppressed()) entityMentionEpoch.bump(this.baseDir);
|
|
2427
2427
|
deleteInFlightReadsForDir(this.baseDir);
|
|
2428
2428
|
}
|
|
2429
2429
|
getArchiveMutationVersion(): number { return archive.getArchiveMutationVersionForDir(this.baseDir); }
|
|
@@ -2434,7 +2434,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
2434
2434
|
* patchHotMemoriesCache refuse to re-key its locally patched corpus at a
|
|
2435
2435
|
* version already reflecting a peer's still-unread concurrent append.
|
|
2436
2436
|
*/
|
|
2437
|
-
private bumpMemoryCorpusVersionExclusive(): { produced: number; exclusive: boolean } {
|
|
2437
|
+
private bumpMemoryCorpusVersionExclusive(opts?: { indexedText?: boolean }): { produced: number; exclusive: boolean } {
|
|
2438
2438
|
const filePath = this.versionFilePath("memory-corpus");
|
|
2439
2439
|
try {
|
|
2440
2440
|
mkdirSync(this.stateDir, { recursive: true });
|
|
@@ -2447,11 +2447,13 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
2447
2447
|
appendFileSync(filePath, "x");
|
|
2448
2448
|
const produced = statSync(filePath).size;
|
|
2449
2449
|
StorageManager.memoryCorpusVersionByDir.set(this.baseDir, produced);
|
|
2450
|
+
if (opts?.indexedText !== false && !entityMentionEpoch.suppressed()) entityMentionEpoch.bump(this.baseDir);
|
|
2450
2451
|
// Exclusive iff exactly our single byte landed between the two stats.
|
|
2451
2452
|
return { produced, exclusive: produced === before + 1 };
|
|
2452
2453
|
} catch {
|
|
2453
2454
|
const next = (StorageManager.memoryCorpusVersionByDir.get(this.baseDir) ?? 0) + 1;
|
|
2454
2455
|
StorageManager.memoryCorpusVersionByDir.set(this.baseDir, next);
|
|
2456
|
+
if (opts?.indexedText !== false && !entityMentionEpoch.suppressed()) entityMentionEpoch.bump(this.baseDir);
|
|
2455
2457
|
return { produced: next, exclusive: true };
|
|
2456
2458
|
}
|
|
2457
2459
|
}
|
|
@@ -4417,8 +4419,8 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
4417
4419
|
/** Invalidate the readAllMemories() cache after writes that add/remove memories. */
|
|
4418
4420
|
/** Public cache invalidation for callers that need authoritative disk reads
|
|
4419
4421
|
* (e.g. projection verify/rebuild). */
|
|
4420
|
-
invalidateAllMemoriesCacheForDir(): void {
|
|
4421
|
-
this.invalidateAllMemoriesCache();
|
|
4422
|
+
invalidateAllMemoriesCacheForDir(opts?: { indexedText?: boolean }): void {
|
|
4423
|
+
this.invalidateAllMemoriesCache(opts);
|
|
4422
4424
|
}
|
|
4423
4425
|
|
|
4424
4426
|
/** Invalidate only the cache layers affected by direct tier file deletes. */
|
|
@@ -4443,9 +4445,9 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
4443
4445
|
}
|
|
4444
4446
|
}
|
|
4445
4447
|
|
|
4446
|
-
/** Clear
|
|
4447
|
-
* (bypassing StorageManager.writeMemory) to avoid stale reads. */
|
|
4448
|
+
/** Clear every static cache. Direct file writes call this so the next read is not stale. */
|
|
4448
4449
|
static clearAllStaticCaches(): void {
|
|
4450
|
+
entityMentionEpoch.reset();
|
|
4449
4451
|
clearInFlightReads();
|
|
4450
4452
|
StorageManager.questionsCache.clear();
|
|
4451
4453
|
StorageManager.coldMemoriesCache.clear(); // also wipe the cold-scan TTL cache
|
|
@@ -4475,12 +4477,12 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
4475
4477
|
* exclusively by invalidateColdMemoriesCache(), which is called only when
|
|
4476
4478
|
* cold content actually changes (hot→cold demotions, writeMemoryFileAtomic
|
|
4477
4479
|
* inside cold/, archiveMemory, etc.). */
|
|
4478
|
-
protected invalidateAllMemoriesCache(): void {
|
|
4480
|
+
protected invalidateAllMemoriesCache(opts?: { indexedText?: boolean }): void {
|
|
4479
4481
|
deleteInFlightReadsForDir(this.baseDir);
|
|
4480
4482
|
// Bulk/ambiguous mutations drop the hot layer wholesale (below); bump the
|
|
4481
4483
|
// corpus sentinel too so PEER processes rescan instead of serving a warm
|
|
4482
4484
|
// pre-mutation corpus entry (issue #1902 cross-process coherence).
|
|
4483
|
-
this.bumpMemoryCorpusVersion();
|
|
4485
|
+
this.bumpMemoryCorpusVersion(opts);
|
|
4484
4486
|
// Invalidation chokepoint (issue #1535 / #1904): evict the layers a
|
|
4485
4487
|
// memory-mutate can affect — hot, archive, derived episode/rule views, and
|
|
4486
4488
|
// both QMD result caches (qmdSearchCache and qmdRecallCache). Before the QMD
|
|
@@ -5356,18 +5358,16 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
5356
5358
|
[buildCapturePathLockIdentity(expected.path), oldIdentity, newIdentity]
|
|
5357
5359
|
);
|
|
5358
5360
|
}
|
|
5359
|
-
/**
|
|
5360
|
-
|
|
5361
|
-
*/
|
|
5361
|
+
/** Frontmatter patch. A replaced body still moves the mention epoch. */
|
|
5362
|
+
private static readonly frontmatterBody = StorageManager.prototype.writeMemoryFrontmatter;
|
|
5362
5363
|
async writeMemoryFrontmatter(
|
|
5363
5364
|
memory: MemoryFile,
|
|
5364
5365
|
patch: Partial<MemoryFrontmatter>,
|
|
5365
|
-
lifecycle?: MemoryLifecycleEventWriteOptions
|
|
5366
|
+
lifecycle?: MemoryLifecycleEventWriteOptions,
|
|
5367
|
+
mentionReentry?: boolean
|
|
5366
5368
|
): Promise<boolean> {
|
|
5367
5369
|
const beforeStatus = memory.frontmatter.status ?? "active";
|
|
5368
|
-
// Canonicalize
|
|
5369
|
-
// unrelated patch must not rewrite an inherited legacy ref back out.
|
|
5370
|
-
// #2807: `patch.updated` is business time, persisted VERBATIM.
|
|
5370
|
+
// Canonicalize merged entityRef (#2213). patch.updated is business time (#2807).
|
|
5371
5371
|
const resolveIds = this.currentHistoricalIds();
|
|
5372
5372
|
const updated: MemoryFrontmatter = entityRefs.canonicalizeEntityRefOption(
|
|
5373
5373
|
{ ...memory.frontmatter, ...patch },
|
|
@@ -5375,6 +5375,11 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
5375
5375
|
);
|
|
5376
5376
|
const refIds = typeof updated.entityRef === "string" ? resolveIds : null;
|
|
5377
5377
|
const afterStatus = updated.status ?? "active";
|
|
5378
|
+
if (!mentionReentry && entityMentionEpoch.neutral(memory.frontmatter, updated)) {
|
|
5379
|
+
const held = await holdMentionNeutralFrontmatter(this, memory, updated, () =>
|
|
5380
|
+
entityMentionEpoch.hold(() => StorageManager.frontmatterBody.call(this, memory, patch, lifecycle, true)));
|
|
5381
|
+
if (held !== undefined) return held;
|
|
5382
|
+
}
|
|
5378
5383
|
|
|
5379
5384
|
const fileContent = `${serializeFrontmatter(this.withOkfType(updated))}\n\n${memory.content}\n`;
|
|
5380
5385
|
await this.writeTombstoneBlockedFrontmatter(memory, fileContent, updated, async () => {
|
|
@@ -5390,6 +5395,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
5390
5395
|
onFailRestore: memory,
|
|
5391
5396
|
});
|
|
5392
5397
|
}
|
|
5398
|
+
if (mentionReentry && !entityMentionEpoch.neutral(memory.frontmatter, updated)) entityMentionEpoch.bump(this.baseDir);
|
|
5393
5399
|
await this.patchHotMemoriesCache({ addedPath: memory.path });
|
|
5394
5400
|
if (memory.path.includes(`${path.sep}cold${path.sep}`)) {
|
|
5395
5401
|
this.invalidateColdMemoriesCache();
|
|
@@ -5422,9 +5428,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
5422
5428
|
lifecycle?.ruleVersion
|
|
5423
5429
|
);
|
|
5424
5430
|
if (beforeStatus !== afterStatus) {
|
|
5425
|
-
// Status
|
|
5426
|
-
// entity/derived caches and peer processes observe it (issue #1902:
|
|
5427
|
-
// restored — corpus bump alone doesn't cover status-derived views).
|
|
5431
|
+
// Status change bumps memory-status; a corpus bump does not cover it (#1902).
|
|
5428
5432
|
this.bumpMemoryStatusVersion();
|
|
5429
5433
|
}
|
|
5430
5434
|
return true;
|
|
@@ -6496,11 +6500,9 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
6496
6500
|
const memoryMap = new Map(memories.map((m) => [m.frontmatter.id, m]));
|
|
6497
6501
|
const memoryPathMap = new Map(memories.map((m) => [path.resolve(m.path), m]));
|
|
6498
6502
|
let updated = 0;
|
|
6499
|
-
//
|
|
6500
|
-
// entries in place and then re-key them to the version this flush produces
|
|
6501
|
-
// (issue #1902). Access-tracking flush is batched (consolidation / buffer
|
|
6502
|
-
// full), not per-recall, so the single corpus bump below is cheap.
|
|
6503
|
+
// Corpus version and warmth are snapshotted before the writes (#1902).
|
|
6503
6504
|
const prevVersion = this.getMemoryCorpusVersion();
|
|
6505
|
+
let entityRefMoved = false;
|
|
6504
6506
|
// Snapshot the secure-store key identity once (Cursor Medium #1902), mirroring
|
|
6505
6507
|
// readAllMemories/patchHotMemoriesCache: a mid-flush setSecureStoreKey change
|
|
6506
6508
|
// would otherwise let loop patches or the re-keyed entry be stored under a
|
|
@@ -6540,6 +6542,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
6540
6542
|
{ onFailRestore: current }
|
|
6541
6543
|
);
|
|
6542
6544
|
}
|
|
6545
|
+
if (!entityMentionEpoch.neutral(current.frontmatter, newFm)) entityRefMoved = true;
|
|
6543
6546
|
return { current, newFm };
|
|
6544
6547
|
});
|
|
6545
6548
|
if (applied === null) continue;
|
|
@@ -6557,14 +6560,11 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
6557
6560
|
}
|
|
6558
6561
|
|
|
6559
6562
|
if (updated > 0) {
|
|
6560
|
-
// Advance the corpus sentinel so
|
|
6561
|
-
// this
|
|
6562
|
-
|
|
6563
|
-
|
|
6564
|
-
|
|
6565
|
-
// exclusive and still the current sentinel; otherwise a peer also wrote
|
|
6566
|
-
// and we must let the next read rescan.
|
|
6567
|
-
const { produced, exclusive } = this.bumpMemoryCorpusVersionExclusive();
|
|
6563
|
+
// Advance the corpus sentinel so peers rescan (#1902). Re-key local patches
|
|
6564
|
+
// only when this bump was exclusive; a peer write must rescan instead.
|
|
6565
|
+
const { produced, exclusive } = this.bumpMemoryCorpusVersionExclusive({
|
|
6566
|
+
indexedText: entityRefMoved ? undefined : false,
|
|
6567
|
+
});
|
|
6568
6568
|
// Drop the in-flight read slot after the bump (parity with
|
|
6569
6569
|
// patchHotMemoriesCache, Cursor Medium #1902): a readAllMemories scan that
|
|
6570
6570
|
// started before the flush would otherwise keep awaiting a pre-flush scan
|
|
@@ -6574,6 +6574,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
6574
6574
|
if (
|
|
6575
6575
|
warm &&
|
|
6576
6576
|
exclusive &&
|
|
6577
|
+
!entityRefMoved &&
|
|
6577
6578
|
produced === prevVersion + 1 &&
|
|
6578
6579
|
this.getMemoryCorpusVersion() === produced &&
|
|
6579
6580
|
this.hotCacheKeyId() === keyId
|
|
@@ -7010,6 +7011,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
7010
7011
|
});
|
|
7011
7012
|
if (!written) return false;
|
|
7012
7013
|
exactReplay = written === "exact-replay";
|
|
7014
|
+
const mentionBefore = { entityRef: currentBefore.frontmatter.entityRef, origin: currentBefore.frontmatter.origin };
|
|
7013
7015
|
if (exactReplay && typeof updatedFm.entityRef === "string") {
|
|
7014
7016
|
await this.entityRefRepair.repair(
|
|
7015
7017
|
currentBefore.path,
|
|
@@ -7020,6 +7022,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
7020
7022
|
{ onFailRestore: currentBefore },
|
|
7021
7023
|
);
|
|
7022
7024
|
}
|
|
7025
|
+
const mentionUnchanged = entityMentionEpoch.neutral(mentionBefore, updatedFm);
|
|
7023
7026
|
const supersededAt = updatedFm.supersededAt ?? initialNow;
|
|
7024
7027
|
const beforeState = this.summarizeLifecycleState(
|
|
7025
7028
|
currentBefore.frontmatter,
|
|
@@ -7041,8 +7044,8 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
7041
7044
|
readMemoryByPath: (filePath) => this.readMemoryByPath(filePath),
|
|
7042
7045
|
isColdOrArchiveTierPath: (memoryPath) => this.isColdOrArchiveTierPath(memoryPath),
|
|
7043
7046
|
invalidateColdMemoriesCache: () => this.invalidateColdMemoriesCache(),
|
|
7044
|
-
invalidateAllMemoriesCache: () => this.invalidateAllMemoriesCache(),
|
|
7045
|
-
bumpMemoryCorpusVersion: () => this.bumpMemoryCorpusVersion(),
|
|
7047
|
+
invalidateAllMemoriesCache: () => this.invalidateAllMemoriesCache({ indexedText: mentionUnchanged ? false : undefined }),
|
|
7048
|
+
bumpMemoryCorpusVersion: () => this.bumpMemoryCorpusVersion({ indexedText: mentionUnchanged ? false : undefined }),
|
|
7046
7049
|
appendLifecycleEvent: async () => {
|
|
7047
7050
|
let lifecycleEvents: MemoryLifecycleEvent[] = [];
|
|
7048
7051
|
try {
|
|
@@ -7156,9 +7159,8 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
7156
7159
|
return true;
|
|
7157
7160
|
});
|
|
7158
7161
|
if (!written) continue;
|
|
7159
|
-
//
|
|
7160
|
-
|
|
7161
|
-
this.bumpMemoryCorpusVersion();
|
|
7162
|
+
// Corpus bump before the lifecycle append (#1902). Epoch moves only if repair changed entityRef or origin.
|
|
7163
|
+
this.bumpMemoryCorpusVersion({ indexedText: entityMentionEpoch.neutral(currentBefore.frontmatter, updatedFm) ? false : undefined });
|
|
7162
7164
|
await this.appendGeneratedMemoryLifecycleEventFailOpen("storage.archiveMemories", {
|
|
7163
7165
|
memoryId: id,
|
|
7164
7166
|
eventType: "archived",
|