@remnic/core 9.69.88 → 9.69.90
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 +74 -72
- package/dist/access-authorization-probe.js +75 -73
- package/dist/access-boundary.js +74 -72
- package/dist/access-cli.js +168 -165
- package/dist/access-cli.js.map +1 -1
- package/dist/access-extraction-force-flush.js +74 -72
- package/dist/access-http-briefing.js +75 -73
- package/dist/access-http-query.js +76 -74
- package/dist/access-http.js +98 -96
- package/dist/access-identity-continuity-surface.js +74 -72
- package/dist/access-lcm-surface.js +74 -72
- package/dist/access-mcp-output-schemas.d.ts.map +1 -1
- package/dist/access-mcp-output-schemas.js +1 -1
- package/dist/access-mcp.js +86 -84
- package/dist/access-memory-search-fanout.js +3 -3
- package/dist/access-namespace-preflight.js +74 -72
- package/dist/access-observe-write-category.js +11 -10
- package/dist/access-observe-write-surface.js +74 -72
- package/dist/access-offline-manifest.js +10 -9
- package/dist/access-operations-batch.js +76 -74
- package/dist/access-operations.js +83 -81
- package/dist/access-recall-concurrency.js +74 -72
- package/dist/access-recall-corpus-versions.d.ts +12 -0
- package/dist/access-recall-corpus-versions.d.ts.map +1 -0
- package/dist/access-recall-corpus-versions.js +10 -0
- package/dist/access-recall-diagnostics.js +5 -5
- package/dist/access-recall-response.d.ts +4 -0
- package/dist/access-recall-response.d.ts.map +1 -1
- package/dist/access-recall-response.js +74 -72
- package/dist/access-recall-surface.d.ts +8 -0
- package/dist/access-recall-surface.d.ts.map +1 -1
- package/dist/access-recall-surface.js +74 -72
- package/dist/access-schema.js +10 -9
- package/dist/access-service.d.ts +5 -0
- package/dist/access-service.d.ts.map +1 -1
- package/dist/access-service.js +74 -72
- package/dist/access-surface-catalog.js +76 -74
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/active-memory-bridge.js +3 -3
- package/dist/active-recall.js +27 -24
- package/dist/active-recall.js.map +1 -1
- package/dist/adapters/index.js +7 -7
- package/dist/adapters/registry.js +3 -3
- package/dist/{auto-sync-U5N3CB5Y.js → auto-sync-PAWBFQWL.js} +5 -5
- package/dist/briefing.js +19 -19
- package/dist/buffer.js +8 -8
- package/dist/calibration.js +2 -2
- package/dist/capabilities.d.ts +2 -1
- package/dist/capabilities.d.ts.map +1 -1
- package/dist/capabilities.js +1 -1
- package/dist/{capsule-crypto-YO5QJ6L3.js → capsule-crypto-7FJQINUR.js} +2 -2
- package/dist/causal-consolidation.js +19 -19
- package/dist/{chunk-BMXEBWBT.js → chunk-2EMROIXS.js} +2 -1
- package/dist/{chunk-BMXEBWBT.js.map → chunk-2EMROIXS.js.map} +1 -1
- package/dist/{chunk-MCTM4YPL.js → chunk-2FLFJTCI.js} +4 -2
- package/dist/chunk-2FLFJTCI.js.map +1 -0
- package/dist/{chunk-RDJ6C7NZ.js → chunk-2IWBHZ3H.js} +5 -5
- package/dist/{chunk-UP75KL3L.js → chunk-2JRB3Z5N.js} +2 -2
- package/dist/{chunk-BXLOS5AJ.js → chunk-2NLLXCJG.js} +2 -2
- package/dist/{chunk-KN6CIN7I.js → chunk-32HO62I4.js} +2 -2
- package/dist/{chunk-JLPNONPH.js → chunk-35A7GCHG.js} +2 -2
- package/dist/{chunk-MXCAJKMA.js → chunk-37ZQYFX4.js} +6 -6
- package/dist/{chunk-LW3HKRL7.js → chunk-3BTHXB7Z.js} +3 -3
- package/dist/{chunk-C7V3KPKJ.js → chunk-47LTKAGL.js} +2 -2
- package/dist/{chunk-3O5BB45T.js → chunk-4DXNOVNW.js} +10 -10
- package/dist/{chunk-65I2LZEK.js → chunk-4G2YCKLT.js} +2 -2
- package/dist/{chunk-OK52IY3W.js → chunk-4GEBLO7S.js} +10 -10
- package/dist/{chunk-M6C7SOR6.js → chunk-4I6PEEFA.js} +3 -3
- package/dist/{chunk-Z4TXB4K7.js → chunk-5BUCKFRE.js} +2 -2
- package/dist/{chunk-BGI4NUAO.js → chunk-5S7SNRSJ.js} +2 -2
- package/dist/{chunk-JVPWRNHA.js → chunk-5YR4UGF2.js} +5 -5
- package/dist/{chunk-YJ7MW627.js → chunk-6BG364RN.js} +2 -2
- package/dist/{chunk-D5BSQR63.js → chunk-76LNUSS5.js} +2 -2
- package/dist/{chunk-7CRUDH7G.js → chunk-77HNHT6S.js} +2 -2
- package/dist/{chunk-OWYHHW67.js → chunk-7XI2UJHL.js} +4 -4
- package/dist/{chunk-BJVO4H5C.js → chunk-7Z2UKRNJ.js} +4 -4
- package/dist/{chunk-2WLMWP2T.js → chunk-A3K2KKSG.js} +2 -2
- package/dist/chunk-A5ZYP4K5.js +130 -0
- package/dist/chunk-A5ZYP4K5.js.map +1 -0
- package/dist/{chunk-AWG3TIAY.js → chunk-ACCOC6UM.js} +2 -2
- package/dist/{chunk-3JDA3XF5.js → chunk-AEGNDL24.js} +2 -2
- package/dist/{chunk-2NAD4YCI.js → chunk-AEUMONCD.js} +2 -2
- package/dist/{chunk-C6U57KG4.js → chunk-AF5PW35O.js} +3 -3
- package/dist/{chunk-IOSZHHJC.js → chunk-ANGZWYL2.js} +6 -6
- package/dist/{chunk-K6T33R4Q.js → chunk-AXGJMDBS.js} +156 -7
- package/dist/chunk-AXGJMDBS.js.map +1 -0
- package/dist/{chunk-6LYAEM54.js → chunk-AXHU56C3.js} +2 -2
- package/dist/{chunk-GWM6T5EQ.js → chunk-BCGMG2RD.js} +2 -2
- package/dist/{chunk-HXCJF4XU.js → chunk-BFIZXFUG.js} +2 -2
- package/dist/{chunk-DBYAY6UW.js → chunk-BTOHGPHC.js} +3 -3
- package/dist/{chunk-5X4MXNEU.js → chunk-C6HPNPNK.js} +3 -3
- package/dist/{chunk-4MP7XR5J.js → chunk-CAKHZAXH.js} +2 -2
- package/dist/{chunk-YSBL7VPO.js → chunk-CDWFWOSZ.js} +2 -2
- package/dist/{chunk-QAW55ZHJ.js → chunk-CZ44FH45.js} +4 -4
- package/dist/{chunk-T3FMRLWQ.js → chunk-D5HQ3VEX.js} +4 -4
- package/dist/{chunk-S7LWX2PQ.js → chunk-DPG5HQLE.js} +4 -4
- package/dist/{chunk-C7ZDKWPS.js → chunk-DVSAMW5T.js} +3 -3
- package/dist/{chunk-WBYQA3VN.js → chunk-E5H4TM4Y.js} +3 -3
- package/dist/{chunk-4RL3JOB3.js → chunk-EEDI3OXB.js} +2 -2
- package/dist/{chunk-3TB2XQ3C.js → chunk-EUL3S3LE.js} +4 -4
- package/dist/{chunk-Q4AUIFUA.js → chunk-F23U5YE7.js} +7 -7
- package/dist/{chunk-ZZZ4I455.js → chunk-GDVORIFM.js} +2 -2
- package/dist/{chunk-QB57WIS6.js → chunk-GXETU7AE.js} +98 -73
- package/dist/chunk-GXETU7AE.js.map +1 -0
- package/dist/{chunk-SWBC3UER.js → chunk-HCPUVB7S.js} +3 -3
- package/dist/{chunk-R3X2T2LP.js → chunk-HFOY2SBG.js} +2 -2
- package/dist/{chunk-LU7E2MXE.js → chunk-HQCUUVG2.js} +20 -20
- package/dist/{chunk-FJLQXMTU.js → chunk-I6B3S62A.js} +2 -2
- package/dist/{chunk-RBITPCMK.js → chunk-IDSSDL4W.js} +9 -9
- package/dist/{chunk-OCFXVDBZ.js → chunk-IVEHY2VT.js} +54 -123
- package/dist/chunk-IVEHY2VT.js.map +1 -0
- package/dist/{chunk-B3OFQP5Y.js → chunk-IY47KPML.js} +6 -6
- package/dist/{chunk-AXC4WSF3.js → chunk-JDOBIFBK.js} +2 -2
- package/dist/{chunk-P2ODTYOF.js → chunk-JGXHQV5N.js} +3 -3
- package/dist/{chunk-7LNHRQKR.js → chunk-JLIGUFPF.js} +2 -2
- package/dist/{chunk-EDIH6X2P.js → chunk-JZ66PN72.js} +2 -2
- package/dist/{chunk-BLVR4WYU.js → chunk-KICEAGKM.js} +2 -2
- package/dist/{chunk-S2GE2K36.js → chunk-KNI4SGQE.js} +109 -96
- package/dist/chunk-KNI4SGQE.js.map +1 -0
- package/dist/{chunk-VDX2J7OX.js → chunk-KQAFEZQX.js} +2 -2
- package/dist/{chunk-PEBHPCX2.js → chunk-KTG23JDX.js} +2 -2
- package/dist/{chunk-BOZJD5PK.js → chunk-KYOZ5E6V.js} +2 -2
- package/dist/{chunk-2DLWLNO4.js → chunk-L3TZXELN.js} +4 -4
- package/dist/{chunk-VALKBYBN.js → chunk-M3N2TUZ7.js} +2 -2
- package/dist/{chunk-76M5OK7V.js → chunk-M7T2NKET.js} +5 -5
- package/dist/chunk-MSAI3Q7D.js +372 -0
- package/dist/chunk-MSAI3Q7D.js.map +1 -0
- package/dist/{chunk-Z5LP6ILP.js → chunk-MZAH3CBT.js} +2 -2
- package/dist/{chunk-QI7K7BZ5.js → chunk-NJW2ZG64.js} +2 -2
- package/dist/{chunk-CZJA2EQE.js → chunk-NSKXRTVZ.js} +2 -2
- package/dist/{chunk-4O4XCBOS.js → chunk-NUSQ3YEL.js} +2 -2
- package/dist/{chunk-4OQET73E.js → chunk-O57FCN42.js} +15 -15
- package/dist/{chunk-WKY7N3L7.js → chunk-OEBUAC3O.js} +10 -10
- package/dist/{chunk-Y23L4YJV.js → chunk-OEIA4IHU.js} +2 -2
- package/dist/{chunk-66DKTOBY.js → chunk-OGZC2WUX.js} +2 -2
- package/dist/{chunk-3SGTV7RD.js → chunk-P62DSJUK.js} +6 -6
- package/dist/{chunk-FKD656D2.js → chunk-PH2V7EXZ.js} +2 -2
- package/dist/{chunk-KKNZ7PUZ.js → chunk-QAIKLICT.js} +2 -2
- package/dist/{chunk-SSUDD72S.js → chunk-QPWUG2S3.js} +2 -2
- package/dist/{chunk-QI2E6ISQ.js → chunk-R2TVWQLR.js} +2 -2
- package/dist/chunk-R2TVWQLR.js.map +1 -0
- package/dist/{chunk-GZDTVYK2.js → chunk-R36IBI2M.js} +3 -3
- package/dist/{chunk-W3XXFPRI.js → chunk-R5B3OWI4.js} +64 -64
- package/dist/{chunk-VL4X7ZHC.js → chunk-RFIJRZ4K.js} +2 -2
- package/dist/{chunk-PWF4JXKD.js → chunk-RKDSELA3.js} +1 -1
- package/dist/chunk-RKDSELA3.js.map +1 -0
- package/dist/{chunk-AEHVZY3X.js → chunk-RPVHRZ5C.js} +2 -2
- package/dist/{chunk-X5SHE2O3.js → chunk-RVBLCU5C.js} +4 -4
- package/dist/{chunk-BUQKSQXL.js → chunk-S533KGX6.js} +5 -5
- package/dist/{chunk-STEOT4DI.js → chunk-SCPHU3RW.js} +7 -7
- package/dist/{chunk-LV5H6FTN.js → chunk-SFSD5Q6O.js} +3 -3
- package/dist/{chunk-AE5U5NMS.js → chunk-SMLKHXPF.js} +2 -2
- package/dist/{chunk-AEU4EQGV.js → chunk-T7R5HI6A.js} +1 -1
- package/dist/{chunk-H5BJWPUI.js → chunk-TVQZAQPE.js} +2 -2
- package/dist/{chunk-H56VY4BY.js → chunk-U36GYZ2P.js} +10 -5
- package/dist/chunk-U36GYZ2P.js.map +1 -0
- package/dist/{chunk-XOV7NRY5.js → chunk-U46P4UAR.js} +3 -3
- package/dist/{chunk-DZ42MDZE.js → chunk-UCJINCZT.js} +2 -2
- package/dist/{chunk-5E6RYRYW.js → chunk-UG5V3Z3R.js} +7 -7
- package/dist/{chunk-IW3RMBPB.js → chunk-VAOC6GHN.js} +2 -2
- package/dist/{chunk-6UQFJULG.js → chunk-VBNA2JEN.js} +2 -2
- package/dist/{chunk-HLB7GKGG.js → chunk-VOZNBQNL.js} +2 -2
- package/dist/{chunk-NYKIUQL6.js → chunk-WHIGRW7T.js} +2 -2
- package/dist/{chunk-AZSGSRIM.js → chunk-WHTMVTU4.js} +3 -3
- package/dist/{chunk-AERXJCOG.js → chunk-WL7N5VGG.js} +5 -5
- package/dist/{chunk-TFA6HPOA.js → chunk-WQUGCOKF.js} +4 -4
- package/dist/{chunk-A4VSOUCB.js → chunk-WTZQM74L.js} +5 -5
- package/dist/{chunk-DQEMWVMT.js → chunk-X7Y7WX73.js} +1 -1
- package/dist/{chunk-T2YX56QI.js → chunk-XWSUK5GL.js} +4 -4
- package/dist/{chunk-ACX55QDO.js → chunk-XYOT5GQU.js} +3 -3
- package/dist/{chunk-Z6EZCN6Z.js → chunk-Y7427SL7.js} +10 -10
- package/dist/{chunk-4KN2JLQV.js → chunk-YHZWVDP7.js} +2 -2
- package/dist/chunk-YVRQ5JRA.js +49 -0
- package/dist/chunk-YVRQ5JRA.js.map +1 -0
- package/dist/{chunk-5MNUBT7T.js → chunk-ZFTODDTX.js} +2 -2
- package/dist/{chunk-VVX5PZFS.js → chunk-ZHXSOMYH.js} +2 -2
- package/dist/{chunk-CRXRZA3G.js → chunk-ZQTYWSO3.js} +2 -2
- package/dist/cli.js +126 -122
- package/dist/coding/export-okf-codegraph.js +17 -17
- package/dist/compounding/engine.js +19 -19
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +27 -24
- package/dist/connectors/codex-materialize-runner.js +18 -18
- package/dist/connectors/index.js +20 -20
- package/dist/contradiction/index.js +3 -3
- package/dist/{contradiction-scan-TAGMOUQ2.js → contradiction-scan-GGRTVB7C.js} +3 -3
- package/dist/convergence-refresh.js +20 -20
- package/dist/conversation-index/backend.js +2 -2
- package/dist/corpus-watermark.js +20 -20
- package/dist/day-summary.js +2 -2
- package/dist/deep-recall-http-glue.js +11 -10
- package/dist/embedding-fallback.js +2 -2
- package/dist/entity-retrieval.js +19 -19
- package/dist/explicit-capture.js +2 -2
- package/dist/external-wiki-access.js +75 -73
- package/dist/extraction-judge.js +3 -3
- package/dist/extraction-normalization.js +3 -3
- package/dist/extraction-prompt.js +2 -2
- package/dist/extraction.js +32 -32
- package/dist/{first-start-migration-7OATHJKB.js → first-start-migration-OM3PHMZO.js} +2 -2
- package/dist/harmonic-retrieval.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +198 -195
- package/dist/lcm/engine.js +4 -4
- package/dist/lcm/index.js +10 -10
- package/dist/local-llm-config.js +1 -1
- package/dist/local-llm.js +3 -3
- package/dist/location/index.js +20 -20
- package/dist/maintenance/memory-governance.js +18 -18
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +18 -18
- package/dist/maintenance/rebuild-memory-projection.js +19 -19
- package/dist/memory-browse-operations.js +75 -73
- package/dist/memory-browse.js +5 -5
- package/dist/namespaces/migrate.js +19 -19
- package/dist/namespaces/principal.js +2 -2
- package/dist/namespaces/search.js +13 -13
- package/dist/namespaces/storage.js +18 -18
- package/dist/offline-sync-changeset-generations.d.ts +82 -0
- package/dist/offline-sync-changeset-generations.d.ts.map +1 -0
- package/dist/offline-sync-changeset-generations.js +21 -0
- package/dist/offline-sync-changeset-generations.js.map +1 -0
- package/dist/offline-sync-embedding-generation.d.ts +50 -0
- package/dist/offline-sync-embedding-generation.d.ts.map +1 -1
- package/dist/offline-sync-embedding-generation.js +4 -2
- package/dist/offline-sync-impression-drain.js +5 -5
- package/dist/offline-sync-snapshot-stream.js +5 -4
- package/dist/offline-sync.d.ts +12 -1
- package/dist/offline-sync.d.ts.map +1 -1
- package/dist/offline-sync.js +6 -5
- package/dist/operator-doctor-corpus.js +21 -21
- package/dist/operator-toolkit.js +39 -36
- package/dist/orchestration/compression-guideline-coordinator.js +2 -2
- package/dist/orchestration/maintenance.js +33 -33
- package/dist/orchestration/orchestrator-helpers.d.ts +1 -0
- package/dist/orchestration/orchestrator-helpers.d.ts.map +1 -1
- package/dist/orchestration/recall-entry.d.ts.map +1 -1
- package/dist/orchestration/recall-search-pipeline.d.ts.map +1 -1
- package/dist/orchestrator.js +168 -165
- package/dist/outcome-boost-config.d.ts +17 -0
- package/dist/outcome-boost-config.d.ts.map +1 -0
- package/dist/outcome-boost-config.js +1 -0
- package/dist/outcome-boost-config.js.map +1 -0
- package/dist/qmd.js +4 -4
- package/dist/recall-explain-renderer.js +3 -3
- package/dist/recall-navigate-access.js +2 -2
- package/dist/recall-navigate-disclosure.js +2 -2
- package/dist/recall-navigate.js +2 -2
- package/dist/recall-navigation-operations.js +75 -73
- package/dist/recall-navigation.js +74 -72
- package/dist/recall-state-view-admission.js +5 -5
- package/dist/recall-why-service.js +9 -9
- package/dist/recall-why.js +3 -3
- package/dist/recall-xray-cli.js +4 -4
- package/dist/recall-xray-renderer.js +3 -3
- package/dist/recall-xray.js +2 -2
- package/dist/rerank-outcome.d.ts +73 -0
- package/dist/rerank-outcome.d.ts.map +1 -0
- package/dist/rerank-outcome.js +28 -0
- package/dist/rerank-outcome.js.map +1 -0
- package/dist/{resolution-K4A3VPKZ.js → resolution-BROE3TRO.js} +4 -4
- package/dist/resolution-BROE3TRO.js.map +1 -0
- package/dist/resume-bundles.js +28 -25
- package/dist/search/embed-helper.js +2 -2
- package/dist/search/factory.js +12 -12
- package/dist/search/index.js +18 -18
- package/dist/search/lancedb-backend.js +2 -2
- package/dist/search/meilisearch-backend.js +2 -2
- package/dist/search/orama-backend.js +2 -2
- package/dist/semantic-consolidation.js +19 -19
- package/dist/semantic-rule-promotion.js +18 -18
- package/dist/semantic-rule-verifier.js +18 -18
- package/dist/shared-context/manager.js +2 -2
- package/dist/source-agent-qualifier.js +26 -26
- package/dist/standup/build.js +18 -18
- package/dist/storage.js +17 -17
- package/dist/summarizer.js +4 -4
- package/dist/support-passport/index.js +77 -75
- package/dist/support-passport/offline-sync-guard.d.ts +6 -2
- package/dist/support-passport/offline-sync-guard.d.ts.map +1 -1
- package/dist/{tier-stats-VF6DS52E.js → tier-stats-M2FMMD2N.js} +2 -2
- package/dist/transfer/backup.js +2 -2
- package/dist/transfer/capsule-export.js +2 -2
- package/dist/transfer/capsule-import.js +2 -2
- package/dist/transfer/export-okf.js +18 -18
- package/dist/types.d.ts +4 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -1
- package/dist/verified-recall.js +18 -18
- package/dist/who-knows-cli.js +19 -19
- package/dist/who-knows.js +18 -18
- package/package.json +13 -3
- package/src/access-mcp-output-schemas.ts +2 -0
- package/src/access-recall-corpus-versions.ts +59 -0
- package/src/access-recall-response.ts +3 -0
- package/src/access-recall-surface.ts +22 -23
- package/src/access-service-raw-excerpt-read-gate.test.ts +1 -1
- package/src/access-service.ts +3 -0
- package/src/capabilities.test.ts +1 -0
- package/src/capabilities.ts +6 -8
- package/src/config.ts +3 -0
- package/src/index.ts +1 -1
- package/src/offline-sync-changeset-generations.test.ts +962 -0
- package/src/offline-sync-changeset-generations.ts +549 -0
- package/src/offline-sync-embedding-generation.ts +272 -4
- package/src/offline-sync.ts +75 -162
- package/src/orchestration/orchestrator-helpers.ts +1 -1
- package/src/orchestration/recall-entry.ts +32 -16
- package/src/orchestration/recall-internal.ts +2 -2
- package/src/orchestration/recall-search-pipeline.ts +3 -0
- package/src/outcome-boost-config.ts +16 -0
- package/src/recall-retrieval-failure.test.ts +456 -4
- package/src/rerank-outcome.test.ts +218 -0
- package/src/rerank-outcome.ts +219 -0
- package/src/support-passport/offline-sync-guard.ts +16 -2
- package/src/types.ts +3 -3
- package/dist/chunk-H56VY4BY.js.map +0 -1
- package/dist/chunk-K6T33R4Q.js.map +0 -1
- package/dist/chunk-MCTM4YPL.js.map +0 -1
- package/dist/chunk-OCFXVDBZ.js.map +0 -1
- package/dist/chunk-PWF4JXKD.js.map +0 -1
- package/dist/chunk-QB57WIS6.js.map +0 -1
- package/dist/chunk-QI2E6ISQ.js.map +0 -1
- package/dist/chunk-S2GE2K36.js.map +0 -1
- /package/dist/{capsule-crypto-YO5QJ6L3.js.map → access-recall-corpus-versions.js.map} +0 -0
- /package/dist/{auto-sync-U5N3CB5Y.js.map → auto-sync-PAWBFQWL.js.map} +0 -0
- /package/dist/{contradiction-scan-TAGMOUQ2.js.map → capsule-crypto-7FJQINUR.js.map} +0 -0
- /package/dist/{chunk-RDJ6C7NZ.js.map → chunk-2IWBHZ3H.js.map} +0 -0
- /package/dist/{chunk-UP75KL3L.js.map → chunk-2JRB3Z5N.js.map} +0 -0
- /package/dist/{chunk-BXLOS5AJ.js.map → chunk-2NLLXCJG.js.map} +0 -0
- /package/dist/{chunk-KN6CIN7I.js.map → chunk-32HO62I4.js.map} +0 -0
- /package/dist/{chunk-JLPNONPH.js.map → chunk-35A7GCHG.js.map} +0 -0
- /package/dist/{chunk-MXCAJKMA.js.map → chunk-37ZQYFX4.js.map} +0 -0
- /package/dist/{chunk-LW3HKRL7.js.map → chunk-3BTHXB7Z.js.map} +0 -0
- /package/dist/{chunk-C7V3KPKJ.js.map → chunk-47LTKAGL.js.map} +0 -0
- /package/dist/{chunk-3O5BB45T.js.map → chunk-4DXNOVNW.js.map} +0 -0
- /package/dist/{chunk-65I2LZEK.js.map → chunk-4G2YCKLT.js.map} +0 -0
- /package/dist/{chunk-OK52IY3W.js.map → chunk-4GEBLO7S.js.map} +0 -0
- /package/dist/{chunk-M6C7SOR6.js.map → chunk-4I6PEEFA.js.map} +0 -0
- /package/dist/{chunk-Z4TXB4K7.js.map → chunk-5BUCKFRE.js.map} +0 -0
- /package/dist/{chunk-BGI4NUAO.js.map → chunk-5S7SNRSJ.js.map} +0 -0
- /package/dist/{chunk-JVPWRNHA.js.map → chunk-5YR4UGF2.js.map} +0 -0
- /package/dist/{chunk-YJ7MW627.js.map → chunk-6BG364RN.js.map} +0 -0
- /package/dist/{chunk-D5BSQR63.js.map → chunk-76LNUSS5.js.map} +0 -0
- /package/dist/{chunk-7CRUDH7G.js.map → chunk-77HNHT6S.js.map} +0 -0
- /package/dist/{chunk-OWYHHW67.js.map → chunk-7XI2UJHL.js.map} +0 -0
- /package/dist/{chunk-BJVO4H5C.js.map → chunk-7Z2UKRNJ.js.map} +0 -0
- /package/dist/{chunk-2WLMWP2T.js.map → chunk-A3K2KKSG.js.map} +0 -0
- /package/dist/{chunk-AWG3TIAY.js.map → chunk-ACCOC6UM.js.map} +0 -0
- /package/dist/{chunk-3JDA3XF5.js.map → chunk-AEGNDL24.js.map} +0 -0
- /package/dist/{chunk-2NAD4YCI.js.map → chunk-AEUMONCD.js.map} +0 -0
- /package/dist/{chunk-C6U57KG4.js.map → chunk-AF5PW35O.js.map} +0 -0
- /package/dist/{chunk-IOSZHHJC.js.map → chunk-ANGZWYL2.js.map} +0 -0
- /package/dist/{chunk-6LYAEM54.js.map → chunk-AXHU56C3.js.map} +0 -0
- /package/dist/{chunk-GWM6T5EQ.js.map → chunk-BCGMG2RD.js.map} +0 -0
- /package/dist/{chunk-HXCJF4XU.js.map → chunk-BFIZXFUG.js.map} +0 -0
- /package/dist/{chunk-DBYAY6UW.js.map → chunk-BTOHGPHC.js.map} +0 -0
- /package/dist/{chunk-5X4MXNEU.js.map → chunk-C6HPNPNK.js.map} +0 -0
- /package/dist/{chunk-4MP7XR5J.js.map → chunk-CAKHZAXH.js.map} +0 -0
- /package/dist/{chunk-YSBL7VPO.js.map → chunk-CDWFWOSZ.js.map} +0 -0
- /package/dist/{chunk-QAW55ZHJ.js.map → chunk-CZ44FH45.js.map} +0 -0
- /package/dist/{chunk-T3FMRLWQ.js.map → chunk-D5HQ3VEX.js.map} +0 -0
- /package/dist/{chunk-S7LWX2PQ.js.map → chunk-DPG5HQLE.js.map} +0 -0
- /package/dist/{chunk-C7ZDKWPS.js.map → chunk-DVSAMW5T.js.map} +0 -0
- /package/dist/{chunk-WBYQA3VN.js.map → chunk-E5H4TM4Y.js.map} +0 -0
- /package/dist/{chunk-4RL3JOB3.js.map → chunk-EEDI3OXB.js.map} +0 -0
- /package/dist/{chunk-3TB2XQ3C.js.map → chunk-EUL3S3LE.js.map} +0 -0
- /package/dist/{chunk-Q4AUIFUA.js.map → chunk-F23U5YE7.js.map} +0 -0
- /package/dist/{chunk-ZZZ4I455.js.map → chunk-GDVORIFM.js.map} +0 -0
- /package/dist/{chunk-SWBC3UER.js.map → chunk-HCPUVB7S.js.map} +0 -0
- /package/dist/{chunk-R3X2T2LP.js.map → chunk-HFOY2SBG.js.map} +0 -0
- /package/dist/{chunk-LU7E2MXE.js.map → chunk-HQCUUVG2.js.map} +0 -0
- /package/dist/{chunk-FJLQXMTU.js.map → chunk-I6B3S62A.js.map} +0 -0
- /package/dist/{chunk-RBITPCMK.js.map → chunk-IDSSDL4W.js.map} +0 -0
- /package/dist/{chunk-B3OFQP5Y.js.map → chunk-IY47KPML.js.map} +0 -0
- /package/dist/{chunk-AXC4WSF3.js.map → chunk-JDOBIFBK.js.map} +0 -0
- /package/dist/{chunk-P2ODTYOF.js.map → chunk-JGXHQV5N.js.map} +0 -0
- /package/dist/{chunk-7LNHRQKR.js.map → chunk-JLIGUFPF.js.map} +0 -0
- /package/dist/{chunk-EDIH6X2P.js.map → chunk-JZ66PN72.js.map} +0 -0
- /package/dist/{chunk-BLVR4WYU.js.map → chunk-KICEAGKM.js.map} +0 -0
- /package/dist/{chunk-VDX2J7OX.js.map → chunk-KQAFEZQX.js.map} +0 -0
- /package/dist/{chunk-PEBHPCX2.js.map → chunk-KTG23JDX.js.map} +0 -0
- /package/dist/{chunk-BOZJD5PK.js.map → chunk-KYOZ5E6V.js.map} +0 -0
- /package/dist/{chunk-2DLWLNO4.js.map → chunk-L3TZXELN.js.map} +0 -0
- /package/dist/{chunk-VALKBYBN.js.map → chunk-M3N2TUZ7.js.map} +0 -0
- /package/dist/{chunk-76M5OK7V.js.map → chunk-M7T2NKET.js.map} +0 -0
- /package/dist/{chunk-Z5LP6ILP.js.map → chunk-MZAH3CBT.js.map} +0 -0
- /package/dist/{chunk-QI7K7BZ5.js.map → chunk-NJW2ZG64.js.map} +0 -0
- /package/dist/{chunk-CZJA2EQE.js.map → chunk-NSKXRTVZ.js.map} +0 -0
- /package/dist/{chunk-4O4XCBOS.js.map → chunk-NUSQ3YEL.js.map} +0 -0
- /package/dist/{chunk-4OQET73E.js.map → chunk-O57FCN42.js.map} +0 -0
- /package/dist/{chunk-WKY7N3L7.js.map → chunk-OEBUAC3O.js.map} +0 -0
- /package/dist/{chunk-Y23L4YJV.js.map → chunk-OEIA4IHU.js.map} +0 -0
- /package/dist/{chunk-66DKTOBY.js.map → chunk-OGZC2WUX.js.map} +0 -0
- /package/dist/{chunk-3SGTV7RD.js.map → chunk-P62DSJUK.js.map} +0 -0
- /package/dist/{chunk-FKD656D2.js.map → chunk-PH2V7EXZ.js.map} +0 -0
- /package/dist/{chunk-KKNZ7PUZ.js.map → chunk-QAIKLICT.js.map} +0 -0
- /package/dist/{chunk-SSUDD72S.js.map → chunk-QPWUG2S3.js.map} +0 -0
- /package/dist/{chunk-GZDTVYK2.js.map → chunk-R36IBI2M.js.map} +0 -0
- /package/dist/{chunk-W3XXFPRI.js.map → chunk-R5B3OWI4.js.map} +0 -0
- /package/dist/{chunk-VL4X7ZHC.js.map → chunk-RFIJRZ4K.js.map} +0 -0
- /package/dist/{chunk-AEHVZY3X.js.map → chunk-RPVHRZ5C.js.map} +0 -0
- /package/dist/{chunk-X5SHE2O3.js.map → chunk-RVBLCU5C.js.map} +0 -0
- /package/dist/{chunk-BUQKSQXL.js.map → chunk-S533KGX6.js.map} +0 -0
- /package/dist/{chunk-STEOT4DI.js.map → chunk-SCPHU3RW.js.map} +0 -0
- /package/dist/{chunk-LV5H6FTN.js.map → chunk-SFSD5Q6O.js.map} +0 -0
- /package/dist/{chunk-AE5U5NMS.js.map → chunk-SMLKHXPF.js.map} +0 -0
- /package/dist/{chunk-AEU4EQGV.js.map → chunk-T7R5HI6A.js.map} +0 -0
- /package/dist/{chunk-H5BJWPUI.js.map → chunk-TVQZAQPE.js.map} +0 -0
- /package/dist/{chunk-XOV7NRY5.js.map → chunk-U46P4UAR.js.map} +0 -0
- /package/dist/{chunk-DZ42MDZE.js.map → chunk-UCJINCZT.js.map} +0 -0
- /package/dist/{chunk-5E6RYRYW.js.map → chunk-UG5V3Z3R.js.map} +0 -0
- /package/dist/{chunk-IW3RMBPB.js.map → chunk-VAOC6GHN.js.map} +0 -0
- /package/dist/{chunk-6UQFJULG.js.map → chunk-VBNA2JEN.js.map} +0 -0
- /package/dist/{chunk-HLB7GKGG.js.map → chunk-VOZNBQNL.js.map} +0 -0
- /package/dist/{chunk-NYKIUQL6.js.map → chunk-WHIGRW7T.js.map} +0 -0
- /package/dist/{chunk-AZSGSRIM.js.map → chunk-WHTMVTU4.js.map} +0 -0
- /package/dist/{chunk-AERXJCOG.js.map → chunk-WL7N5VGG.js.map} +0 -0
- /package/dist/{chunk-TFA6HPOA.js.map → chunk-WQUGCOKF.js.map} +0 -0
- /package/dist/{chunk-A4VSOUCB.js.map → chunk-WTZQM74L.js.map} +0 -0
- /package/dist/{chunk-DQEMWVMT.js.map → chunk-X7Y7WX73.js.map} +0 -0
- /package/dist/{chunk-T2YX56QI.js.map → chunk-XWSUK5GL.js.map} +0 -0
- /package/dist/{chunk-ACX55QDO.js.map → chunk-XYOT5GQU.js.map} +0 -0
- /package/dist/{chunk-Z6EZCN6Z.js.map → chunk-Y7427SL7.js.map} +0 -0
- /package/dist/{chunk-4KN2JLQV.js.map → chunk-YHZWVDP7.js.map} +0 -0
- /package/dist/{chunk-5MNUBT7T.js.map → chunk-ZFTODDTX.js.map} +0 -0
- /package/dist/{chunk-VVX5PZFS.js.map → chunk-ZHXSOMYH.js.map} +0 -0
- /package/dist/{chunk-CRXRZA3G.js.map → chunk-ZQTYWSO3.js.map} +0 -0
- /package/dist/{resolution-K4A3VPKZ.js.map → contradiction-scan-GGRTVB7C.js.map} +0 -0
- /package/dist/{first-start-migration-7OATHJKB.js.map → first-start-migration-OM3PHMZO.js.map} +0 -0
- /package/dist/{tier-stats-VF6DS52E.js.map → tier-stats-M2FMMD2N.js.map} +0 -0
|
@@ -186,6 +186,30 @@ export interface EmbeddingGenerationTransactionInput {
|
|
|
186
186
|
* (codex P1: a daemon mutation between census and lock was discarded).
|
|
187
187
|
*/
|
|
188
188
|
baseStates?: ReadonlyMap<string, { sha256: string }>;
|
|
189
|
+
/**
|
|
190
|
+
* Paths this apply is pre-authorized to remove (changeset deletes / remote
|
|
191
|
+
* tombstones). A base member absent from the under-lock census is
|
|
192
|
+
* divergence UNLESS it is pre-authorized — the retry after a response loss
|
|
193
|
+
* must re-apply idempotently instead of failing as diverged (#3150
|
|
194
|
+
* review). A pre-authorized member still present with a changed digest
|
|
195
|
+
* defers as before, so a daemon rewrite is never silently swept.
|
|
196
|
+
*/
|
|
197
|
+
justifiedRemovals?: ReadonlySet<string>;
|
|
198
|
+
/**
|
|
199
|
+
* Deletion revisions (mtimeMs by path) to record through the delete hook
|
|
200
|
+
* AFTER the swap publishes. Swept members bypass the per-file delete path,
|
|
201
|
+
* so without this their tombstones are lost and a later peer without
|
|
202
|
+
* shared-base evidence can reintroduce the removed shards (codex P1).
|
|
203
|
+
*/
|
|
204
|
+
deletionMtimeByPath?: ReadonlyMap<string, number>;
|
|
205
|
+
/**
|
|
206
|
+
* True when the incoming set claims to be a FRESH creation but carries no
|
|
207
|
+
* base evidence (manifested changeset members are all base-less upserts):
|
|
208
|
+
* a non-empty local generation must match the incoming set exactly or the
|
|
209
|
+
* apply defers as diverged, because the empty-base divergence skip would
|
|
210
|
+
* otherwise silently replace it (#3150 review).
|
|
211
|
+
*/
|
|
212
|
+
freshCreateClaim?: boolean;
|
|
189
213
|
io: EmbeddingGenerationTransactionIo;
|
|
190
214
|
now: number;
|
|
191
215
|
}
|
|
@@ -323,7 +347,11 @@ export async function applyEmbeddingGenerationTransaction(
|
|
|
323
347
|
// secure IO and defer the WHOLE generation when the disk no longer
|
|
324
348
|
// matches the shared base — a concurrent daemon mutation must never be
|
|
325
349
|
// silently discarded by the swap.
|
|
326
|
-
// No shared base (fresh catch-up) = no divergence semantics to protect
|
|
350
|
+
// No shared base (fresh catch-up) = no divergence semantics to protect,
|
|
351
|
+
// UNLESS the apply claims a fresh creation (manifested base-less
|
|
352
|
+
// upserts): an existing local generation must then match the incoming
|
|
353
|
+
// set exactly or defer, instead of being silently replaced.
|
|
354
|
+
const justifiedRemovals = input.justifiedRemovals ?? new Set<string>();
|
|
327
355
|
const baseStates = baseStatesForGeneration(input.baseStates, shardDirRel);
|
|
328
356
|
if (baseStates.size > 0) {
|
|
329
357
|
const localCensus = await censusGenerationState(io, root, markerRel, markerAbs, shardDirAbs, shardDirRel);
|
|
@@ -331,12 +359,23 @@ export async function applyEmbeddingGenerationTransaction(
|
|
|
331
359
|
const censusArr = [...localCensus].map(([relPath, sha256]) => ({ path: relPath, sha256 }));
|
|
332
360
|
const deferrals = divergedEmbeddingGenerationDeferrals({
|
|
333
361
|
incomingFiles: incomingGenerationStates(input),
|
|
334
|
-
|
|
362
|
+
// A pre-authorized removal keeps its base entry only while still on
|
|
363
|
+
// disk (digest auth): present members are compared normally — a
|
|
364
|
+
// daemon rewrite still defers — while an absent member is already
|
|
365
|
+
// applied and must not diverge the retry (#3150 review).
|
|
366
|
+
baseFiles: baseArr.filter((member) => !justifiedRemovals.has(member.path) || localCensus.has(member.path)),
|
|
335
367
|
currentFiles: censusArr,
|
|
336
368
|
});
|
|
369
|
+
const incomingShardPaths = new Set(input.incomingShardPaths);
|
|
337
370
|
const addedOrRemovedSinceBase =
|
|
338
|
-
censusArr.some((member) =>
|
|
339
|
-
|
|
371
|
+
censusArr.some((member) =>
|
|
372
|
+
!baseStates.has(member.path) &&
|
|
373
|
+
!justifiedRemovals.has(member.path) &&
|
|
374
|
+
// An incoming member found in the census is the apply's own
|
|
375
|
+
// already-published work (response-loss retry), not a local
|
|
376
|
+
// addition; its bytes were verified above.
|
|
377
|
+
!incomingShardPaths.has(member.path)) ||
|
|
378
|
+
baseArr.some((member) => !localCensus.has(member.path) && !justifiedRemovals.has(member.path));
|
|
340
379
|
if (deferrals.length > 0 || addedOrRemovedSinceBase) {
|
|
341
380
|
const handled = new Set<string>(input.incomingShardPaths);
|
|
342
381
|
if (input.incomingMarker) handled.add(input.incomingMarker.path);
|
|
@@ -355,6 +394,35 @@ export async function applyEmbeddingGenerationTransaction(
|
|
|
355
394
|
deferredLocalDivergence: true,
|
|
356
395
|
};
|
|
357
396
|
}
|
|
397
|
+
} else if (input.freshCreateClaim) {
|
|
398
|
+
const localCensus = await censusGenerationState(io, root, markerRel, markerAbs, shardDirAbs, shardDirRel);
|
|
399
|
+
if (localCensus.size > 0) {
|
|
400
|
+
const incomingArr = incomingGenerationStates(input).sort((left, right) => left.path.localeCompare(right.path));
|
|
401
|
+
const censusArr = [...localCensus]
|
|
402
|
+
.map(([relPath, sha256]) => ({ path: relPath, sha256 }))
|
|
403
|
+
.sort((left, right) => left.path.localeCompare(right.path));
|
|
404
|
+
const identical =
|
|
405
|
+
censusArr.length === incomingArr.length &&
|
|
406
|
+
censusArr.every((member, index) => member.path === incomingArr[index]?.path && member.sha256 === incomingArr[index]?.sha256);
|
|
407
|
+
if (!identical) {
|
|
408
|
+
const handled = new Set<string>(input.incomingShardPaths);
|
|
409
|
+
if (input.incomingMarker) handled.add(input.incomingMarker.path);
|
|
410
|
+
if (input.incomingMarkerPresent) handled.add(markerRel);
|
|
411
|
+
for (const relPath of localCensus.keys()) handled.add(relPath);
|
|
412
|
+
log.warn(
|
|
413
|
+
`embedding generation ${shardDirRel} deferred: base-less creation does not match the existing local generation under the mutation lock; nothing published, nothing removed`,
|
|
414
|
+
);
|
|
415
|
+
return {
|
|
416
|
+
shardDirRel,
|
|
417
|
+
upserted: 0,
|
|
418
|
+
deleted: 0,
|
|
419
|
+
writtenStates: new Map<string, OfflineSyncFileState>(),
|
|
420
|
+
removedPaths: new Set<string>(),
|
|
421
|
+
handledPaths: handled,
|
|
422
|
+
deferredLocalDivergence: true,
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
}
|
|
358
426
|
}
|
|
359
427
|
|
|
360
428
|
const published = new Map<string, Buffer>();
|
|
@@ -507,6 +575,32 @@ export async function applyEmbeddingGenerationTransaction(
|
|
|
507
575
|
log.warn(`embedding generation ${shardDirRel}: marker cleanup deferred after publish: ${err}`);
|
|
508
576
|
}
|
|
509
577
|
}
|
|
578
|
+
// Swept members bypass the per-file delete path, so record their
|
|
579
|
+
// deletion revisions here — mirroring the whole-generation removal
|
|
580
|
+
// path — or a later peer without shared-base evidence can reintroduce
|
|
581
|
+
// the removed shards (codex P1). An empty map still records (with
|
|
582
|
+
// `now`) when the caller declared a deletion context, so tombstones
|
|
583
|
+
// whose changeset deletes omit mtimeMs are not lost. Every member
|
|
584
|
+
// gets an attempt before the failure propagates: the push side then
|
|
585
|
+
// retries a fully-recorded apply or nothing, and the
|
|
586
|
+
// justified-removals exemption keeps that retry idempotent.
|
|
587
|
+
if (input.deletionMtimeByPath !== undefined && io.deleteFile) {
|
|
588
|
+
let firstTombstoneError: unknown = null;
|
|
589
|
+
for (const relPath of removedPaths) {
|
|
590
|
+
try {
|
|
591
|
+
await io.deleteFile({
|
|
592
|
+
root: root.abs,
|
|
593
|
+
path: relPath,
|
|
594
|
+
filePath: await resolveSafeArchiveTarget(root, relPath),
|
|
595
|
+
mtimeMs: input.deletionMtimeByPath.get(relPath) ?? input.now,
|
|
596
|
+
});
|
|
597
|
+
} catch (err) {
|
|
598
|
+
firstTombstoneError ??= err;
|
|
599
|
+
log.warn(`embedding generation ${shardDirRel}: tombstone recording failed for ${relPath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
if (firstTombstoneError) throw firstTombstoneError;
|
|
603
|
+
}
|
|
510
604
|
return {
|
|
511
605
|
shardDirRel,
|
|
512
606
|
upserted: published.size,
|
|
@@ -883,3 +977,177 @@ export function divergedEmbeddingGenerationDeferrals(options: {
|
|
|
883
977
|
}
|
|
884
978
|
return deferred.sort((left, right) => left.localeCompare(right));
|
|
885
979
|
}
|
|
980
|
+
|
|
981
|
+
// ---------------------------------------------------------------------------
|
|
982
|
+
// Snapshot-side generation routing, extracted from applyOfflineSyncSnapshot
|
|
983
|
+
// for issue #3150 so the changeset path could share the machinery without
|
|
984
|
+
// growing the offline-sync.ts ratchet ceiling. Behavior-preserving.
|
|
985
|
+
// ---------------------------------------------------------------------------
|
|
986
|
+
|
|
987
|
+
export interface IncomingEmbeddingGenerationApply {
|
|
988
|
+
transactionResults: EmbeddingGenerationTransactionResult[];
|
|
989
|
+
deferredGenerationDirs: Set<string>;
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
export interface IncomingEmbeddingGenerationApplyOptions {
|
|
993
|
+
root: SafeArchiveRoot;
|
|
994
|
+
incomingMap: ReadonlyMap<string, OfflineSyncFileState>;
|
|
995
|
+
incomingBuffers: ReadonlyMap<string, Buffer>;
|
|
996
|
+
baseMap: ReadonlyMap<string, OfflineSyncFileState>;
|
|
997
|
+
currentMap: ReadonlyMap<string, OfflineSyncFileState>;
|
|
998
|
+
deferredPaths: ReadonlySet<string>;
|
|
999
|
+
omittedGenerationDirs: ReadonlySet<string>;
|
|
1000
|
+
deletionMtimeByPath?: ReadonlyMap<string, number>;
|
|
1001
|
+
io: EmbeddingGenerationTransactionIo;
|
|
1002
|
+
/** True when the caller supplied ANY custom storage IO. */
|
|
1003
|
+
customIoPresent: boolean;
|
|
1004
|
+
now: number;
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
/**
|
|
1008
|
+
* Snapshot-side generation routing, extracted from applyOfflineSyncSnapshot
|
|
1009
|
+
* for issue #3150 (the changeset path needed the same machinery and the
|
|
1010
|
+
* offline-sync.ts line ratchet had no headroom). Incoming generations replace
|
|
1011
|
+
* as ONE unit through the shared locked transaction. Behavior-preserving —
|
|
1012
|
+
* the #3148 regression suites own this contract.
|
|
1013
|
+
*/
|
|
1014
|
+
export async function applyIncomingEmbeddingGenerations(
|
|
1015
|
+
options: IncomingEmbeddingGenerationApplyOptions,
|
|
1016
|
+
): Promise<IncomingEmbeddingGenerationApply> {
|
|
1017
|
+
const incomingGenerations = detectIncomingEmbeddingGenerations(options.incomingMap.keys());
|
|
1018
|
+
const generationDirs = new Set<string>([
|
|
1019
|
+
...incomingGenerations.shardDirs,
|
|
1020
|
+
...incomingGenerations.legacyMarkerDirs,
|
|
1021
|
+
]);
|
|
1022
|
+
const deferredGenerationDirs = new Set<string>();
|
|
1023
|
+
for (const deferredPath of options.deferredPaths) {
|
|
1024
|
+
const membership = embeddingGenerationMembership(deferredPath);
|
|
1025
|
+
if (membership) deferredGenerationDirs.add(membership.shardDir);
|
|
1026
|
+
}
|
|
1027
|
+
const transactionResults: EmbeddingGenerationTransactionResult[] = [];
|
|
1028
|
+
// Included and omitted cannot describe the same generation.
|
|
1029
|
+
for (const shardDir of generationDirs) {
|
|
1030
|
+
if (options.omittedGenerationDirs.has(shardDir)) {
|
|
1031
|
+
throw new EmbeddingIndexStorageError(
|
|
1032
|
+
`offline sync snapshot both includes and omits embedding generation ${shardDir}; refusing to apply`,
|
|
1033
|
+
);
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
// Fail closed BEFORE any publication: custom storage IO (encrypted or
|
|
1037
|
+
// otherwise) without the staging pair would make the generation transaction
|
|
1038
|
+
// fall back to unencrypted raw writes — a plaintext downgrade of the staged
|
|
1039
|
+
// generation. Callers must wire both staging hooks (the CLI does).
|
|
1040
|
+
if (
|
|
1041
|
+
generationDirs.size > 0 &&
|
|
1042
|
+
options.customIoPresent &&
|
|
1043
|
+
!(options.io.writeStagingFile && options.io.readStagingFile)
|
|
1044
|
+
) {
|
|
1045
|
+
throw new EmbeddingIndexStorageError(
|
|
1046
|
+
"refusing to replace embedding generation: custom storage IO requires both writeStagingFile and readStagingFile hooks; unencrypted raw staging would plaintext-downgrade the index",
|
|
1047
|
+
);
|
|
1048
|
+
}
|
|
1049
|
+
for (const shardDir of generationDirs) {
|
|
1050
|
+
if (deferredGenerationDirs.has(shardDir)) continue;
|
|
1051
|
+
if (
|
|
1052
|
+
incomingGenerations.legacyMarkerDirs.has(shardDir) &&
|
|
1053
|
+
!incomingGenerations.shardDirs.has(shardDir)
|
|
1054
|
+
) {
|
|
1055
|
+
// Cross-layout: an incoming legacy marker replaces a local sharded
|
|
1056
|
+
// generation as a whole (codex round 4). When shards are ALSO
|
|
1057
|
+
// incoming, the sharded set is the generation and the marker is
|
|
1058
|
+
// written as an inert artifact by the per-file loop below.
|
|
1059
|
+
const markerRel = [...options.incomingMap.keys()].find(
|
|
1060
|
+
(relPath) => embeddingMarkerDirOf(relPath) === shardDir.slice(0, -`/${EMBEDDING_SHARD_DIR_BASENAME}`.length),
|
|
1061
|
+
);
|
|
1062
|
+
if (!markerRel) continue;
|
|
1063
|
+
transactionResults.push(await applyEmbeddingGenerationTransaction({
|
|
1064
|
+
root: options.root,
|
|
1065
|
+
shardDirRel: shardDir,
|
|
1066
|
+
incomingShardPaths: [],
|
|
1067
|
+
incomingMarker: {
|
|
1068
|
+
path: markerRel,
|
|
1069
|
+
sha256: options.incomingMap.get(markerRel)!.sha256,
|
|
1070
|
+
buffer: options.incomingBuffers.get(markerRel) ?? null,
|
|
1071
|
+
},
|
|
1072
|
+
incomingMarkerPresent: false,
|
|
1073
|
+
incomingShardStates: new Map(),
|
|
1074
|
+
incomingBuffers: options.incomingBuffers,
|
|
1075
|
+
baseStates: options.baseMap,
|
|
1076
|
+
io: options.io,
|
|
1077
|
+
now: options.now,
|
|
1078
|
+
}));
|
|
1079
|
+
continue;
|
|
1080
|
+
}
|
|
1081
|
+
transactionResults.push(await applyEmbeddingGenerationTransaction({
|
|
1082
|
+
root: options.root,
|
|
1083
|
+
shardDirRel: shardDir,
|
|
1084
|
+
incomingShardPaths: [...options.incomingMap.keys()]
|
|
1085
|
+
.filter((relPath) => embeddingShardDirOf(relPath) === shardDir)
|
|
1086
|
+
.sort(),
|
|
1087
|
+
incomingMarker: null,
|
|
1088
|
+
incomingMarkerPresent: Boolean(
|
|
1089
|
+
incomingGenerations.legacyMarkerDirs.has(shardDir),
|
|
1090
|
+
),
|
|
1091
|
+
incomingShardStates: new Map(
|
|
1092
|
+
[...options.incomingMap.values()]
|
|
1093
|
+
.filter((state) => embeddingShardDirOf(state.path) === shardDir)
|
|
1094
|
+
.map((state) => [state.path, state]),
|
|
1095
|
+
),
|
|
1096
|
+
incomingBuffers: options.incomingBuffers,
|
|
1097
|
+
baseStates: options.baseMap,
|
|
1098
|
+
io: options.io,
|
|
1099
|
+
now: options.now,
|
|
1100
|
+
}));
|
|
1101
|
+
}
|
|
1102
|
+
// Whole-generation removal (codex round 6 P1): when the remote deleted a
|
|
1103
|
+
// previously shared sharded index, the deletion revisions cover EVERY
|
|
1104
|
+
// local member. Remove that generation as ONE atomic swap instead of
|
|
1105
|
+
// deleting shards one-by-one, so a crash or delete failure can never
|
|
1106
|
+
// expose a partial same-identity generation serving missing memories.
|
|
1107
|
+
const localGenerationDirs = new Set<string>();
|
|
1108
|
+
for (const relPath of options.currentMap.keys()) {
|
|
1109
|
+
const membership = embeddingGenerationMembership(relPath);
|
|
1110
|
+
if (membership?.kind === "shard") localGenerationDirs.add(membership.shardDir);
|
|
1111
|
+
}
|
|
1112
|
+
for (const shardDir of localGenerationDirs) {
|
|
1113
|
+
if (
|
|
1114
|
+
generationDirs.has(shardDir) ||
|
|
1115
|
+
deferredGenerationDirs.has(shardDir) ||
|
|
1116
|
+
options.omittedGenerationDirs.has(shardDir)
|
|
1117
|
+
) {
|
|
1118
|
+
continue;
|
|
1119
|
+
}
|
|
1120
|
+
const localMembers = [...options.currentMap.keys()].filter(
|
|
1121
|
+
(relPath) => embeddingGenerationMembership(relPath)?.shardDir === shardDir,
|
|
1122
|
+
);
|
|
1123
|
+
if (localMembers.length === 0) continue;
|
|
1124
|
+
// Tombstone or shared-base absence authorizes whole-generation removal.
|
|
1125
|
+
const baseMembers = localMembers.filter((relPath) => options.baseMap.has(relPath));
|
|
1126
|
+
// Tombstone evidence is satisfied by the members the REMOTE knew: the
|
|
1127
|
+
// remote cannot tombstone local-only extras or an inert legacy marker,
|
|
1128
|
+
// and the removal sweeps those once the remote deletion is established.
|
|
1129
|
+
// Non-empty same-generation tombstones establish remote absence on
|
|
1130
|
+
// their own: they may name shards already absent locally (removed in an
|
|
1131
|
+
// earlier round), so the set is NOT required to intersect localMembers
|
|
1132
|
+
// (codex round 6, XiOb).
|
|
1133
|
+
const tombstonedMembers =
|
|
1134
|
+
options.deletionMtimeByPath === undefined
|
|
1135
|
+
? []
|
|
1136
|
+
: [...options.deletionMtimeByPath.keys()].filter(
|
|
1137
|
+
(relPath) => embeddingGenerationMembership(relPath)?.shardDir === shardDir,
|
|
1138
|
+
);
|
|
1139
|
+
const tombstoneCovered = tombstonedMembers.length > 0;
|
|
1140
|
+
const baseEvidenced =
|
|
1141
|
+
baseMembers.length > 0 && baseMembers.every((relPath) => !options.incomingMap.has(relPath));
|
|
1142
|
+
if (!tombstoneCovered && !baseEvidenced) continue;
|
|
1143
|
+
transactionResults.push(await applyEmbeddingGenerationRemoval({
|
|
1144
|
+
root: options.root,
|
|
1145
|
+
shardDirRel: shardDir,
|
|
1146
|
+
io: { deleteFile: options.io.deleteFile, readFile: options.io.readFile },
|
|
1147
|
+
deletionMtimeByPath: options.deletionMtimeByPath,
|
|
1148
|
+
baseStates: options.baseMap,
|
|
1149
|
+
now: options.now,
|
|
1150
|
+
}));
|
|
1151
|
+
}
|
|
1152
|
+
return { transactionResults, deferredGenerationDirs };
|
|
1153
|
+
}
|
package/src/offline-sync.ts
CHANGED
|
@@ -27,21 +27,19 @@ import { parseFlexibleIsoTimestamp } from "./utils/iso-timestamp.js";
|
|
|
27
27
|
import { EmbeddingIndexStorageError } from "./embedding-index-storage.js";
|
|
28
28
|
import { matchesOfflineSyncDefaultExclude } from "./offline-sync-exclude-globs.js";
|
|
29
29
|
import {
|
|
30
|
-
|
|
31
|
-
applyEmbeddingGenerationRemoval,
|
|
32
|
-
applyEmbeddingGenerationTransaction,
|
|
30
|
+
applyIncomingEmbeddingGenerations,
|
|
33
31
|
assertEmbeddingGenerationStillIncluded,
|
|
34
32
|
computeOmittedEmbeddingGenerationPaths,
|
|
35
|
-
detectIncomingEmbeddingGenerations,
|
|
36
33
|
divergedEmbeddingGenerationDeferrals,
|
|
37
34
|
embeddingGenerationMembership,
|
|
38
|
-
embeddingMarkerDirOf,
|
|
39
|
-
embeddingShardDirOf,
|
|
40
35
|
isEmbeddingGenerationDirPath,
|
|
41
36
|
isPathInOmittedEmbeddingGeneration,
|
|
42
|
-
type EmbeddingGenerationTransactionIo,
|
|
43
|
-
type EmbeddingGenerationTransactionResult,
|
|
44
37
|
} from "./offline-sync-embedding-generation.js";
|
|
38
|
+
import {
|
|
39
|
+
applyChangesetEmbeddingGenerations,
|
|
40
|
+
normalizeChangesetGenerations,
|
|
41
|
+
type OfflineSyncChangesetGeneration,
|
|
42
|
+
} from "./offline-sync-changeset-generations.js";
|
|
45
43
|
import { withEmbeddingGenerationLock, withEmbeddingGenerationLockIter } from "./embedding-generation-lock.js";
|
|
46
44
|
import {
|
|
47
45
|
isCanonicalRuntimeStatePath,
|
|
@@ -50,6 +48,7 @@ import {
|
|
|
50
48
|
} from "./offline-sync-runtime-state.js";
|
|
51
49
|
export { shouldPreferIncomingOfflineRuntimeFile } from "./offline-sync-runtime-state.js";
|
|
52
50
|
export { computeOmittedEmbeddingGenerationPaths } from "./offline-sync-embedding-generation.js";
|
|
51
|
+
export type { OfflineSyncChangesetGeneration } from "./offline-sync-changeset-generations.js";
|
|
53
52
|
export {
|
|
54
53
|
compileOfflineSyncExcludeGlobs,
|
|
55
54
|
globToRegExp,
|
|
@@ -150,6 +149,13 @@ export interface OfflineSyncChangeset {
|
|
|
150
149
|
sourceId: string;
|
|
151
150
|
includeTranscripts: boolean;
|
|
152
151
|
changes: OfflineSyncChange[];
|
|
152
|
+
/**
|
|
153
|
+
* Complete post-change membership of every embedding generation the
|
|
154
|
+
* changeset touches (issue #3150). Absent on legacy senders: receivers
|
|
155
|
+
* defer manifest-less shard upserts as conflicts instead of publishing a
|
|
156
|
+
* mixed generation.
|
|
157
|
+
*/
|
|
158
|
+
embeddingGenerations?: OfflineSyncChangesetGeneration[];
|
|
153
159
|
}
|
|
154
160
|
|
|
155
161
|
export interface OfflineSyncState {
|
|
@@ -170,7 +176,12 @@ export interface OfflineSyncConflict {
|
|
|
170
176
|
| "remote_exists_for_local_create"
|
|
171
177
|
| "remote_changed_for_local_update"
|
|
172
178
|
| "remote_deleted_for_local_update"
|
|
173
|
-
| "remote_changed_for_local_delete"
|
|
179
|
+
| "remote_changed_for_local_delete"
|
|
180
|
+
// Changeset generation deferrals (#3150): the receiver refused a whole
|
|
181
|
+
// embedding generation; surfaced as conflicts so the push side never
|
|
182
|
+
// checkpoints it as applied.
|
|
183
|
+
| "embedding_generation_diverged"
|
|
184
|
+
| "embedding_generation_manifest_required";
|
|
174
185
|
baseSha256?: string;
|
|
175
186
|
localSha256?: string;
|
|
176
187
|
incomingSha256?: string;
|
|
@@ -637,6 +648,7 @@ export function normalizeOfflineSyncChangeset(
|
|
|
637
648
|
if (excludedPath) {
|
|
638
649
|
throw new Error(`offline sync changeset contains excluded path: ${excludedPath}`);
|
|
639
650
|
}
|
|
651
|
+
const embeddingGenerations = normalizeChangesetGenerations(obj.embeddingGenerations, changes);
|
|
640
652
|
return {
|
|
641
653
|
format: OFFLINE_SYNC_CHANGESET_FORMAT,
|
|
642
654
|
schemaVersion: 1,
|
|
@@ -644,6 +656,7 @@ export function normalizeOfflineSyncChangeset(
|
|
|
644
656
|
sourceId,
|
|
645
657
|
includeTranscripts,
|
|
646
658
|
changes: changes.sort(compareByPath),
|
|
659
|
+
...(embeddingGenerations === undefined ? {} : { embeddingGenerations }),
|
|
647
660
|
};
|
|
648
661
|
}
|
|
649
662
|
|
|
@@ -1614,159 +1627,28 @@ export async function applyOfflineSyncSnapshot(options: {
|
|
|
1614
1627
|
return requiredBuffer(incomingBuffers, relPath);
|
|
1615
1628
|
};
|
|
1616
1629
|
|
|
1617
|
-
// Embedding generations travel and replace as ONE unit (issue #3148)
|
|
1618
|
-
//
|
|
1619
|
-
//
|
|
1620
|
-
//
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
throw new EmbeddingIndexStorageError(
|
|
1640
|
-
`offline sync snapshot both includes and omits embedding generation ${shardDir}; refusing to apply`,
|
|
1641
|
-
);
|
|
1642
|
-
}
|
|
1643
|
-
}
|
|
1644
|
-
// Fail closed BEFORE any publication: custom storage IO (encrypted or
|
|
1645
|
-
// otherwise) without the staging pair would make the generation transaction
|
|
1646
|
-
// fall back to unencrypted raw writes — a plaintext downgrade of the staged
|
|
1647
|
-
// generation. Callers must wire both staging hooks (the CLI does).
|
|
1648
|
-
if (
|
|
1649
|
-
generationDirs.size > 0 &&
|
|
1650
|
-
(options.writeFile || options.readFile || options.readFileDigest || options.deleteFile) &&
|
|
1651
|
-
!(options.writeStagingFile && options.readStagingFile)
|
|
1652
|
-
) {
|
|
1653
|
-
throw new EmbeddingIndexStorageError(
|
|
1654
|
-
"refusing to replace embedding generation: custom storage IO requires both writeStagingFile and readStagingFile hooks; unencrypted raw staging would plaintext-downgrade the index",
|
|
1655
|
-
);
|
|
1656
|
-
}
|
|
1657
|
-
for (const shardDir of generationDirs) {
|
|
1658
|
-
if (deferredGenerationDirs.has(shardDir)) continue;
|
|
1659
|
-
if (
|
|
1660
|
-
incomingGenerations.legacyMarkerDirs.has(shardDir) &&
|
|
1661
|
-
!incomingGenerations.shardDirs.has(shardDir)
|
|
1662
|
-
) {
|
|
1663
|
-
// Cross-layout: an incoming legacy marker replaces a local sharded
|
|
1664
|
-
// generation as a whole (codex round 4). When shards are ALSO
|
|
1665
|
-
// incoming, the sharded set is the generation and the marker is
|
|
1666
|
-
// written as an inert artifact by the per-file loop below.
|
|
1667
|
-
const markerRel = [...incomingMap.keys()].find(
|
|
1668
|
-
(relPath) => embeddingMarkerDirOf(relPath) === shardDir.slice(0, -`/${EMBEDDING_SHARD_DIR_BASENAME}`.length),
|
|
1669
|
-
);
|
|
1670
|
-
if (!markerRel) continue;
|
|
1671
|
-
transactionResults.push(await applyEmbeddingGenerationTransaction({
|
|
1672
|
-
root,
|
|
1673
|
-
shardDirRel: shardDir,
|
|
1674
|
-
incomingShardPaths: [],
|
|
1675
|
-
incomingMarker: {
|
|
1676
|
-
path: markerRel,
|
|
1677
|
-
sha256: incomingMap.get(markerRel)!.sha256,
|
|
1678
|
-
buffer: incomingBuffers.get(markerRel) ?? null,
|
|
1679
|
-
},
|
|
1680
|
-
incomingMarkerPresent: false,
|
|
1681
|
-
incomingShardStates: new Map(),
|
|
1682
|
-
incomingBuffers,
|
|
1683
|
-
baseStates: baseMap,
|
|
1684
|
-
io: {
|
|
1685
|
-
readFile: options.readFile,
|
|
1686
|
-
writeStagingFile: options.writeStagingFile,
|
|
1687
|
-
readStagingFile: options.readStagingFile,
|
|
1688
|
-
deleteFile: options.deleteFile,
|
|
1689
|
-
},
|
|
1690
|
-
now: Date.now(),
|
|
1691
|
-
}));
|
|
1692
|
-
continue;
|
|
1693
|
-
}
|
|
1694
|
-
transactionResults.push(await applyEmbeddingGenerationTransaction({
|
|
1695
|
-
root,
|
|
1696
|
-
shardDirRel: shardDir,
|
|
1697
|
-
incomingShardPaths: [...incomingMap.keys()]
|
|
1698
|
-
.filter((relPath) => embeddingShardDirOf(relPath) === shardDir)
|
|
1699
|
-
.sort(),
|
|
1700
|
-
incomingMarker: null,
|
|
1701
|
-
incomingMarkerPresent: Boolean(
|
|
1702
|
-
incomingGenerations.legacyMarkerDirs.has(shardDir),
|
|
1703
|
-
),
|
|
1704
|
-
incomingShardStates: new Map(
|
|
1705
|
-
[...incomingMap.values()]
|
|
1706
|
-
.filter((relPath) => embeddingShardDirOf(relPath.path) === shardDir)
|
|
1707
|
-
.map((state) => [state.path, state]),
|
|
1708
|
-
),
|
|
1709
|
-
incomingBuffers,
|
|
1710
|
-
baseStates: baseMap,
|
|
1711
|
-
io: {
|
|
1712
|
-
readFile: options.readFile,
|
|
1713
|
-
writeStagingFile: options.writeStagingFile,
|
|
1714
|
-
readStagingFile: options.readStagingFile,
|
|
1715
|
-
deleteFile: options.deleteFile,
|
|
1716
|
-
},
|
|
1717
|
-
now: Date.now(),
|
|
1718
|
-
}));
|
|
1719
|
-
}
|
|
1720
|
-
// Whole-generation removal (codex round 6 P1): when the remote deleted a
|
|
1721
|
-
// previously shared sharded index, the deletion revisions cover EVERY
|
|
1722
|
-
// local member. Remove that generation as ONE atomic swap instead of
|
|
1723
|
-
// deleting shards one-by-one, so a crash or delete failure can never
|
|
1724
|
-
// expose a partial same-identity generation serving missing memories.
|
|
1725
|
-
const localGenerationDirs = new Set<string>();
|
|
1726
|
-
for (const relPath of currentMap.keys()) {
|
|
1727
|
-
const membership = embeddingGenerationMembership(relPath);
|
|
1728
|
-
if (membership?.kind === "shard") localGenerationDirs.add(membership.shardDir);
|
|
1729
|
-
}
|
|
1730
|
-
for (const shardDir of localGenerationDirs) {
|
|
1731
|
-
if (
|
|
1732
|
-
generationDirs.has(shardDir) ||
|
|
1733
|
-
deferredGenerationDirs.has(shardDir) ||
|
|
1734
|
-
omittedGenerationDirs.has(shardDir)
|
|
1735
|
-
) {
|
|
1736
|
-
continue;
|
|
1737
|
-
}
|
|
1738
|
-
const localMembers = [...currentMap.keys()].filter(
|
|
1739
|
-
(relPath) => embeddingGenerationMembership(relPath)?.shardDir === shardDir,
|
|
1740
|
-
);
|
|
1741
|
-
if (localMembers.length === 0) continue;
|
|
1742
|
-
// Tombstone or shared-base absence authorizes whole-generation removal.
|
|
1743
|
-
const baseMembers = localMembers.filter((relPath) => baseMap.has(relPath));
|
|
1744
|
-
// Tombstone evidence is satisfied by the members the REMOTE knew: the
|
|
1745
|
-
// remote cannot tombstone local-only extras or an inert legacy marker,
|
|
1746
|
-
// and the removal sweeps those once the remote deletion is established.
|
|
1747
|
-
// Non-empty same-generation tombstones establish remote absence on
|
|
1748
|
-
// their own: they may name shards already absent locally (removed in an
|
|
1749
|
-
// earlier round), so the set is NOT required to intersect localMembers
|
|
1750
|
-
// (codex round 6, XiOb).
|
|
1751
|
-
const tombstonedMembers =
|
|
1752
|
-
deletionMtimeByPath === undefined
|
|
1753
|
-
? []
|
|
1754
|
-
: [...deletionMtimeByPath.keys()].filter(
|
|
1755
|
-
(relPath) => embeddingGenerationMembership(relPath)?.shardDir === shardDir,
|
|
1756
|
-
);
|
|
1757
|
-
const tombstoneCovered = tombstonedMembers.length > 0;
|
|
1758
|
-
const baseEvidenced =
|
|
1759
|
-
baseMembers.length > 0 && baseMembers.every((relPath) => !incomingMap.has(relPath));
|
|
1760
|
-
if (!tombstoneCovered && !baseEvidenced) continue;
|
|
1761
|
-
transactionResults.push(await applyEmbeddingGenerationRemoval({
|
|
1762
|
-
root,
|
|
1763
|
-
shardDirRel: shardDir,
|
|
1764
|
-
io: { deleteFile: options.deleteFile, readFile: options.readFile },
|
|
1765
|
-
deletionMtimeByPath,
|
|
1766
|
-
baseStates: baseMap,
|
|
1767
|
-
now: Date.now(),
|
|
1768
|
-
}));
|
|
1769
|
-
}
|
|
1630
|
+
// Embedding generations travel and replace as ONE unit (issue #3148):
|
|
1631
|
+
// atomic replacement, cross-layout marker conversion, whole-generation
|
|
1632
|
+
// removal on tombstones — all extracted to the generation module (issue
|
|
1633
|
+
// #3150) so the changeset path can share it without growing this file.
|
|
1634
|
+
const { transactionResults, deferredGenerationDirs } = await applyIncomingEmbeddingGenerations({
|
|
1635
|
+
root,
|
|
1636
|
+
incomingMap,
|
|
1637
|
+
incomingBuffers,
|
|
1638
|
+
baseMap,
|
|
1639
|
+
currentMap,
|
|
1640
|
+
deferredPaths,
|
|
1641
|
+
omittedGenerationDirs,
|
|
1642
|
+
deletionMtimeByPath,
|
|
1643
|
+
io: {
|
|
1644
|
+
readFile: options.readFile,
|
|
1645
|
+
writeStagingFile: options.writeStagingFile,
|
|
1646
|
+
readStagingFile: options.readStagingFile,
|
|
1647
|
+
deleteFile: options.deleteFile,
|
|
1648
|
+
},
|
|
1649
|
+
customIoPresent: Boolean(options.writeFile || options.readFile || options.readFileDigest || options.deleteFile),
|
|
1650
|
+
now: Date.now(),
|
|
1651
|
+
});
|
|
1770
1652
|
|
|
1771
1653
|
const transactionHandled = new Set<string>();
|
|
1772
1654
|
let generationUpserted = 0;
|
|
@@ -1993,6 +1875,8 @@ export async function applyOfflineSyncChangeset(options: {
|
|
|
1993
1875
|
readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;
|
|
1994
1876
|
readFileDigest?: (target: OfflineSyncFileTarget) => Promise<OfflineSyncFileDigest>;
|
|
1995
1877
|
writeFile?: (target: OfflineSyncFileWriteTarget) => Promise<void>;
|
|
1878
|
+
writeStagingFile?: (target: OfflineSyncFileStagingWriteTarget) => Promise<void>;
|
|
1879
|
+
readStagingFile?: (target: OfflineSyncFileStagingReadTarget) => Promise<Buffer>;
|
|
1996
1880
|
deleteFile?: (target: OfflineSyncFileDeleteTarget) => Promise<void>;
|
|
1997
1881
|
recordDeletionRevision?: OfflineSyncRecordDeletionRevision;
|
|
1998
1882
|
}): Promise<OfflineSyncApplyChangesetResult> {
|
|
@@ -2030,7 +1914,30 @@ export async function applyOfflineSyncChangeset(options: {
|
|
|
2030
1914
|
let appliedDeletes = 0;
|
|
2031
1915
|
let skipped = 0;
|
|
2032
1916
|
|
|
1917
|
+
// Embedding generations apply as ONE unit through the shared locked
|
|
1918
|
+
// transaction (issue #3150). Deferred generations surface as conflicts so
|
|
1919
|
+
// the push side never checkpoints them as applied.
|
|
1920
|
+
const generationRouting = await applyChangesetEmbeddingGenerations({
|
|
1921
|
+
root,
|
|
1922
|
+
changeset,
|
|
1923
|
+
incomingBuffers,
|
|
1924
|
+
currentMap,
|
|
1925
|
+
io: {
|
|
1926
|
+
readFile: options.readFile,
|
|
1927
|
+
writeStagingFile: options.writeStagingFile,
|
|
1928
|
+
readStagingFile: options.readStagingFile,
|
|
1929
|
+
deleteFile: options.deleteFile,
|
|
1930
|
+
},
|
|
1931
|
+
customIoPresent: Boolean(options.writeFile || options.readFile || options.readFileDigest || options.deleteFile),
|
|
1932
|
+
now: Date.now(),
|
|
1933
|
+
});
|
|
1934
|
+
appliedUpserts += generationRouting.appliedUpserts;
|
|
1935
|
+
appliedDeletes += generationRouting.appliedDeletes;
|
|
1936
|
+
conflicts.push(...generationRouting.conflicts);
|
|
1937
|
+
|
|
2033
1938
|
for (const change of changeset.changes) {
|
|
1939
|
+
if (generationRouting.conflictedPaths.has(change.path)) continue;
|
|
1940
|
+
if (generationRouting.transactionHandled.has(change.path)) continue;
|
|
2034
1941
|
const currentEntry = currentMap.get(change.path);
|
|
2035
1942
|
if (change.type === "upsert") {
|
|
2036
1943
|
if (currentEntry?.sha256 === change.file.sha256) {
|
|
@@ -2110,6 +2017,12 @@ export async function applyOfflineSyncChangeset(options: {
|
|
|
2110
2017
|
});
|
|
2111
2018
|
}
|
|
2112
2019
|
|
|
2020
|
+
// Generation transactions bypassed the per-file loop; fold their published
|
|
2021
|
+
// and removed members into the partial result map (returnCurrentFiles ===
|
|
2022
|
+
// false consumers) so it reflects the post-apply generation exactly.
|
|
2023
|
+
for (const [relPath, state] of generationRouting.writtenStates) currentMap.set(relPath, state);
|
|
2024
|
+
for (const relPath of generationRouting.removedPaths) currentMap.delete(relPath);
|
|
2025
|
+
|
|
2113
2026
|
return {
|
|
2114
2027
|
appliedUpserts,
|
|
2115
2028
|
appliedDeletes,
|
|
@@ -199,6 +199,7 @@ export interface RecallInvocationOptions {
|
|
|
199
199
|
namespace?: string;
|
|
200
200
|
topK?: number;
|
|
201
201
|
mode?: RecallPlanMode;
|
|
202
|
+
onRecallPlanResolved?: (mode: RecallPlanMode, readNamespaces: readonly string[]) => void | Promise<void>;
|
|
202
203
|
abortSignal?: AbortSignal;
|
|
203
204
|
/** Server-resolved identity of the connector performing this recall. */
|
|
204
205
|
sourceConnector?: string;
|
|
@@ -689,7 +690,6 @@ export function buildCompressionGuidelinesMarkdown(
|
|
|
689
690
|
return buildCompressionGuidelinesMarkdownV2(events, generatedAtIso);
|
|
690
691
|
}
|
|
691
692
|
|
|
692
|
-
|
|
693
693
|
export function applyQueryAwareCandidateFilter(
|
|
694
694
|
candidates: QmdSearchResult[],
|
|
695
695
|
candidatePaths: Set<string> | null,
|