@remnic/core 10.0.48 → 10.0.50
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 +73 -70
- package/dist/access-audit.js +2 -2
- package/dist/access-authorization-probe.js +74 -71
- package/dist/access-boundary.js +73 -70
- package/dist/access-cli.js +170 -167
- package/dist/access-cli.js.map +1 -1
- package/dist/access-extraction-force-flush.js +73 -70
- package/dist/access-http-briefing.d.ts +2 -0
- package/dist/access-http-briefing.d.ts.map +1 -1
- package/dist/access-http-briefing.js +74 -71
- package/dist/access-http-query.js +75 -72
- package/dist/access-http.d.ts.map +1 -1
- package/dist/access-http.js +96 -93
- package/dist/access-identity-continuity-surface.js +73 -70
- package/dist/access-lcm-surface.js +73 -70
- package/dist/access-mcp.js +85 -82
- package/dist/access-namespace-preflight.js +73 -70
- package/dist/access-observe-write-category.d.ts +1 -1
- package/dist/access-observe-write-category.d.ts.map +1 -1
- package/dist/access-observe-write-category.js +15 -14
- package/dist/access-observe-write-surface.d.ts.map +1 -1
- package/dist/access-observe-write-surface.js +73 -70
- package/dist/access-offline-manifest.js +9 -8
- package/dist/access-operations-batch.js +76 -73
- package/dist/access-operations.js +83 -80
- package/dist/access-recall-concurrency.js +73 -70
- package/dist/access-recall-response.js +73 -70
- package/dist/access-recall-surface.js +73 -70
- package/dist/access-schema.js +11 -10
- package/dist/access-service.d.ts +5 -0
- package/dist/access-service.d.ts.map +1 -1
- package/dist/access-service.js +73 -70
- package/dist/access-surface-catalog.js +75 -72
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/active-recall.js +32 -30
- package/dist/active-recall.js.map +1 -1
- package/dist/adapters/index.js +4 -4
- package/dist/adapters/registry.js +2 -2
- package/dist/{auto-sync-BNCBMU6H.js → auto-sync-UQQ6YJSB.js} +3 -3
- package/dist/briefing-deadline.d.ts +7 -0
- package/dist/briefing-deadline.d.ts.map +1 -0
- package/dist/briefing-deadline.js +13 -0
- package/dist/briefing-window.d.ts +12 -4
- package/dist/briefing-window.d.ts.map +1 -1
- package/dist/briefing-window.js +3 -1
- package/dist/briefing.d.ts +2 -0
- package/dist/briefing.d.ts.map +1 -1
- package/dist/briefing.js +22 -20
- package/dist/buffer.js +6 -6
- package/dist/calibration.js +2 -2
- package/dist/{capsule-crypto-GWVG7LGC.js → capsule-crypto-7FJQINUR.js} +2 -2
- package/dist/{capsule-merge-RNQUP2VL.js → capsule-merge-D4BTIJGK.js} +3 -3
- package/dist/capture-write-lock-scope.d.ts +7 -0
- package/dist/capture-write-lock-scope.d.ts.map +1 -0
- package/dist/capture-write-lock-scope.js +10 -0
- package/dist/causal-behavior.js +2 -2
- package/dist/causal-chain.js +2 -2
- package/dist/causal-consolidation.js +23 -22
- 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-FAKRTS3Y.js → chunk-2AKIVSHP.js} +2 -2
- package/dist/{chunk-EIYJK7OD.js → chunk-2M36PR7R.js} +2 -2
- package/dist/{chunk-OWHERGF2.js → chunk-2NLLXCJG.js} +2 -2
- package/dist/{chunk-6P6MZDBL.js → chunk-3NL4ALUP.js} +2 -2
- package/dist/{chunk-6CC2YCKG.js → chunk-43TUWQNR.js} +3 -3
- package/dist/{chunk-H7BZBSP6.js → chunk-52II7PB6.js} +4 -4
- package/dist/{chunk-2NLCDNGA.js → chunk-564YP3DW.js} +2 -2
- package/dist/{chunk-5KGYR5VN.js → chunk-5DVOBBTV.js} +2 -2
- package/dist/{chunk-RT2GN6KQ.js → chunk-5FUDSK6Z.js} +2 -2
- package/dist/{chunk-B4XSXFKI.js → chunk-5G53JSRO.js} +2 -2
- package/dist/{chunk-BGK3SFCC.js → chunk-5X2H3X4J.js} +2 -2
- package/dist/{chunk-OXSTKCYK.js → chunk-6AEKSOWV.js} +33 -5
- package/dist/chunk-6AEKSOWV.js.map +1 -0
- package/dist/{chunk-4J7BNL7B.js → chunk-6ZQX3R66.js} +2 -2
- package/dist/{chunk-JNLYHJG7.js → chunk-74AY3S7U.js} +4 -4
- package/dist/{chunk-RUAIO5UA.js → chunk-7J6A5MV2.js} +2 -2
- package/dist/{chunk-A45QXZMU.js → chunk-7SAE6T36.js} +2 -2
- package/dist/chunk-7VLBZKNB.js +26 -0
- package/dist/chunk-7VLBZKNB.js.map +1 -0
- package/dist/{chunk-QE2XQM3S.js → chunk-7YVER7ZO.js} +2 -2
- package/dist/{chunk-IJH6METJ.js → chunk-A3UFV4K3.js} +4 -4
- package/dist/{chunk-LWRIGKFM.js → chunk-A5L5KGDI.js} +19 -1
- package/dist/chunk-A5L5KGDI.js.map +1 -0
- package/dist/{chunk-LXN737FX.js → chunk-AAANTXCQ.js} +2 -2
- package/dist/{chunk-I3IPXGFQ.js → chunk-AJJPXUE6.js} +4 -4
- package/dist/{chunk-2DPJFJFH.js → chunk-BNJAVRNJ.js} +11 -11
- package/dist/{chunk-YL564QS2.js → chunk-CCL2OXFO.js} +3 -3
- package/dist/{chunk-CHSRA76M.js → chunk-CRN3EPE2.js} +4 -3
- package/dist/chunk-CRN3EPE2.js.map +1 -0
- package/dist/{chunk-ZX5N5D6M.js → chunk-DAOMWGO2.js} +4 -4
- package/dist/{chunk-YUE7J2HZ.js → chunk-DMKTOCC7.js} +2 -2
- package/dist/chunk-DMKTOCC7.js.map +1 -0
- package/dist/{chunk-FRXS6SC7.js → chunk-EKUI7I2X.js} +20 -4
- package/dist/chunk-EKUI7I2X.js.map +1 -0
- package/dist/{chunk-PKPOO6X5.js → chunk-EKYWZYZJ.js} +25 -17
- package/dist/chunk-EKYWZYZJ.js.map +1 -0
- package/dist/{chunk-23ZMQONL.js → chunk-ERMT5WQM.js} +2 -2
- package/dist/{chunk-VTCNVGM6.js → chunk-EWBXMGXR.js} +2 -2
- package/dist/{chunk-YNDLCWXS.js → chunk-EZ25VE3G.js} +4 -4
- package/dist/{chunk-XTN54NML.js → chunk-G3T6YMBO.js} +4 -4
- package/dist/{chunk-2JNBPOZ2.js → chunk-GDYLZ6FR.js} +3 -3
- package/dist/{chunk-DZPTR2XQ.js → chunk-GFAEKSFR.js} +2 -2
- package/dist/{chunk-L46MG2GE.js → chunk-GQIYL7OD.js} +400 -301
- package/dist/chunk-GQIYL7OD.js.map +1 -0
- package/dist/{chunk-M7LA4QBY.js → chunk-GXVXBYRA.js} +3 -3
- package/dist/{chunk-UXAF4RQM.js → chunk-HKOMHP6D.js} +27 -15
- package/dist/chunk-HKOMHP6D.js.map +1 -0
- package/dist/{chunk-JGMJZBFV.js → chunk-HPNXS6W6.js} +2 -2
- package/dist/{chunk-BFPF5N3H.js → chunk-HXFIILGF.js} +4 -4
- package/dist/{chunk-YBKQAVPZ.js → chunk-IMKOJVD4.js} +101 -81
- package/dist/chunk-IMKOJVD4.js.map +1 -0
- package/dist/{chunk-CMNL3QSL.js → chunk-IN6U2BS5.js} +2 -2
- package/dist/{chunk-BWRX322G.js → chunk-IUYXCTA7.js} +2 -2
- package/dist/{chunk-LU57EEJW.js → chunk-JBWD3J5U.js} +3 -3
- package/dist/chunk-JNA7LFMQ.js +41 -0
- package/dist/chunk-JNA7LFMQ.js.map +1 -0
- package/dist/{chunk-2V664H6O.js → chunk-JS44PBCM.js} +5 -5
- package/dist/{chunk-XKTHJHSQ.js → chunk-JZCBMKR5.js} +3 -3
- package/dist/{chunk-MXPVNDGO.js → chunk-K5QQXVG6.js} +12 -12
- package/dist/{chunk-BUKK5SWA.js → chunk-KQAFEZQX.js} +2 -2
- package/dist/{chunk-WUBGMV3G.js → chunk-KRAMCBIW.js} +9 -9
- package/dist/{chunk-NDMPRT3Z.js → chunk-KW5YZELC.js} +2 -2
- package/dist/{chunk-2RQR4TXV.js → chunk-LIBVANOF.js} +2 -2
- package/dist/{chunk-M7L5A2AT.js → chunk-LMMBV7QC.js} +4 -4
- package/dist/{chunk-PJBYVJKO.js → chunk-LXXIV7Y2.js} +2 -2
- package/dist/{chunk-MZCTS3ZG.js → chunk-M2DOJBH7.js} +2 -2
- package/dist/{chunk-WOPZ2P5Z.js → chunk-M4HRYLOA.js} +2 -2
- package/dist/{chunk-JCYEDMOY.js → chunk-M6TP6UYD.js} +3 -3
- package/dist/{chunk-KAUCVTAW.js → chunk-MLNXATFG.js} +2 -2
- package/dist/{chunk-2NX7JTST.js → chunk-MPWOAIIH.js} +2 -2
- package/dist/{chunk-RQLTCHUL.js → chunk-MWURUSRE.js} +13 -13
- package/dist/{chunk-3EGL7XZO.js → chunk-N74WJ7B2.js} +2 -2
- package/dist/{chunk-DRXTMDAG.js → chunk-N7FNCE7F.js} +2 -2
- package/dist/{chunk-6CWAY4R7.js → chunk-NPLM7AFU.js} +2 -2
- package/dist/{chunk-VECRSYQG.js → chunk-NRGQ5HJO.js} +1 -1
- package/dist/{chunk-PPDNG7WC.js → chunk-NSP5PIQH.js} +2 -2
- package/dist/{chunk-6HVLHIAB.js → chunk-P7OVFGMU.js} +2 -2
- package/dist/{chunk-EX27VKU6.js → chunk-PDTNQLPC.js} +2 -2
- package/dist/{chunk-ME5LVISI.js → chunk-PJCVI44H.js} +2 -2
- package/dist/{chunk-LJCHDFLP.js → chunk-Q3PNQYAC.js} +2 -2
- package/dist/{chunk-YFJHFEET.js → chunk-QS765SBL.js} +2 -2
- package/dist/{chunk-FJ264QBP.js → chunk-QTDZ2NYC.js} +11 -11
- package/dist/{chunk-Q6UZREJK.js → chunk-RKRX4C4H.js} +2 -2
- package/dist/{chunk-YFXRLRKP.js → chunk-S4OZKPBS.js} +7 -11
- package/dist/{chunk-YFXRLRKP.js.map → chunk-S4OZKPBS.js.map} +1 -1
- package/dist/{chunk-GLZWOIU3.js → chunk-SJTSWG2Z.js} +3 -3
- package/dist/{chunk-Y57GJDG5.js → chunk-SWRRZNHM.js} +14 -17
- package/dist/chunk-SWRRZNHM.js.map +1 -0
- package/dist/{chunk-CCTLRRV6.js → chunk-TEH5MDX5.js} +55 -34
- package/dist/chunk-TEH5MDX5.js.map +1 -0
- package/dist/{chunk-XM747YJF.js → chunk-TFWJXWL6.js} +2 -2
- package/dist/{chunk-QFQ4UG3I.js → chunk-TXKQBQYW.js} +4 -4
- package/dist/{chunk-BMOJFGVX.js → chunk-UALXWWGN.js} +2 -2
- package/dist/{chunk-B44NFHWI.js → chunk-UNOAVHV4.js} +2 -2
- package/dist/{chunk-TF5NZGPS.js → chunk-UQBOPCDK.js} +2 -2
- package/dist/{chunk-SUKPM6DV.js → chunk-UWMZT2TY.js} +47 -4
- package/dist/chunk-UWMZT2TY.js.map +1 -0
- package/dist/{chunk-5R2IF2KI.js → chunk-UXGXJUZ5.js} +7 -7
- package/dist/{chunk-FWV2SXSL.js → chunk-UZVQFGAY.js} +101 -98
- package/dist/chunk-UZVQFGAY.js.map +1 -0
- package/dist/{chunk-J6B6FK2X.js → chunk-VCOMACR6.js} +53 -53
- package/dist/{chunk-WCGJK4NQ.js → chunk-VKQI47DJ.js} +7 -7
- package/dist/{chunk-MPJDQC4G.js → chunk-WJCXUE2J.js} +2 -2
- package/dist/{chunk-BCDECPVO.js → chunk-WV4UYDP6.js} +2 -2
- package/dist/{chunk-VWJ56T63.js → chunk-WXJC2L66.js} +2 -2
- package/dist/chunk-X2KO4FK5.js +40 -0
- package/dist/chunk-X2KO4FK5.js.map +1 -0
- package/dist/{chunk-UVYI6VIX.js → chunk-X7Y7WX73.js} +1 -1
- package/dist/{chunk-FPANDKMQ.js → chunk-XC3H7KON.js} +2 -2
- package/dist/{chunk-OOOX5C4X.js → chunk-XL2EE5W3.js} +4 -4
- package/dist/{chunk-3DKKZVXS.js → chunk-XTXWR6KQ.js} +26 -11
- package/dist/chunk-XTXWR6KQ.js.map +1 -0
- package/dist/{chunk-3SL52JKD.js → chunk-XVZA6VXC.js} +4 -4
- package/dist/{chunk-CZVNOTLR.js → chunk-XXR4A33N.js} +2 -2
- package/dist/{chunk-2AV2U2SZ.js → chunk-YDIOMDBW.js} +2 -2
- package/dist/{chunk-XTVH2NAW.js → chunk-YECEEJUU.js} +3 -3
- package/dist/{chunk-QR6W3FSW.js → chunk-Z5277JWF.js} +3 -3
- package/dist/{chunk-CTHYR4QK.js → chunk-ZFNXJEUG.js} +2 -2
- package/dist/{chunk-6Q56WDHG.js → chunk-ZLCBLDJO.js} +2 -2
- package/dist/{chunk-VY6BD5KB.js → chunk-ZMO2S5RT.js} +12 -10
- package/dist/chunk-ZMO2S5RT.js.map +1 -0
- package/dist/{chunk-KRACAE73.js → chunk-ZNRTHYYW.js} +6 -6
- package/dist/{chunk-7AIPWNM7.js → chunk-ZSMA67FV.js} +2 -2
- package/dist/cli.js +123 -120
- package/dist/coding/export-okf-codegraph.js +19 -18
- package/dist/coding/export-okf-codegraph.js.map +1 -1
- package/dist/coding/pre-action-gate.js +2 -2
- package/dist/compounding/engine.js +21 -20
- package/dist/config.js +32 -30
- package/dist/connectors/codex-materialize-runner.js +20 -19
- package/dist/connectors/index.js +20 -19
- package/dist/consolidation-provenance-check.js +4 -4
- package/dist/consolidation-undo.js +2 -2
- package/dist/convergence-refresh.js +22 -21
- package/dist/corpus-watermark.js +22 -21
- package/dist/correction/passive-correction-notifications.d.ts +1 -1
- package/dist/correction/passive-correction-notifications.d.ts.map +1 -1
- package/dist/dashboard-runtime.js +2 -2
- package/dist/deep-recall-http-glue.js +12 -11
- package/dist/deep-recall.js +2 -2
- package/dist/embedding-fallback.js +3 -2
- package/dist/embedding-generation-marker.d.ts +16 -0
- package/dist/embedding-generation-marker.d.ts.map +1 -0
- package/dist/embedding-generation-marker.js +19 -0
- package/dist/embedding-generation-marker.js.map +1 -0
- package/dist/embedding-index-storage.d.ts +2 -4
- package/dist/embedding-index-storage.d.ts.map +1 -1
- package/dist/embedding-index-storage.js +2 -1
- package/dist/{entity-canonical-id-migration-2YOLMOFC.js → entity-canonical-id-migration-ZBNRGUNV.js} +3 -3
- package/dist/entity-canonical-id-migration-ZBNRGUNV.js.map +1 -0
- package/dist/entity-retrieval.js +22 -21
- package/dist/event-order-recall.js +2 -2
- package/dist/explicit-capture.js +3 -3
- package/dist/external-wiki-access.js +74 -71
- package/dist/extraction-span-materialize.js +2 -2
- package/dist/extraction.js +30 -29
- package/dist/{graph-edge-decay-3HVLMT6U.js → graph-edge-decay-IU75NV42.js} +6 -6
- package/dist/graph-edge-decay-IU75NV42.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 +20 -19
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +230 -218
- package/dist/lcm/engine.js +3 -3
- package/dist/lcm/index.js +5 -5
- package/dist/local-llm.js +2 -2
- package/dist/location/index.js +25 -24
- package/dist/location/tagging.d.ts +7 -5
- package/dist/location/tagging.d.ts.map +1 -1
- package/dist/maintenance/memory-governance.js +20 -19
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +20 -19
- package/dist/maintenance/rebuild-memory-projection-runner.js +22 -21
- package/dist/maintenance/rebuild-memory-projection.js +21 -20
- package/dist/memory-browse-operations.js +74 -71
- package/dist/memory-browse.js +5 -5
- package/dist/namespaces/migrate.js +21 -20
- package/dist/namespaces/search.js +6 -6
- package/dist/namespaces/storage.js +20 -19
- package/dist/offline-sync-changeset-generations.js +5 -4
- package/dist/offline-sync-embedding-generation.d.ts +12 -2
- package/dist/offline-sync-embedding-generation.d.ts.map +1 -1
- package/dist/offline-sync-embedding-generation.js +6 -3
- package/dist/offline-sync-file-io.d.ts +15 -0
- package/dist/offline-sync-file-io.d.ts.map +1 -1
- package/dist/offline-sync-file-io.js +9 -1
- package/dist/offline-sync-snapshot-stream.js +9 -8
- package/dist/offline-sync-upload-staging.js +2 -2
- package/dist/offline-sync.d.ts.map +1 -1
- package/dist/offline-sync.js +10 -9
- package/dist/operator-doctor-corpus.js +23 -22
- package/dist/operator-toolkit.js +45 -43
- package/dist/orchestration/maintenance.js +33 -32
- package/dist/orchestrator.d.ts +1 -0
- package/dist/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator.js +170 -167
- package/dist/page-versioning.js +2 -2
- package/dist/qmd.js +2 -2
- package/dist/recall-navigation-operations.js +74 -71
- package/dist/recall-navigation.js +73 -70
- package/dist/recall-state-view-admission.js +5 -5
- package/dist/recall-why-service.js +5 -5
- package/dist/resume-bundles.js +33 -31
- package/dist/search/factory.js +5 -5
- package/dist/search/index.js +9 -9
- package/dist/semantic-consolidation.js +25 -24
- package/dist/semantic-rule-promotion.js +20 -19
- package/dist/semantic-rule-verifier.js +20 -19
- package/dist/source-agent-qualifier.js +24 -23
- package/dist/standup/build.js +20 -19
- package/dist/storage/entity-canonical-id-migration-adapter.d.ts +1 -0
- package/dist/storage/entity-canonical-id-migration-adapter.d.ts.map +1 -1
- package/dist/storage/entity-canonical-id-migration.d.ts +7 -0
- package/dist/storage/entity-canonical-id-migration.d.ts.map +1 -1
- package/dist/storage/entity-canonical-id-references.d.ts +2 -0
- package/dist/storage/entity-canonical-id-references.d.ts.map +1 -1
- package/dist/storage/entity-migration-completion-cache.d.ts +46 -0
- package/dist/storage/entity-migration-completion-cache.d.ts.map +1 -0
- package/dist/storage/entity-store.d.ts +1 -8
- package/dist/storage/entity-store.d.ts.map +1 -1
- package/dist/storage/memory-read-store.d.ts +3 -2
- package/dist/storage/memory-read-store.d.ts.map +1 -1
- package/dist/storage/windowed-memory-read.d.ts +6 -0
- package/dist/storage/windowed-memory-read.d.ts.map +1 -1
- package/dist/storage.d.ts +2 -0
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +19 -18
- package/dist/summarizer.js +3 -3
- package/dist/support-passport/index.js +76 -73
- package/dist/transfer/backup.js +2 -2
- package/dist/transfer/capsule-export.js +2 -2
- package/dist/transfer/capsule-import.js +4 -4
- package/dist/transfer/export-okf.js +20 -19
- package/dist/verified-recall.js +20 -19
- package/dist/who-knows-cli.js +21 -20
- package/dist/who-knows.js +20 -19
- package/package.json +2 -2
- package/src/access-http-briefing.ts +4 -0
- package/src/access-http.test.ts +40 -11
- package/src/access-http.ts +6 -0
- package/src/access-observe-write-category.ts +1 -1
- package/src/access-observe-write-surface.ts +24 -19
- package/src/access-operations-batch.ts +18 -2
- package/src/access-service-peer-capture-backoff.test.ts +236 -0
- package/src/access-service.ts +11 -2
- package/src/briefing-abort.test.ts +173 -0
- package/src/briefing-deadline.test.ts +84 -0
- package/src/briefing-deadline.ts +33 -0
- package/src/briefing-window-abort.test.ts +47 -0
- package/src/briefing-window.ts +33 -4
- package/src/briefing.ts +23 -16
- package/src/capture-write-lock-scope.test.ts +32 -0
- package/src/capture-write-lock-scope.ts +30 -0
- package/src/correction/passive-correction-notifications-abort.test.ts +42 -0
- package/src/correction/passive-correction-notifications.ts +4 -0
- package/src/embedding-generation-marker.ts +51 -0
- package/src/embedding-index-storage.ts +13 -29
- package/src/entity-lazy-compatibility.test.ts +229 -0
- package/src/entity-migration-completion-notification.test.ts +148 -0
- package/src/index.ts +2 -2
- package/src/location/tagging.ts +14 -12
- package/src/offline-sync-embedding-delete-digest.test.ts +58 -0
- package/src/offline-sync-embedding-generation-marker.test.ts +245 -0
- package/src/offline-sync-embedding-generation.ts +47 -2
- package/src/offline-sync-embedding-lock-loss.test.ts +42 -0
- package/src/offline-sync-file-io.ts +61 -2
- package/src/offline-sync.test.ts +313 -20
- package/src/offline-sync.ts +47 -22
- package/src/orchestrator-init.test.ts +49 -1
- package/src/orchestrator.ts +9 -8
- package/src/storage/entity-canonical-id-migration-adapter.ts +16 -1
- package/src/storage/entity-canonical-id-migration.ts +17 -8
- package/src/storage/entity-canonical-id-references.ts +24 -0
- package/src/storage/entity-migration-completion-cache.nofollow.test.ts +223 -0
- package/src/storage/entity-migration-completion-cache.ts +153 -0
- package/src/storage/entity-store.ts +58 -86
- package/src/storage/memory-read-store.ts +9 -3
- package/src/storage/windowed-memory-read.ts +8 -0
- package/src/storage-startup-nonblocking-migration.test.ts +183 -0
- package/src/storage.ts +9 -3
- package/src/testing/subjects/entity-migration-completion-cache.test.ts +90 -0
- package/dist/chunk-3DKKZVXS.js.map +0 -1
- package/dist/chunk-CCTLRRV6.js.map +0 -1
- package/dist/chunk-CHSRA76M.js.map +0 -1
- package/dist/chunk-FRXS6SC7.js.map +0 -1
- package/dist/chunk-FWV2SXSL.js.map +0 -1
- package/dist/chunk-L46MG2GE.js.map +0 -1
- package/dist/chunk-LWRIGKFM.js.map +0 -1
- package/dist/chunk-OXSTKCYK.js.map +0 -1
- package/dist/chunk-PKPOO6X5.js.map +0 -1
- package/dist/chunk-SUKPM6DV.js.map +0 -1
- package/dist/chunk-UXAF4RQM.js.map +0 -1
- package/dist/chunk-VY6BD5KB.js.map +0 -1
- package/dist/chunk-Y57GJDG5.js.map +0 -1
- package/dist/chunk-YBKQAVPZ.js.map +0 -1
- package/dist/chunk-YUE7J2HZ.js.map +0 -1
- /package/dist/{auto-sync-BNCBMU6H.js.map → auto-sync-UQQ6YJSB.js.map} +0 -0
- /package/dist/{capsule-crypto-GWVG7LGC.js.map → briefing-deadline.js.map} +0 -0
- /package/dist/{entity-canonical-id-migration-2YOLMOFC.js.map → capsule-crypto-7FJQINUR.js.map} +0 -0
- /package/dist/{capsule-merge-RNQUP2VL.js.map → capsule-merge-D4BTIJGK.js.map} +0 -0
- /package/dist/{graph-edge-decay-3HVLMT6U.js.map → capture-write-lock-scope.js.map} +0 -0
- /package/dist/{chunk-FAKRTS3Y.js.map → chunk-2AKIVSHP.js.map} +0 -0
- /package/dist/{chunk-EIYJK7OD.js.map → chunk-2M36PR7R.js.map} +0 -0
- /package/dist/{chunk-OWHERGF2.js.map → chunk-2NLLXCJG.js.map} +0 -0
- /package/dist/{chunk-6P6MZDBL.js.map → chunk-3NL4ALUP.js.map} +0 -0
- /package/dist/{chunk-6CC2YCKG.js.map → chunk-43TUWQNR.js.map} +0 -0
- /package/dist/{chunk-H7BZBSP6.js.map → chunk-52II7PB6.js.map} +0 -0
- /package/dist/{chunk-2NLCDNGA.js.map → chunk-564YP3DW.js.map} +0 -0
- /package/dist/{chunk-5KGYR5VN.js.map → chunk-5DVOBBTV.js.map} +0 -0
- /package/dist/{chunk-RT2GN6KQ.js.map → chunk-5FUDSK6Z.js.map} +0 -0
- /package/dist/{chunk-B4XSXFKI.js.map → chunk-5G53JSRO.js.map} +0 -0
- /package/dist/{chunk-BGK3SFCC.js.map → chunk-5X2H3X4J.js.map} +0 -0
- /package/dist/{chunk-4J7BNL7B.js.map → chunk-6ZQX3R66.js.map} +0 -0
- /package/dist/{chunk-JNLYHJG7.js.map → chunk-74AY3S7U.js.map} +0 -0
- /package/dist/{chunk-RUAIO5UA.js.map → chunk-7J6A5MV2.js.map} +0 -0
- /package/dist/{chunk-A45QXZMU.js.map → chunk-7SAE6T36.js.map} +0 -0
- /package/dist/{chunk-QE2XQM3S.js.map → chunk-7YVER7ZO.js.map} +0 -0
- /package/dist/{chunk-IJH6METJ.js.map → chunk-A3UFV4K3.js.map} +0 -0
- /package/dist/{chunk-LXN737FX.js.map → chunk-AAANTXCQ.js.map} +0 -0
- /package/dist/{chunk-I3IPXGFQ.js.map → chunk-AJJPXUE6.js.map} +0 -0
- /package/dist/{chunk-2DPJFJFH.js.map → chunk-BNJAVRNJ.js.map} +0 -0
- /package/dist/{chunk-YL564QS2.js.map → chunk-CCL2OXFO.js.map} +0 -0
- /package/dist/{chunk-ZX5N5D6M.js.map → chunk-DAOMWGO2.js.map} +0 -0
- /package/dist/{chunk-23ZMQONL.js.map → chunk-ERMT5WQM.js.map} +0 -0
- /package/dist/{chunk-VTCNVGM6.js.map → chunk-EWBXMGXR.js.map} +0 -0
- /package/dist/{chunk-YNDLCWXS.js.map → chunk-EZ25VE3G.js.map} +0 -0
- /package/dist/{chunk-XTN54NML.js.map → chunk-G3T6YMBO.js.map} +0 -0
- /package/dist/{chunk-2JNBPOZ2.js.map → chunk-GDYLZ6FR.js.map} +0 -0
- /package/dist/{chunk-DZPTR2XQ.js.map → chunk-GFAEKSFR.js.map} +0 -0
- /package/dist/{chunk-M7LA4QBY.js.map → chunk-GXVXBYRA.js.map} +0 -0
- /package/dist/{chunk-JGMJZBFV.js.map → chunk-HPNXS6W6.js.map} +0 -0
- /package/dist/{chunk-BFPF5N3H.js.map → chunk-HXFIILGF.js.map} +0 -0
- /package/dist/{chunk-CMNL3QSL.js.map → chunk-IN6U2BS5.js.map} +0 -0
- /package/dist/{chunk-BWRX322G.js.map → chunk-IUYXCTA7.js.map} +0 -0
- /package/dist/{chunk-LU57EEJW.js.map → chunk-JBWD3J5U.js.map} +0 -0
- /package/dist/{chunk-2V664H6O.js.map → chunk-JS44PBCM.js.map} +0 -0
- /package/dist/{chunk-XKTHJHSQ.js.map → chunk-JZCBMKR5.js.map} +0 -0
- /package/dist/{chunk-MXPVNDGO.js.map → chunk-K5QQXVG6.js.map} +0 -0
- /package/dist/{chunk-BUKK5SWA.js.map → chunk-KQAFEZQX.js.map} +0 -0
- /package/dist/{chunk-WUBGMV3G.js.map → chunk-KRAMCBIW.js.map} +0 -0
- /package/dist/{chunk-NDMPRT3Z.js.map → chunk-KW5YZELC.js.map} +0 -0
- /package/dist/{chunk-2RQR4TXV.js.map → chunk-LIBVANOF.js.map} +0 -0
- /package/dist/{chunk-M7L5A2AT.js.map → chunk-LMMBV7QC.js.map} +0 -0
- /package/dist/{chunk-PJBYVJKO.js.map → chunk-LXXIV7Y2.js.map} +0 -0
- /package/dist/{chunk-MZCTS3ZG.js.map → chunk-M2DOJBH7.js.map} +0 -0
- /package/dist/{chunk-WOPZ2P5Z.js.map → chunk-M4HRYLOA.js.map} +0 -0
- /package/dist/{chunk-JCYEDMOY.js.map → chunk-M6TP6UYD.js.map} +0 -0
- /package/dist/{chunk-KAUCVTAW.js.map → chunk-MLNXATFG.js.map} +0 -0
- /package/dist/{chunk-2NX7JTST.js.map → chunk-MPWOAIIH.js.map} +0 -0
- /package/dist/{chunk-RQLTCHUL.js.map → chunk-MWURUSRE.js.map} +0 -0
- /package/dist/{chunk-3EGL7XZO.js.map → chunk-N74WJ7B2.js.map} +0 -0
- /package/dist/{chunk-DRXTMDAG.js.map → chunk-N7FNCE7F.js.map} +0 -0
- /package/dist/{chunk-6CWAY4R7.js.map → chunk-NPLM7AFU.js.map} +0 -0
- /package/dist/{chunk-VECRSYQG.js.map → chunk-NRGQ5HJO.js.map} +0 -0
- /package/dist/{chunk-PPDNG7WC.js.map → chunk-NSP5PIQH.js.map} +0 -0
- /package/dist/{chunk-6HVLHIAB.js.map → chunk-P7OVFGMU.js.map} +0 -0
- /package/dist/{chunk-EX27VKU6.js.map → chunk-PDTNQLPC.js.map} +0 -0
- /package/dist/{chunk-ME5LVISI.js.map → chunk-PJCVI44H.js.map} +0 -0
- /package/dist/{chunk-LJCHDFLP.js.map → chunk-Q3PNQYAC.js.map} +0 -0
- /package/dist/{chunk-YFJHFEET.js.map → chunk-QS765SBL.js.map} +0 -0
- /package/dist/{chunk-FJ264QBP.js.map → chunk-QTDZ2NYC.js.map} +0 -0
- /package/dist/{chunk-Q6UZREJK.js.map → chunk-RKRX4C4H.js.map} +0 -0
- /package/dist/{chunk-GLZWOIU3.js.map → chunk-SJTSWG2Z.js.map} +0 -0
- /package/dist/{chunk-XM747YJF.js.map → chunk-TFWJXWL6.js.map} +0 -0
- /package/dist/{chunk-QFQ4UG3I.js.map → chunk-TXKQBQYW.js.map} +0 -0
- /package/dist/{chunk-BMOJFGVX.js.map → chunk-UALXWWGN.js.map} +0 -0
- /package/dist/{chunk-B44NFHWI.js.map → chunk-UNOAVHV4.js.map} +0 -0
- /package/dist/{chunk-TF5NZGPS.js.map → chunk-UQBOPCDK.js.map} +0 -0
- /package/dist/{chunk-5R2IF2KI.js.map → chunk-UXGXJUZ5.js.map} +0 -0
- /package/dist/{chunk-J6B6FK2X.js.map → chunk-VCOMACR6.js.map} +0 -0
- /package/dist/{chunk-WCGJK4NQ.js.map → chunk-VKQI47DJ.js.map} +0 -0
- /package/dist/{chunk-MPJDQC4G.js.map → chunk-WJCXUE2J.js.map} +0 -0
- /package/dist/{chunk-BCDECPVO.js.map → chunk-WV4UYDP6.js.map} +0 -0
- /package/dist/{chunk-VWJ56T63.js.map → chunk-WXJC2L66.js.map} +0 -0
- /package/dist/{chunk-UVYI6VIX.js.map → chunk-X7Y7WX73.js.map} +0 -0
- /package/dist/{chunk-FPANDKMQ.js.map → chunk-XC3H7KON.js.map} +0 -0
- /package/dist/{chunk-OOOX5C4X.js.map → chunk-XL2EE5W3.js.map} +0 -0
- /package/dist/{chunk-3SL52JKD.js.map → chunk-XVZA6VXC.js.map} +0 -0
- /package/dist/{chunk-CZVNOTLR.js.map → chunk-XXR4A33N.js.map} +0 -0
- /package/dist/{chunk-2AV2U2SZ.js.map → chunk-YDIOMDBW.js.map} +0 -0
- /package/dist/{chunk-XTVH2NAW.js.map → chunk-YECEEJUU.js.map} +0 -0
- /package/dist/{chunk-QR6W3FSW.js.map → chunk-Z5277JWF.js.map} +0 -0
- /package/dist/{chunk-CTHYR4QK.js.map → chunk-ZFNXJEUG.js.map} +0 -0
- /package/dist/{chunk-6Q56WDHG.js.map → chunk-ZLCBLDJO.js.map} +0 -0
- /package/dist/{chunk-KRACAE73.js.map → chunk-ZNRTHYYW.js.map} +0 -0
- /package/dist/{chunk-7AIPWNM7.js.map → chunk-ZSMA67FV.js.map} +0 -0
package/src/offline-sync.test.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
|
-
import { chmod, mkdir, mkdtemp, readdir, readFile, rm, stat, utimes, writeFile } from "node:fs/promises";
|
|
3
|
+
import { chmod, mkdir, mkdtemp, readdir, readFile, rm, stat, symlink, utimes, writeFile } from "node:fs/promises";
|
|
4
4
|
import os from "node:os";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import test from "node:test";
|
|
@@ -3714,33 +3714,37 @@ test("applyOfflineSyncSnapshot consumes readIncomingFile for records without inl
|
|
|
3714
3714
|
}
|
|
3715
3715
|
});
|
|
3716
3716
|
|
|
3717
|
-
test("buildOfflineSyncSnapshot
|
|
3717
|
+
test("buildOfflineSyncSnapshot fails closed when a file vanishes during digest", async () => {
|
|
3718
3718
|
const root = await tempDir("remnic-offline-vanish");
|
|
3719
3719
|
try {
|
|
3720
3720
|
await write(root, "facts/keep.md", "keep");
|
|
3721
3721
|
await write(root, "facts/gone.md", "gone");
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3722
|
+
await assert.rejects(
|
|
3723
|
+
() => buildOfflineSyncSnapshot({
|
|
3724
|
+
root,
|
|
3725
|
+
sourceId: "local",
|
|
3726
|
+
includeContent: false,
|
|
3727
|
+
readFileDigest: async ({ path: relPath, filePath }) => {
|
|
3728
|
+
if (relPath.endsWith("gone.md")) {
|
|
3729
|
+
await rm(filePath);
|
|
3730
|
+
throw Object.assign(new Error("ENOENT: vanished"), { code: "ENOENT" });
|
|
3731
|
+
}
|
|
3732
|
+
const content = await readFile(filePath);
|
|
3733
|
+
return {
|
|
3734
|
+
sha256: createHash("sha256").update(content).digest("hex"),
|
|
3735
|
+
bytes: content.length,
|
|
3736
|
+
};
|
|
3737
|
+
},
|
|
3738
|
+
}),
|
|
3739
|
+
/census race|vanished during digest|retry the snapshot/i,
|
|
3740
|
+
);
|
|
3741
|
+
assert.equal(await readUtf8(root, "facts/keep.md"), "keep");
|
|
3739
3742
|
} finally {
|
|
3740
3743
|
await rm(root, { recursive: true, force: true });
|
|
3741
3744
|
}
|
|
3742
3745
|
});
|
|
3743
3746
|
|
|
3747
|
+
|
|
3744
3748
|
test("base snapshot fails when a base-known file vanishes before the fast-base stat", async () => {
|
|
3745
3749
|
const root = await tempDir("remnic-offline-base-vanish");
|
|
3746
3750
|
try {
|
|
@@ -3770,7 +3774,7 @@ test("base snapshot fails when a base-known file vanishes before the fast-base s
|
|
|
3770
3774
|
}
|
|
3771
3775
|
});
|
|
3772
3776
|
|
|
3773
|
-
test("base snapshot omits a brand-new file that vanishes
|
|
3777
|
+
test("base snapshot omits a brand-new file that vanishes before the fast-base stat", async () => {
|
|
3774
3778
|
const root = await tempDir("remnic-offline-new-vanish");
|
|
3775
3779
|
try {
|
|
3776
3780
|
await write(root, "facts/keep.md", "keep");
|
|
@@ -3798,6 +3802,7 @@ test("base snapshot omits a brand-new file that vanishes during the walk", async
|
|
|
3798
3802
|
}
|
|
3799
3803
|
});
|
|
3800
3804
|
|
|
3805
|
+
|
|
3801
3806
|
test("snapshot fails when an embedding generation member vanishes during the walk", async () => {
|
|
3802
3807
|
const root = await tempDir("remnic-offline-shard-vanish");
|
|
3803
3808
|
try {
|
|
@@ -3822,3 +3827,291 @@ test("snapshot fails when an embedding generation member vanishes during the wal
|
|
|
3822
3827
|
await rm(root, { recursive: true, force: true });
|
|
3823
3828
|
}
|
|
3824
3829
|
});
|
|
3830
|
+
|
|
3831
|
+
test("a transient snapshot omission must not emit a delete for a shared-base file", async () => {
|
|
3832
|
+
const root = await tempDir("remnic-offline-uncertain-delete");
|
|
3833
|
+
try {
|
|
3834
|
+
await write(root, "facts/keep.md", "keep");
|
|
3835
|
+
await write(root, "facts/race.md", "race-v1");
|
|
3836
|
+
const base = await buildOfflineSyncSnapshot({
|
|
3837
|
+
root,
|
|
3838
|
+
sourceId: "local",
|
|
3839
|
+
includeContent: false,
|
|
3840
|
+
});
|
|
3841
|
+
// Live census fail-closes on digest ENOENT. A stale/incomplete currentFiles
|
|
3842
|
+
// list is still possible from an older client cache — that path must not
|
|
3843
|
+
// emit a confirmed delete when the file is back on disk.
|
|
3844
|
+
const incompleteFiles = base.files.filter((file) => file.path !== "facts/race.md");
|
|
3845
|
+
assert.deepEqual(
|
|
3846
|
+
incompleteFiles.map((file) => file.path),
|
|
3847
|
+
["facts/keep.md"],
|
|
3848
|
+
"fixture: the race path is absent from the incomplete currentFiles view",
|
|
3849
|
+
);
|
|
3850
|
+
await write(root, "facts/race.md", "race-v1");
|
|
3851
|
+
const changeset = await buildOfflineSyncChangesetFromSnapshot({
|
|
3852
|
+
root,
|
|
3853
|
+
sourceId: "local",
|
|
3854
|
+
currentFiles: incompleteFiles,
|
|
3855
|
+
baseFiles: base.files,
|
|
3856
|
+
});
|
|
3857
|
+
assert.equal(
|
|
3858
|
+
changeset.changes.filter((change) => change.path === "facts/race.md" && change.type === "delete").length,
|
|
3859
|
+
0,
|
|
3860
|
+
"an unreadable/recreated path must not become a confirmed delete against the shared base",
|
|
3861
|
+
);
|
|
3862
|
+
} finally {
|
|
3863
|
+
await rm(root, { recursive: true, force: true });
|
|
3864
|
+
}
|
|
3865
|
+
});
|
|
3866
|
+
|
|
3867
|
+
test("apply must not overwrite a recreated local file omitted from the local census", async () => {
|
|
3868
|
+
const root = await tempDir("remnic-offline-uncertain-overwrite");
|
|
3869
|
+
try {
|
|
3870
|
+
const recreated = "recreated local bytes";
|
|
3871
|
+
const incoming = "incoming remote bytes";
|
|
3872
|
+
await write(root, "facts/race.md", recreated);
|
|
3873
|
+
const incomingSha = createHash("sha256").update(incoming).digest("hex");
|
|
3874
|
+
// Local census omitted the recreated path (stale/racy currentFiles).
|
|
3875
|
+
// Incoming is base-less, so the apply path would treat it as a pure create.
|
|
3876
|
+
const result = await applyOfflineSyncSnapshot({
|
|
3877
|
+
root,
|
|
3878
|
+
currentFiles: [],
|
|
3879
|
+
baseFiles: [],
|
|
3880
|
+
snapshot: {
|
|
3881
|
+
format: OFFLINE_SYNC_SNAPSHOT_FORMAT,
|
|
3882
|
+
schemaVersion: 1,
|
|
3883
|
+
createdAt: new Date().toISOString(),
|
|
3884
|
+
sourceId: "remote",
|
|
3885
|
+
includeTranscripts: false,
|
|
3886
|
+
files: [{
|
|
3887
|
+
path: "facts/race.md",
|
|
3888
|
+
sha256: incomingSha,
|
|
3889
|
+
bytes: Buffer.byteLength(incoming),
|
|
3890
|
+
mtimeMs: 2,
|
|
3891
|
+
contentBase64: Buffer.from(incoming).toString("base64"),
|
|
3892
|
+
}],
|
|
3893
|
+
},
|
|
3894
|
+
});
|
|
3895
|
+
assert.equal(
|
|
3896
|
+
await readUtf8(root, "facts/race.md"),
|
|
3897
|
+
recreated,
|
|
3898
|
+
"recreated local content must survive when the local census omitted it",
|
|
3899
|
+
);
|
|
3900
|
+
assert.equal(result.upserted, 0, "must not publish over an uncertain local path");
|
|
3901
|
+
} finally {
|
|
3902
|
+
await rm(root, { recursive: true, force: true });
|
|
3903
|
+
}
|
|
3904
|
+
});
|
|
3905
|
+
|
|
3906
|
+
test("changeset apply must not overwrite a recreated local file omitted by controlled digest census", async () => {
|
|
3907
|
+
// Public applyOfflineSyncChangeset builds local currentFiles via
|
|
3908
|
+
// buildOfflineSyncSnapshotForPaths when currentFiles is omitted. A controlled
|
|
3909
|
+
// digest that recreates local bytes then throws ENOENT must fail closed at
|
|
3910
|
+
// the shared census boundary — never export confirmed absence and overwrite.
|
|
3911
|
+
const root = await tempDir("remnic-offline-changeset-uncertain-overwrite");
|
|
3912
|
+
try {
|
|
3913
|
+
const recreated = "recreated local bytes";
|
|
3914
|
+
const incoming = "incoming remote bytes";
|
|
3915
|
+
const incomingSha = createHash("sha256").update(incoming).digest("hex");
|
|
3916
|
+
await write(root, "facts/race.md", recreated);
|
|
3917
|
+
|
|
3918
|
+
await assert.rejects(
|
|
3919
|
+
() => applyOfflineSyncChangeset({
|
|
3920
|
+
root,
|
|
3921
|
+
// No currentFiles: exercise the public snapshotForPaths census path.
|
|
3922
|
+
returnCurrentFiles: false,
|
|
3923
|
+
writeConflictCopies: false,
|
|
3924
|
+
readFileDigest: async ({ path: relPath, filePath }) => {
|
|
3925
|
+
if (relPath === "facts/race.md") {
|
|
3926
|
+
await writeFile(filePath, recreated);
|
|
3927
|
+
throw Object.assign(new Error("ENOENT: vanished during census"), { code: "ENOENT" });
|
|
3928
|
+
}
|
|
3929
|
+
const content = await readFile(filePath);
|
|
3930
|
+
return {
|
|
3931
|
+
sha256: createHash("sha256").update(content).digest("hex"),
|
|
3932
|
+
bytes: content.length,
|
|
3933
|
+
};
|
|
3934
|
+
},
|
|
3935
|
+
changeset: {
|
|
3936
|
+
format: "remnic.offline-sync.changeset.v1",
|
|
3937
|
+
schemaVersion: 1,
|
|
3938
|
+
createdAt: new Date().toISOString(),
|
|
3939
|
+
sourceId: "remote",
|
|
3940
|
+
includeTranscripts: false,
|
|
3941
|
+
changes: [{
|
|
3942
|
+
type: "upsert",
|
|
3943
|
+
path: "facts/race.md",
|
|
3944
|
+
file: {
|
|
3945
|
+
path: "facts/race.md",
|
|
3946
|
+
sha256: incomingSha,
|
|
3947
|
+
bytes: Buffer.byteLength(incoming),
|
|
3948
|
+
mtimeMs: 2,
|
|
3949
|
+
contentBase64: Buffer.from(incoming).toString("base64"),
|
|
3950
|
+
},
|
|
3951
|
+
}],
|
|
3952
|
+
},
|
|
3953
|
+
}),
|
|
3954
|
+
/census race|vanished during digest|retry the snapshot/i,
|
|
3955
|
+
);
|
|
3956
|
+
|
|
3957
|
+
assert.equal(
|
|
3958
|
+
await readUtf8(root, "facts/race.md"),
|
|
3959
|
+
recreated,
|
|
3960
|
+
"recreated local content must survive a fail-closed public changeset census race",
|
|
3961
|
+
);
|
|
3962
|
+
} finally {
|
|
3963
|
+
await rm(root, { recursive: true, force: true });
|
|
3964
|
+
}
|
|
3965
|
+
});
|
|
3966
|
+
|
|
3967
|
+
test("sender snapshot omission from digest race must not delete receiver shared-base file", async () => {
|
|
3968
|
+
// Root premise: sender digest race must not export an apparently-complete
|
|
3969
|
+
// snapshot that omits the path. Fail closed at the shared census boundary so
|
|
3970
|
+
// no consumer can assign confirmed absence. Sender and receiver bytes stay.
|
|
3971
|
+
const senderRoot = await tempDir("remnic-offline-sender-uncertain-omit");
|
|
3972
|
+
const receiverRoot = await tempDir("remnic-offline-receiver-shared-base");
|
|
3973
|
+
try {
|
|
3974
|
+
const good = "unchanged good fact bytes";
|
|
3975
|
+
const keep = "keep peer";
|
|
3976
|
+
await write(senderRoot, "facts/race.md", good);
|
|
3977
|
+
await write(senderRoot, "facts/keep.md", keep);
|
|
3978
|
+
await write(receiverRoot, "facts/race.md", good);
|
|
3979
|
+
await write(receiverRoot, "facts/keep.md", keep);
|
|
3980
|
+
|
|
3981
|
+
const sharedBase = await buildOfflineSyncSnapshot({
|
|
3982
|
+
root: receiverRoot,
|
|
3983
|
+
sourceId: "shared",
|
|
3984
|
+
includeContent: false,
|
|
3985
|
+
});
|
|
3986
|
+
assert.ok(
|
|
3987
|
+
sharedBase.files.some((file) => file.path === "facts/race.md"),
|
|
3988
|
+
"fixture: shared base includes the good race path",
|
|
3989
|
+
);
|
|
3990
|
+
|
|
3991
|
+
await assert.rejects(
|
|
3992
|
+
() => buildOfflineSyncSnapshot({
|
|
3993
|
+
root: senderRoot,
|
|
3994
|
+
sourceId: "sender",
|
|
3995
|
+
includeContent: false,
|
|
3996
|
+
readFileDigest: async ({ path: relPath, filePath }) => {
|
|
3997
|
+
if (relPath === "facts/race.md") {
|
|
3998
|
+
await writeFile(filePath, good);
|
|
3999
|
+
throw Object.assign(new Error("ENOENT: vanished during sender census"), { code: "ENOENT" });
|
|
4000
|
+
}
|
|
4001
|
+
const content = await readFile(filePath);
|
|
4002
|
+
return {
|
|
4003
|
+
sha256: createHash("sha256").update(content).digest("hex"),
|
|
4004
|
+
bytes: content.length,
|
|
4005
|
+
};
|
|
4006
|
+
},
|
|
4007
|
+
}),
|
|
4008
|
+
/census race|vanished during digest|retry the snapshot/i,
|
|
4009
|
+
);
|
|
4010
|
+
|
|
4011
|
+
assert.equal(await readUtf8(senderRoot, "facts/race.md"), good, "sender bytes preserved");
|
|
4012
|
+
assert.equal(await readUtf8(receiverRoot, "facts/race.md"), good, "receiver bytes preserved without a false snapshot");
|
|
4013
|
+
assert.equal(await readUtf8(receiverRoot, "facts/keep.md"), keep);
|
|
4014
|
+
} finally {
|
|
4015
|
+
await rm(senderRoot, { recursive: true, force: true });
|
|
4016
|
+
await rm(receiverRoot, { recursive: true, force: true });
|
|
4017
|
+
}
|
|
4018
|
+
});
|
|
4019
|
+
|
|
4020
|
+
|
|
4021
|
+
test("a file vanishing during the changeset upsert read keeps the retryable changed-while-building message", async () => {
|
|
4022
|
+
const root = await mkdtemp(path.join(os.tmpdir(), "remnic-offline-changeset-vanish-"));
|
|
4023
|
+
try {
|
|
4024
|
+
const rel = "facts/volatile.md";
|
|
4025
|
+
const bytes = Buffer.from("volatile bytes\n");
|
|
4026
|
+
await mkdir(path.join(root, "facts"), { recursive: true });
|
|
4027
|
+
await writeFile(path.join(root, rel), bytes);
|
|
4028
|
+
const currentFile = {
|
|
4029
|
+
path: rel,
|
|
4030
|
+
sha256: createHash("sha256").update(bytes).digest("hex"),
|
|
4031
|
+
bytes: bytes.byteLength,
|
|
4032
|
+
mtimeMs: 1,
|
|
4033
|
+
};
|
|
4034
|
+
await assert.rejects(
|
|
4035
|
+
buildOfflineSyncChangesetFromSnapshot({
|
|
4036
|
+
root,
|
|
4037
|
+
sourceId: "laptop",
|
|
4038
|
+
baseFiles: [],
|
|
4039
|
+
currentFiles: [currentFile],
|
|
4040
|
+
readFile: async () => {
|
|
4041
|
+
await rm(path.join(root, rel), { force: true });
|
|
4042
|
+
throw Object.assign(new Error("ENOENT: file vanished"), { code: "ENOENT" });
|
|
4043
|
+
},
|
|
4044
|
+
}),
|
|
4045
|
+
(error: Error) => {
|
|
4046
|
+
// The CLI retry loop matches this exact prefix to defer the path and rebuild the census.
|
|
4047
|
+
assert.equal(error.message, `offline sync file changed while building changeset: ${rel}`);
|
|
4048
|
+
return true;
|
|
4049
|
+
},
|
|
4050
|
+
);
|
|
4051
|
+
} finally {
|
|
4052
|
+
await rm(root, { recursive: true, force: true });
|
|
4053
|
+
}
|
|
4054
|
+
});
|
|
4055
|
+
|
|
4056
|
+
test("a tracked file replaced by a symlink is a local delete, not a push-blocking error", async () => {
|
|
4057
|
+
const root = await mkdtemp(path.join(os.tmpdir(), "remnic-offline-symlink-replaced-"));
|
|
4058
|
+
const outside = await mkdtemp(path.join(os.tmpdir(), "remnic-offline-symlink-target-"));
|
|
4059
|
+
try {
|
|
4060
|
+
const rel = "facts/tracked.md";
|
|
4061
|
+
const bytes = Buffer.from("tracked bytes\n");
|
|
4062
|
+
await mkdir(path.join(root, "facts"), { recursive: true });
|
|
4063
|
+
await writeFile(path.join(outside, "target.md"), "outside\n");
|
|
4064
|
+
await symlink(path.join(outside, "target.md"), path.join(root, rel));
|
|
4065
|
+
const baseFile = {
|
|
4066
|
+
path: rel,
|
|
4067
|
+
sha256: createHash("sha256").update(bytes).digest("hex"),
|
|
4068
|
+
bytes: bytes.byteLength,
|
|
4069
|
+
mtimeMs: 1,
|
|
4070
|
+
};
|
|
4071
|
+
const changeset = await buildOfflineSyncChangesetFromSnapshot({
|
|
4072
|
+
root,
|
|
4073
|
+
sourceId: "laptop",
|
|
4074
|
+
baseFiles: [baseFile],
|
|
4075
|
+
currentFiles: [],
|
|
4076
|
+
});
|
|
4077
|
+
assert.deepEqual(
|
|
4078
|
+
changeset.changes.map((change) => [change.type, change.path]),
|
|
4079
|
+
[["delete", rel]],
|
|
4080
|
+
"a symlink is not a regular local file: it reads as a delete, as before the census change",
|
|
4081
|
+
);
|
|
4082
|
+
} finally {
|
|
4083
|
+
await rm(root, { recursive: true, force: true });
|
|
4084
|
+
await rm(outside, { recursive: true, force: true });
|
|
4085
|
+
}
|
|
4086
|
+
});
|
|
4087
|
+
|
|
4088
|
+
test("a tracked file under a directory replaced by an in-root symlink is a local delete", async () => {
|
|
4089
|
+
const root = await mkdtemp(path.join(os.tmpdir(), "remnic-offline-symlink-parent-"));
|
|
4090
|
+
try {
|
|
4091
|
+
const rel = "facts/tracked.md";
|
|
4092
|
+
const bytes = Buffer.from("tracked bytes\n");
|
|
4093
|
+
await mkdir(path.join(root, "elsewhere"), { recursive: true });
|
|
4094
|
+
await writeFile(path.join(root, "elsewhere", "tracked.md"), bytes);
|
|
4095
|
+
// The census skips a symlinked directory, so facts/tracked.md is not in it.
|
|
4096
|
+
await symlink(path.join(root, "elsewhere"), path.join(root, "facts"));
|
|
4097
|
+
const baseFile = {
|
|
4098
|
+
path: rel,
|
|
4099
|
+
sha256: createHash("sha256").update(bytes).digest("hex"),
|
|
4100
|
+
bytes: bytes.byteLength,
|
|
4101
|
+
mtimeMs: 1,
|
|
4102
|
+
};
|
|
4103
|
+
const changeset = await buildOfflineSyncChangesetFromSnapshot({
|
|
4104
|
+
root,
|
|
4105
|
+
sourceId: "laptop",
|
|
4106
|
+
baseFiles: [baseFile],
|
|
4107
|
+
currentFiles: [],
|
|
4108
|
+
});
|
|
4109
|
+
assert.deepEqual(
|
|
4110
|
+
changeset.changes.map((change) => [change.type, change.path]),
|
|
4111
|
+
[["delete", rel]],
|
|
4112
|
+
"a path reached only through a symlinked parent is absent, as the census sees it",
|
|
4113
|
+
);
|
|
4114
|
+
} finally {
|
|
4115
|
+
await rm(root, { recursive: true, force: true });
|
|
4116
|
+
}
|
|
4117
|
+
});
|
package/src/offline-sync.ts
CHANGED
|
@@ -32,6 +32,7 @@ import { isMacOsReplicationJunkBasename } from "./utils/macos-replication-junk.j
|
|
|
32
32
|
import {
|
|
33
33
|
applyIncomingEmbeddingGenerations,
|
|
34
34
|
assertEmbeddingGenerationStillIncluded,
|
|
35
|
+
advanceEmbeddingGenerationMarker,
|
|
35
36
|
computeOmittedEmbeddingGenerationPaths,
|
|
36
37
|
divergedEmbeddingGenerationDeferrals,
|
|
37
38
|
embeddingGenerationMembership,
|
|
@@ -69,6 +70,10 @@ import {
|
|
|
69
70
|
setSafeFileMtime,
|
|
70
71
|
assertNonNegativeFinite,
|
|
71
72
|
assertOfflineSyncMtimeMs,
|
|
73
|
+
offlineSyncRegularFilePresent,
|
|
74
|
+
OfflineSyncCensusRaceError,
|
|
75
|
+
censusRaceAsChangedWhileBuilding,
|
|
76
|
+
changedWhileBuildingChangesetError,
|
|
72
77
|
OFFLINE_SYNC_FAST_BASE_MTIME_TOLERANCE_MS,
|
|
73
78
|
} from "./offline-sync-file-io.js";
|
|
74
79
|
import { CENSUS_MAX_MTIME_MS, isSha256Hex } from "./census-validation.js";
|
|
@@ -792,19 +797,29 @@ async function canReuseFastBaseFileStateFromDisk(
|
|
|
792
797
|
|
|
793
798
|
async function readOfflineSyncFileRecord(
|
|
794
799
|
options: OfflineSyncFileRecordOptions,
|
|
795
|
-
): Promise<OfflineSyncFileRecord
|
|
800
|
+
): Promise<OfflineSyncFileRecord> {
|
|
796
801
|
try {
|
|
797
802
|
return await readPresentOfflineSyncFileRecord(options);
|
|
798
803
|
} catch (error) {
|
|
799
|
-
//
|
|
800
|
-
|
|
804
|
+
// Caller already observed the path (readdir/lstat). Digest ENOENT is an
|
|
805
|
+
// ambiguous race: exporting a silent omission assigns confirmed absence to
|
|
806
|
+
// every consumer (full snapshot apply + changeset apply). Fail closed.
|
|
807
|
+
if (isNotFoundError(error)) {
|
|
808
|
+
if (embeddingGenerationMembership(options.relPath) !== null) {
|
|
809
|
+
throw new Error(
|
|
810
|
+
`offline sync embedding generation member vanished during snapshot walk: ${options.relPath}`,
|
|
811
|
+
);
|
|
812
|
+
}
|
|
813
|
+
throw new OfflineSyncCensusRaceError(options.relPath, error);
|
|
814
|
+
}
|
|
801
815
|
throw error;
|
|
802
816
|
}
|
|
803
817
|
}
|
|
804
818
|
|
|
805
|
-
|
|
806
|
-
//
|
|
807
|
-
//
|
|
819
|
+
|
|
820
|
+
// Pre-stat vanish (readdir then lstat/stat ENOENT) may omit only when nothing
|
|
821
|
+
// can misread the gap: embedding generations travel as one unit (issue #3148),
|
|
822
|
+
// and a base-known file omitted here would fabricate a delete in
|
|
808
823
|
// buildOfflineSyncChangesetFromSnapshot.
|
|
809
824
|
function assertSnapshotVanishIsSafe(relPath: string, base: ReadonlyMap<string, unknown> | undefined): void {
|
|
810
825
|
if (embeddingGenerationMembership(relPath) !== null) {
|
|
@@ -815,6 +830,7 @@ function assertSnapshotVanishIsSafe(relPath: string, base: ReadonlyMap<string, u
|
|
|
815
830
|
}
|
|
816
831
|
}
|
|
817
832
|
|
|
833
|
+
|
|
818
834
|
async function readPresentOfflineSyncFileRecord(
|
|
819
835
|
options: OfflineSyncFileRecordOptions,
|
|
820
836
|
): Promise<OfflineSyncFileRecord> {
|
|
@@ -922,7 +938,7 @@ export async function* iterateOfflineSyncSnapshotFileRecords(options: {
|
|
|
922
938
|
path: relPosix,
|
|
923
939
|
filePath: abs,
|
|
924
940
|
})) continue;
|
|
925
|
-
|
|
941
|
+
yield await readOfflineSyncFileRecord({
|
|
926
942
|
root,
|
|
927
943
|
relPath: relPosix,
|
|
928
944
|
filePath: abs,
|
|
@@ -931,8 +947,7 @@ export async function* iterateOfflineSyncSnapshotFileRecords(options: {
|
|
|
931
947
|
readFileDigest: options.readFileDigest,
|
|
932
948
|
signal: options.signal,
|
|
933
949
|
});
|
|
934
|
-
|
|
935
|
-
else assertSnapshotVanishIsSafe(relPosix, undefined);
|
|
950
|
+
|
|
936
951
|
}
|
|
937
952
|
}
|
|
938
953
|
|
|
@@ -1093,8 +1108,7 @@ export async function buildOfflineSyncSnapshotFromBase(options: {
|
|
|
1093
1108
|
try {
|
|
1094
1109
|
st = await stat(abs);
|
|
1095
1110
|
} catch (error) {
|
|
1096
|
-
//
|
|
1097
|
-
// path could fabricate a delete or downgrade a generation.
|
|
1111
|
+
// Pre-stat vanish after readdir: omit only when assertSnapshotVanishIsSafe allows.
|
|
1098
1112
|
if (isNotFoundError(error)) {
|
|
1099
1113
|
assertSnapshotVanishIsSafe(relPosix, base);
|
|
1100
1114
|
continue;
|
|
@@ -1111,7 +1125,7 @@ export async function buildOfflineSyncSnapshotFromBase(options: {
|
|
|
1111
1125
|
files.push(baseEntry);
|
|
1112
1126
|
continue;
|
|
1113
1127
|
}
|
|
1114
|
-
|
|
1128
|
+
files.push(await readOfflineSyncFileRecord({
|
|
1115
1129
|
root,
|
|
1116
1130
|
relPath: relPosix,
|
|
1117
1131
|
filePath: abs,
|
|
@@ -1119,9 +1133,7 @@ export async function buildOfflineSyncSnapshotFromBase(options: {
|
|
|
1119
1133
|
readFile: options.readFile,
|
|
1120
1134
|
readFileDigest: options.readFileDigest,
|
|
1121
1135
|
signal: options.signal,
|
|
1122
|
-
});
|
|
1123
|
-
if (record) files.push(record);
|
|
1124
|
-
else assertSnapshotVanishIsSafe(relPosix, base);
|
|
1136
|
+
}));
|
|
1125
1137
|
}
|
|
1126
1138
|
}
|
|
1127
1139
|
|
|
@@ -1207,7 +1219,7 @@ export async function buildOfflineSyncSnapshotForPaths(options: {
|
|
|
1207
1219
|
})) {
|
|
1208
1220
|
throw new Error(`offline sync snapshot path is excluded: ${relPath}`);
|
|
1209
1221
|
}
|
|
1210
|
-
|
|
1222
|
+
files.push(await readOfflineSyncFileRecord({
|
|
1211
1223
|
root,
|
|
1212
1224
|
relPath,
|
|
1213
1225
|
filePath,
|
|
@@ -1215,9 +1227,7 @@ export async function buildOfflineSyncSnapshotForPaths(options: {
|
|
|
1215
1227
|
readFile: options.readFile,
|
|
1216
1228
|
readFileDigest: options.readFileDigest,
|
|
1217
1229
|
signal: options.signal,
|
|
1218
|
-
});
|
|
1219
|
-
if (record) files.push(record);
|
|
1220
|
-
else assertSnapshotVanishIsSafe(relPath, undefined);
|
|
1230
|
+
}));
|
|
1221
1231
|
}
|
|
1222
1232
|
throwIfOfflineSyncAborted(options.signal);
|
|
1223
1233
|
|
|
@@ -1413,6 +1423,11 @@ export async function buildOfflineSyncChangesetFromSnapshot(options: {
|
|
|
1413
1423
|
excludeNodeLocalState?: boolean;
|
|
1414
1424
|
readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;
|
|
1415
1425
|
}): Promise<OfflineSyncChangeset> {
|
|
1426
|
+
const root = await prepareSafeArchiveRoot(
|
|
1427
|
+
path.resolve(options.root),
|
|
1428
|
+
"buildOfflineSyncChangesetFromSnapshot",
|
|
1429
|
+
"root",
|
|
1430
|
+
);
|
|
1416
1431
|
const includeTranscripts = options.includeTranscripts !== false;
|
|
1417
1432
|
const excludedPaths = new Set(
|
|
1418
1433
|
(options.excludePaths ?? []).map((relPath) => normalizeRelativePath(relPath, "excludePaths[]")),
|
|
@@ -1452,10 +1467,10 @@ export async function buildOfflineSyncChangesetFromSnapshot(options: {
|
|
|
1452
1467
|
now: options.now,
|
|
1453
1468
|
userExcludeRegexps: options.userExcludeRegexps,
|
|
1454
1469
|
readFile: options.readFile,
|
|
1455
|
-
});
|
|
1470
|
+
}).catch(censusRaceAsChangedWhileBuilding(relPath));
|
|
1456
1471
|
const record = file.files[0];
|
|
1457
1472
|
if (!record || typeof record.contentBase64 !== "string" || record.sha256 !== currentEntry.sha256) {
|
|
1458
|
-
throw
|
|
1473
|
+
throw changedWhileBuildingChangesetError(relPath);
|
|
1459
1474
|
}
|
|
1460
1475
|
changes.push({
|
|
1461
1476
|
type: "upsert",
|
|
@@ -1466,6 +1481,8 @@ export async function buildOfflineSyncChangesetFromSnapshot(options: {
|
|
|
1466
1481
|
continue;
|
|
1467
1482
|
}
|
|
1468
1483
|
if (!currentEntry && baseEntry) {
|
|
1484
|
+
// Census miss is not confirmed delete — recheck disk (transient ENOENT / recreate).
|
|
1485
|
+
if (await offlineSyncRegularFilePresent(root, relPath)) continue;
|
|
1469
1486
|
const mtimeMs = deletionMtimeByPath?.get(relPath);
|
|
1470
1487
|
changes.push({
|
|
1471
1488
|
type: "delete",
|
|
@@ -1807,6 +1824,12 @@ export async function applyOfflineSyncSnapshot(options: {
|
|
|
1807
1824
|
continue;
|
|
1808
1825
|
}
|
|
1809
1826
|
if (!currentEntry && !base) {
|
|
1827
|
+
// Census miss with on-disk file: uncertain local presence, do not overwrite.
|
|
1828
|
+
if (await offlineSyncRegularFilePresent(root, relPath)) {
|
|
1829
|
+
pendingLocal += 1;
|
|
1830
|
+
skipped += 1;
|
|
1831
|
+
continue;
|
|
1832
|
+
}
|
|
1810
1833
|
await writeSafeFile(root, relPath, requiredBuffer(incomingBuffers, relPath), options.writeFile, incoming.mtimeMs);
|
|
1811
1834
|
nextBase.set(relPath, toFileState(incoming));
|
|
1812
1835
|
upserted += 1;
|
|
@@ -2466,7 +2489,9 @@ export async function applyOfflineSyncFileContentChunk(options: {
|
|
|
2466
2489
|
};
|
|
2467
2490
|
}
|
|
2468
2491
|
|
|
2469
|
-
await
|
|
2492
|
+
await advanceEmbeddingGenerationMarker(root.abs, embeddingGenerationMembership(relPath), () =>
|
|
2493
|
+
writeSafeFileFromUpload(root, relPath, upload, options.readFile, options.writeFileChunks, mtimeMs),
|
|
2494
|
+
);
|
|
2470
2495
|
return {
|
|
2471
2496
|
...baseResult,
|
|
2472
2497
|
applied: true,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
|
-
import {
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
3
4
|
import os from "node:os";
|
|
4
5
|
import path from "node:path";
|
|
5
6
|
import test from "node:test";
|
|
@@ -1547,3 +1548,50 @@ test("startupSearchSync composes its caller abort into the QMD probe", async ()
|
|
|
1547
1548
|
await rm(memoryDir, { recursive: true, force: true, maxRetries: 3, retryDelay: 50 });
|
|
1548
1549
|
}
|
|
1549
1550
|
});
|
|
1551
|
+
|
|
1552
|
+
// Both startup call sites must open read readiness without migration replay.
|
|
1553
|
+
for (const namespace of ["default", "shared"]) {
|
|
1554
|
+
test(`startup defers entity migration for ${namespace} storage`, async () => {
|
|
1555
|
+
const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-init-migration-defer-"));
|
|
1556
|
+
const orchestrator = new Orchestrator(
|
|
1557
|
+
parseConfig({
|
|
1558
|
+
memoryDir,
|
|
1559
|
+
workspaceDir: path.join(memoryDir, "workspace"),
|
|
1560
|
+
qmdEnabled: false,
|
|
1561
|
+
namespacesEnabled: namespace === "shared",
|
|
1562
|
+
namespaceCatalogEnabled: false,
|
|
1563
|
+
defaultNamespace: "default",
|
|
1564
|
+
sharedNamespace: "shared",
|
|
1565
|
+
namespacePolicies: [],
|
|
1566
|
+
embeddingFallbackEnabled: false,
|
|
1567
|
+
identityContinuityEnabled: false,
|
|
1568
|
+
transcriptEnabled: false,
|
|
1569
|
+
hourlySummariesEnabled: false,
|
|
1570
|
+
compoundingEnabled: false,
|
|
1571
|
+
knowledgeIndexEnabled: false,
|
|
1572
|
+
}),
|
|
1573
|
+
);
|
|
1574
|
+
const storage = await orchestrator.getStorage(namespace);
|
|
1575
|
+
const lockPath = path.join(storage.dir, "state", "entity-canonical-id-migration.lock");
|
|
1576
|
+
const journalPath = path.join(storage.dir, "state", "entity-canonical-id-migration-v1.json");
|
|
1577
|
+
try {
|
|
1578
|
+
await mkdir(path.dirname(lockPath), { recursive: true });
|
|
1579
|
+
await writeFile(lockPath, `${process.pid} init-migration-test ${new Date().toISOString()}\n`);
|
|
1580
|
+
const outcome = await withTestDeadline(
|
|
1581
|
+
orchestrator.initialize().then(() => "settled" as const, () => "rejected" as const),
|
|
1582
|
+
);
|
|
1583
|
+
assert.equal(outcome, "settled", "startup must succeed while the migration lock is held");
|
|
1584
|
+
assert.equal(existsSync(lockPath), true);
|
|
1585
|
+
assert.equal(existsSync(journalPath), false, "startup must not run the migration");
|
|
1586
|
+
await rm(lockPath);
|
|
1587
|
+
await storage.ensureDirectories();
|
|
1588
|
+
// SAFETY: the journal is written by the migration under test and carries an optional boolean `complete`.
|
|
1589
|
+
const state = JSON.parse(await readFile(journalPath, "utf8")) as { complete?: boolean };
|
|
1590
|
+
assert.equal(state.complete, true, "default setup must still run migration");
|
|
1591
|
+
} finally {
|
|
1592
|
+
await rm(lockPath, { force: true });
|
|
1593
|
+
await orchestrator.destroy();
|
|
1594
|
+
await rm(memoryDir, { recursive: true, force: true, maxRetries: 3, retryDelay: 50 });
|
|
1595
|
+
}
|
|
1596
|
+
});
|
|
1597
|
+
}
|
package/src/orchestrator.ts
CHANGED
|
@@ -746,6 +746,7 @@ export class Orchestrator {
|
|
|
746
746
|
private _dependencyPropagationDelivery: DependencyPropagationDelivery | undefined;
|
|
747
747
|
private _dependencyPropagationRecovery: Promise<void> | null = null;
|
|
748
748
|
private destroyed = false;
|
|
749
|
+
private acceptingEntityMigrationMaintenance = true;
|
|
749
750
|
|
|
750
751
|
private get dependencyPropagationDelivery(): DependencyPropagationDelivery {
|
|
751
752
|
if (this.destroyed) throw new Error("orchestrator has been destroyed");
|
|
@@ -967,6 +968,7 @@ export class Orchestrator {
|
|
|
967
968
|
* commands should call it before returning to let Node exit naturally.
|
|
968
969
|
*/
|
|
969
970
|
async destroy(): Promise<void> {
|
|
971
|
+
this.acceptingEntityMigrationMaintenance = false;
|
|
970
972
|
this._orchestratorInitCoordinator?.retireStartupEpoch();
|
|
971
973
|
this.abortDeferredInit();
|
|
972
974
|
this.extractionQueueCoordinator.stopAccepting();
|
|
@@ -1499,14 +1501,6 @@ export class Orchestrator {
|
|
|
1499
1501
|
(namespace) => this.namespaceSearchRouter.backendForNamespace(namespace),
|
|
1500
1502
|
(msg) => log.debug(msg),
|
|
1501
1503
|
);
|
|
1502
|
-
const defaultNs = this.config.defaultNamespace;
|
|
1503
|
-
this.storage.onMemoryWrite = (filePath) => this.prioritizedEmbedding?.enqueue(filePath, defaultNs);
|
|
1504
|
-
this.storageRouter.onStorageCreated = (storage, namespace) => {
|
|
1505
|
-
storage.onMemoryWrite = (filePath) => this.prioritizedEmbedding?.enqueue(filePath, namespace);
|
|
1506
|
-
};
|
|
1507
|
-
this.storageRouter.forEachCachedStorage((storage, namespace) => {
|
|
1508
|
-
storage.onMemoryWrite = (filePath) => this.prioritizedEmbedding?.enqueue(filePath, namespace);
|
|
1509
|
-
});
|
|
1510
1504
|
}
|
|
1511
1505
|
this.maintenanceScheduler = new MaintenanceScheduler({
|
|
1512
1506
|
config,
|
|
@@ -1516,6 +1510,13 @@ export class Orchestrator {
|
|
|
1516
1510
|
getStorage: () => this.storage, storageForNamespace: (namespace) => this.storageRouter.storageFor(namespace),
|
|
1517
1511
|
onActivitySynced: (summary) => { if (!this.config.meetings.enabled) return; void this.getMeetingsService().then((s) => s.requestBuildForActivitySync(summary.ranAt, this.config.activity.timezone, summary.touchedDates)).catch((err) => log.warn(`meetings: activity tail-step build failed to schedule: ${err instanceof Error ? err.message : String(err)}`)); },
|
|
1518
1512
|
});
|
|
1513
|
+
const bindStorage = (storage: StorageManager, namespace: string) => {
|
|
1514
|
+
storage.onEntityMigrationComplete = () => { if (this.acceptingEntityMigrationMaintenance) this.requestQmdMaintenance(); };
|
|
1515
|
+
if (this.prioritizedEmbedding) storage.onMemoryWrite = (filePath) => this.prioritizedEmbedding?.enqueue(filePath, namespace);
|
|
1516
|
+
};
|
|
1517
|
+
bindStorage(this.storage, this.config.defaultNamespace);
|
|
1518
|
+
this.storageRouter.onStorageCreated = bindStorage;
|
|
1519
|
+
this.storageRouter.forEachCachedStorage(bindStorage);
|
|
1519
1520
|
// Issue #1526: background extraction queue lives on its own coordinator.
|
|
1520
1521
|
this.extractionQueueCoordinator = new ExtractionQueueCoordinator();
|
|
1521
1522
|
|