@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
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/storage/entity-canonical-id-lock.ts","../src/storage/entity-id-safety.ts","../src/storage/entity-canonical-id-references.ts"],"sourcesContent":["import { appendFileSync, mkdirSync, realpathSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { invalidateForScope } from \"../memory-cache.js\";\nimport { serializeMutations, withHeldFileLock } from \"../utils/serialize-mutations.js\";\n\nconst ENTITY_CANONICAL_ID_MUTATION_LOCK_STALE_MS = 60_000;\nconst ENTITY_CANONICAL_ID_MUTATION_LOCK_MAX_WAIT_MS = 300_000;\n\nexport function isEntityPagePath(baseDir: string, filePath: string): boolean {\n if (path.extname(filePath) !== \".md\") return false;\n const parentDir = path.dirname(path.resolve(filePath));\n const entitiesDir = path.resolve(baseDir, \"entities\");\n if (parentDir === entitiesDir) return true;\n try {\n return realpathSync(parentDir) === path.join(realpathSync(baseDir), \"entities\");\n } catch {\n return false;\n }\n}\n\nfunction recordRawEntityMutation(baseDir: string, stateDir: string): void {\n invalidateForScope(baseDir, \"entity-write\");\n mkdirSync(stateDir, { recursive: true });\n appendFileSync(path.join(stateDir, \".entity-mutation-version.log\"), \"x\");\n}\n\nexport function withEntityCanonicalMutationLock<T>(\n stateDir: string,\n task: (refreshLock: () => Promise<boolean>) => Promise<T>,\n): Promise<T> {\n const lockPath = path.join(stateDir, \"entity-canonical-id-mutation.lock\");\n return serializeMutations(lockPath, () =>\n withHeldFileLock(\n lockPath,\n {\n staleMs: ENTITY_CANONICAL_ID_MUTATION_LOCK_STALE_MS,\n maxWaitMs: ENTITY_CANONICAL_ID_MUTATION_LOCK_MAX_WAIT_MS,\n },\n async (acquired, lock) => {\n if (!acquired) throw new Error(\"Timed out waiting for entity mutation lock.\");\n return task(() => lock.refresh());\n },\n ),\n );\n}\n\nexport async function withRawEntityPageMutation<T>(\n baseDir: string,\n filePath: string,\n task: (refreshLock: () => Promise<boolean>) => Promise<T>,\n): Promise<T> {\n if (!isEntityPagePath(baseDir, filePath)) {\n return task(async () => true);\n }\n const stateDir = path.join(baseDir, \"state\");\n return withEntityCanonicalMutationLock(stateDir, async (refreshLock) => {\n try {\n return await task(refreshLock);\n } finally {\n recordRawEntityMutation(baseDir, stateDir);\n }\n });\n}\n","const UNSAFE_ENTITY_ID_PATTERN = /[\\/\\\\\\p{Cc}\\p{Zl}\\p{Zp}]/u;\n\nexport function assertSafeEntityId(entityId: string): void {\n if (UNSAFE_ENTITY_ID_PATTERN.test(entityId)) {\n throw new Error(\"Refusing unsafe entity id containing a path separator or control character.\");\n }\n}\n","import { statSync } from \"node:fs\";\n/**\n * Write-boundary surface of the entity canonical-id migration (issue #2213).\n *\n * The migration itself (entity-canonical-id-migration.ts) renames legacy\n * entity files and rewrites references ONCE, to convergence, then retires.\n * Everything here exists so nothing can re-introduce a legacy reference\n * afterwards without the migration having to rescan the corpus:\n *\n * - store-mediated writes canonicalize the caller-supplied `entityRef`\n * ({@link canonicalizeEntityRefOption});\n * - bulk writers that persist raw record bytes (capsule import/merge)\n * canonicalize the frontmatter line ({@link canonicalizeEntityRefFrontmatter});\n * - raw-byte writers that CANNOT parse what they write (offline sync,\n * consolidation-undo, governance restores) request one bounded\n * reconciliation pass instead ({@link requestEntityCanonicalIdReconcile}).\n */\nimport path from \"node:path\";\nimport {\n closeSync,\n constants,\n fstatSync,\n lstatSync,\n realpathSync,\n openSync,\n readFileSync,\n renameSync,\n rmSync,\n writeFileSync,\n} from \"node:fs\";\nimport { randomUUID } from \"node:crypto\";\nimport { log } from \"../logger.js\";\nimport { isErrnoCode } from \"../utils/errno.js\";\nimport { RECALL_FALLBACK_DIRS } from \"../utils/category-dir.js\";\nimport { withEntityCanonicalMutationLock } from \"./entity-canonical-id-lock.js\";\nimport { assertSafeEntityId } from \"./entity-id-safety.js\";\nimport { normalizeSupersessionKey } from \"../temporal-supersession.js\";\n\nexport const ENTITY_CANONICAL_ID_MIGRATION_FILE = \"entity-canonical-id-migration-v1.json\";\n\n/**\n * Parse a journal document into a mapping table. A document without a valid\n * `mappings` object is a LEGITIMATELY empty table; an unreadable/unparsable\n * document THROWS so callers can distinguish \"empty\" from \"failed\".\n */\nfunction parseJournalMappings(raw: string): Readonly<Record<string, string>> {\n const parsed: unknown = JSON.parse(raw);\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed) || !(\"mappings\" in parsed)) return {};\n const mappings = parsed.mappings;\n if (!mappings || typeof mappings !== \"object\" || Array.isArray(mappings)) return {};\n // Null prototype: journal-supplied ids like `constructor` must be own\n // entries, never collide with Object.prototype (Codex P2, round 20).\n const cleaned: Record<string, string> = Object.create(null) as Record<string, string>;\n for (const [legacyId, canonicalId] of Object.entries(mappings)) {\n if (legacyId.length > 0 && typeof canonicalId === \"string\" && canonicalId.length > 0) {\n assertSafeEntityId(legacyId);\n assertSafeEntityId(canonicalId);\n cleaned[legacyId] = canonicalId;\n }\n }\n return cleaned;\n}\n\n/** Whether the journal says its migration completed. Throws like the mapping parser. */\nfunction parseJournalComplete(raw: string): boolean {\n // SAFETY: JSON.parse output is unknown; the shape is validated on access.\n const parsed = JSON.parse(raw) as { complete?: unknown };\n return parsed !== null && parsed.complete === true;\n}\n\ntype JournalRead =\n | { kind: \"ok\"; raw: string; key: string }\n | { kind: \"missing\" }\n | { kind: \"refused\" }\n | { kind: \"error\" };\n\n/**\n * Open the journal WITHOUT following symlinks and read content + identity\n * from the same opened inode (repo rule: reject symlink traversal from\n * memory directories). O_NOFOLLOW makes the open refuse a symlinked FINAL\n * component (ELOOP); the parent `state/` directory is verified AFTER the\n * open, together with a path↔fd identity pairing, so a parent swapped\n * around the open cannot hold: a swap still in place fails the parent\n * lstat, and a swap reverted fails the dev/ino pairing against the real\n * journal. Platforms without O_NOFOLLOW get the same post-open checks.\n */\nfunction readJournalFileNoFollow(statePath: string): JournalRead {\n let fd: number;\n try {\n fd = openSync(statePath, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));\n } catch (error) {\n if (isErrnoCode(error, \"ENOENT\")) return { kind: \"missing\" };\n if (isErrnoCode(error, \"ELOOP\")) return { kind: \"refused\" };\n return { kind: \"error\" };\n }\n try {\n const s = fstatSync(fd);\n if (!s.isFile()) return { kind: \"refused\" };\n const parent = lstatSync(path.dirname(statePath));\n if (parent.isSymbolicLink() || !parent.isDirectory()) return { kind: \"refused\" };\n const l = lstatSync(statePath);\n if (l.isSymbolicLink() || l.dev !== s.dev || l.ino !== s.ino) return { kind: \"refused\" };\n return {\n kind: \"ok\",\n raw: readFileSync(fd, \"utf-8\"),\n key: `${s.dev}:${s.ino}:${s.mtimeMs}:${s.ctimeMs}:${s.size}`,\n };\n } catch {\n return { kind: \"error\" };\n } finally {\n closeSync(fd);\n }\n}\n\nexport function loadHistoricalEntityCanonicalIds(stateDir: string): Readonly<Record<string, string>> {\n const result = readJournalFileNoFollow(path.join(stateDir, ENTITY_CANONICAL_ID_MIGRATION_FILE));\n if (result.kind !== \"ok\") return {};\n try {\n return parseJournalMappings(result.raw);\n } catch {\n return {};\n }\n}\n\n/**\n * Append a tombstone with its identity canonicalized against the CURRENT\n * journal, then recheck: a peer publishing a mapping inside the\n * resolve-to-append window would leave the guard under the legacy id while\n * lookups canonicalize. Each identity change appends the replacement FIRST\n * (AGENTS.md §14 — the retired fact must never be without an active guard),\n * then revokes the superseded one — a park makes the prior canonical\n * claimant a distinct entity, and a stale keyed guard under it would\n * suppress that entity's facts. When the journal will not settle, one final\n * replacement runs under the entity MUTATION lock (parks publish under it).\n */\nexport async function appendCanonicalizedTombstone(\n stateDir: string,\n input: { entityRef?: string; supersessionKey?: string },\n currentIds: () => Readonly<Record<string, string>>,\n append: (identity: TombstoneIdentity) => Promise<string | null>,\n revoke: (tombstoneId: string) => Promise<unknown>,\n label: string,\n): Promise<string | null> {\n let refIds = currentIds();\n let identity = canonicalizeTombstoneIdentity(input.entityRef, input.supersessionKey, refIds);\n let result = await append(identity);\n const replaceIfChanged = async (next: TombstoneIdentity): Promise<boolean> => {\n if (next.entityRef === identity.entityRef && next.supersessionKey === identity.supersessionKey) {\n return false;\n }\n identity = next;\n const superseded = result;\n result = await append(next);\n if (superseded !== null) {\n try {\n await revoke(superseded);\n } catch (err) {\n log.warn(`failed to revoke superseded tombstone ${superseded} for ${label}: ${err}`);\n }\n }\n return true;\n };\n for (let attempt = 0; attempt < 3; attempt += 1) {\n const fresh = currentIds();\n if (fresh === refIds) return result;\n refIds = fresh;\n if (!(await replaceIfChanged(canonicalizeTombstoneIdentity(input.entityRef, input.supersessionKey, fresh)))) {\n return result;\n }\n }\n await withEntityCanonicalMutationLock(stateDir, async () => {\n await replaceIfChanged(canonicalizeTombstoneIdentity(input.entityRef, input.supersessionKey, currentIds()));\n });\n return result;\n}\n\n/**\n * Journal mapping table keyed by the journal FILE's identity, so a long-lived\n * StorageManager never canonicalizes against a stale snapshot after ANY other\n * writer changes the journal — a peer process completing a migration, or\n * `pruneBlocked()` parking a contested mapping (which rewrites the journal\n * without bumping any shared version). `writeState` publishes via\n * temp-file-plus-rename, so every journal write swaps the inode and the key\n * always moves — the identity is taken from the fstat of the SAME opened\n * inode the content is read from (no stat→read window). Reload cost is one\n * open per lookup and one journal parse per actual change.\n *\n * Failure semantics: last-known data is served ONLY for the SAME state dir\n * (module-level instances can face several stores — another store's table\n * must never leak in), and a failed read/parse never commits the journal's\n * identity, so the next lookup retries instead of caching an empty table\n * under a valid key.\n */\n\n/** Journal lookup result: mapping table plus its completion flag. */\nexport type HistoricalEntityIdsEntry = {\n mappings: Readonly<Record<string, string>>;\n complete: boolean;\n};\n\n\n\n/**\n * Memoized journal-completion view keyed on the journal file's stat identity.\n * entityList consults completion once per listed entity; without this each\n * consult re-opens and re-reads the journal (quadratic I/O on large corpora).\n */\nexport function memoizedJournalCompletion(\n cache: HistoricalEntityCanonicalIdCache,\n stateDir: () => string,\n): () => boolean {\n let memo: { key: string; complete: boolean } | undefined;\n return (): boolean => {\n let key = \"missing\";\n try {\n const journalPath = path.join(stateDir(), ENTITY_CANONICAL_ID_MIGRATION_FILE);\n const j = statSync(journalPath);\n key = `${j.dev}:${j.ino}:${j.mtimeMs}:${j.ctimeMs}:${j.size}`;\n } catch {\n key = \"missing\";\n }\n if (memo && memo.key === key) return memo.complete;\n const entry = cache.getEntry(stateDir());\n memo = { key, complete: entry.complete };\n return memo.complete;\n };\n}\n\nexport class HistoricalEntityCanonicalIdCache {\n private mappings: Readonly<Record<string, string>> = {};\n private complete = false;\n private key: string | null = null;\n private stateDir: string | null = null;\n\n get(stateDir: string): Readonly<Record<string, string>> {\n return this.getEntry(stateDir).mappings;\n }\n\n\n /** Table plus the journal's completion flag, cached under one identity. */\n getEntry(stateDir: string): HistoricalEntityIdsEntry {\n const lastKnownMappings = this.stateDir === stateDir ? this.mappings : {};\n const lastKnownComplete = this.stateDir === stateDir ? this.complete : false;\n const lastKnown: HistoricalEntityIdsEntry = { mappings: lastKnownMappings, complete: lastKnownComplete };\n const result = readJournalFileNoFollow(path.join(stateDir, ENTITY_CANONICAL_ID_MIGRATION_FILE));\n if (result.kind === \"refused\") {\n // Symlinked/non-regular journal: never follow it, never adopt its\n // identity — serve this store's last-known table. If it later becomes\n // a regular file its identity differs from the stored key and reloads.\n log.warn(\"ignoring non-regular entity canonical-id journal (symlink refused)\");\n return lastKnown;\n }\n if (result.kind === \"error\") {\n // A TRANSIENT open/read failure (EACCES/EIO) must not dump a valid\n // table for {}: a write during the outage would skip canonicalization\n // AND its post-write identity check would compare equal. Serve this\n // store's last-known table; only a genuine ENOENT means \"no journal\".\n return lastKnown;\n }\n const key = result.kind === \"missing\" ? \"missing\" : result.key;\n if (key !== this.key || stateDir !== this.stateDir) {\n let table: Readonly<Record<string, string>> = {};\n let complete = false;\n if (result.kind === \"ok\") {\n try {\n table = parseJournalMappings(result.raw);\n complete = parseJournalComplete(result.raw);\n } catch {\n // Parse failed under a VALID identity: do not commit the key —\n // the next lookup retries instead of pinning an empty table.\n return lastKnown;\n }\n }\n this.mappings = table;\n this.complete = complete;\n this.key = key;\n this.stateDir = stateDir;\n }\n return { mappings: this.mappings, complete: this.complete };\n }\n}\n\nexport function resolveHistoricalEntityCanonicalId(\n normalized: string,\n mappings: Readonly<Record<string, string>>,\n): string {\n let current = normalized;\n const seen = new Set<string>();\n while (!seen.has(current)) {\n seen.add(current);\n // Own properties only: an unmapped id like `constructor` must not read\n // Object.prototype and return a function (Codex P2, round 20).\n const next = Object.hasOwn(mappings, current) ? mappings[current] : undefined;\n if (!next || next === current) break;\n current = next;\n }\n return current;\n}\n\n/**\n * Canonicalize the `entityRef` a memory-write caller supplied (issue #2213).\n *\n * Extraction and capture callers pass whatever id the LLM or user produced,\n * which can name a legacy id this migration already renamed. Resolving at the\n * WRITE boundary means store-mediated writes can never re-introduce legacy\n * references — which is what let the completed migration retire its recurring\n * full-corpus reference rewrite. It also keeps write-time tombstone lookups on\n * the same id space as migrated tombstones. Unknown ids pass through verbatim.\n */\nexport function canonicalizeEntityRefOption<T extends { entityRef?: string }>(\n options: T,\n mappings: Readonly<Record<string, string>>,\n): T {\n // Non-strings (absent, or a JS caller's null/junk) pass through untouched:\n // this boundary canonicalizes ids, it does not take over input validation\n // the write path never performed — serialization already drops falsy refs.\n if (typeof options.entityRef !== \"string\") return options;\n return { ...options, entityRef: resolveHistoricalEntityCanonicalId(options.entityRef, mappings) };\n}\n\n/**\n * Canonicalize the effective `entityRef:` line inside a raw memory record's\n * leading frontmatter block (issue #2213). Bulk writers that persist record\n * bytes verbatim — capsule import/merge — are a write boundary too: a capsule\n * can carry pre-migration memories whose refs the target's completed journal\n * already renamed, and no later reconciliation pass exists to absorb them.\n *\n * Line selection mirrors the frontmatter parser and the migration's own\n * serializer: the LAST `entityRef` key wins (indentation tolerated), its\n * indent is preserved, and CRLF records keep their line endings. The closing\n * delimiter must be a standalone `---` line. Non-frontmatter content, records\n * without an `entityRef` line, and ids the journal does not map all pass\n * through byte-identical.\n */\nexport function canonicalizeEntityRefFrontmatter(\n content: string,\n mappings: Readonly<Record<string, string>>,\n): string {\n if (Object.keys(mappings).length === 0) return content;\n const loc = locateEntityRefLine(content);\n if (loc === null) return content;\n const canonical = resolveHistoricalEntityCanonicalId(loc.value, mappings);\n if (canonical === loc.value) return content;\n const line = loc.lines[loc.index]!;\n const indent = /^\\s*/.exec(line)?.[0] ?? \"\";\n loc.lines[loc.index] = `${indent}entityRef: ${canonical}${line.endsWith(\"\\r\") ? \"\\r\" : \"\"}`;\n return loc.lines.join(\"\\n\") + content.slice(loc.closeIndex);\n}\n\n/** The raw `entityRef` value in a record's leading frontmatter, or null. */\nexport function readEntityRefFromFrontmatter(content: string): string | null {\n return locateEntityRefLine(content)?.value ?? null;\n}\n\nfunction locateEntityRefLine(\n content: string,\n): { lines: string[]; index: number; value: string; closeIndex: number } | null {\n if (!/^---\\r?\\n/.test(content)) return null;\n const close = /\\r?\\n---(?:\\r?\\n|$)/g;\n close.lastIndex = content.indexOf(\"\\n\") + 1;\n const closeMatch = close.exec(content);\n if (!closeMatch) return null;\n const lines = content.slice(0, closeMatch.index).split(\"\\n\");\n let index = -1;\n for (let i = 1; i < lines.length; i += 1) {\n if (/^\\s*entityRef\\s*:/.test(lines[i] ?? \"\")) index = i;\n }\n if (index === -1) return null;\n const line = lines[index]!;\n const value = line.slice(line.indexOf(\":\") + 1).replace(/\\r$/, \"\").trim();\n if (value.length === 0) return null;\n return { lines, index, value, closeIndex: closeMatch.index };\n}\n\n/**\n * Reconcile-pending marker (issue #2213). Raw-byte memory writers that CANNOT\n * canonicalize inline — offline-sync file replication (opaque, possibly\n * encrypted buffers), consolidation-undo restores, governance-run restores —\n * touch this marker instead. The next migration invocation honors it by\n * running ONE bounded reference-reconciliation pass over the completed\n * journal's retained mappings, then clears it. This replaces the retired\n * every-run corpus rewrite with a signal that fires only when a raw writer\n * actually landed unvetted bytes.\n */\nexport const ENTITY_CANONICAL_ID_RECONCILE_MARKER = \"entity-canonical-id-reconcile.pending\";\n/** The generation a migration run renamed aside for consumption; a crash can strand it. */\nexport const ENTITY_CANONICAL_ID_RECONCILE_CONSUMING_MARKER = `${ENTITY_CANONICAL_ID_RECONCILE_MARKER}.consuming`;\n\nexport function requestEntityCanonicalIdReconcileSync(stateDir: string): void {\n const markerPath = path.join(stateDir, ENTITY_CANONICAL_ID_RECONCILE_MARKER);\n const temporary = `${markerPath}.${process.pid}.${randomUUID()}.tmp`;\n try {\n // Never write THROUGH a symlinked marker OR a symlinked state dir (repo\n // rule: reject symlink traversal from memory directories). The parent is\n // lstat-verified as a real directory — direct restore/import callers can\n // reach this helper without validateRoots() — and temp-file-plus-rename\n // handles the final component: rename() replaces a planted link ITSELF\n // rather than following it, with no O_NOFOLLOW dependency.\n const parent = lstatSync(stateDir);\n if (parent.isSymbolicLink() || !parent.isDirectory()) {\n log.warn(`refusing to write entity canonical-id reconcile marker: ${stateDir} is not a real directory`);\n return;\n }\n const parentRealPath = realpathSync(stateDir);\n writeFileSync(temporary, `${new Date().toISOString()}\\n`, { mode: 0o600 });\n // Revalidate the parent between the temp write and publication (Codex\n // P2, round 20): a state-dir swapped for a symlink after the check above\n // would have landed the temp file through the link. Node has no openat,\n // so the residual window is the realpath→rename gap — this recheck\n // reduces check-then-use to the platform primitive's own atomicity.\n const recheck = lstatSync(stateDir);\n if (recheck.isSymbolicLink() || !recheck.isDirectory() || realpathSync(stateDir) !== parentRealPath) {\n rmSync(temporary, { force: true });\n log.warn(`refusing to publish entity canonical-id reconcile marker: ${stateDir} changed during write`);\n return;\n }\n renameSync(temporary, markerPath);\n } catch (error) {\n rmSync(temporary, { force: true });\n // Best effort by design: a marker failure must not fail the restore/sync\n // that requested it (AGENTS.md §4). The reference stays legacy-but-readable\n // until the next mapping change.\n log.warn(`could not request entity canonical-id reconcile: ${error}`);\n }\n}\n\nexport async function requestEntityCanonicalIdReconcile(stateDir: string): Promise<void> {\n requestEntityCanonicalIdReconcileSync(stateDir);\n}\n\n/**\n * Post-persist TOCTOU guard (issue #2213). A writer resolves `entityRef`\n * against one journal generation, then awaits (snapshots, locks, fsyncs)\n * before its bytes land — a peer migration can publish AND finish its final\n * reference scan inside that window, leaving the just-written file behind.\n * Callers pass the mapping table captured at resolve time plus a fresh cache\n * read taken AFTER the write: the cache returns the identical object while\n * the journal file is unchanged, so an identity mismatch means the journal\n * moved mid-write and one bounded reconcile pass is requested.\n */\nexport function reconcileIfJournalMovedSync(\n stateDir: string,\n idsAtResolve: Readonly<Record<string, string>>,\n idsAfterWrite: Readonly<Record<string, string>>,\n): void {\n if (idsAtResolve === idsAfterWrite) return;\n requestEntityCanonicalIdReconcileSync(stateDir);\n}\n\nexport async function reconcileIfJournalMoved(\n stateDir: string,\n idsAtResolve: Readonly<Record<string, string>>,\n idsAfterWrite: Readonly<Record<string, string>>,\n): Promise<void> {\n reconcileIfJournalMovedSync(stateDir, idsAtResolve, idsAfterWrite);\n}\n\n/**\n * Classify a raw write target for entity-reference handling (issue #2213):\n * - `\"memory\"` — hot recall / cold / archive record whose FRONTMATTER\n * `entityRef` the writer must canonicalize at the write (and repair after).\n * - `\"entity\"` — an `entities/` page. Its migrated surface is relationship\n * TARGETS in the body, which only `rewriteRelationshipTargets` understands;\n * raw writers persist bytes faithfully and request the bounded reconcile\n * pass instead of attempting a frontmatter rewrite.\n * - `\"outside\"` — transcripts, profiles, runtime state, and every other file\n * outside the migration's scan scope: write byte-identical, no marker.\n */\nexport type EntityRefWritePathKind = \"memory\" | \"entity\" | \"outside\";\n\nexport function classifyEntityRefWritePath(baseDir: string, filePath: string): EntityRefWritePathKind {\n if (!filePath.endsWith(\".md\")) return \"outside\";\n const rel = path.relative(baseDir, filePath);\n if (rel.startsWith(\"..\") || path.isAbsolute(rel)) return \"outside\";\n const top = rel.split(path.sep)[0] ?? \"\";\n if (top === \"entities\") return \"entity\";\n return RECALL_FALLBACK_DIRS.includes(top) || top === \"cold\" || top === \"archive\" ? \"memory\" : \"outside\";\n}\n\n/** True when `filePath` is in the migration's scan scope at all. */\nexport function pathMayCarryEntityRefs(baseDir: string, filePath: string): boolean {\n return classifyEntityRefWritePath(baseDir, filePath) !== \"outside\";\n}\n\n/**\n * Canonicalize a tombstone's identity fields at the append chokepoint\n * (issue #2213): emitters (forget, temporal supersession, pattern\n * reinforcement, supersede) build inputs from records that may have been\n * read before a peer migration completed. The supersession key embeds the\n * NORMALIZED entity segment (`entity::attr`), so it is re-prefixed when the\n * ref moved — otherwise the keyed guard lands in the legacy id space while\n * write-time lookups canonicalize, and a paraphrase resurrects.\n */\nexport interface TombstoneIdentity {\n entityRef: string | undefined;\n supersessionKey: string | undefined;\n}\n\nexport function canonicalizeTombstoneIdentity(\n entityRef: string | undefined,\n supersessionKey: string | undefined,\n refIds: Readonly<Record<string, string>>,\n): TombstoneIdentity {\n if (typeof entityRef !== \"string\") return { entityRef, supersessionKey };\n const canonical = resolveHistoricalEntityCanonicalId(entityRef, refIds);\n if (canonical === entityRef) return { entityRef, supersessionKey };\n if (supersessionKey) {\n const stalePrefix = `${normalizeSupersessionKey(entityRef)}::`;\n if (supersessionKey.startsWith(stalePrefix)) {\n supersessionKey = `${normalizeSupersessionKey(canonical)}::${supersessionKey.slice(stalePrefix.length)}`;\n }\n }\n return { entityRef: canonical, supersessionKey };\n}\n\n/**\n * Post-persist repair (issue #2213): when the journal moved across a persist,\n * re-resolve the caller's ORIGINAL ref against the fresh table and rewrite\n * the file in place (bounded). When the journal will not settle, take the\n * entity MUTATION lock — parks/removals (the direction the reconcile pass\n * cannot repair, because the removed mapping is gone from the table) publish\n * under it — settle once, then request the marker for additive moves only.\n */\nexport async function repairEntityRefAfterJournalMove(options: {\n stateDir: string;\n currentIds: () => Readonly<Record<string, string>>;\n idsAtResolve: Readonly<Record<string, string>>;\n rawRef: string;\n frontmatter: { entityRef?: string };\n rewrite: () => Promise<void>;\n}): Promise<void> {\n let refIds = options.idsAtResolve;\n for (let attempt = 0; attempt < 3; attempt += 1) {\n const fresh = options.currentIds();\n if (fresh === refIds) return;\n refIds = fresh;\n const desired = resolveHistoricalEntityCanonicalId(options.rawRef, fresh);\n if (desired === options.frontmatter.entityRef) return;\n options.frontmatter.entityRef = desired;\n await options.rewrite();\n }\n await withEntityCanonicalMutationLock(options.stateDir, async () => {\n const desired = resolveHistoricalEntityCanonicalId(options.rawRef, options.currentIds());\n if (desired !== options.frontmatter.entityRef) {\n options.frontmatter.entityRef = desired;\n await options.rewrite();\n }\n });\n await requestEntityCanonicalIdReconcile(options.stateDir);\n}\n\n/**\n * Content-form counterpart of {@link repairEntityRefAfterJournalMove} for\n * async writers that persist raw record bytes (capsule import/merge,\n * binary-lifecycle redirects): same bounded loop, same locked settle.\n */\nexport async function repairContentAfterJournalMove(options: {\n stateDir: string;\n cache: HistoricalEntityCanonicalIdCache;\n idsAtWrite: Readonly<Record<string, string>>;\n rawContent: string;\n lastWritten: string;\n rewrite: (content: string) => Promise<void>;\n}): Promise<void> {\n let refIds = options.idsAtWrite;\n let written = options.lastWritten;\n for (let attempt = 0; attempt < 3; attempt += 1) {\n const fresh = options.cache.get(options.stateDir);\n if (fresh === refIds) return;\n refIds = fresh;\n const desired = canonicalizeEntityRefFrontmatter(options.rawContent, fresh);\n if (desired === written) return;\n written = desired;\n await options.rewrite(desired);\n }\n await withEntityCanonicalMutationLock(options.stateDir, async () => {\n const desired = canonicalizeEntityRefFrontmatter(options.rawContent, options.cache.get(options.stateDir));\n if (desired !== written) {\n written = desired;\n await options.rewrite(desired);\n }\n });\n await requestEntityCanonicalIdReconcile(options.stateDir);\n}\n\n/**\n * Sync variant (space promotion, curation, review actions). Sync callers\n * cannot take the async mutation lock, so exhaustion surfaces a retryable\n * error after requesting the marker — a silent return could leave the bytes\n * on a parked canonical claimant the reconcile pass cannot restore.\n */\nexport function repairContentAfterJournalMoveSync(options: {\n stateDir: string;\n cache: HistoricalEntityCanonicalIdCache;\n idsAtWrite: Readonly<Record<string, string>>;\n rawContent: string;\n lastWritten: string;\n rewrite: (content: string) => void;\n}): void {\n let refIds = options.idsAtWrite;\n let written = options.lastWritten;\n for (let attempt = 0; attempt < 3; attempt += 1) {\n const fresh = options.cache.get(options.stateDir);\n if (fresh === refIds) return;\n refIds = fresh;\n const desired = canonicalizeEntityRefFrontmatter(options.rawContent, fresh);\n if (desired === written) return;\n written = desired;\n options.rewrite(desired);\n }\n requestEntityCanonicalIdReconcileSync(options.stateDir);\n throw new Error(\n \"entity canonical-id journal kept changing during post-write repair; retry the write\",\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,gBAAgB,WAAW,oBAAoB;AACxD,OAAO,UAAU;AAIjB,IAAM,6CAA6C;AACnD,IAAM,gDAAgD;AAE/C,SAAS,iBAAiB,SAAiB,UAA2B;AAC3E,MAAI,KAAK,QAAQ,QAAQ,MAAM,MAAO,QAAO;AAC7C,QAAM,YAAY,KAAK,QAAQ,KAAK,QAAQ,QAAQ,CAAC;AACrD,QAAM,cAAc,KAAK,QAAQ,SAAS,UAAU;AACpD,MAAI,cAAc,YAAa,QAAO;AACtC,MAAI;AACF,WAAO,aAAa,SAAS,MAAM,KAAK,KAAK,aAAa,OAAO,GAAG,UAAU;AAAA,EAChF,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,wBAAwB,SAAiB,UAAwB;AACxE,qBAAmB,SAAS,cAAc;AAC1C,YAAU,UAAU,EAAE,WAAW,KAAK,CAAC;AACvC,iBAAe,KAAK,KAAK,UAAU,8BAA8B,GAAG,GAAG;AACzE;AAEO,SAAS,gCACd,UACA,MACY;AACZ,QAAM,WAAW,KAAK,KAAK,UAAU,mCAAmC;AACxE,SAAO;AAAA,IAAmB;AAAA,IAAU,MAClC;AAAA,MACE;AAAA,MACA;AAAA,QACE,SAAS;AAAA,QACT,WAAW;AAAA,MACb;AAAA,MACA,OAAO,UAAU,SAAS;AACxB,YAAI,CAAC,SAAU,OAAM,IAAI,MAAM,6CAA6C;AAC5E,eAAO,KAAK,MAAM,KAAK,QAAQ,CAAC;AAAA,MAClC;AAAA,IACF;AAAA,EACF;AACF;AAEA,eAAsB,0BACpB,SACA,UACA,MACY;AACZ,MAAI,CAAC,iBAAiB,SAAS,QAAQ,GAAG;AACxC,WAAO,KAAK,YAAY,IAAI;AAAA,EAC9B;AACA,QAAM,WAAW,KAAK,KAAK,SAAS,OAAO;AAC3C,SAAO,gCAAgC,UAAU,OAAO,gBAAgB;AACtE,QAAI;AACF,aAAO,MAAM,KAAK,WAAW;AAAA,IAC/B,UAAE;AACA,8BAAwB,SAAS,QAAQ;AAAA,IAC3C;AAAA,EACF,CAAC;AACH;;;AC9DA,IAAM,2BAA2B;AAE1B,SAAS,mBAAmB,UAAwB;AACzD,MAAI,yBAAyB,KAAK,QAAQ,GAAG;AAC3C,UAAM,IAAI,MAAM,6EAA6E;AAAA,EAC/F;AACF;;;ACNA,SAAS,gBAAgB;AAiBzB,OAAOA,WAAU;AACjB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,gBAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,kBAAkB;AAQpB,IAAM,qCAAqC;AAOlD,SAAS,qBAAqB,KAA+C;AAC3E,QAAM,SAAkB,KAAK,MAAM,GAAG;AACtC,MAAI,CAAC,UAAU,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,KAAK,EAAE,cAAc,QAAS,QAAO,CAAC;AACvG,QAAM,WAAW,OAAO;AACxB,MAAI,CAAC,YAAY,OAAO,aAAa,YAAY,MAAM,QAAQ,QAAQ,EAAG,QAAO,CAAC;AAGlF,QAAM,UAAkC,uBAAO,OAAO,IAAI;AAC1D,aAAW,CAAC,UAAU,WAAW,KAAK,OAAO,QAAQ,QAAQ,GAAG;AAC9D,QAAI,SAAS,SAAS,KAAK,OAAO,gBAAgB,YAAY,YAAY,SAAS,GAAG;AACpF,yBAAmB,QAAQ;AAC3B,yBAAmB,WAAW;AAC9B,cAAQ,QAAQ,IAAI;AAAA,IACtB;AAAA,EACF;AACA,SAAO;AACT;AAGA,SAAS,qBAAqB,KAAsB;AAElD,QAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,SAAO,WAAW,QAAQ,OAAO,aAAa;AAChD;AAkBA,SAAS,wBAAwB,WAAgC;AAC/D,MAAI;AACJ,MAAI;AACF,SAAK,SAAS,WAAW,UAAU,YAAY,UAAU,cAAc,EAAE;AAAA,EAC3E,SAAS,OAAO;AACd,QAAI,YAAY,OAAO,QAAQ,EAAG,QAAO,EAAE,MAAM,UAAU;AAC3D,QAAI,YAAY,OAAO,OAAO,EAAG,QAAO,EAAE,MAAM,UAAU;AAC1D,WAAO,EAAE,MAAM,QAAQ;AAAA,EACzB;AACA,MAAI;AACF,UAAM,IAAI,UAAU,EAAE;AACtB,QAAI,CAAC,EAAE,OAAO,EAAG,QAAO,EAAE,MAAM,UAAU;AAC1C,UAAM,SAAS,UAAUC,MAAK,QAAQ,SAAS,CAAC;AAChD,QAAI,OAAO,eAAe,KAAK,CAAC,OAAO,YAAY,EAAG,QAAO,EAAE,MAAM,UAAU;AAC/E,UAAM,IAAI,UAAU,SAAS;AAC7B,QAAI,EAAE,eAAe,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAK,QAAO,EAAE,MAAM,UAAU;AACvF,WAAO;AAAA,MACL,MAAM;AAAA,MACN,KAAK,aAAa,IAAI,OAAO;AAAA,MAC7B,KAAK,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,EAAE,OAAO,IAAI,EAAE,OAAO,IAAI,EAAE,IAAI;AAAA,IAC5D;AAAA,EACF,QAAQ;AACN,WAAO,EAAE,MAAM,QAAQ;AAAA,EACzB,UAAE;AACA,cAAU,EAAE;AAAA,EACd;AACF;AAuBA,eAAsB,6BACpB,UACA,OACA,YACA,QACA,QACA,OACwB;AACxB,MAAI,SAAS,WAAW;AACxB,MAAI,WAAW,8BAA8B,MAAM,WAAW,MAAM,iBAAiB,MAAM;AAC3F,MAAI,SAAS,MAAM,OAAO,QAAQ;AAClC,QAAM,mBAAmB,OAAO,SAA8C;AAC5E,QAAI,KAAK,cAAc,SAAS,aAAa,KAAK,oBAAoB,SAAS,iBAAiB;AAC9F,aAAO;AAAA,IACT;AACA,eAAW;AACX,UAAM,aAAa;AACnB,aAAS,MAAM,OAAO,IAAI;AAC1B,QAAI,eAAe,MAAM;AACvB,UAAI;AACF,cAAM,OAAO,UAAU;AAAA,MACzB,SAAS,KAAK;AACZ,YAAI,KAAK,yCAAyC,UAAU,QAAQ,KAAK,KAAK,GAAG,EAAE;AAAA,MACrF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACA,WAAS,UAAU,GAAG,UAAU,GAAG,WAAW,GAAG;AAC/C,UAAM,QAAQ,WAAW;AACzB,QAAI,UAAU,OAAQ,QAAO;AAC7B,aAAS;AACT,QAAI,CAAE,MAAM,iBAAiB,8BAA8B,MAAM,WAAW,MAAM,iBAAiB,KAAK,CAAC,GAAI;AAC3G,aAAO;AAAA,IACT;AAAA,EACF;AACA,QAAM,gCAAgC,UAAU,YAAY;AAC1D,UAAM,iBAAiB,8BAA8B,MAAM,WAAW,MAAM,iBAAiB,WAAW,CAAC,CAAC;AAAA,EAC5G,CAAC;AACD,SAAO;AACT;AAiCO,SAAS,0BACd,OACA,UACe;AACf,MAAI;AACJ,SAAO,MAAe;AACpB,QAAI,MAAM;AACV,QAAI;AACF,YAAM,cAAcC,MAAK,KAAK,SAAS,GAAG,kCAAkC;AAC5E,YAAM,IAAI,SAAS,WAAW;AAC9B,YAAM,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,EAAE,OAAO,IAAI,EAAE,OAAO,IAAI,EAAE,IAAI;AAAA,IAC7D,QAAQ;AACN,YAAM;AAAA,IACR;AACA,QAAI,QAAQ,KAAK,QAAQ,IAAK,QAAO,KAAK;AAC1C,UAAM,QAAQ,MAAM,SAAS,SAAS,CAAC;AACvC,WAAO,EAAE,KAAK,UAAU,MAAM,SAAS;AACvC,WAAO,KAAK;AAAA,EACd;AACF;AAEO,IAAM,mCAAN,MAAuC;AAAA,EACpC,WAA6C,CAAC;AAAA,EAC9C,WAAW;AAAA,EACX,MAAqB;AAAA,EACrB,WAA0B;AAAA,EAElC,IAAI,UAAoD;AACtD,WAAO,KAAK,SAAS,QAAQ,EAAE;AAAA,EACjC;AAAA;AAAA,EAIA,SAAS,UAA4C;AACnD,UAAM,oBAAoB,KAAK,aAAa,WAAW,KAAK,WAAW,CAAC;AACxE,UAAM,oBAAoB,KAAK,aAAa,WAAW,KAAK,WAAW;AACvE,UAAM,YAAsC,EAAE,UAAU,mBAAmB,UAAU,kBAAkB;AACvG,UAAM,SAAS,wBAAwBA,MAAK,KAAK,UAAU,kCAAkC,CAAC;AAC9F,QAAI,OAAO,SAAS,WAAW;AAI7B,UAAI,KAAK,oEAAoE;AAC7E,aAAO;AAAA,IACT;AACA,QAAI,OAAO,SAAS,SAAS;AAK3B,aAAO;AAAA,IACT;AACA,UAAM,MAAM,OAAO,SAAS,YAAY,YAAY,OAAO;AAC3D,QAAI,QAAQ,KAAK,OAAO,aAAa,KAAK,UAAU;AAClD,UAAI,QAA0C,CAAC;AAC/C,UAAI,WAAW;AACf,UAAI,OAAO,SAAS,MAAM;AACxB,YAAI;AACF,kBAAQ,qBAAqB,OAAO,GAAG;AACvC,qBAAW,qBAAqB,OAAO,GAAG;AAAA,QAC5C,QAAQ;AAGN,iBAAO;AAAA,QACT;AAAA,MACF;AACA,WAAK,WAAW;AAChB,WAAK,WAAW;AAChB,WAAK,MAAM;AACX,WAAK,WAAW;AAAA,IAClB;AACA,WAAO,EAAE,UAAU,KAAK,UAAU,UAAU,KAAK,SAAS;AAAA,EAC5D;AACF;AAEO,SAAS,mCACd,YACA,UACQ;AACR,MAAI,UAAU;AACd,QAAM,OAAO,oBAAI,IAAY;AAC7B,SAAO,CAAC,KAAK,IAAI,OAAO,GAAG;AACzB,SAAK,IAAI,OAAO;AAGhB,UAAM,OAAO,OAAO,OAAO,UAAU,OAAO,IAAI,SAAS,OAAO,IAAI;AACpE,QAAI,CAAC,QAAQ,SAAS,QAAS;AAC/B,cAAU;AAAA,EACZ;AACA,SAAO;AACT;AAYO,SAAS,4BACd,SACA,UACG;AAIH,MAAI,OAAO,QAAQ,cAAc,SAAU,QAAO;AAClD,SAAO,EAAE,GAAG,SAAS,WAAW,mCAAmC,QAAQ,WAAW,QAAQ,EAAE;AAClG;AAgBO,SAAS,iCACd,SACA,UACQ;AACR,MAAI,OAAO,KAAK,QAAQ,EAAE,WAAW,EAAG,QAAO;AAC/C,QAAM,MAAM,oBAAoB,OAAO;AACvC,MAAI,QAAQ,KAAM,QAAO;AACzB,QAAM,YAAY,mCAAmC,IAAI,OAAO,QAAQ;AACxE,MAAI,cAAc,IAAI,MAAO,QAAO;AACpC,QAAM,OAAO,IAAI,MAAM,IAAI,KAAK;AAChC,QAAM,SAAS,OAAO,KAAK,IAAI,IAAI,CAAC,KAAK;AACzC,MAAI,MAAM,IAAI,KAAK,IAAI,GAAG,MAAM,cAAc,SAAS,GAAG,KAAK,SAAS,IAAI,IAAI,OAAO,EAAE;AACzF,SAAO,IAAI,MAAM,KAAK,IAAI,IAAI,QAAQ,MAAM,IAAI,UAAU;AAC5D;AAGO,SAAS,6BAA6B,SAAgC;AAC3E,SAAO,oBAAoB,OAAO,GAAG,SAAS;AAChD;AAEA,SAAS,oBACP,SAC8E;AAC9E,MAAI,CAAC,YAAY,KAAK,OAAO,EAAG,QAAO;AACvC,QAAM,QAAQ;AACd,QAAM,YAAY,QAAQ,QAAQ,IAAI,IAAI;AAC1C,QAAM,aAAa,MAAM,KAAK,OAAO;AACrC,MAAI,CAAC,WAAY,QAAO;AACxB,QAAM,QAAQ,QAAQ,MAAM,GAAG,WAAW,KAAK,EAAE,MAAM,IAAI;AAC3D,MAAI,QAAQ;AACZ,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,GAAG;AACxC,QAAI,oBAAoB,KAAK,MAAM,CAAC,KAAK,EAAE,EAAG,SAAQ;AAAA,EACxD;AACA,MAAI,UAAU,GAAI,QAAO;AACzB,QAAM,OAAO,MAAM,KAAK;AACxB,QAAM,QAAQ,KAAK,MAAM,KAAK,QAAQ,GAAG,IAAI,CAAC,EAAE,QAAQ,OAAO,EAAE,EAAE,KAAK;AACxE,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,SAAO,EAAE,OAAO,OAAO,OAAO,YAAY,WAAW,MAAM;AAC7D;AAYO,IAAM,uCAAuC;AAE7C,IAAM,iDAAiD,GAAG,oCAAoC;AAE9F,SAAS,sCAAsC,UAAwB;AAC5E,QAAM,aAAaA,MAAK,KAAK,UAAU,oCAAoC;AAC3E,QAAM,YAAY,GAAG,UAAU,IAAI,QAAQ,GAAG,IAAI,WAAW,CAAC;AAC9D,MAAI;AAOF,UAAM,SAAS,UAAU,QAAQ;AACjC,QAAI,OAAO,eAAe,KAAK,CAAC,OAAO,YAAY,GAAG;AACpD,UAAI,KAAK,2DAA2D,QAAQ,0BAA0B;AACtG;AAAA,IACF;AACA,UAAM,iBAAiBC,cAAa,QAAQ;AAC5C,kBAAc,WAAW,IAAG,oBAAI,KAAK,GAAE,YAAY,CAAC;AAAA,GAAM,EAAE,MAAM,IAAM,CAAC;AAMzE,UAAM,UAAU,UAAU,QAAQ;AAClC,QAAI,QAAQ,eAAe,KAAK,CAAC,QAAQ,YAAY,KAAKA,cAAa,QAAQ,MAAM,gBAAgB;AACnG,aAAO,WAAW,EAAE,OAAO,KAAK,CAAC;AACjC,UAAI,KAAK,6DAA6D,QAAQ,uBAAuB;AACrG;AAAA,IACF;AACA,eAAW,WAAW,UAAU;AAAA,EAClC,SAAS,OAAO;AACd,WAAO,WAAW,EAAE,OAAO,KAAK,CAAC;AAIjC,QAAI,KAAK,oDAAoD,KAAK,EAAE;AAAA,EACtE;AACF;AAEA,eAAsB,kCAAkC,UAAiC;AACvF,wCAAsC,QAAQ;AAChD;AAYO,SAAS,4BACd,UACA,cACA,eACM;AACN,MAAI,iBAAiB,cAAe;AACpC,wCAAsC,QAAQ;AAChD;AAuBO,SAAS,2BAA2B,SAAiB,UAA0C;AACpG,MAAI,CAAC,SAAS,SAAS,KAAK,EAAG,QAAO;AACtC,QAAM,MAAMC,MAAK,SAAS,SAAS,QAAQ;AAC3C,MAAI,IAAI,WAAW,IAAI,KAAKA,MAAK,WAAW,GAAG,EAAG,QAAO;AACzD,QAAM,MAAM,IAAI,MAAMA,MAAK,GAAG,EAAE,CAAC,KAAK;AACtC,MAAI,QAAQ,WAAY,QAAO;AAC/B,SAAO,qBAAqB,SAAS,GAAG,KAAK,QAAQ,UAAU,QAAQ,YAAY,WAAW;AAChG;AAGO,SAAS,uBAAuB,SAAiB,UAA2B;AACjF,SAAO,2BAA2B,SAAS,QAAQ,MAAM;AAC3D;AAgBO,SAAS,8BACd,WACA,iBACA,QACmB;AACnB,MAAI,OAAO,cAAc,SAAU,QAAO,EAAE,WAAW,gBAAgB;AACvE,QAAM,YAAY,mCAAmC,WAAW,MAAM;AACtE,MAAI,cAAc,UAAW,QAAO,EAAE,WAAW,gBAAgB;AACjE,MAAI,iBAAiB;AACnB,UAAM,cAAc,GAAG,yBAAyB,SAAS,CAAC;AAC1D,QAAI,gBAAgB,WAAW,WAAW,GAAG;AAC3C,wBAAkB,GAAG,yBAAyB,SAAS,CAAC,KAAK,gBAAgB,MAAM,YAAY,MAAM,CAAC;AAAA,IACxG;AAAA,EACF;AACA,SAAO,EAAE,WAAW,WAAW,gBAAgB;AACjD;AAUA,eAAsB,gCAAgC,SAOpC;AAChB,MAAI,SAAS,QAAQ;AACrB,WAAS,UAAU,GAAG,UAAU,GAAG,WAAW,GAAG;AAC/C,UAAM,QAAQ,QAAQ,WAAW;AACjC,QAAI,UAAU,OAAQ;AACtB,aAAS;AACT,UAAM,UAAU,mCAAmC,QAAQ,QAAQ,KAAK;AACxE,QAAI,YAAY,QAAQ,YAAY,UAAW;AAC/C,YAAQ,YAAY,YAAY;AAChC,UAAM,QAAQ,QAAQ;AAAA,EACxB;AACA,QAAM,gCAAgC,QAAQ,UAAU,YAAY;AAClE,UAAM,UAAU,mCAAmC,QAAQ,QAAQ,QAAQ,WAAW,CAAC;AACvF,QAAI,YAAY,QAAQ,YAAY,WAAW;AAC7C,cAAQ,YAAY,YAAY;AAChC,YAAM,QAAQ,QAAQ;AAAA,IACxB;AAAA,EACF,CAAC;AACD,QAAM,kCAAkC,QAAQ,QAAQ;AAC1D;AAOA,eAAsB,8BAA8B,SAOlC;AAChB,MAAI,SAAS,QAAQ;AACrB,MAAI,UAAU,QAAQ;AACtB,WAAS,UAAU,GAAG,UAAU,GAAG,WAAW,GAAG;AAC/C,UAAM,QAAQ,QAAQ,MAAM,IAAI,QAAQ,QAAQ;AAChD,QAAI,UAAU,OAAQ;AACtB,aAAS;AACT,UAAM,UAAU,iCAAiC,QAAQ,YAAY,KAAK;AAC1E,QAAI,YAAY,QAAS;AACzB,cAAU;AACV,UAAM,QAAQ,QAAQ,OAAO;AAAA,EAC/B;AACA,QAAM,gCAAgC,QAAQ,UAAU,YAAY;AAClE,UAAM,UAAU,iCAAiC,QAAQ,YAAY,QAAQ,MAAM,IAAI,QAAQ,QAAQ,CAAC;AACxG,QAAI,YAAY,SAAS;AACvB,gBAAU;AACV,YAAM,QAAQ,QAAQ,OAAO;AAAA,IAC/B;AAAA,EACF,CAAC;AACD,QAAM,kCAAkC,QAAQ,QAAQ;AAC1D;AAQO,SAAS,kCAAkC,SAOzC;AACP,MAAI,SAAS,QAAQ;AACrB,MAAI,UAAU,QAAQ;AACtB,WAAS,UAAU,GAAG,UAAU,GAAG,WAAW,GAAG;AAC/C,UAAM,QAAQ,QAAQ,MAAM,IAAI,QAAQ,QAAQ;AAChD,QAAI,UAAU,OAAQ;AACtB,aAAS;AACT,UAAM,UAAU,iCAAiC,QAAQ,YAAY,KAAK;AAC1E,QAAI,YAAY,QAAS;AACzB,cAAU;AACV,YAAQ,QAAQ,OAAO;AAAA,EACzB;AACA,wCAAsC,QAAQ,QAAQ;AACtD,QAAM,IAAI;AAAA,IACR;AAAA,EACF;AACF;","names":["path","realpathSync","path","path","realpathSync","path"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/offline-sync-embedding-generation.ts"],"sourcesContent":["// Embedding-index generation semantics for offline sync (issue #3146, PR\n// #3148). Extracted from offline-sync.ts so the god-file line-count ratchet\n// does not grow when the rules gain behavior. The snapshot walker treats\n// every `state/embeddings/` shard set — or a legacy `state/embeddings.json`\n// marker — as ONE generation, in both directions:\n//\n// 1. Atomic replacement (apply side): an incoming generation is staged\n// complete, verified byte-for-byte, and published through the store's\n// single backup-swap state machine. A crash or write failure can never\n// leave a mix of the local and incoming generation on disk, and a\n// local-only shard of a replaced generation is removed by the swap, not\n// merged into the incoming set.\n// 2. Filter-to-omit, never filter-to-delete (push side): when an exclusion\n// filter removes ANY member of a local generation from a push, the\n// WHOLE generation is omitted — files and deletion metadata — and the\n// receiver keeps its copy. A filtered generation must never look\n// deleted, and a partially filtered snapshot must never look like a\n// complete generation.\nimport { createHash, randomBytes } from \"node:crypto\";\nimport { lstat, mkdir, readFile, readdir, rm, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport {\n type EmbeddingIndexFile,\n EmbeddingIndexFileStore,\n type EmbeddingIndexIdentity,\n type EmbeddingIndexStoreIo,\n EmbeddingIndexStorageError,\n parseEmbeddingIndexDocument,\n serializeEmbeddingShard,\n shardEntriesForIndex,\n validateShardMembership,\n} from \"./embedding-index-storage.js\";\nimport {\n assertEmbeddingGenerationLockHeld,\n type EmbeddingGenerationFence,\n embeddingGenerationLockPath,\n withEmbeddingGenerationLock,\n} from \"./embedding-generation-lock.js\";\nimport type { OfflineSyncExcludeFile, OfflineSyncFileTarget } from \"./offline-sync-file-io.js\";\nimport { EMBEDDING_SHARD_FILE_PATTERN } from \"./offline-sync-runtime-state.js\";\nimport { log } from \"./logger.js\";\nimport type {\n OfflineSyncFileDeleteTarget,\n OfflineSyncFileStagingReadTarget,\n OfflineSyncFileStagingWriteTarget,\n OfflineSyncFileState,\n} from \"./offline-sync.js\";\nimport { type SafeArchiveRoot, resolveSafeArchiveTarget } from \"./transfer/fs-utils.js\";\n\nconst EMBEDDING_MARKER_BASENAME = \"embeddings.json\";\nexport const EMBEDDING_SHARD_DIR_BASENAME = \"embeddings\";\n\n/**\n * Canonical `state` dir prefix (\"state\" or \"namespaces/<ns>/state\") for a\n * path's segments, or null when the path is not canonical runtime state.\n */\nfunction canonicalStateDirPrefix(parts: string[]): string | null {\n if (parts[0] === \"state\") return \"state\";\n if (parts[0] === \"namespaces\" && parts.length >= 4 && parts[2] === \"state\") {\n return `namespaces/${parts[1]}/state`;\n }\n return null;\n}\n\n/** The sharded-generation directory when `relPath` is one of its shards. */\nexport function embeddingShardDirOf(relPath: string): string | null {\n const parts = relPath.split(\"/\");\n if (parts.length < 3) return null;\n if (!EMBEDDING_SHARD_FILE_PATTERN.test(parts[parts.length - 1] ?? \"\")) return null;\n if (parts[parts.length - 2] !== EMBEDDING_SHARD_DIR_BASENAME) return null;\n if (canonicalStateDirPrefix(parts) === null) return null;\n return parts.slice(0, -1).join(\"/\");\n}\n\n/**\n * True when `dirPath` is a canonical embeddings generation dir\n * (`state/embeddings` or `namespaces/<ns>/state/embeddings`). Encodes the\n * snapshot-field shape contract without a ReDoS-shaped literal (issue #2439).\n */\nexport function isEmbeddingGenerationDirPath(dirPath: string): boolean {\n const membership = embeddingGenerationMembership(`${dirPath}/shard-0000.json`);\n return membership !== null && membership.shardDir === dirPath;\n}\n\n/** The state dir when `relPath` is the legacy single-file marker. */\nexport function embeddingMarkerDirOf(relPath: string): string | null {\n const parts = relPath.split(\"/\");\n if ((parts[parts.length - 1] ?? \"\") !== EMBEDDING_MARKER_BASENAME) return null;\n if (canonicalStateDirPrefix(parts) === null) return null;\n return parts.slice(0, -1).join(\"/\");\n}\n\n/**\n * Membership of `relPath` in an embedding generation: shards belong to their\n * `.../embeddings` directory, the legacy marker belongs to the sibling\n * `.../embeddings` directory of its state dir.\n */\nexport function embeddingGenerationMembership(relPath: string): { kind: \"shard\" | \"marker\"; shardDir: string } | null {\n const shardDir = embeddingShardDirOf(relPath);\n if (shardDir) return { kind: \"shard\", shardDir };\n const markerDir = embeddingMarkerDirOf(relPath);\n if (markerDir) return { kind: \"marker\", shardDir: `${markerDir}/${EMBEDDING_SHARD_DIR_BASENAME}` };\n return null;\n}\n\nexport interface IncomingEmbeddingGenerations {\n /** Generation dirs with at least one incoming shard. */\n shardDirs: Set<string>;\n /** State dirs whose incoming snapshot carries the legacy marker. */\n legacyMarkerDirs: Set<string>;\n}\n\n/** Classify incoming snapshot paths into embedding generations. */\nexport function detectIncomingEmbeddingGenerations(incomingPaths: Iterable<string>): IncomingEmbeddingGenerations {\n const shardDirs = new Set<string>();\n const legacyMarkerDirs = new Set<string>();\n for (const relPath of incomingPaths) {\n const membership = embeddingGenerationMembership(relPath);\n if (!membership) continue;\n if (membership.kind === \"shard\") shardDirs.add(membership.shardDir);\n else legacyMarkerDirs.add(membership.shardDir);\n }\n return { shardDirs, legacyMarkerDirs };\n}\n\nfunction shardRelPath(shardDirRel: string, shardIndex: number): string {\n return `${shardDirRel}/shard-${String(shardIndex).padStart(4, \"0\")}.json`;\n}\n\nfunction describeIndexReadFailure(\n read: { outcome: \"absent\" } | { outcome: \"foreign\" } | { outcome: \"unreadable\"; reason: string }\n): string {\n if (read.outcome === \"unreadable\") return read.reason;\n if (read.outcome === \"foreign\") return \"unrecognized index format\";\n return \"generation document is absent\";\n}\n\nfunction sha256Hex(buffer: Buffer): string {\n return createHash(\"sha256\").update(buffer).digest(\"hex\");\n}\n\nasync function pathExists(absPath: string): Promise<boolean> {\n try {\n await lstat(absPath);\n return true;\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") return false;\n throw err;\n }\n}\n\nexport interface EmbeddingGenerationTransactionIo {\n /** Storage-backed local read: hydrates unchanged shards (metadata-only\n * pulls skip their content) and decrypts secure-store files. */\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n writeStagingFile?: (target: OfflineSyncFileStagingWriteTarget) => Promise<void>;\n readStagingFile?: (target: OfflineSyncFileStagingReadTarget) => Promise<Buffer>;\n deleteFile?: (target: OfflineSyncFileDeleteTarget) => Promise<void>;\n}\n\nexport interface EmbeddingGenerationTransactionInput {\n root: SafeArchiveRoot;\n /** The generation dir, e.g. `state/embeddings`. */\n shardDirRel: string;\n /** Incoming shard rel paths — the complete incoming sharded generation. */\n incomingShardPaths: string[];\n /** Incoming legacy marker (rel path + verified content), when the\n * incoming generation is legacy-layout. Mutually exclusive with\n * `incomingShardPaths`. */\n incomingMarker: { path: string; sha256: string; buffer: Buffer | null } | null;\n /** True when the incoming snapshot ALSO carries the legacy marker while\n * shards form the generation (mixed remote): the per-file loop then writes\n * the marker as the inert remote artifact, so this transaction must NOT\n * remove a local marker. */\n incomingMarkerPresent: boolean;\n /** Incoming shard records (sha256 for local hydration of unchanged\n * metadata-only pulls). */\n incomingShardStates: ReadonlyMap<string, OfflineSyncFileState>;\n /** Verified incoming content by rel path (absent for shards the metadata\n * hydration skipped because the local hash already matches). */\n incomingBuffers: ReadonlyMap<string, Buffer>;\n /**\n * Shared-base states (pre-census): lets the transaction re-evaluate\n * divergence against ACTUAL disk contents while holding the mutation\n * lock, instead of trusting the census taken before the lock\n * (codex P1: a daemon mutation between census and lock was discarded).\n */\n baseStates?: ReadonlyMap<string, { sha256: string }>;\n /**\n * Paths this apply is pre-authorized to remove (changeset deletes / remote\n * tombstones). A base member absent from the under-lock census is\n * divergence UNLESS it is pre-authorized — the retry after a response loss\n * must re-apply idempotently instead of failing as diverged (#3150\n * review). A pre-authorized member still present with a changed digest\n * defers as before, so a daemon rewrite is never silently swept.\n */\n justifiedRemovals?: ReadonlySet<string>;\n /**\n * Deletion revisions (mtimeMs by path) to record through the delete hook\n * AFTER the swap publishes. Swept members bypass the per-file delete path,\n * so without this their tombstones are lost and a later peer without\n * shared-base evidence can reintroduce the removed shards (codex P1).\n */\n deletionMtimeByPath?: ReadonlyMap<string, number>;\n /**\n * True when the incoming set claims to be a FRESH creation but carries no\n * base evidence (manifested changeset members are all base-less upserts):\n * a non-empty local generation must match the incoming set exactly or the\n * apply defers as diverged, because the empty-base divergence skip would\n * otherwise silently replace it (#3150 review).\n */\n freshCreateClaim?: boolean;\n io: EmbeddingGenerationTransactionIo;\n now: number;\n}\n\nexport interface EmbeddingGenerationTransactionResult {\n shardDirRel: string;\n upserted: number;\n deleted: number;\n /** nextBase states for files the transaction published. */\n writtenStates: Map<string, OfflineSyncFileState>;\n /** nextBase paths the transaction removed (stale shards, demoted marker). */\n removedPaths: Set<string>;\n /** Paths the per-file apply loop must skip — all handled here. */\n handledPaths: Set<string>;\n /** True when the generation was deferred (not published) because the disk\n * diverged from the shared base while the lock was held. */\n deferredLocalDivergence?: boolean;\n}\n\n/**\n * Content for ONE incoming generation member: the verified incoming buffer,\n * or the LOCAL file hash-verified against the incoming record (metadata-only\n * pulls skip content whose local hash already matches — the local bytes ARE\n * the incoming content). Shared by the shard and legacy-marker branches.\n */\nasync function hydratedIncomingBuffer(\n io: EmbeddingGenerationTransactionIo,\n root: SafeArchiveRoot,\n relPath: string,\n expectedSha256: string,\n incoming: Buffer | null | undefined,\n): Promise<Buffer> {\n if (incoming) return incoming;\n const filePath = await resolveSafeArchiveTarget(root, relPath);\n const local = io.readFile\n ? await io.readFile({ root: root.abs, path: relPath, filePath })\n : await readFile(filePath);\n if (sha256Hex(local) !== expectedSha256) {\n throw new EmbeddingIndexStorageError(\n `cannot hydrate unchanged embedding index file ${relPath}: local digest does not match the incoming record; local generation preserved`,\n );\n }\n return local;\n}\n\n/**\n * Apply ONE incoming embedding generation atomically (issue #3148, round 4):\n * recover an interrupted replacement, validate the complete incoming\n * generation (legacy markers are converted to the sharded layout so the\n * one-way layout is preserved), stage it, verify the staged bytes, then\n * publish through the shared backup-swap. Any failure before the swap leaves\n * the local generation untouched; a crash in the swap gap is rolled back by\n * the store's recovery on next use.\n */\n/**\n * Enumerate and hash the ACTUAL local generation on disk (legacy marker +\n * every shard) through the configured secure IO — the fresh in-lock census\n * the stale pre-lock apply census cannot be trusted for (codex P1).\n */\n/** Scope the shared vault base to this physical embedding generation. */\nfunction baseStatesForGeneration(\n base: ReadonlyMap<string, { sha256: string }> | undefined,\n shardDirRel: string,\n): Map<string, { sha256: string }> {\n return new Map([...base ?? []].filter(([relPath]) => embeddingGenerationMembership(relPath)?.shardDir === shardDirRel));\n}\n\nasync function censusGenerationState(\n io: EmbeddingGenerationTransactionIo,\n root: SafeArchiveRoot,\n markerRel: string,\n markerAbs: string,\n shardDirAbs: string,\n shardDirRel: string,\n): Promise<Map<string, string>> {\n const census = new Map<string, string>();\n const readSha = async (relPath: string, filePath: string) =>\n sha256Hex(io.readFile ? await io.readFile({ root: root.abs, path: relPath, filePath }) : await readFile(filePath));\n if (await pathExists(markerAbs)) census.set(markerRel, await readSha(markerRel, markerAbs));\n const names = await readdir(shardDirAbs).catch((err: NodeJS.ErrnoException) => {\n if (err.code === \"ENOENT\") return [] as string[];\n throw err;\n });\n for (const name of names.filter((candidate) => EMBEDDING_SHARD_FILE_PATTERN.test(candidate)).sort()) {\n const relPath = `${shardDirRel}/${name}`;\n census.set(relPath, await readSha(relPath, path.join(shardDirAbs, name)));\n }\n return census;\n}\n\n/** Incoming member states for the divergence helper (digests as fallback). */\nfunction incomingGenerationStates(input: EmbeddingGenerationTransactionInput): { path: string; sha256: string }[] {\n const states = input.incomingShardPaths.map((relPath) => ({\n path: relPath,\n sha256: input.incomingShardStates.get(relPath)?.sha256 ?? sha256Hex(input.incomingBuffers.get(relPath) ?? Buffer.alloc(0)),\n }));\n if (input.incomingMarker) {\n states.push({ path: input.incomingMarker.path, sha256: input.incomingMarker.sha256 });\n }\n return states;\n}\n\nexport async function applyEmbeddingGenerationTransaction(\n input: EmbeddingGenerationTransactionInput\n): Promise<EmbeddingGenerationTransactionResult> {\n const { root, shardDirRel, io } = input;\n const stateDirRel = shardDirRel.slice(0, -`/${EMBEDDING_SHARD_DIR_BASENAME}`.length);\n const stateDirAbs = await resolveSafeArchiveTarget(root, stateDirRel);\n return await withEmbeddingGenerationLock(stateDirAbs, async (section) => {\n const lockPath = embeddingGenerationLockPath(stateDirAbs);\n const fence: EmbeddingGenerationFence = () => assertEmbeddingGenerationLockHeld(lockPath, section);\n const markerRel = `${stateDirRel}/${EMBEDDING_MARKER_BASENAME}`;\n const shardDirAbs = await resolveSafeArchiveTarget(root, shardDirRel);\n const markerAbs = await resolveSafeArchiveTarget(root, markerRel);\n const store = new EmbeddingIndexFileStore(\n markerAbs,\n shardDirAbs,\n await resolveSafeArchiveTarget(root, `${stateDirRel}/embedding-fallback-status.json`)\n );\n\n // 1. Close a pending rename gap (old generation restored) before staging:\n // the swap below must never build on a half-replaced generation. The\n // fixed backup path is validated first: a planted symlink (or any\n // escape) must fail closed instead of being renamed into the published\n // position or removed through. The restored target is re-resolved so a\n // symlinked restoration cannot slip past the subsequent IO.\n const backupRel = `${stateDirRel}/embeddings.pre-replace.tmp`;\n await resolveSafeArchiveTarget(root, backupRel);\n if (await store.recoverIfInterrupted(fence)) {\n await resolveSafeArchiveTarget(root, shardDirRel);\n }\n\n // Codex P1: the apply census was taken BEFORE this lock, so it may be\n // stale. Re-enumerate and hash the ACTUAL local generation through the\n // secure IO and defer the WHOLE generation when the disk no longer\n // matches the shared base — a concurrent daemon mutation must never be\n // silently discarded by the swap.\n // No shared base (fresh catch-up) = no divergence semantics to protect,\n // UNLESS the apply claims a fresh creation (manifested base-less\n // upserts): an existing local generation must then match the incoming\n // set exactly or defer, instead of being silently replaced.\n const justifiedRemovals = input.justifiedRemovals ?? new Set<string>();\n const baseStates = baseStatesForGeneration(input.baseStates, shardDirRel);\n if (baseStates.size > 0) {\n const localCensus = await censusGenerationState(io, root, markerRel, markerAbs, shardDirAbs, shardDirRel);\n const baseArr = [...baseStates].map(([relPath, state]) => ({ path: relPath, sha256: state.sha256 }));\n const censusArr = [...localCensus].map(([relPath, sha256]) => ({ path: relPath, sha256 }));\n const deferrals = divergedEmbeddingGenerationDeferrals({\n incomingFiles: incomingGenerationStates(input),\n // A pre-authorized removal keeps its base entry only while still on\n // disk (digest auth): present members are compared normally — a\n // daemon rewrite still defers — while an absent member is already\n // applied and must not diverge the retry (#3150 review).\n baseFiles: baseArr.filter((member) => !justifiedRemovals.has(member.path) || localCensus.has(member.path)),\n currentFiles: censusArr,\n });\n const incomingShardPaths = new Set(input.incomingShardPaths);\n const addedOrRemovedSinceBase =\n censusArr.some((member) =>\n !baseStates.has(member.path) &&\n !justifiedRemovals.has(member.path) &&\n // An incoming member found in the census is the apply's own\n // already-published work (response-loss retry), not a local\n // addition; its bytes were verified above.\n !incomingShardPaths.has(member.path)) ||\n baseArr.some((member) => !localCensus.has(member.path) && !justifiedRemovals.has(member.path));\n if (deferrals.length > 0 || addedOrRemovedSinceBase) {\n const handled = new Set<string>(input.incomingShardPaths);\n if (input.incomingMarker) handled.add(input.incomingMarker.path);\n if (input.incomingMarkerPresent) handled.add(markerRel);\n for (const relPath of localCensus.keys()) handled.add(relPath);\n log.warn(\n `embedding generation ${shardDirRel} deferred: disk diverged from the shared base under the mutation lock (${deferrals.length > 0 ? deferrals.join(\", \") : \"generation membership changed since base\"}); nothing published, nothing removed`,\n );\n return {\n shardDirRel,\n upserted: 0,\n deleted: 0,\n writtenStates: new Map<string, OfflineSyncFileState>(),\n removedPaths: new Set<string>(),\n handledPaths: handled,\n deferredLocalDivergence: true,\n };\n }\n } else if (input.freshCreateClaim) {\n const localCensus = await censusGenerationState(io, root, markerRel, markerAbs, shardDirAbs, shardDirRel);\n if (localCensus.size > 0) {\n const incomingArr = incomingGenerationStates(input).sort((left, right) => left.path.localeCompare(right.path));\n const censusArr = [...localCensus]\n .map(([relPath, sha256]) => ({ path: relPath, sha256 }))\n .sort((left, right) => left.path.localeCompare(right.path));\n const identical =\n censusArr.length === incomingArr.length &&\n censusArr.every((member, index) => member.path === incomingArr[index]?.path && member.sha256 === incomingArr[index]?.sha256);\n if (!identical) {\n const handled = new Set<string>(input.incomingShardPaths);\n if (input.incomingMarker) handled.add(input.incomingMarker.path);\n if (input.incomingMarkerPresent) handled.add(markerRel);\n for (const relPath of localCensus.keys()) handled.add(relPath);\n log.warn(\n `embedding generation ${shardDirRel} deferred: base-less creation does not match the existing local generation under the mutation lock; nothing published, nothing removed`,\n );\n return {\n shardDirRel,\n upserted: 0,\n deleted: 0,\n writtenStates: new Map<string, OfflineSyncFileState>(),\n removedPaths: new Set<string>(),\n handledPaths: handled,\n deferredLocalDivergence: true,\n };\n }\n }\n }\n\n const published = new Map<string, Buffer>();\n let identity: EmbeddingIndexIdentity | null = null;\n // Divergence re-evaluation happens HERE, under the lock, against real\n // disk bytes: the apply-side census may already be stale.\n // 2. Build the complete incoming generation (final rel path → plaintext\n // bytes) and validate every document BEFORE touching local state.\n if (input.incomingMarker) {\n const markerBuffer = await hydratedIncomingBuffer(\n io,\n root,\n input.incomingMarker.path,\n input.incomingMarker.sha256,\n input.incomingMarker.buffer,\n );\n const read = parseEmbeddingIndexDocument(markerBuffer.toString(\"utf-8\"));\n if (read.outcome !== \"ok\") {\n throw new EmbeddingIndexStorageError(\n `refusing incoming embedding index generation ${markerRel}: ${describeIndexReadFailure(read)}; local generation preserved`\n );\n }\n identity = { provider: read.file.provider, model: read.file.model };\n const groups = shardEntriesForIndex(read.file);\n for (const [shardIndex, entries] of groups) {\n if (Object.keys(entries).length === 0) continue;\n published.set(\n shardRelPath(shardDirRel, shardIndex),\n Buffer.from(serializeEmbeddingShard(read.file, shardIndex, entries), \"utf-8\")\n );\n }\n } else {\n for (const relPath of input.incomingShardPaths) {\n // Metadata-only pulls skip content whose local hash already matches\n // the incoming record: the LOCAL bytes ARE the incoming content, so\n // read and hash-verify them instead of failing (codex rounds 5-6).\n const state = input.incomingShardStates.get(relPath);\n const buffer = await hydratedIncomingBuffer(\n io,\n root,\n relPath,\n state?.sha256 ?? \"\",\n input.incomingBuffers.get(relPath),\n );\n const read = parseEmbeddingIndexDocument(buffer.toString(\"utf-8\"));\n if (read.outcome !== \"ok\") {\n throw new EmbeddingIndexStorageError(\n `refusing incoming embedding index shard ${relPath}: ${describeIndexReadFailure(read)}; local generation preserved`\n );\n }\n validateShardMembership(relPath.split(\"/\").pop() ?? \"\", read.file);\n const shardIdentity = { provider: read.file.provider, model: read.file.model };\n if (!identity) identity = shardIdentity;\n if (identity.provider !== shardIdentity.provider || identity.model !== shardIdentity.model) {\n throw new EmbeddingIndexStorageError(\n `refusing mixed-identity incoming embedding index generation in ${shardDirRel}: ${relPath} is ${shardIdentity.provider}/${shardIdentity.model} but the generation is ${identity.provider}/${identity.model}; local generation preserved`\n );\n }\n published.set(relPath, buffer);\n }\n if (published.size === 0) {\n throw new EmbeddingIndexStorageError(\n `incoming embedding index generation ${shardDirRel} is empty; local generation preserved`\n );\n }\n }\n\n const stagingRel = `${stateDirRel}/embeddings.staging.tmp-sync-${process.pid}-${input.now}-${randomBytes(8).toString(\"hex\")}`;\n const stagingAbs = await resolveSafeArchiveTarget(root, stagingRel);\n try {\n await mkdir(stagingAbs, { recursive: true });\n\n // 3. Stage the complete generation. With storage-backed IO the staged\n // ciphertext binds its FINAL canonical path (`aadRelPath`), so after\n // the directory swap it decrypts at the published path — a physical\n // staging-path AAD would make the published generation unreadable.\n for (const [relPath, buffer] of published) {\n const stagedRel = `${stagingRel}/${path.basename(relPath)}`;\n const stagedAbs = await resolveSafeArchiveTarget(root, stagedRel);\n const finalAbs = await resolveSafeArchiveTarget(root, relPath);\n if (io.writeStagingFile) {\n await io.writeStagingFile({\n root: root.abs,\n path: stagedRel,\n filePath: stagedAbs,\n content: buffer,\n finalAadFilePath: finalAbs,\n });\n } else {\n await writeFile(stagedAbs, buffer, { mode: 0o600 });\n }\n }\n\n // 4. Verify the staged bytes against the incoming content before the\n // published generation is touched at all.\n for (const [relPath, buffer] of published) {\n const stagedRel = `${stagingRel}/${path.basename(relPath)}`;\n const stagedAbs = await resolveSafeArchiveTarget(root, stagedRel);\n const staged = io.readStagingFile\n ? await io.readStagingFile({\n root: root.abs,\n path: stagedRel,\n filePath: stagedAbs,\n finalAadFilePath: await resolveSafeArchiveTarget(root, relPath),\n })\n : await readFile(stagedAbs);\n if (!staged.equals(buffer)) {\n throw new EmbeddingIndexStorageError(\n `staged embedding index file ${stagedRel} does not match the incoming content; local generation preserved`\n );\n }\n }\n\n // 5. Publish with the ONE swap state machine shared with persist(). The\n // old directory moves aside wholesale, so local shards absent from\n // the incoming generation are removed by the swap — never merged.\n const localShardRels = (\n await readdir(shardDirAbs).catch((err) => {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") return [] as string[];\n throw err;\n })\n )\n .filter((name) => EMBEDDING_SHARD_FILE_PATTERN.test(name))\n .map((name) => `${shardDirRel}/${name}`)\n .sort();\n await store.publishSwappedGeneration(stagingAbs, fence);\n\n const writtenStates = new Map<string, OfflineSyncFileState>();\n for (const [relPath, buffer] of published) {\n writtenStates.set(relPath, {\n path: relPath,\n sha256: sha256Hex(buffer),\n bytes: buffer.length,\n mtimeMs: input.now,\n });\n }\n const removedPaths = new Set<string>(localShardRels.filter((rel) => !published.has(rel)));\n let deleted = removedPaths.size;\n let markerCleanupFailed = false;\n if ((await pathExists(markerAbs)) && !input.incomingMarker && !input.incomingMarkerPresent) {\n // Publication is already committed. Keep its base advancement even if\n // marker cleanup fails, retaining the marker in base for a retry.\n try {\n if (io.deleteFile) await io.deleteFile({ root: root.abs, path: markerRel, filePath: markerAbs });\n else await rm(markerAbs, { force: true });\n removedPaths.add(markerRel);\n deleted += 1;\n } catch (err) {\n markerCleanupFailed = true;\n log.warn(`embedding generation ${shardDirRel}: marker cleanup deferred after publish: ${err}`);\n }\n }\n // Swept members bypass the per-file delete path, so record their\n // deletion revisions here — mirroring the whole-generation removal\n // path — or a later peer without shared-base evidence can reintroduce\n // the removed shards (codex P1). An empty map still records (with\n // `now`) when the caller declared a deletion context, so tombstones\n // whose changeset deletes omit mtimeMs are not lost. Every member\n // gets an attempt before the failure propagates: the push side then\n // retries a fully-recorded apply or nothing, and the\n // justified-removals exemption keeps that retry idempotent.\n if (input.deletionMtimeByPath !== undefined && io.deleteFile) {\n let firstTombstoneError: unknown = null;\n for (const relPath of removedPaths) {\n try {\n await io.deleteFile({\n root: root.abs,\n path: relPath,\n filePath: await resolveSafeArchiveTarget(root, relPath),\n mtimeMs: input.deletionMtimeByPath.get(relPath) ?? input.now,\n });\n } catch (err) {\n firstTombstoneError ??= err;\n log.warn(`embedding generation ${shardDirRel}: tombstone recording failed for ${relPath}: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n if (firstTombstoneError) throw firstTombstoneError;\n }\n return {\n shardDirRel,\n upserted: published.size,\n deleted,\n writtenStates,\n removedPaths,\n handledPaths: new Set([...published.keys(), ...removedPaths, ...(markerCleanupFailed ? [markerRel] : [])]),\n };\n } catch (err) {\n await rm(stagingAbs, { recursive: true, force: true }).catch(() => undefined);\n throw err;\n }\n });\n}\n\n// ---------------------------------------------------------------------------\n// Push-side whole-generation omission\n// ---------------------------------------------------------------------------\n\nexport interface EmbeddingGenerationOmissionOptions {\n rootAbs: string;\n userExcludeRegexps?: readonly RegExp[];\n excludeFile?: OfflineSyncExcludeFile;\n /** Recorded deletion-revision paths: a tombstoned member counts as a\n * generation member for omission detection even though it is absent on\n * disk (its exclusion must omit the WHOLE generation). */\n tombstonedPaths?: readonly string[];\n /**\n * Per-path push exclusion predicate (structural + node-local defaults +\n * user regexps). Defaults to the built-in default excludes + the supplied\n * user regexps, matching the walk that consumes the result.\n */\n isExcludedRelPath?: (relPath: string) => boolean;\n}\n\nexport interface EmbeddingGenerationOmission {\n /** Existing member paths omitted because their generation is partial. */\n omittedPaths: Set<string>;\n /** Generation dirs whose members are omitted (snapshot field value). */\n omittedDirs: string[];\n}\n\n/**\n * Compute the push-side whole-generation omission set: when ANY on-disk\n * member of an embedding generation is excluded by a push filter, EVERY\n * member of that generation is omitted (issue #3148, round 4).\n */\nexport async function computeOmittedEmbeddingGenerationPaths(\n options: EmbeddingGenerationOmissionOptions\n): Promise<EmbeddingGenerationOmission> {\n const omittedPaths = new Set<string>();\n const omittedDirs: string[] = [];\n const stateDirs = [\"state\"];\n let namespaceNames: string[] = [];\n try {\n namespaceNames = (await readdir(path.join(options.rootAbs, \"namespaces\"), { withFileTypes: true }))\n .filter((entry) => entry.isDirectory())\n .map((entry) => entry.name);\n } catch {\n // no namespaces\n }\n for (const ns of namespaceNames) stateDirs.push(`namespaces/${ns}/state`);\n const isExcluded = options.isExcludedRelPath ??\n ((relPath: string) =>\n matchesOfflineSyncDefaultExclude(relPath) ||\n Boolean(options.userExcludeRegexps?.some((re) => re.test(relPath))));\n\n for (const stateDir of stateDirs) {\n const markerRel = `${stateDir}/${EMBEDDING_MARKER_BASENAME}`;\n const shardDirRel = `${stateDir}/${EMBEDDING_SHARD_DIR_BASENAME}`;\n const shardDirAbs = path.join(options.rootAbs, ...shardDirRel.split(\"/\"));\n const memberRels: string[] = [];\n if (await pathExists(path.join(options.rootAbs, ...markerRel.split(\"/\")))) {\n memberRels.push(markerRel);\n }\n let shardNames: string[] = [];\n try {\n shardNames = (await readdir(shardDirAbs, { withFileTypes: true }))\n .filter((entry) => entry.isFile() && EMBEDDING_SHARD_FILE_PATTERN.test(entry.name))\n .map((entry) => entry.name);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") throw err;\n }\n for (const name of shardNames) memberRels.push(`${shardDirRel}/${name}`);\n // A tombstoned member is part of the generation even though it is\n // already absent on disk: its exclusion must omit the WHOLE generation,\n // not just drop its revision individually (codex round 6, XkFf).\n for (const tombstoned of options.tombstonedPaths ?? []) {\n const membership = embeddingGenerationMembership(tombstoned);\n if (membership?.shardDir === shardDirRel && !memberRels.includes(tombstoned)) {\n memberRels.push(tombstoned);\n }\n }\n if (memberRels.length === 0) continue;\n\n const excludedMembers: string[] = [];\n for (const relPath of memberRels) {\n let excluded = isExcluded(relPath);\n if (!excluded && options.excludeFile) {\n excluded = await options.excludeFile({\n root: options.rootAbs,\n path: relPath,\n filePath: path.join(options.rootAbs, ...relPath.split(\"/\")),\n });\n }\n if (excluded) excludedMembers.push(relPath);\n }\n if (excludedMembers.length === 0) continue;\n omittedDirs.push(shardDirRel);\n omittedPaths.add(shardDirRel); // skip new shards after the omission header\n for (const relPath of memberRels) omittedPaths.add(relPath);\n }\n return { omittedPaths, omittedDirs };\n}\n\n/** Reject an exclusion introduced after the snapshot header was computed. */\nexport async function assertEmbeddingGenerationStillIncluded(\n rootAbs: string, shardDirRel: string, excludeFile: OfflineSyncExcludeFile | undefined,\n isExcludedRelPath: (relPath: string) => boolean, tombstonedPaths: readonly string[],\n): Promise<void> {\n const current = await computeOmittedEmbeddingGenerationPaths({ rootAbs, excludeFile, isExcludedRelPath, tombstonedPaths });\n if (current.omittedDirs.includes(shardDirRel)) {\n throw new EmbeddingIndexStorageError(\n `embedding generation ${shardDirRel} became partially excluded during snapshot capture; retry with a fresh omission header`,\n );\n }\n}\n\n/** True when a path belongs to a generation the push omitted. */\nexport function isPathInOmittedEmbeddingGeneration(relPath: string, omittedDirs: ReadonlySet<string>): boolean {\n const membership = embeddingGenerationMembership(relPath);\n return membership !== null && omittedDirs.has(membership.shardDir);\n}\n\nexport type { EmbeddingIndexFile };\n\nimport { matchesOfflineSyncDefaultExclude } from \"./offline-sync-exclude-globs.js\";\nimport type { OfflineSyncDeletionRevision } from \"./offline-sync.js\";\n\nexport interface PushEmbeddingGenerationState {\n /** Generation dirs omitted by the push filters (snapshot header value). */\n omittedDirs: string[];\n /** All omitted member paths (walk skip set). */\n omittedPaths: Set<string>;\n /** Deletions with whole-generation suppression applied. */\n deletions: OfflineSyncDeletionRevision[];\n}\n\n/**\n * One-call push-side generation state for streaming snapshot builders: the\n * whole-generation omission set (from user regexps, excludeFile, and default\n * excludes) plus the deletion list with omitted-generation revisions\n * suppressed — including revisions for members that are already absent, so a\n * filtered generation can never be announced as deleted.\n */\nexport async function resolvePushEmbeddingGenerationState(options: {\n rootAbs: string;\n includeTranscripts: boolean;\n userExcludeRegexps?: readonly RegExp[];\n excludeFile?: OfflineSyncExcludeFile;\n deletions: readonly OfflineSyncDeletionRevision[];\n}): Promise<PushEmbeddingGenerationState> {\n const omission = await computeOmittedEmbeddingGenerationPaths({\n rootAbs: options.rootAbs,\n userExcludeRegexps: options.userExcludeRegexps,\n excludeFile: options.excludeFile,\n // RAW pre-filter tombstones: a deleted member's exclusion must omit the\n // whole generation even though the member is already absent on disk.\n tombstonedPaths: options.deletions.map((deletion) => deletion.path),\n isExcludedRelPath: (relPath) =>\n matchesOfflineSyncDefaultExclude(relPath) ||\n Boolean(options.userExcludeRegexps?.some((re) => re.test(relPath))),\n });\n const omittedDirs = new Set(omission.omittedDirs);\n const deletions = options.deletions.filter((deletion) => {\n if (matchesOfflineSyncDefaultExclude(deletion.path)) return false;\n if (options.userExcludeRegexps?.some((re) => re.test(deletion.path))) return false;\n const membership = embeddingGenerationMembership(deletion.path);\n if (membership && omittedDirs.has(membership.shardDir)) return false;\n return true;\n });\n return { omittedDirs: omission.omittedDirs, omittedPaths: omission.omittedPaths, deletions };\n}\n\n\ninterface StorageBackedIndexIoHost {\n readOfflineSyncFile(filePath: string, opts?: { aadFilePath?: string }): Promise<Buffer>;\n writeOfflineSyncStagingFile(\n filePath: string,\n content: Buffer,\n opts?: { aadFilePath?: string },\n ): Promise<void>;\n}\n\n/**\n * Daemon wiring for the index store IO backed by a StorageManager:\n * canonical-path secure reads/writes, so sync-published encrypted shards\n * decrypt in the daemon and daemon-written shards decrypt on sync. Shard\n * STAGING writes bind the FINAL published path.\n */\nexport function storageBackedIndexStoreIo(storage: StorageBackedIndexIoHost): EmbeddingIndexStoreIo {\n return {\n readUtf8: async (filePath) => (await storage.readOfflineSyncFile(filePath)).toString(\"utf-8\"),\n writeUtf8: (filePath, contents, opts) =>\n storage.writeOfflineSyncStagingFile(\n filePath,\n Buffer.from(contents, \"utf-8\"),\n opts?.finalAadFilePath === undefined ? undefined : { aadFilePath: opts.finalAadFilePath },\n ),\n };\n}\n\nexport interface EmbeddingGenerationRemovalInput {\n root: SafeArchiveRoot;\n /** The generation dir, e.g. `state/embeddings`. */\n shardDirRel: string;\n io: Pick<EmbeddingGenerationTransactionIo, \"deleteFile\" | \"readFile\">;\n /** Incoming deletion revisions by path, threaded so each removed member's\n * tombstone is recorded through the configured delete hook AFTER the\n * atomic empty publication (round 6: raw removal must not lose them). */\n deletionMtimeByPath?: ReadonlyMap<string, number>;\n now: number;\n /**\n * Shared-base states: when the live generation diverged from the base\n * (daemon indexed, added, or removed members after the census), the\n * removal DEFERS instead of erasing the local work (codex P1).\n */\n baseStates?: ReadonlyMap<string, { sha256: string }>;\n}\n\n/**\n * Remove a LOCAL embedding generation atomically because the remote deleted\n * it wholesale (every member has a deletion revision): recover first, then\n * demote the published directory through the store's single swap state\n * machine and delete the backup — a crash or delete failure can never leave\n * a partial same-identity generation serving silently missing memories.\n * The local legacy marker, when present, is removed through the same delete\n * hook the per-file path uses.\n */\nexport async function applyEmbeddingGenerationRemoval(\n input: EmbeddingGenerationRemovalInput,\n): Promise<EmbeddingGenerationTransactionResult> {\n const { root, shardDirRel, io } = input;\n const stateDirRel = shardDirRel.slice(0, -(`/${EMBEDDING_SHARD_DIR_BASENAME}`.length));\n const stateDirAbs = await resolveSafeArchiveTarget(root, stateDirRel);\n return await withEmbeddingGenerationLock(stateDirAbs, async (section) => {\n const lockPath = embeddingGenerationLockPath(stateDirAbs);\n const fence: EmbeddingGenerationFence = () => assertEmbeddingGenerationLockHeld(lockPath, section);\n const markerRel = `${stateDirRel}/${EMBEDDING_MARKER_BASENAME}`;\n const shardDirAbs = await resolveSafeArchiveTarget(root, shardDirRel);\n const markerAbs = await resolveSafeArchiveTarget(root, markerRel);\n const store = new EmbeddingIndexFileStore(\n markerAbs,\n shardDirAbs,\n await resolveSafeArchiveTarget(root, `${stateDirRel}/embedding-fallback-status.json`),\n );\n await store.recoverIfInterrupted(fence);\n\n // Codex P1: the deletion census is stale by the time the lock is held.\n // When the live generation no longer matches the shared base (daemon\n // indexed, added, or removed members), DEFER the removal — the local\n // work survives and a later sync re-evaluates with a fresh base.\n // No shared base (fresh catch-up) = no divergence semantics to protect.\n const baseStates = baseStatesForGeneration(input.baseStates, shardDirRel);\n if (baseStates.size > 0) {\n const localCensus = await censusGenerationState(io, root, markerRel, markerAbs, shardDirAbs, shardDirRel);\n const baseArr = [...baseStates].map(([relPath, state]) => ({ path: relPath, sha256: state.sha256 }));\n const censusArr = [...localCensus].map(([relPath, sha256]) => ({ path: relPath, sha256 }));\n const changedSinceBase =\n censusArr.some((member) => {\n // A MODIFIED member must also defer: removing the generation would\n // erase the daemon's rewrite, not just the remote's stale copy.\n const baseSha = baseStates.get(member.path)?.sha256;\n return baseSha === undefined || baseSha !== member.sha256;\n }) || baseArr.some((member) => !localCensus.has(member.path));\n if (changedSinceBase) {\n const removedPaths = new Set<string>([...localCensus.keys()]);\n log.warn(\n `embedding generation removal ${shardDirRel} deferred: disk diverged from the shared base under the mutation lock; local generation preserved`,\n );\n return {\n shardDirRel,\n upserted: 0,\n deleted: 0,\n writtenStates: new Map<string, OfflineSyncFileState>(),\n removedPaths,\n handledPaths: new Set(removedPaths),\n deferredLocalDivergence: true,\n };\n }\n }\n const localShardRels = (await readdir(shardDirAbs).catch((err) => {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") return [] as string[];\n throw err;\n }))\n .filter((name) => EMBEDDING_SHARD_FILE_PATTERN.test(name))\n .map((name) => `${shardDirRel}/${name}`)\n .sort();\n await store.removePublishedGeneration(fence);\n const removedPaths = new Set(localShardRels);\n let deleted = removedPaths.size;\n const markerPresent = await pathExists(markerAbs);\n if (markerPresent) {\n removedPaths.add(markerRel);\n deleted += 1;\n }\n // Preserve the replicated tombstones through the configured hooks AFTER\n // the atomic publication: raw removal must not lose the deletion\n // revisions, or a downstream sync without base evidence retains stale\n // entries. EVERY member (shards and marker) is recorded exactly ONCE with\n // the remote revision when known, so a first hook call without a revision\n // is never overwritten by an older replicated one. The storage hook\n // tolerates already-absent paths.\n let firstError: unknown = null;\n for (const relPath of removedPaths) {\n const memberAbs = relPath === markerRel ? markerAbs : await resolveSafeArchiveTarget(root, relPath);\n const mtimeMs = input.deletionMtimeByPath?.get(relPath) ?? input.now;\n if (io.deleteFile) {\n try {\n await io.deleteFile({\n root: root.abs,\n path: relPath,\n filePath: await resolveSafeArchiveTarget(root, relPath),\n mtimeMs,\n });\n } catch (err) {\n firstError ??= err;\n log.warn(`embedding generation removal: tombstone recording failed for ${relPath}: ${err instanceof Error ? err.message : String(err)}`);\n }\n } else if (relPath === markerRel && markerPresent) {\n await rm(markerAbs, { force: true });\n }\n }\n if (firstError) throw firstError;\n return {\n shardDirRel,\n upserted: 0,\n deleted,\n writtenStates: new Map(),\n removedPaths,\n handledPaths: new Set(removedPaths),\n };\n });\n}\n\n/** Defer a whole generation when the shared remote base would erase a local change. */\nexport function divergedEmbeddingGenerationDeferrals(options: {\n incomingFiles: readonly { path: string; sha256: string }[];\n baseFiles: readonly { path: string; sha256: string }[];\n currentFiles: readonly { path: string; sha256: string }[];\n}): string[] {\n const base = new Map(options.baseFiles.map((f) => [f.path, f.sha256]));\n const current = new Map(options.currentFiles.map((f) => [f.path, f.sha256]));\n const incomingByPath = new Map(options.incomingFiles.map((f) => [f.path, f.sha256]));\n const sharedDirs = new Set(options.baseFiles.map((f) => embeddingGenerationMembership(f.path)?.shardDir));\n const conflictedDirs = new Set<string>();\n for (const relPath of new Set([...base.keys(), ...current.keys(), ...incomingByPath.keys()])) {\n const membership = embeddingGenerationMembership(relPath);\n // Without a shared generation base this is an initial remote-authoritative\n // import, not evidence of local indexing after a synchronized snapshot.\n if (!membership || !sharedDirs.has(membership.shardDir)) continue;\n const currentSha = current.get(relPath);\n if (currentSha !== base.get(relPath) && currentSha !== incomingByPath.get(relPath)) {\n conflictedDirs.add(membership.shardDir);\n }\n }\n if (conflictedDirs.size === 0) return [];\n const deferred: string[] = [];\n // Include local/base members too: an all-absent remote generation still\n // needs a concrete deferral so its removal cannot erase a local change.\n for (const relPath of new Set([...base.keys(), ...current.keys(), ...incomingByPath.keys()])) {\n const membership = embeddingGenerationMembership(relPath);\n if (membership && conflictedDirs.has(membership.shardDir)) deferred.push(relPath);\n }\n return deferred.sort((left, right) => left.localeCompare(right));\n}\n\n// ---------------------------------------------------------------------------\n// Snapshot-side generation routing, extracted from applyOfflineSyncSnapshot\n// for issue #3150 so the changeset path could share the machinery without\n// growing the offline-sync.ts ratchet ceiling. Behavior-preserving.\n// ---------------------------------------------------------------------------\n\nexport interface IncomingEmbeddingGenerationApply {\n transactionResults: EmbeddingGenerationTransactionResult[];\n deferredGenerationDirs: Set<string>;\n}\n\nexport interface IncomingEmbeddingGenerationApplyOptions {\n root: SafeArchiveRoot;\n incomingMap: ReadonlyMap<string, OfflineSyncFileState>;\n incomingBuffers: ReadonlyMap<string, Buffer>;\n baseMap: ReadonlyMap<string, OfflineSyncFileState>;\n currentMap: ReadonlyMap<string, OfflineSyncFileState>;\n deferredPaths: ReadonlySet<string>;\n omittedGenerationDirs: ReadonlySet<string>;\n deletionMtimeByPath?: ReadonlyMap<string, number>;\n io: EmbeddingGenerationTransactionIo;\n /** True when the caller supplied ANY custom storage IO. */\n customIoPresent: boolean;\n now: number;\n}\n\n/**\n * Snapshot-side generation routing, extracted from applyOfflineSyncSnapshot\n * for issue #3150 (the changeset path needed the same machinery and the\n * offline-sync.ts line ratchet had no headroom). Incoming generations replace\n * as ONE unit through the shared locked transaction. Behavior-preserving —\n * the #3148 regression suites own this contract.\n */\nexport async function applyIncomingEmbeddingGenerations(\n options: IncomingEmbeddingGenerationApplyOptions,\n): Promise<IncomingEmbeddingGenerationApply> {\n const incomingGenerations = detectIncomingEmbeddingGenerations(options.incomingMap.keys());\n const generationDirs = new Set<string>([\n ...incomingGenerations.shardDirs,\n ...incomingGenerations.legacyMarkerDirs,\n ]);\n const deferredGenerationDirs = new Set<string>();\n for (const deferredPath of options.deferredPaths) {\n const membership = embeddingGenerationMembership(deferredPath);\n if (membership) deferredGenerationDirs.add(membership.shardDir);\n }\n const transactionResults: EmbeddingGenerationTransactionResult[] = [];\n // Included and omitted cannot describe the same generation.\n for (const shardDir of generationDirs) {\n if (options.omittedGenerationDirs.has(shardDir)) {\n throw new EmbeddingIndexStorageError(\n `offline sync snapshot both includes and omits embedding generation ${shardDir}; refusing to apply`,\n );\n }\n }\n // Fail closed BEFORE any publication: custom storage IO (encrypted or\n // otherwise) without the staging pair would make the generation transaction\n // fall back to unencrypted raw writes — a plaintext downgrade of the staged\n // generation. Callers must wire both staging hooks (the CLI does).\n if (\n generationDirs.size > 0 &&\n options.customIoPresent &&\n !(options.io.writeStagingFile && options.io.readStagingFile)\n ) {\n throw new EmbeddingIndexStorageError(\n \"refusing to replace embedding generation: custom storage IO requires both writeStagingFile and readStagingFile hooks; unencrypted raw staging would plaintext-downgrade the index\",\n );\n }\n for (const shardDir of generationDirs) {\n if (deferredGenerationDirs.has(shardDir)) continue;\n if (\n incomingGenerations.legacyMarkerDirs.has(shardDir) &&\n !incomingGenerations.shardDirs.has(shardDir)\n ) {\n // Cross-layout: an incoming legacy marker replaces a local sharded\n // generation as a whole (codex round 4). When shards are ALSO\n // incoming, the sharded set is the generation and the marker is\n // written as an inert artifact by the per-file loop below.\n const markerRel = [...options.incomingMap.keys()].find(\n (relPath) => embeddingMarkerDirOf(relPath) === shardDir.slice(0, -`/${EMBEDDING_SHARD_DIR_BASENAME}`.length),\n );\n if (!markerRel) continue;\n transactionResults.push(await applyEmbeddingGenerationTransaction({\n root: options.root,\n shardDirRel: shardDir,\n incomingShardPaths: [],\n incomingMarker: {\n path: markerRel,\n sha256: options.incomingMap.get(markerRel)!.sha256,\n buffer: options.incomingBuffers.get(markerRel) ?? null,\n },\n incomingMarkerPresent: false,\n incomingShardStates: new Map(),\n incomingBuffers: options.incomingBuffers,\n baseStates: options.baseMap,\n io: options.io,\n now: options.now,\n }));\n continue;\n }\n transactionResults.push(await applyEmbeddingGenerationTransaction({\n root: options.root,\n shardDirRel: shardDir,\n incomingShardPaths: [...options.incomingMap.keys()]\n .filter((relPath) => embeddingShardDirOf(relPath) === shardDir)\n .sort(),\n incomingMarker: null,\n incomingMarkerPresent: Boolean(\n incomingGenerations.legacyMarkerDirs.has(shardDir),\n ),\n incomingShardStates: new Map(\n [...options.incomingMap.values()]\n .filter((state) => embeddingShardDirOf(state.path) === shardDir)\n .map((state) => [state.path, state]),\n ),\n incomingBuffers: options.incomingBuffers,\n baseStates: options.baseMap,\n io: options.io,\n now: options.now,\n }));\n }\n // Whole-generation removal (codex round 6 P1): when the remote deleted a\n // previously shared sharded index, the deletion revisions cover EVERY\n // local member. Remove that generation as ONE atomic swap instead of\n // deleting shards one-by-one, so a crash or delete failure can never\n // expose a partial same-identity generation serving missing memories.\n const localGenerationDirs = new Set<string>();\n for (const relPath of options.currentMap.keys()) {\n const membership = embeddingGenerationMembership(relPath);\n if (membership?.kind === \"shard\") localGenerationDirs.add(membership.shardDir);\n }\n for (const shardDir of localGenerationDirs) {\n if (\n generationDirs.has(shardDir) ||\n deferredGenerationDirs.has(shardDir) ||\n options.omittedGenerationDirs.has(shardDir)\n ) {\n continue;\n }\n const localMembers = [...options.currentMap.keys()].filter(\n (relPath) => embeddingGenerationMembership(relPath)?.shardDir === shardDir,\n );\n if (localMembers.length === 0) continue;\n // Tombstone or shared-base absence authorizes whole-generation removal.\n const baseMembers = localMembers.filter((relPath) => options.baseMap.has(relPath));\n // Tombstone evidence is satisfied by the members the REMOTE knew: the\n // remote cannot tombstone local-only extras or an inert legacy marker,\n // and the removal sweeps those once the remote deletion is established.\n // Non-empty same-generation tombstones establish remote absence on\n // their own: they may name shards already absent locally (removed in an\n // earlier round), so the set is NOT required to intersect localMembers\n // (codex round 6, XiOb).\n const tombstonedMembers =\n options.deletionMtimeByPath === undefined\n ? []\n : [...options.deletionMtimeByPath.keys()].filter(\n (relPath) => embeddingGenerationMembership(relPath)?.shardDir === shardDir,\n );\n const tombstoneCovered = tombstonedMembers.length > 0;\n const baseEvidenced =\n baseMembers.length > 0 && baseMembers.every((relPath) => !options.incomingMap.has(relPath));\n if (!tombstoneCovered && !baseEvidenced) continue;\n transactionResults.push(await applyEmbeddingGenerationRemoval({\n root: options.root,\n shardDirRel: shardDir,\n io: { deleteFile: options.io.deleteFile, readFile: options.io.readFile },\n deletionMtimeByPath: options.deletionMtimeByPath,\n baseStates: options.baseMap,\n now: options.now,\n }));\n }\n return { transactionResults, deferredGenerationDirs };\n}\n"],"mappings":"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","names":["removedPaths"]}
|