@remnic/core 10.0.49 → 10.0.51
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 +49 -48
- package/dist/access-authorization-probe.js +50 -49
- package/dist/access-boundary.d.ts +6 -1
- package/dist/access-boundary.d.ts.map +1 -1
- package/dist/access-boundary.js +49 -48
- package/dist/access-cli.js +120 -119
- package/dist/access-cli.js.map +1 -1
- package/dist/access-errors.d.ts.map +1 -1
- package/dist/access-errors.js +1 -1
- package/dist/access-extraction-force-flush.js +49 -48
- 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 +50 -49
- package/dist/access-http-query.js +51 -50
- package/dist/access-http.d.ts.map +1 -1
- package/dist/access-http.js +70 -69
- package/dist/access-identity-continuity-surface.js +49 -48
- package/dist/access-lcm-surface.js +49 -48
- package/dist/access-mcp.js +60 -59
- package/dist/access-memory-search-fanout.js +2 -2
- package/dist/access-namespace-preflight.js +49 -48
- 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 +10 -10
- package/dist/access-observe-write-surface.d.ts.map +1 -1
- package/dist/access-observe-write-surface.js +49 -48
- package/dist/access-offline-manifest.js +6 -6
- package/dist/access-operations-batch.js +50 -49
- package/dist/access-operations.js +57 -56
- package/dist/access-recall-concurrency.js +49 -48
- package/dist/access-recall-diagnostics.js +2 -2
- package/dist/access-recall-response.js +49 -48
- package/dist/access-recall-surface.js +49 -48
- package/dist/access-schema.d.ts +245 -773
- package/dist/access-schema.d.ts.map +1 -1
- package/dist/access-schema.js +6 -6
- package/dist/access-service.d.ts +5 -0
- package/dist/access-service.d.ts.map +1 -1
- package/dist/access-service.js +49 -48
- package/dist/access-surface-catalog.js +51 -50
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/access-token-capabilities.js +2 -2
- package/dist/active-recall.js +16 -16
- 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 +12 -11
- package/dist/buffer.js +3 -3
- package/dist/calibration.js +2 -2
- package/dist/{capsule-merge-RNQUP2VL.js → capsule-merge-D4BTIJGK.js} +3 -3
- package/dist/causal-consolidation.js +11 -11
- package/dist/{chunk-ESDOQEJM.js → chunk-2AKIVSHP.js} +2 -2
- package/dist/{chunk-BWF3KNSQ.js → chunk-2EXF6IIB.js} +2 -2
- package/dist/{chunk-AGCEJDG2.js → chunk-2ONKXEC7.js} +3 -3
- package/dist/{chunk-3NYIXVCT.js → chunk-2S6JADBB.js} +2 -2
- package/dist/chunk-2S6JADBB.js.map +1 -0
- package/dist/{chunk-ZSEFGDCI.js → chunk-2TGIKMMZ.js} +2 -2
- package/dist/{chunk-MCS4LIXP.js → chunk-43TUWQNR.js} +2 -2
- package/dist/{chunk-Q6PYCPHO.js → chunk-44EUCSG4.js} +2 -2
- package/dist/{chunk-2J6BIOVN.js → chunk-4FM35YIA.js} +3 -3
- package/dist/{chunk-2NLCDNGA.js → chunk-564YP3DW.js} +2 -2
- package/dist/{chunk-YY6PWFUC.js → chunk-6ZAU7LAR.js} +3 -3
- package/dist/{chunk-HCPVL6SF.js → chunk-72CBJ5VP.js} +3 -3
- package/dist/{chunk-AF4UIHON.js → chunk-74AY3S7U.js} +9 -9
- package/dist/{chunk-N6EM7ESC.js → chunk-75BK4XGV.js} +27 -19
- package/dist/chunk-75BK4XGV.js.map +1 -0
- package/dist/{chunk-5IDQVE4U.js → chunk-A3UFV4K3.js} +6 -6
- package/dist/{chunk-LWRIGKFM.js → chunk-A5L5KGDI.js} +19 -1
- package/dist/chunk-A5L5KGDI.js.map +1 -0
- package/dist/{chunk-RZDDNH63.js → chunk-A6JDT6QF.js} +27 -15
- package/dist/chunk-A6JDT6QF.js.map +1 -0
- package/dist/{chunk-XFND63OB.js → chunk-AHGOOZUC.js} +2 -2
- package/dist/{chunk-A7AISUJI.js → chunk-AJG2TAMR.js} +2 -2
- package/dist/{chunk-2BY56HE6.js → chunk-AZLD4CKG.js} +36 -36
- package/dist/{chunk-E47UQBYW.js → chunk-B35EQQ7L.js} +3 -3
- package/dist/{chunk-E6UNM67F.js → chunk-B6SPPYGJ.js} +2 -2
- package/dist/{chunk-CMOYD5CA.js → chunk-CCL2OXFO.js} +2 -2
- package/dist/{chunk-SVJ5JVZO.js → chunk-CK6GCGMX.js} +4 -4
- package/dist/{chunk-QZK6HG4J.js → chunk-DF6ZF2BN.js} +3 -3
- package/dist/{chunk-CPBYKOTC.js → chunk-DJFULNXK.js} +4 -4
- package/dist/{chunk-VGRBKEBH.js → chunk-DQOGZZJA.js} +3 -3
- package/dist/{chunk-YB3WN6XA.js → chunk-EC2KVA27.js} +12 -12
- package/dist/{chunk-FRXS6SC7.js → chunk-EKUI7I2X.js} +20 -4
- package/dist/chunk-EKUI7I2X.js.map +1 -0
- package/dist/{chunk-YNDLCWXS.js → chunk-EZ25VE3G.js} +4 -4
- package/dist/{chunk-WIBWONL4.js → chunk-EZS6QJNC.js} +2 -2
- package/dist/{chunk-C7WDWD35.js → chunk-FNNGWN3O.js} +5 -5
- package/dist/{chunk-PBWJVRKE.js → chunk-FT75AQ74.js} +3 -3
- package/dist/{chunk-VY6BD5KB.js → chunk-G6A3SGCE.js} +14 -12
- package/dist/chunk-G6A3SGCE.js.map +1 -0
- package/dist/{chunk-O4CA53UY.js → chunk-GBGU5OZP.js} +111 -104
- package/dist/chunk-GBGU5OZP.js.map +1 -0
- package/dist/{chunk-WJCAAVZX.js → chunk-GE3ZX6YK.js} +2 -2
- package/dist/{chunk-3PVKV3XL.js → chunk-HCIRR3BA.js} +3 -3
- package/dist/{chunk-BJTFLP3J.js → chunk-HEF4BRMT.js} +3 -3
- package/dist/{chunk-BMG3SAXA.js → chunk-HQUYENKK.js} +9 -12
- package/dist/chunk-HQUYENKK.js.map +1 -0
- package/dist/{chunk-6UDLN4IA.js → chunk-I6ORDT54.js} +2 -2
- package/dist/{chunk-N5PISU26.js → chunk-IN6U2BS5.js} +2 -2
- package/dist/{chunk-3INLTKTW.js → chunk-IUQXRRJB.js} +4 -4
- package/dist/{chunk-6W3QH3QW.js → chunk-JIJAWTRK.js} +388 -292
- package/dist/chunk-JIJAWTRK.js.map +1 -0
- package/dist/{chunk-4KS4IHKH.js → chunk-JX3E4XCW.js} +2 -2
- package/dist/{chunk-SW3WHVKN.js → chunk-KAJYSO3U.js} +2 -2
- package/dist/{chunk-D76AHITY.js → chunk-KETS5A62.js} +2 -2
- package/dist/{chunk-LCHFINL4.js → chunk-KIWO4327.js} +2 -2
- package/dist/{chunk-FC3ZFEXF.js → chunk-KJ3MDX4V.js} +2 -2
- package/dist/{chunk-7LCGFUMB.js → chunk-KQAFEZQX.js} +4 -4
- package/dist/{chunk-6TIVVOVU.js → chunk-L3EFYRYK.js} +9 -9
- package/dist/{chunk-3MUKQQ7A.js → chunk-LGEH473S.js} +24 -29
- package/dist/chunk-LGEH473S.js.map +1 -0
- package/dist/{chunk-X52SXKVC.js → chunk-LMB47UM6.js} +2 -2
- package/dist/{chunk-A3WXV7YU.js → chunk-LWMLBVGB.js} +2 -2
- package/dist/{chunk-KMTMMBEB.js → chunk-MC7PXJDP.js} +7 -7
- package/dist/{chunk-NMOEOQV4.js → chunk-MUNYUSBU.js} +2 -2
- package/dist/{chunk-VKUMKVEU.js → chunk-OCRLJJOV.js} +5 -5
- package/dist/{chunk-XSJL62LE.js → chunk-ON77FQXH.js} +2 -2
- package/dist/{chunk-C3HRYVGD.js → chunk-POJRFSJM.js} +3 -3
- package/dist/{chunk-LKRXGOQW.js → chunk-QA3Y2O6H.js} +2 -2
- package/dist/{chunk-23ZLN5X6.js → chunk-QT5MGENX.js} +14 -6
- package/dist/chunk-QT5MGENX.js.map +1 -0
- package/dist/{chunk-QFTNWDJ6.js → chunk-RA7YRL6H.js} +2 -2
- package/dist/{chunk-WQFHHJWK.js → chunk-RJDYDF5K.js} +4 -4
- package/dist/{chunk-E3DL3CAL.js → chunk-ROAKLYOL.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-NWIT3U2N.js → chunk-S5CQI2KF.js} +2 -2
- package/dist/{chunk-P6P35FY4.js → chunk-SDESKFKT.js} +2 -2
- package/dist/{chunk-OD7ZXCUF.js → chunk-SFRBUBUZ.js} +10 -10
- package/dist/{chunk-7XFQSQYS.js → chunk-SHNM7RIT.js} +5 -4
- package/dist/chunk-SHNM7RIT.js.map +1 -0
- package/dist/{chunk-NH37SP6V.js → chunk-SJD334AG.js} +81 -78
- package/dist/chunk-SJD334AG.js.map +1 -0
- package/dist/{chunk-O7GNSHFF.js → chunk-SPTPBKZX.js} +2 -2
- package/dist/{chunk-HI53EK3Y.js → chunk-TC55M5PO.js} +2 -2
- package/dist/{chunk-SA6P2KS3.js → chunk-TEH5MDX5.js} +33 -17
- package/dist/chunk-TEH5MDX5.js.map +1 -0
- package/dist/{chunk-FOKTW6GY.js → chunk-UCLJTGP3.js} +2 -2
- package/dist/{chunk-FYZXZUGU.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-754XN6LX.js → chunk-V27FK6D6.js} +2 -2
- package/dist/{chunk-DM6SOROF.js → chunk-V6Z4NAJZ.js} +2 -2
- package/dist/{chunk-5FNZ3G6X.js → chunk-VKQI47DJ.js} +4 -4
- package/dist/{chunk-NUK5XU3P.js → chunk-VUMWVYMR.js} +28 -13
- package/dist/chunk-VUMWVYMR.js.map +1 -0
- package/dist/{chunk-MPJDQC4G.js → chunk-WJCXUE2J.js} +2 -2
- package/dist/{chunk-VCBS5GRQ.js → chunk-WY66J4PI.js} +2 -2
- package/dist/chunk-X2KO4FK5.js +40 -0
- package/dist/chunk-X2KO4FK5.js.map +1 -0
- package/dist/{chunk-OOOX5C4X.js → chunk-XL2EE5W3.js} +4 -4
- package/dist/{chunk-V4GPFCJ7.js → chunk-XWJUFER3.js} +3 -3
- package/dist/{chunk-CZVNOTLR.js → chunk-XXR4A33N.js} +2 -2
- package/dist/{chunk-CRJX4OMN.js → chunk-Y3T5KQCR.js} +2 -2
- package/dist/{chunk-KNCR7APE.js → chunk-Y77FXULH.js} +8 -8
- package/dist/{chunk-2AV2U2SZ.js → chunk-YDIOMDBW.js} +2 -2
- package/dist/{chunk-IG747LRN.js → chunk-YO2JEX2Z.js} +2 -2
- package/dist/{chunk-HDT3DMUF.js → chunk-ZKK3VMWU.js} +2 -2
- package/dist/cli.js +92 -91
- package/dist/coding/export-okf-codegraph.js +9 -9
- package/dist/compounding/engine.js +11 -11
- package/dist/config.js +16 -16
- package/dist/connectors/codex-materialize-runner.js +10 -10
- package/dist/connectors/index.js +14 -14
- package/dist/consolidation-provenance-check.js +4 -4
- package/dist/consolidation-undo.js +2 -2
- package/dist/convergence-refresh.js +12 -12
- package/dist/corpus-watermark.js +14 -14
- 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-config.js +2 -2
- package/dist/deep-recall-http-glue.js +9 -9
- package/dist/{entity-canonical-id-migration-2YOLMOFC.js → entity-canonical-id-migration-F3JVG6K6.js} +3 -3
- package/dist/entity-canonical-id-migration-F3JVG6K6.js.map +1 -0
- package/dist/entity-retrieval.js +11 -11
- package/dist/explicit-capture.js +2 -2
- package/dist/external-wiki-access.js +50 -49
- package/dist/extraction-span-wire.d.ts.map +1 -1
- package/dist/extraction-span-wire.js +1 -1
- package/dist/extraction.js +22 -22
- package/dist/{first-start-migration-QVD22WWS.js → first-start-migration-A6PHIBUQ.js} +4 -4
- package/dist/harmonic-retrieval.js +10 -10
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +143 -135
- package/dist/lcm/engine.js +2 -2
- package/dist/lcm/index.js +5 -5
- package/dist/local-llm.js +2 -2
- package/dist/location/index.js +16 -16
- package/dist/location/tagging.d.ts +7 -5
- package/dist/location/tagging.d.ts.map +1 -1
- package/dist/maintenance/memory-governance.js +10 -10
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +10 -10
- package/dist/maintenance/rebuild-memory-projection-runner.js +12 -12
- package/dist/maintenance/rebuild-memory-projection.js +11 -11
- package/dist/memory-browse-http-glue.js +2 -2
- package/dist/memory-browse-operations.js +50 -49
- package/dist/namespaces/migrate.js +11 -11
- package/dist/namespaces/storage.js +10 -10
- 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-impression-drain.js +2 -2
- package/dist/offline-sync-snapshot-stream.js +4 -4
- package/dist/offline-sync-upload-staging.js +2 -2
- package/dist/offline-sync.d.ts.map +1 -1
- package/dist/offline-sync.js +3 -3
- package/dist/operator-doctor-corpus.js +17 -17
- package/dist/operator-doctor-replica.js +4 -4
- package/dist/operator-toolkit.js +29 -29
- package/dist/orchestration/maintenance.js +25 -25
- package/dist/orchestrator.d.ts +1 -0
- package/dist/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator.js +122 -121
- package/dist/page-versioning.js +2 -2
- package/dist/recall-navigation-http-glue.js +2 -2
- package/dist/recall-navigation-operations.js +50 -49
- package/dist/recall-navigation.js +49 -48
- package/dist/relay/mission.d.ts +731 -3403
- package/dist/relay/mission.d.ts.map +1 -1
- package/dist/replica-divergence.js +3 -3
- package/dist/resume-bundles.js +17 -17
- package/dist/schemas.d.ts +346 -1771
- package/dist/schemas.d.ts.map +1 -1
- package/dist/semantic-consolidation.js +15 -15
- package/dist/semantic-rule-promotion.js +10 -10
- package/dist/semantic-rule-verifier.js +10 -10
- package/dist/shared-context/manager.d.ts +13 -33
- package/dist/shared-context/manager.d.ts.map +1 -1
- package/dist/source-agent-qualifier.js +18 -18
- package/dist/standup/build.js +11 -11
- 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 +9 -9
- package/dist/summarizer.js +3 -3
- package/dist/support-passport/access-operations.d.ts +51 -51
- package/dist/support-passport/contracts.d.ts +85 -126
- package/dist/support-passport/contracts.d.ts.map +1 -1
- package/dist/support-passport/generated-batch.d.ts +3 -17
- package/dist/support-passport/generated-batch.d.ts.map +1 -1
- package/dist/support-passport/grant-contracts.d.ts +75 -381
- package/dist/support-passport/grant-contracts.d.ts.map +1 -1
- package/dist/support-passport/index.js +52 -51
- package/dist/support-passport/model-audit.d.ts +17 -82
- package/dist/support-passport/model-audit.d.ts.map +1 -1
- package/dist/support-passport/model-bridge.d.ts +12 -51
- package/dist/support-passport/model-bridge.d.ts.map +1 -1
- package/dist/support-passport/model-contracts.d.ts +53 -192
- package/dist/support-passport/model-contracts.d.ts.map +1 -1
- package/dist/tokens.js +3 -3
- package/dist/transfer/capsule-export.js +2 -2
- package/dist/transfer/capsule-import.js +4 -4
- package/dist/transfer/export-okf.js +10 -10
- package/dist/transfer/types.d.ts +32 -737
- package/dist/transfer/types.d.ts.map +1 -1
- package/dist/verified-recall.js +10 -10
- package/dist/who-knows-cli.js +12 -12
- package/dist/who-knows.js +11 -11
- package/package.json +3 -4
- package/src/access-boundary.test.ts +14 -0
- package/src/access-boundary.ts +48 -42
- package/src/access-category-alias.test.ts +9 -7
- package/src/access-errors.test.ts +21 -9
- package/src/access-errors.ts +45 -31
- package/src/access-http-briefing.ts +4 -0
- package/src/access-http.test.ts +41 -12
- 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-schema.ts +13 -17
- package/src/access-service.ts +5 -0
- 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/correction/passive-correction-notifications-abort.test.ts +42 -0
- package/src/correction/passive-correction-notifications.ts +4 -0
- package/src/entity-lazy-compatibility.test.ts +229 -0
- package/src/entity-migration-completion-notification.test.ts +148 -0
- package/src/extraction-scope-source-agent.test.ts +6 -6
- package/src/extraction-span-wire.test.ts +28 -0
- package/src/extraction-span-wire.ts +34 -6
- package/src/index.ts +1 -1
- package/src/location/tagging.ts +14 -12
- package/src/offline-sync-file-io.ts +61 -2
- package/src/offline-sync.test.ts +313 -20
- package/src/offline-sync.ts +43 -21
- 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 +19 -10
- 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 +7 -2
- package/src/testing/subjects/entity-migration-completion-cache.test.ts +90 -0
- package/dist/chunk-23ZLN5X6.js.map +0 -1
- package/dist/chunk-3MUKQQ7A.js.map +0 -1
- package/dist/chunk-3NYIXVCT.js.map +0 -1
- package/dist/chunk-6W3QH3QW.js.map +0 -1
- package/dist/chunk-7XFQSQYS.js.map +0 -1
- package/dist/chunk-BMG3SAXA.js.map +0 -1
- package/dist/chunk-FRXS6SC7.js.map +0 -1
- package/dist/chunk-LWRIGKFM.js.map +0 -1
- package/dist/chunk-N6EM7ESC.js.map +0 -1
- package/dist/chunk-NH37SP6V.js.map +0 -1
- package/dist/chunk-NUK5XU3P.js.map +0 -1
- package/dist/chunk-O4CA53UY.js.map +0 -1
- package/dist/chunk-RZDDNH63.js.map +0 -1
- package/dist/chunk-SA6P2KS3.js.map +0 -1
- package/dist/chunk-SUKPM6DV.js.map +0 -1
- package/dist/chunk-VY6BD5KB.js.map +0 -1
- /package/dist/{auto-sync-BNCBMU6H.js.map → auto-sync-UQQ6YJSB.js.map} +0 -0
- /package/dist/{entity-canonical-id-migration-2YOLMOFC.js.map → briefing-deadline.js.map} +0 -0
- /package/dist/{capsule-merge-RNQUP2VL.js.map → capsule-merge-D4BTIJGK.js.map} +0 -0
- /package/dist/{chunk-ESDOQEJM.js.map → chunk-2AKIVSHP.js.map} +0 -0
- /package/dist/{chunk-BWF3KNSQ.js.map → chunk-2EXF6IIB.js.map} +0 -0
- /package/dist/{chunk-AGCEJDG2.js.map → chunk-2ONKXEC7.js.map} +0 -0
- /package/dist/{chunk-ZSEFGDCI.js.map → chunk-2TGIKMMZ.js.map} +0 -0
- /package/dist/{chunk-MCS4LIXP.js.map → chunk-43TUWQNR.js.map} +0 -0
- /package/dist/{chunk-Q6PYCPHO.js.map → chunk-44EUCSG4.js.map} +0 -0
- /package/dist/{chunk-2J6BIOVN.js.map → chunk-4FM35YIA.js.map} +0 -0
- /package/dist/{chunk-2NLCDNGA.js.map → chunk-564YP3DW.js.map} +0 -0
- /package/dist/{chunk-YY6PWFUC.js.map → chunk-6ZAU7LAR.js.map} +0 -0
- /package/dist/{chunk-HCPVL6SF.js.map → chunk-72CBJ5VP.js.map} +0 -0
- /package/dist/{chunk-AF4UIHON.js.map → chunk-74AY3S7U.js.map} +0 -0
- /package/dist/{chunk-5IDQVE4U.js.map → chunk-A3UFV4K3.js.map} +0 -0
- /package/dist/{chunk-XFND63OB.js.map → chunk-AHGOOZUC.js.map} +0 -0
- /package/dist/{chunk-A7AISUJI.js.map → chunk-AJG2TAMR.js.map} +0 -0
- /package/dist/{chunk-2BY56HE6.js.map → chunk-AZLD4CKG.js.map} +0 -0
- /package/dist/{chunk-E47UQBYW.js.map → chunk-B35EQQ7L.js.map} +0 -0
- /package/dist/{chunk-E6UNM67F.js.map → chunk-B6SPPYGJ.js.map} +0 -0
- /package/dist/{chunk-CMOYD5CA.js.map → chunk-CCL2OXFO.js.map} +0 -0
- /package/dist/{chunk-SVJ5JVZO.js.map → chunk-CK6GCGMX.js.map} +0 -0
- /package/dist/{chunk-QZK6HG4J.js.map → chunk-DF6ZF2BN.js.map} +0 -0
- /package/dist/{chunk-CPBYKOTC.js.map → chunk-DJFULNXK.js.map} +0 -0
- /package/dist/{chunk-VGRBKEBH.js.map → chunk-DQOGZZJA.js.map} +0 -0
- /package/dist/{chunk-YB3WN6XA.js.map → chunk-EC2KVA27.js.map} +0 -0
- /package/dist/{chunk-YNDLCWXS.js.map → chunk-EZ25VE3G.js.map} +0 -0
- /package/dist/{chunk-WIBWONL4.js.map → chunk-EZS6QJNC.js.map} +0 -0
- /package/dist/{chunk-C7WDWD35.js.map → chunk-FNNGWN3O.js.map} +0 -0
- /package/dist/{chunk-PBWJVRKE.js.map → chunk-FT75AQ74.js.map} +0 -0
- /package/dist/{chunk-WJCAAVZX.js.map → chunk-GE3ZX6YK.js.map} +0 -0
- /package/dist/{chunk-3PVKV3XL.js.map → chunk-HCIRR3BA.js.map} +0 -0
- /package/dist/{chunk-BJTFLP3J.js.map → chunk-HEF4BRMT.js.map} +0 -0
- /package/dist/{chunk-6UDLN4IA.js.map → chunk-I6ORDT54.js.map} +0 -0
- /package/dist/{chunk-N5PISU26.js.map → chunk-IN6U2BS5.js.map} +0 -0
- /package/dist/{chunk-3INLTKTW.js.map → chunk-IUQXRRJB.js.map} +0 -0
- /package/dist/{chunk-4KS4IHKH.js.map → chunk-JX3E4XCW.js.map} +0 -0
- /package/dist/{chunk-SW3WHVKN.js.map → chunk-KAJYSO3U.js.map} +0 -0
- /package/dist/{chunk-D76AHITY.js.map → chunk-KETS5A62.js.map} +0 -0
- /package/dist/{chunk-LCHFINL4.js.map → chunk-KIWO4327.js.map} +0 -0
- /package/dist/{chunk-FC3ZFEXF.js.map → chunk-KJ3MDX4V.js.map} +0 -0
- /package/dist/{chunk-7LCGFUMB.js.map → chunk-KQAFEZQX.js.map} +0 -0
- /package/dist/{chunk-6TIVVOVU.js.map → chunk-L3EFYRYK.js.map} +0 -0
- /package/dist/{chunk-X52SXKVC.js.map → chunk-LMB47UM6.js.map} +0 -0
- /package/dist/{chunk-A3WXV7YU.js.map → chunk-LWMLBVGB.js.map} +0 -0
- /package/dist/{chunk-KMTMMBEB.js.map → chunk-MC7PXJDP.js.map} +0 -0
- /package/dist/{chunk-NMOEOQV4.js.map → chunk-MUNYUSBU.js.map} +0 -0
- /package/dist/{chunk-VKUMKVEU.js.map → chunk-OCRLJJOV.js.map} +0 -0
- /package/dist/{chunk-XSJL62LE.js.map → chunk-ON77FQXH.js.map} +0 -0
- /package/dist/{chunk-C3HRYVGD.js.map → chunk-POJRFSJM.js.map} +0 -0
- /package/dist/{chunk-LKRXGOQW.js.map → chunk-QA3Y2O6H.js.map} +0 -0
- /package/dist/{chunk-QFTNWDJ6.js.map → chunk-RA7YRL6H.js.map} +0 -0
- /package/dist/{chunk-WQFHHJWK.js.map → chunk-RJDYDF5K.js.map} +0 -0
- /package/dist/{chunk-E3DL3CAL.js.map → chunk-ROAKLYOL.js.map} +0 -0
- /package/dist/{chunk-NWIT3U2N.js.map → chunk-S5CQI2KF.js.map} +0 -0
- /package/dist/{chunk-P6P35FY4.js.map → chunk-SDESKFKT.js.map} +0 -0
- /package/dist/{chunk-OD7ZXCUF.js.map → chunk-SFRBUBUZ.js.map} +0 -0
- /package/dist/{chunk-O7GNSHFF.js.map → chunk-SPTPBKZX.js.map} +0 -0
- /package/dist/{chunk-HI53EK3Y.js.map → chunk-TC55M5PO.js.map} +0 -0
- /package/dist/{chunk-FOKTW6GY.js.map → chunk-UCLJTGP3.js.map} +0 -0
- /package/dist/{chunk-FYZXZUGU.js.map → chunk-UQBOPCDK.js.map} +0 -0
- /package/dist/{chunk-754XN6LX.js.map → chunk-V27FK6D6.js.map} +0 -0
- /package/dist/{chunk-DM6SOROF.js.map → chunk-V6Z4NAJZ.js.map} +0 -0
- /package/dist/{chunk-5FNZ3G6X.js.map → chunk-VKQI47DJ.js.map} +0 -0
- /package/dist/{chunk-MPJDQC4G.js.map → chunk-WJCXUE2J.js.map} +0 -0
- /package/dist/{chunk-VCBS5GRQ.js.map → chunk-WY66J4PI.js.map} +0 -0
- /package/dist/{chunk-OOOX5C4X.js.map → chunk-XL2EE5W3.js.map} +0 -0
- /package/dist/{chunk-V4GPFCJ7.js.map → chunk-XWJUFER3.js.map} +0 -0
- /package/dist/{chunk-CZVNOTLR.js.map → chunk-XXR4A33N.js.map} +0 -0
- /package/dist/{chunk-CRJX4OMN.js.map → chunk-Y3T5KQCR.js.map} +0 -0
- /package/dist/{chunk-KNCR7APE.js.map → chunk-Y77FXULH.js.map} +0 -0
- /package/dist/{chunk-2AV2U2SZ.js.map → chunk-YDIOMDBW.js.map} +0 -0
- /package/dist/{chunk-IG747LRN.js.map → chunk-YO2JEX2Z.js.map} +0 -0
- /package/dist/{chunk-HDT3DMUF.js.map → chunk-ZKK3VMWU.js.map} +0 -0
- /package/dist/{first-start-migration-QVD22WWS.js.map → first-start-migration-A6PHIBUQ.js.map} +0 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { mkdir, mkdtemp, readFile, readdir, rm, symlink, unlink, writeFile } from "node:fs/promises";
|
|
4
|
+
import os from "node:os";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import test from "node:test";
|
|
7
|
+
|
|
8
|
+
import { StorageManager } from "./storage.js";
|
|
9
|
+
import { sleep } from "./utils/sleep.js";
|
|
10
|
+
|
|
11
|
+
// Issue #3139 (Q2 briefing 60s ceiling): the CLI briefing path awaits
|
|
12
|
+
// orchestrator.initialize(), which awaited storage.ensureDirectories(), which
|
|
13
|
+
// awaited the entity canonical-id migration lock/replay (up to a 300s bounded
|
|
14
|
+
// wait on a busy lock). Startup READ readiness must not sit behind that
|
|
15
|
+
// migration; writes must. These tests pin the boundary with the real on-disk
|
|
16
|
+
// migration lock and a real temp corpus — no orchestrator stubs. Every wait is
|
|
17
|
+
// bounded so a regression fails fast instead of stalling the run.
|
|
18
|
+
|
|
19
|
+
const MIGRATION_LOCK_FILE = path.join("state", "entity-canonical-id-migration.lock");
|
|
20
|
+
const MIGRATION_JOURNAL_FILE = path.join("state", "entity-canonical-id-migration-v1.json");
|
|
21
|
+
const READINESS_BUDGET_MS = 500;
|
|
22
|
+
const BARRIER_PROBE_MS = 250;
|
|
23
|
+
|
|
24
|
+
async function withMemoryDir(run: (dir: string) => Promise<void>): Promise<void> {
|
|
25
|
+
const dir = await mkdtemp(path.join(os.tmpdir(), "remnic-startup-migration-"));
|
|
26
|
+
try {
|
|
27
|
+
await run(dir);
|
|
28
|
+
} finally {
|
|
29
|
+
StorageManager.clearAllStaticCaches();
|
|
30
|
+
await rm(dir, { recursive: true, force: true });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Hold the migration's own cross-process lock (the exact file
|
|
36
|
+
* migrateLegacyEntityCanonicalIds acquires via withHeldFileLock: poll 50ms,
|
|
37
|
+
* stale 60s — a hold for the lifetime of one test). Returns the release.
|
|
38
|
+
*/
|
|
39
|
+
async function gateMigration(dir: string): Promise<() => Promise<void>> {
|
|
40
|
+
const lockPath = path.join(dir, MIGRATION_LOCK_FILE);
|
|
41
|
+
await mkdir(path.dirname(lockPath), { recursive: true });
|
|
42
|
+
await writeFile(lockPath, `${process.pid} startup-migration-test ${new Date().toISOString()}\n`);
|
|
43
|
+
return () => unlink(lockPath);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async function journalComplete(dir: string): Promise<boolean> {
|
|
47
|
+
try {
|
|
48
|
+
// SAFETY: the journal is written by this test fixture and carries an optional boolean `complete`.
|
|
49
|
+
const state = JSON.parse(await readFile(path.join(dir, MIGRATION_JOURNAL_FILE), "utf8")) as {
|
|
50
|
+
complete?: boolean;
|
|
51
|
+
};
|
|
52
|
+
return state.complete === true;
|
|
53
|
+
} catch {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
test("startup read readiness can defer the entity canonical-id migration", async () => {
|
|
59
|
+
await withMemoryDir(async (dir) => {
|
|
60
|
+
const storage = new StorageManager(dir);
|
|
61
|
+
const releaseGate = await gateMigration(dir);
|
|
62
|
+
const readiness = storage.ensureDirectories({ waitForEntityMigration: false });
|
|
63
|
+
// Regression: on the awaited path this call sits behind the held lock and
|
|
64
|
+
// only surfaces after the 300s bounded wait. The startup option must
|
|
65
|
+
// settle while the lock is still held — asserted against a bounded race
|
|
66
|
+
// so main fails behaviorally in ~500ms instead of stalling the job.
|
|
67
|
+
let failure: unknown;
|
|
68
|
+
try {
|
|
69
|
+
const outcome = await Promise.race([readiness, sleep(READINESS_BUDGET_MS).then(() => "timeout")]);
|
|
70
|
+
assert.notEqual(outcome, "timeout", "startup read readiness must not wait for the gated migration");
|
|
71
|
+
assert.equal(existsSync(path.join(dir, "entities")), true);
|
|
72
|
+
assert.equal(
|
|
73
|
+
existsSync(path.join(dir, MIGRATION_LOCK_FILE)),
|
|
74
|
+
true,
|
|
75
|
+
"the deferred startup must not take the migration lock",
|
|
76
|
+
);
|
|
77
|
+
assert.equal(
|
|
78
|
+
existsSync(path.join(dir, MIGRATION_JOURNAL_FILE)),
|
|
79
|
+
false,
|
|
80
|
+
"the deferred startup must not run the migration",
|
|
81
|
+
);
|
|
82
|
+
} catch (err) {
|
|
83
|
+
failure = err;
|
|
84
|
+
} finally {
|
|
85
|
+
await releaseGate();
|
|
86
|
+
}
|
|
87
|
+
// The write-side ensure still runs the migration and awaits it.
|
|
88
|
+
await readiness;
|
|
89
|
+
await storage.ensureDirectories();
|
|
90
|
+
if (failure !== undefined) throw failure;
|
|
91
|
+
assert.equal(await journalComplete(dir), true);
|
|
92
|
+
// Normal entity writes still work after the deferred migration settles.
|
|
93
|
+
await storage.writeEntity("Alice", "person", ["Alice works on Remnic"]);
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test("default ensureDirectories still waits behind a held migration lock", async () => {
|
|
98
|
+
await withMemoryDir(async (dir) => {
|
|
99
|
+
const storage = new StorageManager(dir);
|
|
100
|
+
const releaseGate = await gateMigration(dir);
|
|
101
|
+
let settled = false;
|
|
102
|
+
let setupError: Error | undefined;
|
|
103
|
+
const gatedSetup = storage.ensureDirectories().then(
|
|
104
|
+
() => {
|
|
105
|
+
settled = true;
|
|
106
|
+
},
|
|
107
|
+
(err: Error) => {
|
|
108
|
+
setupError = err;
|
|
109
|
+
settled = true;
|
|
110
|
+
},
|
|
111
|
+
);
|
|
112
|
+
let failure: unknown;
|
|
113
|
+
try {
|
|
114
|
+
await sleep(BARRIER_PROBE_MS);
|
|
115
|
+
assert.equal(settled, false, "default ensureDirectories must not resolve while the migration lock is held");
|
|
116
|
+
} catch (err) {
|
|
117
|
+
failure = err;
|
|
118
|
+
} finally {
|
|
119
|
+
await releaseGate();
|
|
120
|
+
}
|
|
121
|
+
await gatedSetup;
|
|
122
|
+
assert.equal(setupError, undefined);
|
|
123
|
+
if (failure !== undefined) throw failure;
|
|
124
|
+
assert.equal(await journalComplete(dir), true);
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test("deferred startup still refuses unsafe entity entries before serving reads", async () => {
|
|
129
|
+
const outside = await mkdtemp(path.join(os.tmpdir(), "remnic-startup-migration-outside-"));
|
|
130
|
+
try {
|
|
131
|
+
await withMemoryDir(async (dir) => {
|
|
132
|
+
const storage = new StorageManager(dir);
|
|
133
|
+
await mkdir(path.join(dir, "entities"), { recursive: true });
|
|
134
|
+
await symlink(path.join(outside, "leaked.md"), path.join(dir, "entities", "leaked.md"));
|
|
135
|
+
await assert.rejects(
|
|
136
|
+
() => storage.ensureDirectories({ waitForEntityMigration: false }),
|
|
137
|
+
/Refusing entity canonical-id migration through symlink/,
|
|
138
|
+
);
|
|
139
|
+
});
|
|
140
|
+
} finally {
|
|
141
|
+
await rm(outside, { recursive: true, force: true });
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
test("entity writes queue behind the migration they trigger", async () => {
|
|
146
|
+
await withMemoryDir(async (dir) => {
|
|
147
|
+
const storage = new StorageManager(dir);
|
|
148
|
+
const releaseGate = await gateMigration(dir);
|
|
149
|
+
const readiness = storage.ensureDirectories({ waitForEntityMigration: false });
|
|
150
|
+
const { promise: written, resolve: writeSettled } = Promise.withResolvers<void>();
|
|
151
|
+
let writeError: Error | undefined;
|
|
152
|
+
let failure: unknown;
|
|
153
|
+
try {
|
|
154
|
+
const outcome = await Promise.race([readiness, sleep(READINESS_BUDGET_MS).then(() => "timeout")]);
|
|
155
|
+
assert.notEqual(outcome, "timeout", "startup read readiness must not wait for the gated migration");
|
|
156
|
+
// A real entity write must queue behind the migration it triggers — the
|
|
157
|
+
// deferred startup opens READ readiness only.
|
|
158
|
+
storage.writeEntity("Alice", "person", ["Alice works on Remnic"]).then(
|
|
159
|
+
() => writeSettled(),
|
|
160
|
+
(err: Error) => {
|
|
161
|
+
writeError = err;
|
|
162
|
+
writeSettled();
|
|
163
|
+
},
|
|
164
|
+
);
|
|
165
|
+
const writeProbe = await Promise.race([written, sleep(BARRIER_PROBE_MS).then(() => "pending")]);
|
|
166
|
+
assert.equal(writeProbe, "pending", "entity writes must queue behind the migration they trigger");
|
|
167
|
+
} catch (err) {
|
|
168
|
+
failure = err;
|
|
169
|
+
} finally {
|
|
170
|
+
await releaseGate();
|
|
171
|
+
}
|
|
172
|
+
await readiness;
|
|
173
|
+
await storage.ensureDirectories();
|
|
174
|
+
if (failure === undefined) {
|
|
175
|
+
const settled = await Promise.race([written, sleep(10_000).then(() => "deadline")]);
|
|
176
|
+
assert.notEqual(settled, "deadline", "entity write must complete once the gate releases");
|
|
177
|
+
assert.equal(writeError, undefined);
|
|
178
|
+
const entries = await readdir(path.join(dir, "entities"));
|
|
179
|
+
assert.equal(entries.some((name) => name.endsWith(".md")), true, "entity file must land after the migration settles");
|
|
180
|
+
}
|
|
181
|
+
if (failure !== undefined) throw failure;
|
|
182
|
+
});
|
|
183
|
+
});
|
package/src/storage.ts
CHANGED
|
@@ -1923,6 +1923,8 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
1923
1923
|
onCatalogWrite?: () => void;
|
|
1924
1924
|
/** Post-write embedding hook (#2019). Installed by the orchestrator; fire-and-forget. */
|
|
1925
1925
|
onMemoryWrite?: (filePath: string) => void;
|
|
1926
|
+
/** Request search maintenance after a completed entity replay. */
|
|
1927
|
+
onEntityMigrationComplete?: () => void;
|
|
1926
1928
|
private notifyMemoryWrite(filePath: string): void {
|
|
1927
1929
|
try {
|
|
1928
1930
|
this.onMemoryWrite?.(filePath);
|
|
@@ -4834,13 +4836,16 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
4834
4836
|
candidateBatchPaths: string[],
|
|
4835
4837
|
remainingSlots: number,
|
|
4836
4838
|
remainingInspectionBudget: number,
|
|
4837
|
-
readBatchSize: number
|
|
4839
|
+
readBatchSize: number,
|
|
4840
|
+
options?: CorpusReadOptions
|
|
4838
4841
|
): Promise<{ memories: MemoryFile[]; filePaths: string[] }> {
|
|
4839
4842
|
const memories: MemoryFile[] = [];
|
|
4840
4843
|
const filePaths: string[] = [];
|
|
4841
4844
|
const normalizedReadBatchSize = this.normalizeMemoryReadBatchSize(readBatchSize);
|
|
4842
4845
|
|
|
4843
4846
|
for (let index = 0; index < candidateBatchPaths.length; ) {
|
|
4847
|
+
// Per batch: an abandoned caller must not keep the scan running (#3139).
|
|
4848
|
+
checkCorpusReadAbort(options);
|
|
4844
4849
|
if (memories.length >= remainingSlots || filePaths.length >= remainingInspectionBudget) break;
|
|
4845
4850
|
const availableSlots = remainingSlots - memories.length;
|
|
4846
4851
|
const availableInspectionBudget = remainingInspectionBudget - filePaths.length;
|
|
@@ -4853,7 +4858,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
4853
4858
|
index += candidatePaths.length;
|
|
4854
4859
|
if (candidatePaths.length === 0) break;
|
|
4855
4860
|
filePaths.push(...candidatePaths);
|
|
4856
|
-
const parsedMemories = await this.readParsedMemoriesFromPaths(candidatePaths, candidatePaths.length);
|
|
4861
|
+
const parsedMemories = await this.readParsedMemoriesFromPaths(candidatePaths, candidatePaths.length, options);
|
|
4857
4862
|
if (parsedMemories.length === 0) continue;
|
|
4858
4863
|
memories.push(...parsedMemories.slice(0, availableSlots));
|
|
4859
4864
|
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lifecycle matrix subject for the amortized entity migration-completion
|
|
3
|
+
* cache. Exercises the helper only through StorageManager.readEntity — never
|
|
4
|
+
* a direct cache test double.
|
|
5
|
+
*/
|
|
6
|
+
import assert from "node:assert/strict";
|
|
7
|
+
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
8
|
+
import path from "node:path";
|
|
9
|
+
|
|
10
|
+
import { StorageManager } from "../../storage.js";
|
|
11
|
+
import { type LifecycleSubject, type MatrixRow, runLifecycleMatrix } from "../lifecycle-matrix.js";
|
|
12
|
+
import { mkTempMemoryDir } from "../orchestrator-lite.js";
|
|
13
|
+
|
|
14
|
+
interface CompletionCacheState {
|
|
15
|
+
dir: string;
|
|
16
|
+
previousId: string;
|
|
17
|
+
reader: StorageManager;
|
|
18
|
+
warmMiss: string;
|
|
19
|
+
afterAlias?: string;
|
|
20
|
+
afterRestart?: string;
|
|
21
|
+
restarted?: StorageManager;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const subject: LifecycleSubject<CompletionCacheState> = {
|
|
25
|
+
async setup(row: MatrixRow): Promise<CompletionCacheState> {
|
|
26
|
+
const dir = await mkTempMemoryDir(`entity-mig-complete-${row.id}`);
|
|
27
|
+
try {
|
|
28
|
+
const seed = new StorageManager(dir);
|
|
29
|
+
const previousId = await seed.writeEntity("Café", "project", ["Synthetic legacy fact."]);
|
|
30
|
+
await seed.ensureDirectories();
|
|
31
|
+
const reader = new StorageManager(dir);
|
|
32
|
+
await reader.ensureDirectories({ waitForEntityMigration: false });
|
|
33
|
+
return { dir, previousId, reader, warmMiss: "" };
|
|
34
|
+
} catch (error) {
|
|
35
|
+
await rm(dir, { recursive: true, force: true });
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
async exercise(state: CompletionCacheState, row: MatrixRow): Promise<void> {
|
|
41
|
+
// Warm the amortized completion verdict on a miss (key + fingerprint path).
|
|
42
|
+
state.warmMiss = await state.reader.readEntity("project-missing");
|
|
43
|
+
|
|
44
|
+
await mkdir(path.join(state.dir, "config"), { recursive: true });
|
|
45
|
+
await writeFile(path.join(state.dir, "config", "aliases.json"), JSON.stringify({ café: "coffee" }));
|
|
46
|
+
await state.reader.loadAliases();
|
|
47
|
+
const canonical = state.reader.normalizeEntityName("Café", "project");
|
|
48
|
+
assert.notEqual(canonical, state.previousId, `${row.id}: alias must move the canonical id`);
|
|
49
|
+
state.afterAlias = await state.reader.readEntity(canonical);
|
|
50
|
+
|
|
51
|
+
if (row.dimensions.restart) {
|
|
52
|
+
const restarted = new StorageManager(state.dir);
|
|
53
|
+
state.restarted = restarted;
|
|
54
|
+
await restarted.ensureDirectories({ waitForEntityMigration: false });
|
|
55
|
+
await restarted.loadAliases();
|
|
56
|
+
state.afterRestart = await restarted.readEntity(restarted.normalizeEntityName("Café", "project"));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (row.dimensions.dedupeOrReplay) {
|
|
60
|
+
// Second miss with stable inputs must stay a cheap empty miss (no throw).
|
|
61
|
+
assert.equal(await state.reader.readEntity("project-missing-again"), "");
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
async invariants(state: CompletionCacheState, row: MatrixRow): Promise<void> {
|
|
66
|
+
assert.equal(state.warmMiss, "", `${row.id}: warm miss must return empty`);
|
|
67
|
+
assert.match(
|
|
68
|
+
state.afterAlias ?? "",
|
|
69
|
+
/Synthetic legacy fact/,
|
|
70
|
+
`${row.id}: alias drift must not hide the entity behind a stale completion cache`,
|
|
71
|
+
);
|
|
72
|
+
if (row.dimensions.restart) {
|
|
73
|
+
assert.match(
|
|
74
|
+
state.afterRestart ?? "",
|
|
75
|
+
/Synthetic legacy fact/,
|
|
76
|
+
`${row.id}: restarted reader must still resolve the alias-moved entity`,
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
async teardown(state: CompletionCacheState): Promise<void> {
|
|
82
|
+
// The deferred startup replay runs in the background; let it finish before the directory goes.
|
|
83
|
+
await state.reader.drainEntityCanonicalIdMigration();
|
|
84
|
+
await state.restarted?.drainEntityCanonicalIdMigration();
|
|
85
|
+
StorageManager.clearAllStaticCaches();
|
|
86
|
+
await rm(state.dir, { recursive: true, force: true });
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
runLifecycleMatrix("entity-migration-completion-cache", subject);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/extraction-span-wire.ts"],"sourcesContent":["/**\n * Extraction seam for span mode (issue #2333 leftover slice + #2952).\n *\n * Default off. Callers pass `enabled` to `applySpanMode`. The provider JSON\n * schema is mode-aware so off-mode structured output cannot advertise `span`.\n */\n\nimport { zodToJsonSchema } from \"zod-to-json-schema\";\nimport type { ExtractionSpanConfig } from \"./extraction-span-config.js\";\nimport { parseSpanOffsets, type ParsedSpan } from \"./extraction-span.js\";\nimport { ExtractionProviderOutputSchema } from \"./schemas.js\";\n\nexport function applySpanMode(opts: {\n enabled?: boolean | 0 | 1;\n text: string;\n start: number;\n end: number;\n}): ParsedSpan {\n return parseSpanOffsets(opts.text, { start: opts.start, end: opts.end }, opts.enabled);\n}\n\nconst JSON_SCHEMA_OPTS = { $refStrategy: \"none\" as const, effectStrategy: \"input\" as const };\n\nconst EXTRACTION_PROVIDER_JSON_SCHEMA_WITH_SPAN = zodToJsonSchema(\n ExtractionProviderOutputSchema,\n JSON_SCHEMA_OPTS,\n) as Record<string, unknown>;\n\ntype FactItems = {\n properties?: Record<string, unknown>;\n required?: string[];\n};\n\nfunction omitFactSpan(schema: Record<string, unknown>): Record<string, unknown> {\n const clone = structuredClone(schema) as {\n properties?: { facts?: { items?: FactItems } };\n };\n const items = clone.properties?.facts?.items;\n if (!items?.properties || !(\"span\" in items.properties)) {\n throw new Error(\"extraction provider schema is missing facts.items.properties.span\");\n }\n delete items.properties.span;\n if (Array.isArray(items.required)) {\n items.required = items.required.filter((key) => key !== \"span\");\n }\n return clone as Record<string, unknown>;\n}\n\nconst EXTRACTION_PROVIDER_JSON_SCHEMA_WITHOUT_SPAN = omitFactSpan(\n EXTRACTION_PROVIDER_JSON_SCHEMA_WITH_SPAN,\n);\n\n/** Provider JSON schema: `span` is present in on/shadow, absent in off. */\nexport function extractionProviderJsonSchema(\n spanMode: ExtractionSpanConfig[\"spanMode\"] = \"off\",\n): Record<string, unknown> {\n return spanMode === \"off\"\n ? EXTRACTION_PROVIDER_JSON_SCHEMA_WITHOUT_SPAN\n : EXTRACTION_PROVIDER_JSON_SCHEMA_WITH_SPAN;\n}\n\nexport function extractionProviderResponseFormat(spanMode: ExtractionSpanConfig[\"spanMode\"] = \"off\") {\n return {\n type: \"json_schema\" as const,\n json_schema: {\n name: \"extraction_result\",\n schema: extractionProviderJsonSchema(spanMode),\n strict: false,\n },\n };\n}\n"],"mappings":";;;;;;;;AAOA,SAAS,uBAAuB;AAKzB,SAAS,cAAc,MAKf;AACb,SAAO,iBAAiB,KAAK,MAAM,EAAE,OAAO,KAAK,OAAO,KAAK,KAAK,IAAI,GAAG,KAAK,OAAO;AACvF;AAEA,IAAM,mBAAmB,EAAE,cAAc,QAAiB,gBAAgB,QAAiB;AAE3F,IAAM,4CAA4C;AAAA,EAChD;AAAA,EACA;AACF;AAOA,SAAS,aAAa,QAA0D;AAC9E,QAAM,QAAQ,gBAAgB,MAAM;AAGpC,QAAM,QAAQ,MAAM,YAAY,OAAO;AACvC,MAAI,CAAC,OAAO,cAAc,EAAE,UAAU,MAAM,aAAa;AACvD,UAAM,IAAI,MAAM,mEAAmE;AAAA,EACrF;AACA,SAAO,MAAM,WAAW;AACxB,MAAI,MAAM,QAAQ,MAAM,QAAQ,GAAG;AACjC,UAAM,WAAW,MAAM,SAAS,OAAO,CAAC,QAAQ,QAAQ,MAAM;AAAA,EAChE;AACA,SAAO;AACT;AAEA,IAAM,+CAA+C;AAAA,EACnD;AACF;AAGO,SAAS,6BACd,WAA6C,OACpB;AACzB,SAAO,aAAa,QAChB,+CACA;AACN;AAEO,SAAS,iCAAiC,WAA6C,OAAO;AACnG,SAAO;AAAA,IACL,MAAM;AAAA,IACN,aAAa;AAAA,MACX,MAAM;AAAA,MACN,QAAQ,6BAA6B,QAAQ;AAAA,MAC7C,QAAQ;AAAA,IACV;AAAA,EACF;AACF;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/access-errors.ts"],"sourcesContent":["/**\n * Tool-surface error enrichment: nearest-tool suggestions and arg-shape hints.\n *\n * Each function is a pure message builder — it returns a better error string\n * without changing semantics, status codes, or rejection behavior.\n *\n * @module access-errors\n */\n\nimport type { ZodError } from \"zod\";\n\n// ─── Existing error classes (restored from pre-#3042) ─────────────────────\n\n/** Authenticated caller lacks the required authorization (HTTP 403). */\nexport class EngramAccessForbiddenError extends Error {}\n\n/** Invalid caller input (HTTP 400). */\nexport class EngramAccessInputError extends Error {}\n\n/**\n * A write rejected by the namespace write-ACL (issue #1888). Subclasses\n * EngramAccessInputError so every existing catch/HTTP-400 mapping still\n * applies, but carries the attempted namespace + principal so the observe/\n * write surfaces can dead-letter the payload before re-throwing (fail-closed\n * placement is unchanged; only the destroyed-payload behavior is fixed).\n */\nexport class NamespaceNotWritableError extends EngramAccessInputError {\n constructor(\n readonly attemptedNamespace: string,\n readonly principal: string | undefined,\n message?: string,\n ) {\n super(message ?? `namespace is not writable: ${attemptedNamespace}`);\n this.name = \"NamespaceNotWritableError\";\n }\n}\n\n// ─── Levenshtein distance ─────────────────────────────────────────────────\n\n/**\n * Standard Levenshtein edit distance. O(n*m) over bounded inputs.\n * Exported so the test can verify it without importing private helpers.\n */\nexport function levenshtein(a: string, b: string): number {\n const an = a.length;\n const bn = b.length;\n // Fast paths for empty strings.\n if (an === 0) return bn;\n if (bn === 0) return an;\n\n // Use two rows to keep memory O(min(n,m)).\n let prev: number[] = [];\n let curr: number[] = [];\n\n // Align loops to the shorter string.\n const [shorter, longer, sn, ln] =\n an < bn ? [a, b, an, bn] : [b, a, bn, an];\n\n for (let i = 0; i <= sn; i++) prev[i] = i;\n\n for (let j = 1; j <= ln; j++) {\n curr[0] = j;\n for (let i = 1; i <= sn; i++) {\n const cost = shorter[i - 1] === longer[j - 1] ? 0 : 1;\n curr[i] = Math.min(\n prev[i] + 1, // deletion\n curr[i - 1] + 1, // insertion\n prev[i - 1] + cost, // substitution\n );\n }\n [prev, curr] = [curr, prev];\n }\n return prev[sn];\n}\n\n// ─── Similar-name helpers ─────────────────────────────────────────────────\n\nconst SUGGESTION_DISTANCE_CAP = 3;\n/**\n * Upper bound on the requested tool name. Anything longer is rejected before\n * the O(n*m) Levenshtein pass (#3042 review, P2): a 128 KB request over ~30\n * tools would otherwise run hundreds of millions of comparisons and block\n * the server event loop. The repo documents 64 chars as the tool-name shape;\n * this matches the limit enforced by every published surface.\n */\nexport const SUGGESTION_REQUEST_MAX_LEN = 64;\n\nexport interface SuggestionCandidate {\n name: string;\n distance: number;\n}\n\n/**\n * Find the nearest registered tool names by Levenshtein distance.\n * Results are sorted by distance ascending then name ascending (deterministic).\n * Only names with distance <= {@link SUGGESTION_DISTANCE_CAP} are returned;\n * when no name is that close the caller falls back to listing the full set.\n */\nexport function nearestSuggestions(\n requested: string,\n registeredNames: readonly string[],\n): SuggestionCandidate[] {\n // Defense in depth: the entry point already caps; this guards any direct\n // caller of the helper from an unbounded Levenshtein pass (issue #3042).\n if (requested.length > SUGGESTION_REQUEST_MAX_LEN) return [];\n const candidates: SuggestionCandidate[] = [];\n for (const name of registeredNames) {\n const distance = levenshtein(requested.toLowerCase(), name.toLowerCase());\n if (distance <= SUGGESTION_DISTANCE_CAP) {\n candidates.push({ name, distance });\n }\n }\n // Total comparator: distance asc, then name asc.\n candidates.sort((a, b) => {\n if (a.distance !== b.distance) return a.distance < b.distance ? -1 : 1;\n return a.name < b.name ? -1 : a.name > b.name ? 1 : 0;\n });\n return candidates;\n}\n\n/**\n * Build a human-readable \"did you mean?\" suggestion string.\n * When no close match is found, returns a fallback listing.\n */\nfunction buildSuggestion(\n requested: string,\n registeredNames: readonly string[],\n): string {\n const suggestions = nearestSuggestions(requested, registeredNames);\n if (suggestions.length === 0) {\n return `Registered tools: ${registeredNames.join(\", \")}`;\n }\n return `Did you mean ${suggestions.map((s) => s.name).join(\", \")}?`;\n}\n\n/**\n * Read a Zod type tag without asserting a shape.\n *\n * Zod keeps its discriminant at `_def.typeName`. Both hops are narrowed with\n * `in`/`typeof` rather than an inline cast, so a non-Zod object yields\n * `undefined` instead of a fabricated read.\n */\nfunction zodTypeName(schema: unknown): string | undefined {\n if (typeof schema !== \"object\" || schema === null || !(\"_def\" in schema)) return undefined;\n const def = schema._def;\n if (typeof def !== \"object\" || def === null || !(\"typeName\" in def)) return undefined;\n return typeof def.typeName === \"string\" ? def.typeName : undefined;\n}\n\n/** Read `_def.<key>` with the same narrowing discipline. */\nfunction zodDefField(schema: unknown, key: string): unknown {\n if (typeof schema !== \"object\" || schema === null || !(\"_def\" in schema)) return undefined;\n const def = schema._def;\n if (typeof def !== \"object\" || def === null) return undefined;\n return Object.hasOwn(def, key) ? (def as Record<string, unknown>)[key] : undefined;\n}\n\n/**\n * Reverse-engineer ONE synthetic example value from a Zod schema type.\n * Returns a deterministic placeholder intended to round-trip through parse().\n */\nfunction exampleFromSchema(schema: unknown): unknown {\n switch (zodTypeName(schema)) {\n case \"ZodString\":\n return \"<string>\";\n case \"ZodNumber\":\n return 42;\n case \"ZodBoolean\":\n return true;\n case \"ZodNullable\":\n return null;\n case \"ZodArray\":\n return [];\n case \"ZodOptional\":\n // Optional fields are omitted from the example rather than sent as null.\n return undefined;\n case \"ZodEnum\": {\n const values = zodDefField(schema, \"values\");\n return Array.isArray(values) && values.length > 0 ? values[0] : \"<value>\";\n }\n case \"ZodObject\": {\n const shapeFn = zodDefField(schema, \"shape\");\n const shape = typeof shapeFn === \"function\" ? shapeFn() : undefined;\n if (typeof shape !== \"object\" || shape === null) return {};\n const result: Record<string, unknown> = {};\n for (const key of Object.getOwnPropertyNames(shape)) {\n if (!Object.hasOwn(shape, key)) continue;\n const field = (shape as Record<string, unknown>)[key];\n const value = exampleFromSchema(field);\n if (value !== undefined) result[key] = value;\n }\n return result;\n }\n default:\n return undefined;\n }\n}\n/**\n * Build an enriched \"unknown tool\" error message.\n *\n * @param requested - the tool name the caller used\n * @param registeredNames - ALL registered tool names (including aliases)\n */\nexport function unknownToolError(\n requested: string,\n registeredNames: readonly string[],\n): string {\n // Cap the request before the suggestion pass: a 128 KB name would otherwise\n // pay O(n*m) per registered tool (issue #3042 review, P2). The cap matches\n // the documented tool-name shape; an over-long request is rejected with a\n // teaching message rather than a silent truncate.\n if (requested.length > SUGGESTION_REQUEST_MAX_LEN) {\n return `Unknown tool: name exceeds ${SUGGESTION_REQUEST_MAX_LEN} characters (got ${requested.length}).`;\n }\n const suggestion = buildSuggestion(requested, registeredNames);\n return `Unknown tool: ${requested}. ${suggestion}`;\n}\n\n/**\n * Build an enriched \"invalid arguments\" error message.\n *\n * The example is generated from the schema (never hand-written, so it cannot\n * drift) and is shown ONLY when it round-trips through that same schema. It\n * carries schema-derived fields only: injecting the tool name would add an\n * unrecognized property and fail a `.strict()` object (#3035 review finding).\n *\n * @param tool - the tool name that received the invalid args\n * @param zodError - the ZodError from parse()\n * @param schema - the original Zod schema, used to generate the example\n */\nexport function invalidArgsError(\n tool: string,\n zodError: ZodError,\n schema?: unknown,\n): string {\n const issues = zodError.issues.map((issue) => {\n const path = issue.path.length > 0 ? issue.path.join(\".\") : \"(root)\";\n // `expected` exists only on the invalid_type / invalid_literal variants of\n // ZodIssue, so it is read through a presence check rather than assumed.\n const expected = \"expected\" in issue ? issue.expected : undefined;\n return expected === undefined\n ? `${path}: ${issue.message}`\n : `${path}: ${issue.message} (expected ${String(expected)})`;\n });\n let message = `Invalid arguments for \"${tool}\": ${issues.join(\"; \")}`;\n if (!schema) return message;\n\n const example = exampleFromSchema(schema);\n if (!example || typeof example !== \"object\" || Object.keys(example).length === 0) {\n return message;\n }\n\n // Withhold an example that cannot parse against its own schema: a\n // non-round-tripping example is misinformation, worse than none. Narrowed\n // with `in`/`typeof` rather than an inline cast so the shape is checked.\n let roundTrips = false;\n if (typeof schema === \"object\" && \"safeParse\" in schema) {\n const parser = schema.safeParse;\n if (typeof parser === \"function\") {\n try {\n const parsed: unknown = parser.call(schema, example);\n roundTrips =\n typeof parsed === \"object\"\n && parsed !== null\n && \"success\" in parsed\n && parsed.success === true;\n } catch {\n roundTrips = false;\n }\n }\n }\n\n return roundTrips ? `${message}. Example arguments: ${JSON.stringify(example)}` : message;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/access-observe-write-category.ts"],"sourcesContent":["/**\n * Category-alias split + replay restamp for observe/write (#2829).\n * Extracted from access-observe-write-surface.ts to stay under the 1200-line cap.\n *\n * The wire schema already maps an alias to \"fact\". `rawCategory` is the\n * caller's spelling: it must not reach the write candidate or fingerprint,\n * and a replay must rebuild the note from THIS request's spelling.\n */\nimport {\n canonicalCategoryForAlias,\n categoryAliasCoercion,\n reapplyCategoryCoercion,\n type CategoryAliasCoercion,\n type MemoryCategoryAlias,\n} from \"./access-schema.js\";\n\nexport { reapplyCategoryCoercion };\nexport { applyBriefingLocationContext } from \"./location/tagging.js\";\n\nexport function splitCanonicalWriteRequest<T extends { rawCategory?: string; category?: string }>(\n request: T,\n): {\n canonical: Omit<T, \"rawCategory\">;\n categoryCoercion: CategoryAliasCoercion | undefined;\n} {\n const { rawCategory, ...canonical } = request;\n // #2962: a direct service caller bypasses the wire schema, so an accepted\n // alias can still sit on `category`. Canonicalize it at the same boundary\n // the schema's transform covers for HTTP/MCP/CLI, minting the retained\n // spelling from the request itself. A schema-minted `rawCategory` always\n // wins (it names the spelling the transform actually canonicalized);\n // near-misses pass through untouched and reject at the write candidate\n // with the attempted category echoed.\n if (rawCategory === undefined && typeof canonical.category === \"string\") {\n const mapped = canonicalCategoryForAlias(canonical.category);\n if (mapped !== undefined) {\n const from = canonical.category as MemoryCategoryAlias;\n return {\n canonical: { ...canonical, category: mapped } as Omit<T, \"rawCategory\">,\n categoryCoercion: { from, to: mapped },\n };\n }\n }\n return { canonical, categoryCoercion: categoryAliasCoercion(rawCategory) };\n}\n"],"mappings":";;;;;;AAmBO,SAAS,2BACd,SAIA;AACA,QAAM,EAAE,aAAa,GAAG,UAAU,IAAI;AAQtC,MAAI,gBAAgB,UAAa,OAAO,UAAU,aAAa,UAAU;AACvE,UAAM,SAAS,0BAA0B,UAAU,QAAQ;AAC3D,QAAI,WAAW,QAAW;AACxB,YAAM,OAAO,UAAU;AACvB,aAAO;AAAA,QACL,WAAW,EAAE,GAAG,WAAW,UAAU,OAAO;AAAA,QAC5C,kBAAkB,EAAE,MAAM,IAAI,OAAO;AAAA,MACvC;AAAA,IACF;AAAA,EACF;AACA,SAAO,EAAE,WAAW,kBAAkB,sBAAsB,WAAW,EAAE;AAC3E;","names":[]}
|