@remnic/core 9.7.14 → 9.8.0
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.d.ts +13 -6
- package/dist/access-admin-ops-surface.js +88 -74
- package/dist/access-audit.js +2 -2
- package/dist/access-boundary.d.ts +35 -17
- package/dist/access-boundary.js +89 -77
- package/dist/access-citation.d.ts +28 -0
- package/dist/access-citation.js +9 -0
- package/dist/access-cli.js +197 -181
- package/dist/access-cli.js.map +1 -1
- package/dist/access-errors.d.ts +16 -1
- package/dist/access-errors.js +7 -3
- package/dist/access-http.d.ts +25 -19
- package/dist/access-http.js +103 -90
- package/dist/access-identity-continuity-surface.d.ts +13 -8
- package/dist/access-identity-continuity-surface.js +88 -74
- package/dist/access-lcm-surface.d.ts +16 -9
- package/dist/access-lcm-surface.js +88 -74
- package/dist/access-mcp.d.ts +23 -16
- package/dist/access-mcp.js +99 -87
- package/dist/access-memory-search-fanout.d.ts +93 -0
- package/dist/access-memory-search-fanout.js +18 -0
- package/dist/access-observe-write-surface.d.ts +26 -8
- package/dist/access-observe-write-surface.js +88 -74
- package/dist/access-operations-batch.js +95 -83
- package/dist/access-operations.d.ts +26 -19
- package/dist/access-operations.js +97 -85
- package/dist/access-recall-concurrency.d.ts +250 -0
- package/dist/access-recall-concurrency.js +157 -0
- package/dist/access-recall-response.d.ts +130 -0
- package/dist/access-recall-response.js +147 -0
- package/dist/access-recall-surface.d.ts +15 -7
- package/dist/access-recall-surface.js +88 -74
- package/dist/access-schema.d.ts +34 -34
- package/dist/access-schema.js +8 -6
- package/dist/{access-service-CPhSnLOH.d.ts → access-service-DEL4qCrc.d.ts} +25 -32
- package/dist/access-service.d.ts +13 -6
- package/dist/access-service.js +92 -75
- package/dist/access-surface-catalog.d.ts +23 -16
- package/dist/access-surface-catalog.js +1 -0
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/access-token-capabilities.d.ts +2 -1
- package/dist/access-token-capabilities.js +4 -2
- package/dist/action-confidence.d.ts +3 -1
- package/dist/active-memory-bridge.d.ts +3 -1
- package/dist/active-memory-bridge.js +4 -4
- package/dist/active-recall.d.ts +4 -1
- package/dist/active-recall.js +23 -13
- 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-AAMTVZMK.js → auto-sync-UZG3XQZ5.js} +14 -8
- package/dist/{auto-sync-AAMTVZMK.js.map → auto-sync-UZG3XQZ5.js.map} +1 -1
- package/dist/behavior-learner.d.ts +3 -1
- package/dist/behavior-signals.d.ts +3 -1
- package/dist/bootstrap.d.ts +12 -7
- package/dist/bootstrap.js +2 -2
- package/dist/bounded-jsonl-state.d.ts +54 -0
- package/dist/bounded-jsonl-state.js +10 -0
- package/dist/boxes.js +2 -2
- package/dist/briefing.d.ts +5 -2
- package/dist/briefing.js +37 -27
- package/dist/buffer-surprise-report.d.ts +3 -1
- package/dist/buffer.d.ts +60 -2
- package/dist/buffer.js +3 -3
- package/dist/bulk-import/index.d.ts +5 -3
- package/dist/calibration.d.ts +3 -1
- package/dist/calibration.js +6 -6
- package/dist/capabilities.d.ts +7 -7
- package/dist/capabilities.js +1 -1
- package/dist/{capsule-crypto-CZJSLEFG.js → capsule-crypto-YO5QJ6L3.js} +3 -3
- package/dist/capsule-crypto-YO5QJ6L3.js.map +1 -0
- package/dist/{capsule-merge-Z2HUO6IK.js → capsule-merge-5KKJQBWQ.js} +4 -4
- package/dist/{catalog-uX9sT9ws.d.ts → catalog-BWqHb5HT.d.ts} +1 -1
- package/dist/causal-behavior.d.ts +3 -1
- package/dist/causal-behavior.js +6 -6
- package/dist/causal-chain.js +4 -4
- package/dist/causal-consolidation.d.ts +3 -1
- package/dist/causal-consolidation.js +46 -37
- package/dist/causal-consolidation.js.map +1 -1
- package/dist/causal-retrieval.js +6 -6
- package/dist/causal-trajectory-graph.d.ts +3 -1
- package/dist/causal-trajectory-graph.js +1 -1
- package/dist/causal-trajectory.js +1 -1
- package/dist/{chunk-A3GOMRJG.js → chunk-23L3IXFD.js} +2 -2
- package/dist/chunk-2CGLBUW3.js +15 -0
- package/dist/chunk-2CGLBUW3.js.map +1 -0
- package/dist/{chunk-MRHFJV44.js → chunk-2DQ2XREU.js} +2 -2
- package/dist/{chunk-ASKEM4AR.js → chunk-2EJOEICD.js} +1823 -1483
- package/dist/chunk-2EJOEICD.js.map +1 -0
- package/dist/{chunk-L2B3EE7B.js → chunk-2QMKMVHH.js} +2 -2
- package/dist/{chunk-6CALL5VN.js → chunk-2UFO7X4Q.js} +7 -7
- package/dist/{chunk-2MR3MFQB.js → chunk-2VEOKUPP.js} +3 -3
- package/dist/chunk-2Z24E5W2.js +22 -0
- package/dist/chunk-2Z24E5W2.js.map +1 -0
- package/dist/{chunk-RHOZ5LLO.js → chunk-347WD2LE.js} +2 -2
- package/dist/{chunk-5S7Z5SHA.js → chunk-34RC5RT7.js} +2 -2
- package/dist/{chunk-KGWXHWAH.js → chunk-3QAH2S33.js} +3 -3
- package/dist/{chunk-37CTGERM.js → chunk-3WCASNQZ.js} +12 -1
- package/dist/chunk-3WCASNQZ.js.map +1 -0
- package/dist/{chunk-ZIDSD6VC.js → chunk-3Y224NYC.js} +3 -3
- package/dist/{chunk-RBQLJSJ7.js → chunk-44XZ75OQ.js} +46 -10
- package/dist/chunk-44XZ75OQ.js.map +1 -0
- package/dist/{chunk-VFSP73LP.js → chunk-45GF7Y3V.js} +2 -2
- package/dist/{chunk-7ICYQUOL.js → chunk-4BJQODZF.js} +2514 -1526
- package/dist/chunk-4BJQODZF.js.map +1 -0
- package/dist/{chunk-JMBVCAR4.js → chunk-57OWKFUQ.js} +17 -6
- package/dist/chunk-57OWKFUQ.js.map +1 -0
- package/dist/{chunk-OEHCMALU.js → chunk-5I4M26Q7.js} +5 -5
- package/dist/{chunk-2E6G7FCE.js → chunk-5Q7EVV4X.js} +7 -7
- package/dist/{chunk-LC7OODWZ.js → chunk-5SB7SC2G.js} +80 -49
- package/dist/chunk-5SB7SC2G.js.map +1 -0
- package/dist/{chunk-VZ5OJE4X.js → chunk-5VQJBH2G.js} +2 -2
- package/dist/{chunk-PUBTHW5O.js → chunk-6DRPPQEJ.js} +2 -2
- package/dist/{chunk-NWTGD4AN.js → chunk-6KIQT7RG.js} +10 -9
- package/dist/chunk-6KIQT7RG.js.map +1 -0
- package/dist/{chunk-4LEF6XWJ.js → chunk-6O22TZSB.js} +3 -3
- package/dist/{chunk-ZQ7UBUZ6.js → chunk-6QYST5XN.js} +6 -6
- package/dist/{chunk-W4PGTAS2.js → chunk-6WAFYNVT.js} +3 -3
- package/dist/chunk-6ZMAMSHS.js +20 -0
- package/dist/chunk-6ZMAMSHS.js.map +1 -0
- package/dist/{chunk-R5VAVVHP.js → chunk-72A4L5JJ.js} +2 -2
- package/dist/{chunk-X64YLC24.js → chunk-72VAXGEI.js} +5 -13
- package/dist/chunk-72VAXGEI.js.map +1 -0
- package/dist/{chunk-IKQTFQMI.js → chunk-755Q3DGF.js} +22 -3
- package/dist/chunk-755Q3DGF.js.map +1 -0
- package/dist/{chunk-F7AU34FC.js → chunk-76GLCM57.js} +160 -127
- package/dist/chunk-76GLCM57.js.map +1 -0
- package/dist/{chunk-D7FOKIY5.js → chunk-7AMFUATK.js} +12 -9
- package/dist/{chunk-D7FOKIY5.js.map → chunk-7AMFUATK.js.map} +1 -1
- package/dist/{chunk-BFVEEB7W.js → chunk-7ON2JW73.js} +57 -22
- package/dist/chunk-7ON2JW73.js.map +1 -0
- package/dist/chunk-7RNBVZZO.js +270 -0
- package/dist/chunk-7RNBVZZO.js.map +1 -0
- package/dist/{chunk-3FAMU5TX.js → chunk-A6USBZTO.js} +2 -2
- package/dist/{chunk-TXVD7PLT.js → chunk-A72SWTWW.js} +7 -7
- package/dist/{chunk-FC77VUX5.js → chunk-A7Q43EUZ.js} +2 -2
- package/dist/{chunk-UJBESW6X.js → chunk-AE7WMV4V.js} +7 -7
- package/dist/{chunk-J2HSAU72.js → chunk-AIK5W3IW.js} +29 -1
- package/dist/chunk-AIK5W3IW.js.map +1 -0
- package/dist/{chunk-OKUEZOGW.js → chunk-AITCS2RC.js} +2 -2
- package/dist/{chunk-OC35KQIN.js → chunk-AJ7QCSIS.js} +4 -4
- package/dist/{chunk-FNMFJWBY.js → chunk-ANEUPF6O.js} +5 -5
- package/dist/chunk-AREGMX2J.js +50 -0
- package/dist/chunk-AREGMX2J.js.map +1 -0
- package/dist/chunk-AVPXXV6J.js +448 -0
- package/dist/chunk-AVPXXV6J.js.map +1 -0
- package/dist/{chunk-2A3OXAP2.js → chunk-B7RWBZXW.js} +2 -2
- package/dist/{chunk-GWTFLF2P.js → chunk-BJMBJZ2Y.js} +59 -59
- package/dist/chunk-BJMBJZ2Y.js.map +1 -0
- package/dist/{chunk-N3JDIRBW.js → chunk-BLAKS3CP.js} +4 -4
- package/dist/{chunk-M7VGG3ID.js → chunk-BV5WMSIJ.js} +9 -9
- package/dist/{chunk-2BFLDH5F.js → chunk-BXLOS5AJ.js} +2 -2
- package/dist/{chunk-UXKMMNJD.js → chunk-C23BYTJV.js} +6 -6
- package/dist/{chunk-JZHHREBL.js → chunk-C3AKM55W.js} +2 -2
- package/dist/{chunk-RP7YXA67.js → chunk-C5JF6EZ7.js} +2 -2
- package/dist/{chunk-FBNWOMCE.js → chunk-C6XBRYVD.js} +16 -15
- package/dist/chunk-C6XBRYVD.js.map +1 -0
- package/dist/{chunk-FTYDWKO6.js → chunk-CEN6DW6X.js} +12 -2
- package/dist/chunk-CEN6DW6X.js.map +1 -0
- package/dist/chunk-CGASUJVP.js +421 -0
- package/dist/chunk-CGASUJVP.js.map +1 -0
- package/dist/{chunk-DDGV7NAX.js → chunk-CQMEM5CC.js} +2 -2
- package/dist/{chunk-A7B4RMQG.js → chunk-CXZQOVIE.js} +12 -12
- package/dist/chunk-D3V3UMET.js +44 -0
- package/dist/chunk-D3V3UMET.js.map +1 -0
- package/dist/{chunk-7N2RUBAP.js → chunk-DDA47TES.js} +2 -2
- package/dist/{chunk-64SE4X5G.js → chunk-DEBHXHJR.js} +3 -3
- package/dist/{chunk-EHK6KZHK.js → chunk-DNHVPZOD.js} +2 -2
- package/dist/{chunk-437S3G37.js → chunk-DQEMWVMT.js} +2 -2
- package/dist/{chunk-LZZNTPLR.js → chunk-DX3XRGLH.js} +2 -2
- package/dist/chunk-EA2H5LML.js +72 -0
- package/dist/chunk-EA2H5LML.js.map +1 -0
- package/dist/{chunk-IFJ23BHU.js → chunk-EEC7UJPX.js} +112 -106
- package/dist/chunk-EEC7UJPX.js.map +1 -0
- package/dist/{chunk-KSNVDPDF.js → chunk-EKBNDKDY.js} +21 -20
- package/dist/chunk-EKBNDKDY.js.map +1 -0
- package/dist/{chunk-YF6FMLBT.js → chunk-EQWEIIKQ.js} +64 -34
- package/dist/chunk-EQWEIIKQ.js.map +1 -0
- package/dist/{chunk-7MW3CVLD.js → chunk-ES36HTSC.js} +4 -4
- package/dist/{chunk-TN7THW5U.js → chunk-ET356KSB.js} +2 -2
- package/dist/{chunk-YNDLCWXS.js → chunk-EZ25VE3G.js} +4 -4
- package/dist/{chunk-7LFXDGLH.js → chunk-F7GAIWFA.js} +20 -20
- package/dist/{chunk-IKSELOIV.js → chunk-FFPJINJE.js} +7 -7
- package/dist/chunk-FMLKOL2Z.js +636 -0
- package/dist/chunk-FMLKOL2Z.js.map +1 -0
- package/dist/chunk-FQC3DHH2.js +20 -0
- package/dist/chunk-FQC3DHH2.js.map +1 -0
- package/dist/{chunk-V53GJUSL.js → chunk-FUTF72MJ.js} +15 -15
- package/dist/chunk-GCASGYIO.js +71 -0
- package/dist/chunk-GCASGYIO.js.map +1 -0
- package/dist/{chunk-5UNWK7KU.js → chunk-GFPZS3F5.js} +8 -8
- package/dist/{chunk-BCDKBDSY.js → chunk-GNVZQ5JN.js} +99 -41
- package/dist/chunk-GNVZQ5JN.js.map +1 -0
- package/dist/{chunk-G6NKALRN.js → chunk-H4WG3UQZ.js} +2 -2
- package/dist/{chunk-HLTAPHZZ.js → chunk-HNZKVLAN.js} +2 -2
- package/dist/{chunk-5EZXHU36.js → chunk-HYQJQGD3.js} +2 -2
- package/dist/{chunk-ANADNYWK.js → chunk-IDZFBSHN.js} +8 -6
- package/dist/{chunk-ANADNYWK.js.map → chunk-IDZFBSHN.js.map} +1 -1
- package/dist/{chunk-XVLEGMJI.js → chunk-IFH6LWTO.js} +50 -8
- package/dist/chunk-IFH6LWTO.js.map +1 -0
- package/dist/{chunk-RULE4VG5.js → chunk-ILGC6JH6.js} +21 -6
- package/dist/chunk-ILGC6JH6.js.map +1 -0
- package/dist/chunk-IUM3VSHI.js +113 -0
- package/dist/chunk-IUM3VSHI.js.map +1 -0
- package/dist/{chunk-ND5M64JJ.js → chunk-IYNGIMVG.js} +101 -91
- package/dist/chunk-IYNGIMVG.js.map +1 -0
- package/dist/{chunk-TRWPCR6P.js → chunk-JECBQBEX.js} +3 -3
- package/dist/{chunk-HG32URJJ.js → chunk-JYIFGGEM.js} +2 -2
- package/dist/{chunk-VA4WSW54.js → chunk-JYIJNNN3.js} +3 -3
- package/dist/{chunk-L5HJQC36.js → chunk-K2TDK7GG.js} +3 -3
- package/dist/{chunk-MKDRQAA3.js → chunk-KAVBJSBQ.js} +4 -4
- package/dist/{chunk-EEARRVZ2.js → chunk-KF5EUVKQ.js} +16 -6
- package/dist/chunk-KF5EUVKQ.js.map +1 -0
- package/dist/chunk-KFZY2OFH.js +42 -0
- package/dist/chunk-KFZY2OFH.js.map +1 -0
- package/dist/{chunk-4OKLXWDZ.js → chunk-KNB7IBBU.js} +2 -2
- package/dist/{chunk-QLULYKWZ.js → chunk-KSXJOC4F.js} +2 -2
- package/dist/{chunk-OBMR4VIX.js → chunk-L2DPF4DF.js} +186 -15
- package/dist/chunk-L2DPF4DF.js.map +1 -0
- package/dist/{chunk-JI5AVXYO.js → chunk-LEPOP46W.js} +6 -6
- package/dist/{chunk-O7BBFJLP.js → chunk-LTAVSOZW.js} +2 -2
- package/dist/{chunk-E3VODCC3.js → chunk-LUDXM7MD.js} +14 -2
- package/dist/{chunk-E3VODCC3.js.map → chunk-LUDXM7MD.js.map} +1 -1
- package/dist/{chunk-2IZAGAJR.js → chunk-LULR4IUW.js} +3 -3
- package/dist/{chunk-NUWYOKS6.js → chunk-MC5Q3J7S.js} +398 -7
- package/dist/chunk-MC5Q3J7S.js.map +1 -0
- package/dist/{chunk-WMWVO45V.js → chunk-MC6XO7T4.js} +2 -2
- package/dist/chunk-MKQBXQKU.js +107 -0
- package/dist/chunk-MKQBXQKU.js.map +1 -0
- package/dist/{chunk-7PND4PUC.js → chunk-MMGGVZ4Q.js} +29 -9
- package/dist/{chunk-7PND4PUC.js.map → chunk-MMGGVZ4Q.js.map} +1 -1
- package/dist/{chunk-D6RIFG4O.js → chunk-MNB5RMAY.js} +2 -2
- package/dist/{chunk-67ZCJLJY.js → chunk-MYFQ3ED4.js} +8 -8
- package/dist/{chunk-V3UE5I5F.js → chunk-MYVPLJOO.js} +2 -2
- package/dist/chunk-NINSR6LX.js +83 -0
- package/dist/chunk-NINSR6LX.js.map +1 -0
- package/dist/{chunk-MTWKDOVO.js → chunk-NLE6TSLG.js} +2 -2
- package/dist/{chunk-DBRYEIGY.js → chunk-OJP3N7UK.js} +2 -2
- package/dist/{chunk-AD6AMF2N.js → chunk-OQJIB32H.js} +28 -23
- package/dist/chunk-OQJIB32H.js.map +1 -0
- package/dist/{chunk-SMX5267P.js → chunk-OZKOPQCM.js} +2 -2
- package/dist/{chunk-JCK7V6SN.js → chunk-P65YJEEL.js} +2 -2
- package/dist/{chunk-MTR7BZQN.js → chunk-PBGWYM3H.js} +3 -3
- package/dist/chunk-PIG4WJFQ.js +87 -0
- package/dist/chunk-PIG4WJFQ.js.map +1 -0
- package/dist/chunk-PQVCH2AE.js +76 -0
- package/dist/chunk-PQVCH2AE.js.map +1 -0
- package/dist/{chunk-AXTXN4T6.js → chunk-PWFCHOB3.js} +2 -2
- package/dist/{chunk-FDPZVY6D.js → chunk-QFN4U7AG.js} +2 -2
- package/dist/{chunk-K2ZLHESQ.js → chunk-QIEUU4UK.js} +2 -2
- package/dist/{chunk-AHLPZ2SF.js → chunk-QJAQNXWI.js} +44 -6
- package/dist/chunk-QJAQNXWI.js.map +1 -0
- package/dist/{chunk-3D6AFGQR.js → chunk-QVT3E4CE.js} +7 -7
- package/dist/{chunk-VYOFVVNK.js → chunk-R26ZMXR2.js} +24 -24
- package/dist/{chunk-VYOFVVNK.js.map → chunk-R26ZMXR2.js.map} +1 -1
- package/dist/chunk-R3DJVOSM.js +34 -0
- package/dist/chunk-R3DJVOSM.js.map +1 -0
- package/dist/{chunk-SFQ6QNL7.js → chunk-R6YJI3HE.js} +2 -1
- package/dist/{chunk-5CJVLG3H.js → chunk-RFDD3B7W.js} +5 -5
- package/dist/{chunk-JBPKEARU.js → chunk-RKNJBZ55.js} +4 -4
- package/dist/chunk-ROI7BK7H.js +88 -0
- package/dist/chunk-ROI7BK7H.js.map +1 -0
- package/dist/{chunk-UTRJFDP2.js → chunk-S2BBISHU.js} +4 -4
- package/dist/{chunk-IALLX7EE.js → chunk-S2FSBU4H.js} +3 -3
- package/dist/{chunk-BFPETA3S.js → chunk-SCCO46KZ.js} +3 -2
- package/dist/chunk-SCCO46KZ.js.map +1 -0
- package/dist/chunk-SICXL4MK.js +165 -0
- package/dist/chunk-SICXL4MK.js.map +1 -0
- package/dist/chunk-SK7AMF2J.js +168 -0
- package/dist/chunk-SK7AMF2J.js.map +1 -0
- package/dist/{chunk-GMSDQUCR.js → chunk-TDTXKOAJ.js} +6475 -5748
- package/dist/chunk-TDTXKOAJ.js.map +1 -0
- package/dist/{chunk-KSBEEMQF.js → chunk-TG6IHVE2.js} +151 -6
- package/dist/chunk-TG6IHVE2.js.map +1 -0
- package/dist/{chunk-7K5Q6COX.js → chunk-TVVEYCNW.js} +4 -4
- package/dist/{chunk-PK5XBDA6.js → chunk-U3ZAVRP3.js} +2 -2
- package/dist/{chunk-ODPLEWB6.js → chunk-UFGFMWAD.js} +47 -17
- package/dist/chunk-UFGFMWAD.js.map +1 -0
- package/dist/{chunk-4KJLYTLS.js → chunk-V57NLO5P.js} +2 -2
- package/dist/{chunk-FLVL4L3L.js → chunk-VDX2J7OX.js} +2 -2
- package/dist/{chunk-7XGSIUP5.js → chunk-W4FBGYGK.js} +1 -1
- package/dist/{chunk-TXLGHDHS.js → chunk-W4XJFLAL.js} +53 -32
- package/dist/chunk-W4XJFLAL.js.map +1 -0
- package/dist/{chunk-6SXVCD7W.js → chunk-W7IGLX4G.js} +2 -2
- package/dist/{chunk-KQDNAXOM.js → chunk-WG5HSQ4P.js} +19 -6
- package/dist/chunk-WG5HSQ4P.js.map +1 -0
- package/dist/{chunk-LTJAMRGI.js → chunk-WL5EBRDH.js} +17 -3
- package/dist/chunk-WL5EBRDH.js.map +1 -0
- package/dist/{chunk-KAWTOYAW.js → chunk-WLZYGLJ4.js} +2 -2
- package/dist/{chunk-W5NKDU24.js → chunk-WON4APQY.js} +4 -4
- package/dist/{chunk-NKCPUHCI.js → chunk-WZFAPHIK.js} +6 -6
- package/dist/{chunk-KQPJLK3X.js → chunk-XL24QQ63.js} +2 -2
- package/dist/{chunk-X47LWMKA.js → chunk-XMMESCPD.js} +26 -1
- package/dist/chunk-XMMESCPD.js.map +1 -0
- package/dist/{chunk-4B4MUS5D.js → chunk-YROFNEG5.js} +7 -7
- package/dist/{chunk-WU46YPY6.js → chunk-YV32N67O.js} +1 -1
- package/dist/chunk-YV32N67O.js.map +1 -0
- package/dist/{chunk-B3F4CWQR.js → chunk-YVKF3HEW.js} +1 -1
- package/dist/chunk-YVKF3HEW.js.map +1 -0
- package/dist/{chunk-VRAD2FGO.js → chunk-Z54EM5YZ.js} +12 -12
- package/dist/{chunk-2VN4JAX7.js → chunk-ZOKZIR5K.js} +95 -33
- package/dist/chunk-ZOKZIR5K.js.map +1 -0
- package/dist/{cli-_Y2Bmt6A.d.ts → cli-C_pqqTCw.d.ts} +28 -12
- package/dist/cli.d.ts +16 -9
- package/dist/cli.js +145 -130
- package/dist/compounding/engine.d.ts +5 -2
- package/dist/compounding/engine.js +39 -29
- package/dist/compounding/preference-consolidator.d.ts +3 -1
- package/dist/compounding/preference-consolidator.js +1 -1
- package/dist/compression-optimizer.d.ts +3 -1
- package/dist/config-qmd.d.ts +8 -0
- package/dist/config-qmd.js +20 -0
- package/dist/config-qmd.js.map +1 -0
- package/dist/config.d.ts +3 -1
- package/dist/config.js +15 -10
- package/dist/connectors/codex-materialize-runner.d.ts +3 -1
- package/dist/connectors/codex-materialize-runner.js +39 -29
- package/dist/connectors/codex-materialize.d.ts +3 -1
- package/dist/connectors/codex-materialize.js +2 -2
- package/dist/connectors/index.d.ts +3 -1
- package/dist/connectors/index.js +44 -35
- package/dist/consolidation-provenance-check.d.ts +5 -2
- package/dist/consolidation-provenance-check.js +4 -4
- package/dist/consolidation-undo.d.ts +5 -2
- package/dist/consolidation-undo.js +3 -3
- package/dist/contradiction/index.d.ts +5 -2
- package/dist/contradiction/index.js +10 -4
- package/dist/{contradiction-scan-J57T5QV7.js → contradiction-scan-RJBABNRH.js} +4 -4
- package/dist/contradiction-scan-RJBABNRH.js.map +1 -0
- package/dist/conversation-index/backend.d.ts +3 -1
- package/dist/conversation-index/backend.js +5 -5
- package/dist/conversation-index/chunker.d.ts +3 -1
- package/dist/conversation-index/cleanup.js +2 -2
- package/dist/conversation-index/faiss-adapter.d.ts +3 -1
- package/dist/conversation-index/faiss-adapter.js +2 -2
- package/dist/conversation-index/indexer.d.ts +3 -1
- package/dist/conversation-index/indexer.js +2 -2
- package/dist/conversation-index/search.d.ts +3 -1
- package/dist/conversation-index/search.js +2 -2
- package/dist/cross-namespace-budget.d.ts +45 -1
- package/dist/cross-namespace-budget.js +5 -3
- package/dist/dashboard-runtime.js +2 -2
- package/dist/day-summary.d.ts +3 -1
- package/dist/day-summary.js +3 -3
- package/dist/delinearize.d.ts +3 -1
- package/dist/direct-answer-wiring.d.ts +3 -1
- package/dist/direct-answer.d.ts +3 -1
- package/dist/{dreams-ledger-6UODQOX6.js → dreams-ledger-567VKVOU.js} +4 -2
- package/dist/dreams-ledger-567VKVOU.js.map +1 -0
- package/dist/embedding-fallback.d.ts +3 -1
- package/dist/embedding-fallback.js +3 -3
- package/dist/enrichment/index.d.ts +3 -1
- package/dist/entity-retrieval.d.ts +5 -2
- package/dist/entity-retrieval.js +38 -29
- package/dist/entity-schema.d.ts +3 -1
- package/dist/explicit-capture.d.ts +13 -8
- package/dist/explicit-capture.js +7 -3
- package/dist/extraction-faithfulness.d.ts +3 -1
- package/dist/extraction-faithfulness.js +5 -5
- package/dist/extraction-judge-telemetry.d.ts +3 -1
- package/dist/extraction-judge-telemetry.js +2 -2
- package/dist/extraction-judge-training.d.ts +3 -1
- package/dist/extraction-judge-training.js +2 -2
- package/dist/extraction-judge.d.ts +3 -1
- package/dist/extraction-judge.js +5 -5
- package/dist/extraction.d.ts +3 -1
- package/dist/extraction.js +13 -12
- package/dist/faithfulness-config.js +3 -2
- package/dist/fallback-llm.d.ts +3 -1
- package/dist/fallback-llm.js +4 -4
- package/dist/{first-start-migration-TI67YMLG.js → first-start-migration-CSRHCJIQ.js} +2 -2
- package/dist/{forget-CQCLB5LB.js → forget-HRPLVB3W.js} +5 -5
- package/dist/graph-dashboard-diff.d.ts +3 -1
- package/dist/graph-dashboard-key.d.ts +3 -1
- package/dist/graph-dashboard-parser.d.ts +3 -1
- package/dist/{graph-edge-decay-FO7AM4UR.js → graph-edge-decay-Z6ENALU2.js} +3 -3
- package/dist/graph-edge-decay-Z6ENALU2.js.map +1 -0
- package/dist/graph-edge-reinforcement.d.ts +3 -1
- package/dist/graph-snapshot.d.ts +3 -1
- package/dist/graph-snapshot.js +2 -2
- package/dist/graph.d.ts +57 -10
- package/dist/graph.js +1 -1
- package/dist/identity-continuity.d.ts +1 -2
- package/dist/importance.d.ts +3 -1
- package/dist/importers/index.d.ts +3 -1
- package/dist/in-flight-reads.d.ts +3 -1
- package/dist/index.d.ts +101 -92
- package/dist/index.js +290 -242
- package/dist/intent.d.ts +3 -1
- package/dist/lcm/archive.js +2 -2
- package/dist/lcm/engine.d.ts +3 -1
- package/dist/lcm/engine.js +6 -6
- package/dist/lcm/index.d.ts +3 -1
- package/dist/lcm/index.js +13 -13
- package/dist/lcm/schema.js +2 -2
- package/dist/lcm/summarizer.js +3 -3
- package/dist/lcm/tools.d.ts +3 -1
- package/dist/lifecycle.d.ts +3 -1
- package/dist/live-connectors-runner.d.ts +3 -1
- package/dist/local-llm.d.ts +5 -2
- package/dist/local-llm.js +3 -3
- package/dist/local-model-endpoint.d.ts +3 -1
- package/dist/logger.d.ts +3 -1
- package/dist/logger.js +7 -3
- package/dist/maintenance/archive-observations.js +2 -2
- package/dist/maintenance/memory-governance.d.ts +3 -1
- package/dist/maintenance/memory-governance.js +38 -28
- package/dist/maintenance/migrate-observations.js +3 -3
- package/dist/maintenance/observation-ledger-utils.js +2 -2
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +102 -1
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +40 -28
- package/dist/maintenance/rebuild-memory-projection.js +41 -31
- package/dist/maintenance/rebuild-observations.js +3 -3
- package/dist/mcp-memory-inspector-app.d.ts +22 -15
- package/dist/memory-action-policy.d.ts +3 -1
- package/dist/memory-cache.d.ts +46 -2
- package/dist/memory-cache.js +7 -1
- package/dist/memory-corpus-version.js +2 -2
- package/dist/memory-lifecycle-ledger-utils.d.ts +25 -2
- package/dist/memory-lifecycle-ledger-utils.js +11 -1
- package/dist/memory-projection-store.d.ts +3 -1
- package/dist/memory-projection-store.js +2 -2
- package/dist/memory-provenance.d.ts +3 -1
- package/dist/memory-worth-outcomes.d.ts +5 -2
- package/dist/model-registry.js +2 -2
- package/dist/models-json.d.ts +3 -1
- package/dist/models-json.js +2 -2
- package/dist/namespaces/migrate.d.ts +6 -3
- package/dist/namespaces/migrate.js +54 -45
- package/dist/namespaces/principal.d.ts +27 -2
- package/dist/namespaces/principal.js +6 -2
- package/dist/namespaces/search.d.ts +16 -2
- package/dist/namespaces/search.js +25 -21
- package/dist/namespaces/storage.d.ts +24 -3
- package/dist/namespaces/storage.js +38 -30
- package/dist/native-knowledge.d.ts +3 -1
- package/dist/native-knowledge.js +2 -2
- package/dist/negative.js +2 -2
- package/dist/offline-sync-exclude-globs.d.ts +13 -0
- package/dist/offline-sync-exclude-globs.js +10 -0
- package/dist/offline-sync-exclude-globs.js.map +1 -0
- package/dist/offline-sync-impression-drain.d.ts +78 -0
- package/dist/offline-sync-impression-drain.js +37 -0
- package/dist/offline-sync-impression-drain.js.map +1 -0
- package/dist/offline-sync.js +4 -2
- package/dist/operator-toolkit.d.ts +5 -2
- package/dist/operator-toolkit.js +73 -58
- package/dist/orchestration/compression-guideline-coordinator.d.ts +5 -2
- package/dist/orchestration/compression-guideline-coordinator.js +3 -3
- package/dist/orchestration/maintenance.d.ts +121 -2
- package/dist/orchestration/maintenance.js +47 -34
- package/dist/{orchestrator-BbZ_dQSU.d.ts → orchestrator-CQJ8U7En.d.ts} +85 -79
- package/dist/orchestrator.d.ts +13 -8
- package/dist/orchestrator.js +197 -180
- package/dist/page-versioning.js +3 -3
- package/dist/patterns-cli.d.ts +3 -1
- package/dist/{pipeline-FRMDb1fn.d.ts → pipeline-Cn-kvYeV.d.ts} +1 -1
- package/dist/policy-runtime.d.ts +3 -1
- package/dist/prioritized-embed.d.ts +19 -0
- package/dist/prioritized-embed.js +8 -0
- package/dist/prioritized-embed.js.map +1 -0
- package/dist/proactive-contention.d.ts +28 -0
- package/dist/proactive-contention.js +8 -0
- package/dist/proactive-contention.js.map +1 -0
- package/dist/profiling.js +2 -2
- package/dist/provenance.d.ts +3 -1
- package/dist/provenance.js +3 -2
- package/dist/{purge-NDWV6WYD.js → purge-IRF47ZTX.js} +3 -3
- package/dist/{qmd-xJRrHFbA.d.ts → qmd-oh9VXz1d.d.ts} +11 -1
- package/dist/qmd-preflight.d.ts +5 -2
- package/dist/qmd-recall-cache.d.ts +3 -1
- package/dist/qmd-status.d.ts +57 -0
- package/dist/qmd-status.js +18 -0
- package/dist/qmd-status.js.map +1 -0
- package/dist/qmd.d.ts +5 -2
- package/dist/qmd.js +8 -4
- package/dist/recall-concurrency-config.d.ts +16 -0
- package/dist/recall-concurrency-config.js +10 -0
- package/dist/recall-concurrency-config.js.map +1 -0
- package/dist/recall-disclosure-escalation.d.ts +3 -1
- package/dist/recall-explain-renderer.d.ts +4 -1
- package/dist/recall-explain-renderer.js +3 -3
- package/dist/recall-memory-map.d.ts +26 -0
- package/dist/recall-memory-map.js +18 -0
- package/dist/recall-memory-map.js.map +1 -0
- package/dist/recall-planner-llm.d.ts +3 -1
- package/dist/recall-planner-llm.js +4 -4
- package/dist/recall-qos.js +2 -2
- package/dist/recall-state.d.ts +163 -2
- package/dist/recall-state.js +6 -3
- package/dist/recall-tag-filter.d.ts +3 -1
- package/dist/recall-timings.d.ts +11 -2
- package/dist/recall-timings.js +3 -1
- package/dist/recall-xray-cli.d.ts +3 -1
- package/dist/recall-xray-cli.js +4 -4
- package/dist/recall-xray-renderer.d.ts +3 -1
- package/dist/recall-xray-renderer.js +3 -3
- package/dist/recall-xray.d.ts +3 -1
- package/dist/recall-xray.js +2 -2
- package/dist/relevance.js +3 -3
- package/dist/replay/normalizers/chatgpt.d.ts +3 -1
- package/dist/replay/normalizers/claude.d.ts +3 -1
- package/dist/replay/normalizers/openclaw.d.ts +3 -1
- package/dist/replay/normalizers/shared.d.ts +3 -1
- package/dist/replay/runner.d.ts +3 -1
- package/dist/replay/types.d.ts +3 -1
- package/dist/rerank.d.ts +8 -1
- package/dist/rerank.js +3 -1
- package/dist/resolution-3K27T4VO.js +18 -0
- package/dist/resolution-3K27T4VO.js.map +1 -0
- package/dist/resolve-auth-token.d.ts +3 -1
- package/dist/resolve-provider-secret.js +2 -2
- package/dist/resume-bundles.js +19 -14
- package/dist/retrieval-agents.d.ts +19 -16
- package/dist/retrieval-agents.js +3 -3
- package/dist/retrieval-tiers.d.ts +3 -1
- package/dist/routing/engine.d.ts +3 -1
- package/dist/routing/store.d.ts +3 -1
- package/dist/routing/store.js +2 -2
- package/dist/salvage-envelope.d.ts +18 -0
- package/dist/salvage-envelope.js +15 -0
- package/dist/salvage-envelope.js.map +1 -0
- package/dist/schemas.d.ts +24 -24
- package/dist/scope-profiles-EpJG7yKP.d.ts +30 -0
- package/dist/search/document-scanner.js +3 -2
- package/dist/search/embed-helper.d.ts +3 -1
- package/dist/search/embed-helper.js +3 -3
- package/dist/search/factory.d.ts +3 -1
- package/dist/search/factory.js +19 -17
- package/dist/search/index.d.ts +3 -1
- package/dist/search/index.js +23 -21
- package/dist/search/lancedb-backend.d.ts +3 -1
- package/dist/search/lancedb-backend.js +6 -5
- package/dist/search/meilisearch-backend.d.ts +3 -1
- package/dist/search/meilisearch-backend.js +6 -5
- package/dist/search/noop-backend.d.ts +3 -1
- package/dist/search/orama-backend.d.ts +3 -1
- package/dist/search/orama-backend.js +6 -5
- package/dist/search/port.d.ts +27 -2
- package/dist/search/port.js +1 -1
- package/dist/search/remote-backend.d.ts +3 -1
- package/dist/search/remote-backend.js +3 -3
- package/dist/secure-store/index.d.ts +12 -1
- package/dist/secure-store/index.js +6 -3
- package/dist/{semantic-consolidation-fvdZRa5Z.d.ts → semantic-consolidation-DILZEQq3.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +4 -2
- package/dist/semantic-consolidation.js +41 -32
- package/dist/semantic-rule-promotion.js +37 -27
- package/dist/semantic-rule-verifier.d.ts +3 -1
- package/dist/semantic-rule-verifier.js +38 -28
- package/dist/session-observer-bands.d.ts +3 -1
- package/dist/session-observer-state.d.ts +3 -1
- package/dist/session-observer-state.js +2 -2
- package/dist/session-transcript-migration.js +2 -2
- package/dist/shared-context/manager.d.ts +3 -1
- package/dist/shared-context/manager.js +3 -3
- package/dist/signal.d.ts +3 -1
- package/dist/{storage-CrvzaM9C.d.ts → storage-NIyKYD8g.d.ts} +505 -110
- package/dist/storage-guards.js +2 -2
- package/dist/storage.d.ts +6 -3
- package/dist/storage.js +41 -29
- package/dist/structured-attributes.d.ts +23 -1
- package/dist/structured-attributes.js +7 -1
- package/dist/summarizer.d.ts +3 -1
- package/dist/summarizer.js +11 -11
- package/dist/summary-snapshot.d.ts +3 -1
- package/dist/summary-snapshot.js +2 -2
- package/dist/temporal-index-batch.d.ts +1 -0
- package/dist/temporal-index-batch.js +10 -0
- package/dist/temporal-index-batch.js.map +1 -0
- package/dist/temporal-index-compat.d.ts +279 -1
- package/dist/temporal-index-compat.js +1 -1
- package/dist/temporal-index.d.ts +1 -225
- package/dist/temporal-index.js +35 -3
- package/dist/temporal-supersession.d.ts +5 -2
- package/dist/temporal-supersession.js +2 -2
- package/dist/temporal-timeline-recall.d.ts +3 -1
- package/dist/temporal-validity.d.ts +3 -1
- package/dist/threading.d.ts +3 -1
- package/dist/threading.js +2 -2
- package/dist/tier-migration.d.ts +5 -2
- package/dist/tier-routing.d.ts +3 -1
- package/dist/{tier-stats-KV7IWCJR.js → tier-stats-QEJSPFV2.js} +2 -2
- package/dist/tokens.js +3 -3
- package/dist/topics.d.ts +3 -1
- package/dist/transcript.d.ts +3 -1
- package/dist/transcript.js +2 -2
- package/dist/transfer/backup.js +3 -3
- package/dist/transfer/capsule-export.js +3 -3
- package/dist/transfer/capsule-import.js +6 -6
- package/dist/transfer/types.d.ts +24 -24
- package/dist/trust-score-stage.d.ts +75 -38
- package/dist/trust-score-stage.js +11 -3
- package/dist/trust-score.d.ts +3 -1
- package/dist/{types-Bl4BWDM8.d.ts → types-D_fG2ix8.d.ts} +49 -63
- package/dist/types-continuity.d.ts +52 -0
- package/dist/types-continuity.js +1 -0
- package/dist/types-continuity.js.map +1 -0
- package/dist/types.d.ts +3 -1
- package/dist/types.js +1 -1
- package/dist/utility-runtime.d.ts +3 -1
- package/dist/utils/serialize-mutations.d.ts +31 -2
- package/dist/utils/serialize-mutations.js +1 -1
- package/dist/verified-recall.js +39 -29
- package/dist/write-envelope.d.ts +282 -0
- package/dist/write-envelope.js +35 -0
- package/dist/write-envelope.js.map +1 -0
- package/dist/write-quarantine.d.ts +79 -0
- package/dist/write-quarantine.js +11 -0
- package/dist/write-quarantine.js.map +1 -0
- package/dist/write-rate-limiter.d.ts +45 -0
- package/dist/write-rate-limiter.js +9 -0
- package/dist/write-rate-limiter.js.map +1 -0
- package/package.json +37 -2
- package/src/access-admin-ops-surface.ts +17 -7
- package/src/access-boundary.test.ts +28 -0
- package/src/access-boundary.ts +31 -2
- package/src/access-citation.test.ts +72 -0
- package/src/access-citation.ts +139 -0
- package/src/access-errors.ts +21 -0
- package/src/access-fingerprint-parity.test.ts +211 -0
- package/src/access-http-cancellation.test.ts +59 -21
- package/src/access-http.test.ts +90 -0
- package/src/access-http.ts +79 -79
- package/src/access-mcp-cancellation.test.ts +16 -7
- package/src/access-memory-search-fanout.test.ts +220 -0
- package/src/access-memory-search-fanout.ts +168 -0
- package/src/access-observe-quarantine.test.ts +120 -0
- package/src/access-observe-write-surface.ts +130 -11
- package/src/access-operations-batch.ts +2 -0
- package/src/access-recall-concurrency.ts +773 -0
- package/src/access-recall-response.ts +307 -0
- package/src/access-recall-surface.ts +100 -252
- package/src/access-service-coding-write.test.ts +22 -4
- package/src/access-service-health.test.ts +49 -0
- package/src/access-service-namespace.test.ts +486 -8
- package/src/access-service-observe-scope.test.ts +4 -0
- package/src/access-service-recall-concurrency.test.ts +1990 -0
- package/src/access-service.ts +182 -175
- package/src/access-surface-catalog.ts +1 -0
- package/src/access-token-capabilities.ts +16 -9
- package/src/active-recall.test.ts +35 -0
- package/src/active-recall.ts +7 -0
- package/src/bounded-jsonl-state.ts +93 -0
- package/src/buffer-session.test.ts +422 -5
- package/src/buffer-surprise-trigger.test.ts +41 -0
- package/src/buffer.ts +218 -3
- package/src/capabilities-cluster-b.test.ts +1 -0
- package/src/capabilities.ts +5 -6
- package/src/cli.ts +21 -22
- package/src/coding/architecture-surfaces.test.ts +6 -3
- package/src/coding/architecture-surfaces.ts +36 -25
- package/src/coding/decision-surfaces.ts +42 -34
- package/src/compounding/engine.test.ts +5 -1
- package/src/compounding/engine.ts +7 -7
- package/src/config-qmd.ts +89 -0
- package/src/config.test.ts +136 -0
- package/src/config.ts +122 -118
- package/src/connector-provenance-lifecycle.test.ts +4 -4
- package/src/connectors/coerce.test.ts +131 -0
- package/src/connectors/coerce.ts +80 -7
- package/src/contradiction/contradiction.test.ts +10 -6
- package/src/contradiction/resolution.ts +17 -4
- package/src/correction/correction-access-wiring.ts +62 -18
- package/src/cross-namespace-budget.test.ts +35 -0
- package/src/cross-namespace-budget.ts +86 -19
- package/src/explicit-capture.ts +54 -17
- package/src/extraction.ts +2 -3
- package/src/faithfulness-graph-guard.test.ts +16 -69
- package/src/graph-recall.test.ts +31 -0
- package/src/graph.test.ts +137 -1
- package/src/graph.ts +274 -17
- package/src/index.ts +22 -2
- package/src/local-llm.ts +4 -6
- package/src/logger.ts +16 -0
- package/src/maintenance/dreams-ledger.ts +100 -49
- package/src/maintenance/rebuild-memory-lifecycle-ledger-cli.ts +77 -0
- package/src/maintenance/rebuild-memory-lifecycle-ledger.ts +373 -9
- package/src/memory-cache.ts +70 -0
- package/src/memory-lifecycle-ledger-utils.ts +51 -5
- package/src/namespaces/principal.test.ts +37 -1
- package/src/namespaces/principal.ts +48 -0
- package/src/namespaces/search.test.ts +79 -5
- package/src/namespaces/search.ts +59 -6
- package/src/namespaces/storage.ts +45 -1
- package/src/offline-sync-exclude-globs.ts +58 -0
- package/src/offline-sync-impression-drain.test.ts +316 -0
- package/src/offline-sync-impression-drain.ts +260 -0
- package/src/offline-sync.test.ts +32 -5
- package/src/offline-sync.ts +1 -14
- package/src/operator-toolkit.ts +1 -1
- package/src/orchestration/batch-deindex-flush.test.ts +146 -0
- package/src/orchestration/consolidation-run.ts +96 -85
- package/src/orchestration/extraction-envelope.ts +94 -0
- package/src/orchestration/extraction-persist-promotion.ts +134 -0
- package/src/orchestration/extraction-persist.ts +325 -260
- package/src/orchestration/extraction-run.test.ts +1 -1
- package/src/orchestration/extraction-run.ts +2 -2
- package/src/orchestration/graph-recall-coordinator.ts +18 -7
- package/src/orchestration/lifecycle-policy-coordinator.ts +63 -48
- package/src/orchestration/maintenance.test.ts +2103 -3
- package/src/orchestration/maintenance.ts +581 -2
- package/src/orchestration/namespace-read-fanout.ts +14 -8
- package/src/orchestration/orchestrator-helpers.ts +8 -1
- package/src/orchestration/orchestrator-init.ts +22 -6
- package/src/orchestration/orchestrator-namespace-scope.ts +71 -0
- package/src/orchestration/persistence-index.ts +64 -9
- package/src/orchestration/qmd-result-resolver.ts +27 -0
- package/src/orchestration/recall-entry.ts +34 -19
- package/src/orchestration/recall-internal.ts +207 -79
- package/src/orchestration/recall-rerank-coordinator.ts +229 -82
- package/src/orchestration/recall-result-formatter.ts +76 -20
- package/src/orchestration/recall-search-pipeline.test.ts +70 -0
- package/src/orchestration/recall-search-pipeline.ts +102 -129
- package/src/orchestration/recall-section-coordinator.ts +315 -85
- package/src/orchestration/semantic-consolidation-coordinator.ts +69 -37
- package/src/orchestration/session-context.ts +21 -0
- package/src/orchestration/workspace-ops.test.ts +348 -0
- package/src/orchestration/workspace-ops.ts +172 -34
- package/src/orchestrator-chunked-hash-durability.test.ts +126 -0
- package/src/orchestrator-connector-dedup.test.ts +1061 -40
- package/src/orchestrator-flush.test.ts +155 -39
- package/src/orchestrator-nonchunked-hash-durability.test.ts +121 -0
- package/src/orchestrator-source-attribution.test.ts +9 -9
- package/src/orchestrator.ts +166 -150
- package/src/prioritized-embed.ts +123 -0
- package/src/proactive-contention.test.ts +80 -0
- package/src/proactive-contention.ts +39 -0
- package/src/procedural/procedure-miner.test.ts +19 -14
- package/src/procedural/procedure-miner.ts +44 -13
- package/src/qmd-client.test.ts +111 -1
- package/src/qmd-status.ts +186 -0
- package/src/qmd.test.ts +22 -0
- package/src/qmd.ts +60 -48
- package/src/recall-budget-config.test.ts +30 -0
- package/src/recall-cold-deadline.test.ts +149 -0
- package/src/recall-concurrency-config.ts +28 -0
- package/src/recall-memory-map.ts +74 -0
- package/src/recall-rerank-coordinator.test.ts +508 -0
- package/src/recall-state.test.ts +825 -1
- package/src/recall-state.ts +406 -7
- package/src/recall-timings-access.test.ts +41 -0
- package/src/recall-timings.ts +16 -0
- package/src/relay/mission-access.test.ts +5 -5
- package/src/rerank.ts +22 -0
- package/src/retrieval-agents.test.ts +79 -0
- package/src/retrieval-agents.ts +71 -19
- package/src/salvage-envelope.ts +28 -0
- package/src/scopes/scope-plan.test.ts +42 -0
- package/src/scopes/scope-plan.ts +45 -0
- package/src/search/port.ts +24 -0
- package/src/secure-store/index.ts +1 -0
- package/src/secure-store/secure-fs.ts +48 -0
- package/src/secure-store/secure-store.test.ts +40 -0
- package/src/semantic-rule-promotion.ts +13 -4
- package/src/storage/content-hash-index.ts +655 -0
- package/src/storage/entity-timeline.ts +473 -0
- package/src/storage/memory-lifecycle-ledger-access.ts +603 -0
- package/src/storage/secure-line-reader.test.ts +197 -0
- package/src/storage/secure-line-reader.ts +181 -3
- package/src/storage-append-header-sniff.test.ts +195 -0
- package/src/storage-behavior-signals-cache.test.ts +237 -0
- package/src/storage-contract/cache-coherence.test.ts +96 -1
- package/src/storage-contract/content-hash.test.ts +47 -2
- package/src/storage-fact-hash-index-defer.test.ts +1200 -0
- package/src/storage-memory-lifecycle-ledger.test.ts +1146 -3
- package/src/storage.ts +942 -903
- package/src/structured-attributes.ts +52 -0
- package/src/temporal-index-batch.ts +112 -0
- package/src/temporal-index.test.ts +193 -0
- package/src/temporal-index.ts +49 -53
- package/src/testing/lifecycle-matrix.test.ts +212 -0
- package/src/testing/lifecycle-matrix.ts +271 -0
- package/src/testing/orchestrator-lite.ts +236 -0
- package/src/testing/subjects/dreams-ledger.test.ts +67 -0
- package/src/testing/subjects/extraction-lifecycle.test.ts +442 -0
- package/src/testing/subjects/lifecycle-ledger.test.ts +93 -0
- package/src/testing/subjects/recall-budget.test.ts +461 -0
- package/src/testing/subjects/serialized-write-chain.test.ts +224 -0
- package/src/trust-score-stage.test.ts +154 -0
- package/src/trust-score-stage.ts +216 -53
- package/src/types-continuity.ts +57 -0
- package/src/types.ts +66 -77
- package/src/utils/path-containment.test.ts +75 -0
- package/src/utils/path-containment.ts +76 -0
- package/src/utils/serialize-mutations.test.ts +122 -0
- package/src/utils/serialize-mutations.ts +68 -3
- package/src/wearables/memory-gen.test.ts +31 -9
- package/src/wearables/memory-gen.ts +95 -55
- package/src/wearables/pipeline.test.ts +10 -7
- package/src/wearables/service.test.ts +6 -8
- package/src/wearables/service.ts +2 -2
- package/src/write-envelope.extension.test.ts +111 -0
- package/src/write-envelope.test.ts +683 -0
- package/src/write-envelope.ts +902 -0
- package/src/write-quarantine.test.ts +193 -0
- package/src/write-quarantine.ts +241 -0
- package/src/write-rate-limiter.test.ts +105 -0
- package/src/write-rate-limiter.ts +135 -0
- package/src/write-sealed-parity.test.ts +204 -0
- package/dist/chunk-2VN4JAX7.js.map +0 -1
- package/dist/chunk-37CTGERM.js.map +0 -1
- package/dist/chunk-7ICYQUOL.js.map +0 -1
- package/dist/chunk-AD6AMF2N.js.map +0 -1
- package/dist/chunk-AHLPZ2SF.js.map +0 -1
- package/dist/chunk-ASKEM4AR.js.map +0 -1
- package/dist/chunk-B3F4CWQR.js.map +0 -1
- package/dist/chunk-BCDKBDSY.js.map +0 -1
- package/dist/chunk-BFPETA3S.js.map +0 -1
- package/dist/chunk-BFVEEB7W.js.map +0 -1
- package/dist/chunk-E5BK6CGV.js +0 -335
- package/dist/chunk-E5BK6CGV.js.map +0 -1
- package/dist/chunk-EEARRVZ2.js.map +0 -1
- package/dist/chunk-F7AU34FC.js.map +0 -1
- package/dist/chunk-FBNWOMCE.js.map +0 -1
- package/dist/chunk-FTYDWKO6.js.map +0 -1
- package/dist/chunk-GMSDQUCR.js.map +0 -1
- package/dist/chunk-GWTFLF2P.js.map +0 -1
- package/dist/chunk-IFJ23BHU.js.map +0 -1
- package/dist/chunk-IKQTFQMI.js.map +0 -1
- package/dist/chunk-J2HSAU72.js.map +0 -1
- package/dist/chunk-JMBVCAR4.js.map +0 -1
- package/dist/chunk-KQDNAXOM.js.map +0 -1
- package/dist/chunk-KSBEEMQF.js.map +0 -1
- package/dist/chunk-KSNVDPDF.js.map +0 -1
- package/dist/chunk-LC7OODWZ.js.map +0 -1
- package/dist/chunk-LTJAMRGI.js.map +0 -1
- package/dist/chunk-ND5M64JJ.js.map +0 -1
- package/dist/chunk-NUWYOKS6.js.map +0 -1
- package/dist/chunk-NWTGD4AN.js.map +0 -1
- package/dist/chunk-OBMR4VIX.js.map +0 -1
- package/dist/chunk-ODPLEWB6.js.map +0 -1
- package/dist/chunk-PHK3HARR.js +0 -32
- package/dist/chunk-PHK3HARR.js.map +0 -1
- package/dist/chunk-RANHFI3P.js +0 -8
- package/dist/chunk-RANHFI3P.js.map +0 -1
- package/dist/chunk-RBQLJSJ7.js.map +0 -1
- package/dist/chunk-RULE4VG5.js.map +0 -1
- package/dist/chunk-SVOZFLIQ.js +0 -16
- package/dist/chunk-SVOZFLIQ.js.map +0 -1
- package/dist/chunk-TXLGHDHS.js.map +0 -1
- package/dist/chunk-UN3CH3CO.js +0 -118
- package/dist/chunk-UN3CH3CO.js.map +0 -1
- package/dist/chunk-VSMRDBFT.js +0 -17
- package/dist/chunk-VSMRDBFT.js.map +0 -1
- package/dist/chunk-WU46YPY6.js.map +0 -1
- package/dist/chunk-X47LWMKA.js.map +0 -1
- package/dist/chunk-X64YLC24.js.map +0 -1
- package/dist/chunk-XVLEGMJI.js.map +0 -1
- package/dist/chunk-YF6FMLBT.js.map +0 -1
- package/dist/resolution-VH4NGENZ.js +0 -12
- /package/dist/{capsule-crypto-CZJSLEFG.js.map → access-citation.js.map} +0 -0
- /package/dist/{contradiction-scan-J57T5QV7.js.map → access-memory-search-fanout.js.map} +0 -0
- /package/dist/{dreams-ledger-6UODQOX6.js.map → access-recall-concurrency.js.map} +0 -0
- /package/dist/{graph-edge-decay-FO7AM4UR.js.map → access-recall-response.js.map} +0 -0
- /package/dist/{resolution-VH4NGENZ.js.map → bounded-jsonl-state.js.map} +0 -0
- /package/dist/{capsule-merge-Z2HUO6IK.js.map → capsule-merge-5KKJQBWQ.js.map} +0 -0
- /package/dist/{chunk-A3GOMRJG.js.map → chunk-23L3IXFD.js.map} +0 -0
- /package/dist/{chunk-MRHFJV44.js.map → chunk-2DQ2XREU.js.map} +0 -0
- /package/dist/{chunk-L2B3EE7B.js.map → chunk-2QMKMVHH.js.map} +0 -0
- /package/dist/{chunk-6CALL5VN.js.map → chunk-2UFO7X4Q.js.map} +0 -0
- /package/dist/{chunk-2MR3MFQB.js.map → chunk-2VEOKUPP.js.map} +0 -0
- /package/dist/{chunk-RHOZ5LLO.js.map → chunk-347WD2LE.js.map} +0 -0
- /package/dist/{chunk-5S7Z5SHA.js.map → chunk-34RC5RT7.js.map} +0 -0
- /package/dist/{chunk-KGWXHWAH.js.map → chunk-3QAH2S33.js.map} +0 -0
- /package/dist/{chunk-ZIDSD6VC.js.map → chunk-3Y224NYC.js.map} +0 -0
- /package/dist/{chunk-VFSP73LP.js.map → chunk-45GF7Y3V.js.map} +0 -0
- /package/dist/{chunk-OEHCMALU.js.map → chunk-5I4M26Q7.js.map} +0 -0
- /package/dist/{chunk-2E6G7FCE.js.map → chunk-5Q7EVV4X.js.map} +0 -0
- /package/dist/{chunk-VZ5OJE4X.js.map → chunk-5VQJBH2G.js.map} +0 -0
- /package/dist/{chunk-PUBTHW5O.js.map → chunk-6DRPPQEJ.js.map} +0 -0
- /package/dist/{chunk-4LEF6XWJ.js.map → chunk-6O22TZSB.js.map} +0 -0
- /package/dist/{chunk-ZQ7UBUZ6.js.map → chunk-6QYST5XN.js.map} +0 -0
- /package/dist/{chunk-W4PGTAS2.js.map → chunk-6WAFYNVT.js.map} +0 -0
- /package/dist/{chunk-R5VAVVHP.js.map → chunk-72A4L5JJ.js.map} +0 -0
- /package/dist/{chunk-3FAMU5TX.js.map → chunk-A6USBZTO.js.map} +0 -0
- /package/dist/{chunk-TXVD7PLT.js.map → chunk-A72SWTWW.js.map} +0 -0
- /package/dist/{chunk-FC77VUX5.js.map → chunk-A7Q43EUZ.js.map} +0 -0
- /package/dist/{chunk-UJBESW6X.js.map → chunk-AE7WMV4V.js.map} +0 -0
- /package/dist/{chunk-OKUEZOGW.js.map → chunk-AITCS2RC.js.map} +0 -0
- /package/dist/{chunk-OC35KQIN.js.map → chunk-AJ7QCSIS.js.map} +0 -0
- /package/dist/{chunk-FNMFJWBY.js.map → chunk-ANEUPF6O.js.map} +0 -0
- /package/dist/{chunk-2A3OXAP2.js.map → chunk-B7RWBZXW.js.map} +0 -0
- /package/dist/{chunk-N3JDIRBW.js.map → chunk-BLAKS3CP.js.map} +0 -0
- /package/dist/{chunk-M7VGG3ID.js.map → chunk-BV5WMSIJ.js.map} +0 -0
- /package/dist/{chunk-2BFLDH5F.js.map → chunk-BXLOS5AJ.js.map} +0 -0
- /package/dist/{chunk-UXKMMNJD.js.map → chunk-C23BYTJV.js.map} +0 -0
- /package/dist/{chunk-JZHHREBL.js.map → chunk-C3AKM55W.js.map} +0 -0
- /package/dist/{chunk-RP7YXA67.js.map → chunk-C5JF6EZ7.js.map} +0 -0
- /package/dist/{chunk-DDGV7NAX.js.map → chunk-CQMEM5CC.js.map} +0 -0
- /package/dist/{chunk-A7B4RMQG.js.map → chunk-CXZQOVIE.js.map} +0 -0
- /package/dist/{chunk-7N2RUBAP.js.map → chunk-DDA47TES.js.map} +0 -0
- /package/dist/{chunk-64SE4X5G.js.map → chunk-DEBHXHJR.js.map} +0 -0
- /package/dist/{chunk-EHK6KZHK.js.map → chunk-DNHVPZOD.js.map} +0 -0
- /package/dist/{chunk-437S3G37.js.map → chunk-DQEMWVMT.js.map} +0 -0
- /package/dist/{chunk-LZZNTPLR.js.map → chunk-DX3XRGLH.js.map} +0 -0
- /package/dist/{chunk-7MW3CVLD.js.map → chunk-ES36HTSC.js.map} +0 -0
- /package/dist/{chunk-TN7THW5U.js.map → chunk-ET356KSB.js.map} +0 -0
- /package/dist/{chunk-YNDLCWXS.js.map → chunk-EZ25VE3G.js.map} +0 -0
- /package/dist/{chunk-7LFXDGLH.js.map → chunk-F7GAIWFA.js.map} +0 -0
- /package/dist/{chunk-IKSELOIV.js.map → chunk-FFPJINJE.js.map} +0 -0
- /package/dist/{chunk-V53GJUSL.js.map → chunk-FUTF72MJ.js.map} +0 -0
- /package/dist/{chunk-5UNWK7KU.js.map → chunk-GFPZS3F5.js.map} +0 -0
- /package/dist/{chunk-G6NKALRN.js.map → chunk-H4WG3UQZ.js.map} +0 -0
- /package/dist/{chunk-HLTAPHZZ.js.map → chunk-HNZKVLAN.js.map} +0 -0
- /package/dist/{chunk-5EZXHU36.js.map → chunk-HYQJQGD3.js.map} +0 -0
- /package/dist/{chunk-TRWPCR6P.js.map → chunk-JECBQBEX.js.map} +0 -0
- /package/dist/{chunk-HG32URJJ.js.map → chunk-JYIFGGEM.js.map} +0 -0
- /package/dist/{chunk-VA4WSW54.js.map → chunk-JYIJNNN3.js.map} +0 -0
- /package/dist/{chunk-L5HJQC36.js.map → chunk-K2TDK7GG.js.map} +0 -0
- /package/dist/{chunk-MKDRQAA3.js.map → chunk-KAVBJSBQ.js.map} +0 -0
- /package/dist/{chunk-4OKLXWDZ.js.map → chunk-KNB7IBBU.js.map} +0 -0
- /package/dist/{chunk-QLULYKWZ.js.map → chunk-KSXJOC4F.js.map} +0 -0
- /package/dist/{chunk-JI5AVXYO.js.map → chunk-LEPOP46W.js.map} +0 -0
- /package/dist/{chunk-O7BBFJLP.js.map → chunk-LTAVSOZW.js.map} +0 -0
- /package/dist/{chunk-2IZAGAJR.js.map → chunk-LULR4IUW.js.map} +0 -0
- /package/dist/{chunk-WMWVO45V.js.map → chunk-MC6XO7T4.js.map} +0 -0
- /package/dist/{chunk-D6RIFG4O.js.map → chunk-MNB5RMAY.js.map} +0 -0
- /package/dist/{chunk-67ZCJLJY.js.map → chunk-MYFQ3ED4.js.map} +0 -0
- /package/dist/{chunk-V3UE5I5F.js.map → chunk-MYVPLJOO.js.map} +0 -0
- /package/dist/{chunk-MTWKDOVO.js.map → chunk-NLE6TSLG.js.map} +0 -0
- /package/dist/{chunk-DBRYEIGY.js.map → chunk-OJP3N7UK.js.map} +0 -0
- /package/dist/{chunk-SMX5267P.js.map → chunk-OZKOPQCM.js.map} +0 -0
- /package/dist/{chunk-JCK7V6SN.js.map → chunk-P65YJEEL.js.map} +0 -0
- /package/dist/{chunk-MTR7BZQN.js.map → chunk-PBGWYM3H.js.map} +0 -0
- /package/dist/{chunk-AXTXN4T6.js.map → chunk-PWFCHOB3.js.map} +0 -0
- /package/dist/{chunk-FDPZVY6D.js.map → chunk-QFN4U7AG.js.map} +0 -0
- /package/dist/{chunk-K2ZLHESQ.js.map → chunk-QIEUU4UK.js.map} +0 -0
- /package/dist/{chunk-3D6AFGQR.js.map → chunk-QVT3E4CE.js.map} +0 -0
- /package/dist/{chunk-SFQ6QNL7.js.map → chunk-R6YJI3HE.js.map} +0 -0
- /package/dist/{chunk-5CJVLG3H.js.map → chunk-RFDD3B7W.js.map} +0 -0
- /package/dist/{chunk-JBPKEARU.js.map → chunk-RKNJBZ55.js.map} +0 -0
- /package/dist/{chunk-UTRJFDP2.js.map → chunk-S2BBISHU.js.map} +0 -0
- /package/dist/{chunk-IALLX7EE.js.map → chunk-S2FSBU4H.js.map} +0 -0
- /package/dist/{chunk-7K5Q6COX.js.map → chunk-TVVEYCNW.js.map} +0 -0
- /package/dist/{chunk-PK5XBDA6.js.map → chunk-U3ZAVRP3.js.map} +0 -0
- /package/dist/{chunk-4KJLYTLS.js.map → chunk-V57NLO5P.js.map} +0 -0
- /package/dist/{chunk-FLVL4L3L.js.map → chunk-VDX2J7OX.js.map} +0 -0
- /package/dist/{chunk-7XGSIUP5.js.map → chunk-W4FBGYGK.js.map} +0 -0
- /package/dist/{chunk-6SXVCD7W.js.map → chunk-W7IGLX4G.js.map} +0 -0
- /package/dist/{chunk-KAWTOYAW.js.map → chunk-WLZYGLJ4.js.map} +0 -0
- /package/dist/{chunk-W5NKDU24.js.map → chunk-WON4APQY.js.map} +0 -0
- /package/dist/{chunk-NKCPUHCI.js.map → chunk-WZFAPHIK.js.map} +0 -0
- /package/dist/{chunk-KQPJLK3X.js.map → chunk-XL24QQ63.js.map} +0 -0
- /package/dist/{chunk-4B4MUS5D.js.map → chunk-YROFNEG5.js.map} +0 -0
- /package/dist/{chunk-VRAD2FGO.js.map → chunk-Z54EM5YZ.js.map} +0 -0
- /package/dist/{first-start-migration-TI67YMLG.js.map → first-start-migration-CSRHCJIQ.js.map} +0 -0
- /package/dist/{forget-CQCLB5LB.js.map → forget-HRPLVB3W.js.map} +0 -0
- /package/dist/{purge-NDWV6WYD.js.map → purge-IRF47ZTX.js.map} +0 -0
- /package/dist/{tier-stats-KV7IWCJR.js.map → tier-stats-QEJSPFV2.js.map} +0 -0
|
@@ -0,0 +1,773 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-principal recall concurrency + single-flight coalescing (issue #1906).
|
|
3
|
+
*
|
|
4
|
+
* Extracted from access-service.ts (structural ratchet #1520/#1995): the
|
|
5
|
+
* machinery that replaced the former width-1 `withBudgetLock` recall
|
|
6
|
+
* serialization with a per-principal concurrency semaphore plus query-level
|
|
7
|
+
* single-flight coalescing and atomic cross-namespace budget admission.
|
|
8
|
+
*
|
|
9
|
+
* These are free functions taking a {@link RecallCoordinatorHost} (the
|
|
10
|
+
* EngramAccessService instance) rather than methods, so the per-instance
|
|
11
|
+
* semaphore/flight state and budget/idempotency/execute dependencies stay on
|
|
12
|
+
* the service while the ~600 lines of coalescing logic live in their own
|
|
13
|
+
* module. `raceAbort` and `attachFlightAbort` need no host (they operate on the
|
|
14
|
+
* caller signal / flight object alone).
|
|
15
|
+
*/
|
|
16
|
+
import { abortError, throwIfAborted } from "./abort-error.js";
|
|
17
|
+
import { hashAccessIdempotencyPayload } from "./access-idempotency.js";
|
|
18
|
+
import {
|
|
19
|
+
EngramAccessInputError,
|
|
20
|
+
type EngramAccessRecallRequest,
|
|
21
|
+
type EngramAccessRecallResponse,
|
|
22
|
+
} from "./access-service.js";
|
|
23
|
+
import {
|
|
24
|
+
type BudgetDecision,
|
|
25
|
+
type BudgetReservation,
|
|
26
|
+
type CrossNamespaceBudget,
|
|
27
|
+
toBudgetWarning,
|
|
28
|
+
} from "./cross-namespace-budget.js";
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Per-principal recall concurrency slot (issue #1906). `active` counts
|
|
32
|
+
* in-flight recalls holding a permit; `waiters` is the FIFO queue of callers
|
|
33
|
+
* blocked on a permit. Process-local (per AGENTS.md multi-instance reality);
|
|
34
|
+
* entries self-delete when idle so the map never grows unbounded.
|
|
35
|
+
*/
|
|
36
|
+
interface PrincipalSemaphore {
|
|
37
|
+
active: number;
|
|
38
|
+
waiters: Array<{ take: () => void; drop: () => void }>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Result of one coalesced recall pipeline (issue #1906). */
|
|
42
|
+
export type RecallExecResult = {
|
|
43
|
+
response: EngramAccessRecallResponse;
|
|
44
|
+
budgetRecordPrincipal: string | null;
|
|
45
|
+
/** The pipeline's own atomic budget reservation token, so a consumer that
|
|
46
|
+
* fails AFTER the pipeline (response clone, idempotency put) can release
|
|
47
|
+
* the exact entry (#1906 review round 3). */
|
|
48
|
+
reservation?: BudgetReservation;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* A shared single-flight recall execution (issue #1906 review). Identical
|
|
53
|
+
* concurrent recalls for one principal coalesce onto one `promise`. The flight
|
|
54
|
+
* owns its OWN AbortController so a single caller disconnecting never cancels
|
|
55
|
+
* the shared pipeline; `live` refcounts attached callers and the controller is
|
|
56
|
+
* aborted only when EVERY attached caller has aborted.
|
|
57
|
+
*/
|
|
58
|
+
interface RecallFlight {
|
|
59
|
+
promise: Promise<RecallExecResult>;
|
|
60
|
+
controller: AbortController;
|
|
61
|
+
live: number;
|
|
62
|
+
/** Set true the instant the shared pipeline acquires its concurrency slot and
|
|
63
|
+
* begins executing. Before this, a KEYED flight whose only caller aborts must
|
|
64
|
+
* cancel (nothing has committed); after it, a keyed flight must persist
|
|
65
|
+
* regardless of caller disconnects (round 5 #1). Unkeyed flights ignore it —
|
|
66
|
+
* they carry no `persisted` gate and cancel whenever every caller leaves
|
|
67
|
+
* (round 14 #3). */
|
|
68
|
+
committed: boolean;
|
|
69
|
+
/** Called when the flight goes idle (no attached callers remain). Used to
|
|
70
|
+
* unregister the flight from `recallInFlight` only AFTER its consumers have
|
|
71
|
+
* finished — never on raw pipeline settle — so an identical arrival while a
|
|
72
|
+
* consumer is still finishing (e.g. a slow put) still coalesces (round 6 #1). */
|
|
73
|
+
onIdle?: () => void;
|
|
74
|
+
/** For KEYED flights only: settles when the leader's idempotency persistence
|
|
75
|
+
* (idempotency.put) completes — resolves on success, rejects with the put
|
|
76
|
+
* error on failure. The leader's consumeFlight detaches BEFORE its put runs,
|
|
77
|
+
* so `onIdle` awaits this gate before unregistering the flight — keeping it
|
|
78
|
+
* discoverable through the persistence window so an identical arrival during a
|
|
79
|
+
* slow put still coalesces instead of starting a second pipeline (round 12 #2,
|
|
80
|
+
* originally the round-7 #1 follower gate). */
|
|
81
|
+
persisted?: {
|
|
82
|
+
promise: Promise<void>;
|
|
83
|
+
resolve: () => void;
|
|
84
|
+
reject: (reason: unknown) => void;
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* The EngramAccessService surface these coordinator functions read/mutate. The
|
|
90
|
+
* service passes `this` (via an unknown cast at the single call site) so the
|
|
91
|
+
* per-instance state and dependencies stay owned by the service.
|
|
92
|
+
*/
|
|
93
|
+
export interface RecallCoordinatorHost {
|
|
94
|
+
readonly recallSemaphores: Map<string, PrincipalSemaphore>;
|
|
95
|
+
readonly recallInFlight: Map<string, RecallFlight>;
|
|
96
|
+
readonly budget: Pick<CrossNamespaceBudget, "record" | "release">;
|
|
97
|
+
readonly orchestrator: { readonly config: { readonly recallMaxConcurrentPerPrincipal: number } };
|
|
98
|
+
executeRecall(request: EngramAccessRecallRequest): Promise<RecallExecResult>;
|
|
99
|
+
handleIdempotentRead<T>(options: {
|
|
100
|
+
operation: string;
|
|
101
|
+
idempotencyKey?: string;
|
|
102
|
+
requestFingerprint: unknown;
|
|
103
|
+
execute: () => Promise<T>;
|
|
104
|
+
afterStore?: (response: T) => Promise<void> | void;
|
|
105
|
+
}): Promise<T>;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Acquire a recall slot for `key` (issue #1906). Resolves with a release
|
|
110
|
+
* fn; rejects with an AbortError if `signal` fires while queued. A `limit`
|
|
111
|
+
* of `0` (or any non-positive/non-finite value, which cannot occur after
|
|
112
|
+
* config parse) means "unlimited". Waiters are served FIFO; an aborted
|
|
113
|
+
* waiter leaves the queue immediately and never holds a permit. Empty
|
|
114
|
+
* entries self-delete so the map never grows unbounded (the 2026-07-10
|
|
115
|
+
* unbounded-state-file lesson: every structure has a delete path).
|
|
116
|
+
*/
|
|
117
|
+
function acquireRecallSlot(
|
|
118
|
+
host: RecallCoordinatorHost,
|
|
119
|
+
key: string,
|
|
120
|
+
limit: number,
|
|
121
|
+
signal?: AbortSignal,
|
|
122
|
+
): Promise<{ release: () => void; waitedMs: number }> {
|
|
123
|
+
const cap = Number.isFinite(limit) && limit > 0 ? limit : Infinity;
|
|
124
|
+
const sem = host.recallSemaphores.get(key) ?? { active: 0, waiters: [] };
|
|
125
|
+
host.recallSemaphores.set(key, sem);
|
|
126
|
+
const release = () => {
|
|
127
|
+
sem.active--;
|
|
128
|
+
const next = sem.waiters.shift();
|
|
129
|
+
if (next) {
|
|
130
|
+
sem.active++;
|
|
131
|
+
next.take();
|
|
132
|
+
}
|
|
133
|
+
if (sem.active === 0 && sem.waiters.length === 0) {
|
|
134
|
+
host.recallSemaphores.delete(key);
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
if (sem.active < cap) {
|
|
138
|
+
// Slot free — acquired immediately, NO queue wait. (Measuring wall-clock
|
|
139
|
+
// here would count event-loop scheduling jitter under load and wrongly
|
|
140
|
+
// report a positive queueWaitMs for an uncontended recall.)
|
|
141
|
+
sem.active++;
|
|
142
|
+
return Promise.resolve({ release, waitedMs: 0 });
|
|
143
|
+
}
|
|
144
|
+
// Contended — measure the real time spent blocked for a slot.
|
|
145
|
+
const startedWaiting = Date.now();
|
|
146
|
+
return new Promise<{ release: () => void; waitedMs: number }>((resolve, reject) => {
|
|
147
|
+
const waiter = {
|
|
148
|
+
take: () => {
|
|
149
|
+
signal?.removeEventListener("abort", waiter.drop);
|
|
150
|
+
resolve({ release, waitedMs: Date.now() - startedWaiting });
|
|
151
|
+
},
|
|
152
|
+
drop: () => {
|
|
153
|
+
const i = sem.waiters.indexOf(waiter);
|
|
154
|
+
if (i >= 0) sem.waiters.splice(i, 1);
|
|
155
|
+
if (sem.active === 0 && sem.waiters.length === 0) {
|
|
156
|
+
host.recallSemaphores.delete(key);
|
|
157
|
+
}
|
|
158
|
+
reject(abortError("operation aborted"));
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
if (signal?.aborted) {
|
|
162
|
+
waiter.drop();
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
signal?.addEventListener("abort", waiter.drop, { once: true });
|
|
166
|
+
sem.waiters.push(waiter);
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Runs `fn` under a per-principal recall slot, passing the measured queue
|
|
172
|
+
* wait (ms) — 0 for an uncontended acquire, the real blocked time when the
|
|
173
|
+
* cap was reached — so it can be folded additively into recall-timings.
|
|
174
|
+
* Replaces the former width-1 `withBudgetLock` FIFO serialization (issue
|
|
175
|
+
* #1906): budget accounting stays correct because peek/record are synchronous
|
|
176
|
+
* (see cross-namespace-budget.ts). Release always runs in `finally`.
|
|
177
|
+
*/
|
|
178
|
+
export async function withRecallConcurrency<T>(
|
|
179
|
+
host: RecallCoordinatorHost,
|
|
180
|
+
principal: string,
|
|
181
|
+
signal: AbortSignal | undefined,
|
|
182
|
+
fn: (queueWaitMs: number) => Promise<T>,
|
|
183
|
+
): Promise<T> {
|
|
184
|
+
const key = principal || "__anonymous__";
|
|
185
|
+
const limit = host.orchestrator.config.recallMaxConcurrentPerPrincipal;
|
|
186
|
+
throwIfAborted(signal);
|
|
187
|
+
const { release, waitedMs } = await acquireRecallSlot(host, key, limit, signal);
|
|
188
|
+
try {
|
|
189
|
+
// The signal may have fired while queued: `take()` already removed the
|
|
190
|
+
// abort listener when granting this slot, so re-check before entering `fn`.
|
|
191
|
+
// Without this, a caller (or flight controller) that aborted just after
|
|
192
|
+
// admission would still start the recall pipeline and reserve/run work
|
|
193
|
+
// until a later rollback; the `finally` below releases the slot instead
|
|
194
|
+
// (round 14 #2).
|
|
195
|
+
throwIfAborted(signal);
|
|
196
|
+
return await fn(waitedMs);
|
|
197
|
+
} finally {
|
|
198
|
+
release();
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Race `p` against `signal` (issue #1906). A single-flight caller waits on
|
|
204
|
+
* the shared flight promise but must be able to leave on its own abort. The
|
|
205
|
+
* abort listener is removed as soon as the race settles (either `p` won or
|
|
206
|
+
* the abort fired) so a settled-first promise never leaks a listener on a
|
|
207
|
+
* long-lived signal.
|
|
208
|
+
*
|
|
209
|
+
* Pre-check the signal BEFORE building the race: an already-aborted signal
|
|
210
|
+
* must win even when `p` is already fulfilled. `Promise.race` settles from
|
|
211
|
+
* already-resolved members in array order, so a fulfilled `p` (index 0) would
|
|
212
|
+
* otherwise beat the synchronously-rejected abort racer (index 1) and let an
|
|
213
|
+
* aborted caller proceed into its own persistence + budget accounting before
|
|
214
|
+
* the next abort check runs (round 15 #1).
|
|
215
|
+
*/
|
|
216
|
+
export function raceAbort<T>(p: Promise<T>, signal?: AbortSignal): Promise<T> {
|
|
217
|
+
if (!signal) return p;
|
|
218
|
+
if (signal.aborted) return Promise.reject(abortError("operation aborted"));
|
|
219
|
+
let onAbort: (() => void) | undefined;
|
|
220
|
+
const racer = new Promise<never>((_resolve, reject) => {
|
|
221
|
+
onAbort = () => reject(abortError("operation aborted"));
|
|
222
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
223
|
+
});
|
|
224
|
+
return Promise.race([p, racer]).finally(() => {
|
|
225
|
+
if (onAbort) signal.removeEventListener("abort", onAbort);
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Attach a caller to a single-flight recall (issue #1906 review). Increments
|
|
231
|
+
* the flight refcount and (when `cancelOnAbort`) wires the caller's abort so
|
|
232
|
+
* the SHARED pipeline is cancelled when every attached caller has aborted —
|
|
233
|
+
* EXCEPT a KEYED flight that has already committed to execution, which must
|
|
234
|
+
* persist regardless of caller disconnects (round 5 #1). A caller attached
|
|
235
|
+
* with `cancelOnAbort=false` still holds a refcount slot (keeping the flight
|
|
236
|
+
* alive) but never cancels it. Returns a `detach` to call when the caller
|
|
237
|
+
* settles.
|
|
238
|
+
*/
|
|
239
|
+
function attachFlightAbort(
|
|
240
|
+
flight: RecallFlight,
|
|
241
|
+
signal: AbortSignal | undefined,
|
|
242
|
+
cancelOnAbort: boolean,
|
|
243
|
+
): () => void {
|
|
244
|
+
flight.live += 1;
|
|
245
|
+
let settled = false;
|
|
246
|
+
const onAbort = () => {
|
|
247
|
+
if (settled) return;
|
|
248
|
+
settled = true;
|
|
249
|
+
flight.live -= 1;
|
|
250
|
+
if (flight.live === 0) {
|
|
251
|
+
// A KEYED flight that already began executing must persist even though
|
|
252
|
+
// its last caller left (round 5 #1); cancel only a flight that has not
|
|
253
|
+
// committed (still queued for a slot) or has nothing to persist —
|
|
254
|
+
// unkeyed, no `persisted` gate (round 14 #3).
|
|
255
|
+
if (!flight.persisted || !flight.committed) flight.controller.abort();
|
|
256
|
+
flight.onIdle?.();
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
if (cancelOnAbort && signal) {
|
|
260
|
+
if (signal.aborted) {
|
|
261
|
+
onAbort();
|
|
262
|
+
} else {
|
|
263
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return () => {
|
|
267
|
+
if (settled) return;
|
|
268
|
+
settled = true;
|
|
269
|
+
flight.live -= 1;
|
|
270
|
+
if (cancelOnAbort && signal) signal.removeEventListener("abort", onAbort);
|
|
271
|
+
// Unregister only once the LAST consumer finishes, so a joiner arriving
|
|
272
|
+
// while a consumer is still settling (slow put / hooked consume) still
|
|
273
|
+
// coalesces onto the shared result (round 6 #1).
|
|
274
|
+
if (flight.live === 0) flight.onIdle?.();
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/** Consume a shared recall flight for one caller (issue #1906 review). When
|
|
279
|
+
* `race` is true the caller leaves early on its own abort; when false (a
|
|
280
|
+
* committed idempotency-keyed leader) it awaits the flight to completion so
|
|
281
|
+
* persistence survives its disconnect (round 5 #1). `cancelOnAbort` (default
|
|
282
|
+
* `race`) decides whether this caller's abort counts toward cancelling the
|
|
283
|
+
* shared pipeline: a keyed leader awaits the flight (race=false) yet still
|
|
284
|
+
* wires its abort so that, while the flight is only QUEUED and no other caller
|
|
285
|
+
* is attached, its disconnect cancels the not-yet-committed pipeline (round
|
|
286
|
+
* 14 #3). Records this caller's OWN cross-namespace budget event (coalesced
|
|
287
|
+
* callers), clones the response inside the rollback scope, and returns the
|
|
288
|
+
* reservation this caller owns so an outer failure can release the exact
|
|
289
|
+
* entry. If the caller leaves before observing the result, the pipeline
|
|
290
|
+
* reservation it owns is released once the flight resolves so a cancelled
|
|
291
|
+
* recall never leaks quota (round 5 #2). */
|
|
292
|
+
export async function consumeFlight(
|
|
293
|
+
host: RecallCoordinatorHost,
|
|
294
|
+
flight: RecallFlight,
|
|
295
|
+
request: EngramAccessRecallRequest,
|
|
296
|
+
recordBudget: boolean,
|
|
297
|
+
race: boolean,
|
|
298
|
+
cancelOnAbort: boolean = race,
|
|
299
|
+
): Promise<{ response: EngramAccessRecallResponse; reservation: BudgetReservation | undefined }> {
|
|
300
|
+
const detach = attachFlightAbort(flight, request.abortSignal, cancelOnAbort);
|
|
301
|
+
try {
|
|
302
|
+
let result: RecallExecResult;
|
|
303
|
+
try {
|
|
304
|
+
result = race
|
|
305
|
+
? await raceAbort(flight.promise, request.abortSignal)
|
|
306
|
+
: await flight.promise;
|
|
307
|
+
} catch (err) {
|
|
308
|
+
// This caller left before observing the result. If it OWNS the
|
|
309
|
+
// pipeline's reservation (recordBudget=false) and the flight still
|
|
310
|
+
// resolves with one, release it so a cancelled recall does not leak
|
|
311
|
+
// quota (round 5 #2). A rejected flight already rolled back inside
|
|
312
|
+
// executeRecall, so the resolve handler simply never fires.
|
|
313
|
+
if (!recordBudget) {
|
|
314
|
+
flight.promise.then(
|
|
315
|
+
(settled) => {
|
|
316
|
+
if (settled.reservation) host.budget.release(settled.reservation);
|
|
317
|
+
},
|
|
318
|
+
() => {},
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
throw err;
|
|
322
|
+
}
|
|
323
|
+
// A committed (race=false) caller applies its own abort later (after
|
|
324
|
+
// persistence); a racing caller re-checks here. If the abort landed in the
|
|
325
|
+
// gap AFTER the result resolved, release the pipeline reservation this
|
|
326
|
+
// caller owns (recordBudget=false) rather than leak it (round 6 #2).
|
|
327
|
+
if (race && request.abortSignal?.aborted) {
|
|
328
|
+
if (!recordBudget && result.reservation) {
|
|
329
|
+
host.budget.release(result.reservation);
|
|
330
|
+
}
|
|
331
|
+
throwIfAborted(request.abortSignal);
|
|
332
|
+
}
|
|
333
|
+
// A caller that ran the pipeline inherits its reservation token; a
|
|
334
|
+
// coalesced caller records its OWN cross-namespace event below.
|
|
335
|
+
let reservation = recordBudget ? undefined : result.reservation;
|
|
336
|
+
let ownDecision: BudgetDecision | undefined;
|
|
337
|
+
if (recordBudget && result.budgetRecordPrincipal) {
|
|
338
|
+
const decision = host.budget.record(result.budgetRecordPrincipal);
|
|
339
|
+
if (!decision.allowed) {
|
|
340
|
+
throw new EngramAccessInputError(
|
|
341
|
+
`recall denied: cross-namespace budget exceeded (${decision.count}/${decision.limit.hardLimit} in ${decision.limit.windowMs}ms window)`,
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
reservation = decision.reservation;
|
|
345
|
+
ownDecision = decision;
|
|
346
|
+
}
|
|
347
|
+
try {
|
|
348
|
+
const response = structuredClone(result.response);
|
|
349
|
+
if (ownDecision) {
|
|
350
|
+
// The clone carries the LEADER's budgetWarning; replace it with THIS
|
|
351
|
+
// coalesced caller's OWN soft-limit decision so the caller whose event
|
|
352
|
+
// actually crossed the soft limit sees its own warning (round 4 #2).
|
|
353
|
+
// `toBudgetWarning` strips the server-only `reservation` token so the
|
|
354
|
+
// principal id never reaches the response / cache (round 10 #2).
|
|
355
|
+
response.budgetWarning = toBudgetWarning(ownDecision);
|
|
356
|
+
}
|
|
357
|
+
return { response, reservation };
|
|
358
|
+
} catch (err) {
|
|
359
|
+
// Clone threw on a successful pipeline — release the admission entry
|
|
360
|
+
// rather than leak it (round 3 #1).
|
|
361
|
+
host.budget.release(reservation);
|
|
362
|
+
throw err;
|
|
363
|
+
}
|
|
364
|
+
} finally {
|
|
365
|
+
detach();
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/** UNKEYED follower path (issue #1906 review): join an already-registered
|
|
370
|
+
* flight WITHOUT taking a concurrency slot. Only unkeyed callers reach here —
|
|
371
|
+
* keyed callers enter the idempotency guard first (round 12 #1) and coalesce
|
|
372
|
+
* via leadRecallFlight's existing-join instead. Mirrors the leaders' final
|
|
373
|
+
* post-consume abort guard: a caller that disconnected after its per-caller
|
|
374
|
+
* reservation was recorded but before delivery releases it rather than leaking
|
|
375
|
+
* quota (round 8 #1). */
|
|
376
|
+
async function followRecallFlight(
|
|
377
|
+
host: RecallCoordinatorHost,
|
|
378
|
+
flight: RecallFlight,
|
|
379
|
+
request: EngramAccessRecallRequest,
|
|
380
|
+
): Promise<EngramAccessRecallResponse> {
|
|
381
|
+
const consumed = await consumeFlight(host, flight, request, true, true);
|
|
382
|
+
try {
|
|
383
|
+
throwIfAborted(request.abortSignal);
|
|
384
|
+
} catch (err) {
|
|
385
|
+
host.budget.release(consumed.reservation);
|
|
386
|
+
throw err;
|
|
387
|
+
}
|
|
388
|
+
return consumed.response;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/** Non-coalesced recall (single-flight disabled): per-request execution
|
|
392
|
+
* under a concurrency slot, the caller's own signal driving its pipeline. */
|
|
393
|
+
async function runRecallDirect(
|
|
394
|
+
host: RecallCoordinatorHost,
|
|
395
|
+
request: EngramAccessRecallRequest,
|
|
396
|
+
normalizedRequest: EngramAccessRecallRequest,
|
|
397
|
+
requestFingerprint: unknown,
|
|
398
|
+
queueWaitMs: number,
|
|
399
|
+
): Promise<EngramAccessRecallResponse> {
|
|
400
|
+
let capturedReservation: BudgetReservation | undefined;
|
|
401
|
+
let response: EngramAccessRecallResponse;
|
|
402
|
+
try {
|
|
403
|
+
response = await host.handleIdempotentRead({
|
|
404
|
+
operation: "recall",
|
|
405
|
+
idempotencyKey: request.idempotencyKey,
|
|
406
|
+
requestFingerprint,
|
|
407
|
+
execute: async () => {
|
|
408
|
+
// Create + await the pipeline inside the closure so its rejection is
|
|
409
|
+
// observed immediately (no unhandled-rejection window across the
|
|
410
|
+
// idempotency-lock await). The caller's own signal drives this
|
|
411
|
+
// non-coalesced pipeline.
|
|
412
|
+
const exec = host.executeRecall({ ...normalizedRequest, queueWaitMs });
|
|
413
|
+
let result: RecallExecResult;
|
|
414
|
+
try {
|
|
415
|
+
result = await raceAbort(exec, request.abortSignal);
|
|
416
|
+
} catch (err) {
|
|
417
|
+
// Caller left (abort) before observing the result. If exec still
|
|
418
|
+
// resolves with a reservation, release it so the cancelled recall
|
|
419
|
+
// does not leak quota (round 5 #2). A rejected exec already rolled
|
|
420
|
+
// back inside executeRecall.
|
|
421
|
+
exec.then(
|
|
422
|
+
(settled) => {
|
|
423
|
+
if (settled.reservation) host.budget.release(settled.reservation);
|
|
424
|
+
},
|
|
425
|
+
() => {},
|
|
426
|
+
);
|
|
427
|
+
throw err;
|
|
428
|
+
}
|
|
429
|
+
let cloned: EngramAccessRecallResponse;
|
|
430
|
+
try {
|
|
431
|
+
cloned = structuredClone(result.response);
|
|
432
|
+
} catch (err) {
|
|
433
|
+
// Clone threw on a successful pipeline — release now (round 3 #1);
|
|
434
|
+
// leave capturedReservation unset so the outer catch is a no-op.
|
|
435
|
+
host.budget.release(result.reservation);
|
|
436
|
+
throw err;
|
|
437
|
+
}
|
|
438
|
+
// Clone succeeded — the outer catch owns rollback if a later step
|
|
439
|
+
// (idempotency put) fails (round 4 #1).
|
|
440
|
+
capturedReservation = result.reservation;
|
|
441
|
+
return cloned;
|
|
442
|
+
},
|
|
443
|
+
});
|
|
444
|
+
} catch (err) {
|
|
445
|
+
if (capturedReservation) host.budget.release(capturedReservation);
|
|
446
|
+
throw err;
|
|
447
|
+
}
|
|
448
|
+
try {
|
|
449
|
+
throwIfAborted(request.abortSignal);
|
|
450
|
+
} catch (err) {
|
|
451
|
+
// Abort landed after the result was produced but before delivery. For a
|
|
452
|
+
// NON-persisted (unkeyed) recall the completed result is discarded and
|
|
453
|
+
// will not be replayed, so release its reservation rather than leak quota
|
|
454
|
+
// (round 6 #2). A keyed recall persisted its result (a retry replays it),
|
|
455
|
+
// so its budget event legitimately stands (round 5 #1).
|
|
456
|
+
if (!request.idempotencyKey?.trim() && capturedReservation) {
|
|
457
|
+
host.budget.release(capturedReservation);
|
|
458
|
+
}
|
|
459
|
+
throw err;
|
|
460
|
+
}
|
|
461
|
+
return response;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/** Register a single-flight and start its ONE shared pipeline in the
|
|
465
|
+
* background (issue #1906 review). The pipeline runs under a concurrency
|
|
466
|
+
* slot tied to the FLIGHT'S own abort controller (#3) — so a caller
|
|
467
|
+
* disconnecting (even while the flight is still queued for a slot) never
|
|
468
|
+
* cancels it while other callers still want the result. The flight
|
|
469
|
+
* unregisters via `onIdle` when its LAST consumer finishes (round 6 #1) or
|
|
470
|
+
* when every caller has aborted (round 3 #2) — NOT on raw pipeline settle,
|
|
471
|
+
* so a joiner arriving while a consumer is still finishing still coalesces. */
|
|
472
|
+
export function createAndStartFlight(
|
|
473
|
+
host: RecallCoordinatorHost,
|
|
474
|
+
normalizedRequest: EngramAccessRecallRequest,
|
|
475
|
+
flightKey: string,
|
|
476
|
+
principalKey: string,
|
|
477
|
+
keyed: boolean,
|
|
478
|
+
): RecallFlight {
|
|
479
|
+
const controller = new AbortController();
|
|
480
|
+
let settleExec!: (result: RecallExecResult) => void;
|
|
481
|
+
let failExec!: (reason: unknown) => void;
|
|
482
|
+
const flightPromise = new Promise<RecallExecResult>((resolve, reject) => {
|
|
483
|
+
settleExec = resolve;
|
|
484
|
+
failExec = reject;
|
|
485
|
+
});
|
|
486
|
+
// Consumers attach their own handlers; keep Node quiet if none do yet.
|
|
487
|
+
flightPromise.catch(() => {});
|
|
488
|
+
// KEYED flights carry a persistence gate that fast-path followers await so
|
|
489
|
+
// they never report success before the leader's idempotency.put settled
|
|
490
|
+
// (round 7 #1).
|
|
491
|
+
let persisted: RecallFlight["persisted"];
|
|
492
|
+
if (keyed) {
|
|
493
|
+
let resolvePersist!: () => void;
|
|
494
|
+
let rejectPersist!: (reason: unknown) => void;
|
|
495
|
+
const persistPromise = new Promise<void>((resolve, reject) => {
|
|
496
|
+
resolvePersist = resolve;
|
|
497
|
+
rejectPersist = reject;
|
|
498
|
+
});
|
|
499
|
+
persistPromise.catch(() => {});
|
|
500
|
+
persisted = { promise: persistPromise, resolve: resolvePersist, reject: rejectPersist };
|
|
501
|
+
}
|
|
502
|
+
const flight: RecallFlight = {
|
|
503
|
+
promise: flightPromise,
|
|
504
|
+
controller,
|
|
505
|
+
live: 0,
|
|
506
|
+
committed: false,
|
|
507
|
+
onIdle: () => {
|
|
508
|
+
const unregister = () => {
|
|
509
|
+
if (host.recallInFlight.get(flightKey) === flight) {
|
|
510
|
+
host.recallInFlight.delete(flightKey);
|
|
511
|
+
}
|
|
512
|
+
};
|
|
513
|
+
// A KEYED leader's consumeFlight detaches (live -> 0) BEFORE
|
|
514
|
+
// handleIdempotentRead runs idempotency.put, so unregistering on detach
|
|
515
|
+
// would drop the flight DURING the persistence window — an identical
|
|
516
|
+
// arrival then finds no flight and starts a second pipeline + reserve.
|
|
517
|
+
// Keep the flight discoverable until `persisted` settles so arrivals
|
|
518
|
+
// during a slow put still coalesce onto the one pipeline (round 12 #2).
|
|
519
|
+
// Unkeyed flights have no put: unregister immediately.
|
|
520
|
+
if (persisted) {
|
|
521
|
+
persisted.promise.then(unregister, unregister);
|
|
522
|
+
} else {
|
|
523
|
+
unregister();
|
|
524
|
+
}
|
|
525
|
+
},
|
|
526
|
+
...(persisted ? { persisted } : {}),
|
|
527
|
+
};
|
|
528
|
+
host.recallInFlight.set(flightKey, flight);
|
|
529
|
+
withRecallConcurrency(host, principalKey, controller.signal, async (queueWaitMs) => {
|
|
530
|
+
// A slot was granted and the abort re-check in withRecallConcurrency passed
|
|
531
|
+
// — the pipeline is now committing to execution. Past this point a keyed
|
|
532
|
+
// flight persists even if its callers disconnect (round 5 #1); before it,
|
|
533
|
+
// attachFlightAbort cancels a keyed flight whose only caller aborts while
|
|
534
|
+
// still queued (round 14 #3).
|
|
535
|
+
flight.committed = true;
|
|
536
|
+
return host.executeRecall({
|
|
537
|
+
...normalizedRequest,
|
|
538
|
+
abortSignal: controller.signal,
|
|
539
|
+
queueWaitMs,
|
|
540
|
+
});
|
|
541
|
+
}).then(settleExec, failExec);
|
|
542
|
+
return flight;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/** Leader path (issue #1906 review): consult the idempotency guard FIRST so an
|
|
546
|
+
* idempotent REPLAY returns the stored response WITHOUT starting a pipeline,
|
|
547
|
+
* flight, or budget reserve (#1/#2). On a miss, coalesce onto a LIVE
|
|
548
|
+
* race-registered flight if one exists, else start the one shared pipeline
|
|
549
|
+
* and consume it as the leader. A failure after the reserve (e.g. idempotency
|
|
550
|
+
* put) releases this caller's exact reservation (round 3 #3). */
|
|
551
|
+
export async function leadRecallFlight(
|
|
552
|
+
host: RecallCoordinatorHost,
|
|
553
|
+
request: EngramAccessRecallRequest,
|
|
554
|
+
normalizedRequest: EngramAccessRecallRequest,
|
|
555
|
+
requestFingerprint: unknown,
|
|
556
|
+
flightKey: string,
|
|
557
|
+
principalKey: string,
|
|
558
|
+
): Promise<EngramAccessRecallResponse> {
|
|
559
|
+
const keyed = !!request.idempotencyKey?.trim();
|
|
560
|
+
let capturedReservation: BudgetReservation | undefined;
|
|
561
|
+
// The flight THIS call created (leader) and thus owns persistence for — used
|
|
562
|
+
// to settle its `persisted` gate so keyed fast-path followers learn the
|
|
563
|
+
// put outcome (round 7 #1).
|
|
564
|
+
let ownedFlight: RecallFlight | undefined;
|
|
565
|
+
let response: EngramAccessRecallResponse;
|
|
566
|
+
try {
|
|
567
|
+
response = await host.handleIdempotentRead({
|
|
568
|
+
operation: "recall",
|
|
569
|
+
idempotencyKey: request.idempotencyKey,
|
|
570
|
+
requestFingerprint,
|
|
571
|
+
execute: async () => {
|
|
572
|
+
// A keyed request commits (race=false): the leader awaits the flight
|
|
573
|
+
// to completion so idempotency.put persists even if the leader itself
|
|
574
|
+
// disconnects (round 5 #1). A non-keyed request races its own signal
|
|
575
|
+
// and may leave early (nothing to persist).
|
|
576
|
+
const race = !keyed;
|
|
577
|
+
const existing = host.recallInFlight.get(flightKey);
|
|
578
|
+
if (existing && !existing.controller.signal.aborted) {
|
|
579
|
+
// A LIVE identical flight registered between our fast-path miss and
|
|
580
|
+
// the idempotency guard — join it and record our own event. But a
|
|
581
|
+
// caller that already disconnected must NOT join: a keyed join is
|
|
582
|
+
// non-racing (race=false), so it would record its own cross-namespace
|
|
583
|
+
// budget event and run idempotency.put before the late abort check.
|
|
584
|
+
// Reject at admission instead; the existing flight continues for its
|
|
585
|
+
// other live consumers (round 10 #1).
|
|
586
|
+
throwIfAborted(request.abortSignal);
|
|
587
|
+
// `cancelOnAbort=true` (not the race=false default): a keyed
|
|
588
|
+
// existing-join follower is non-racing (it awaits the shared flight
|
|
589
|
+
// to completion), but its abort must still be COUNTED in the flight's
|
|
590
|
+
// live refcount while the flight is only QUEUED. Otherwise, at
|
|
591
|
+
// recallMaxConcurrentPerPrincipal=1, if the leader disconnects
|
|
592
|
+
// (live 2 -> 1) and this follower then disconnects, live would stay 1
|
|
593
|
+
// and the flight would execute + reserve + persist with no caller
|
|
594
|
+
// connected. Counting drops live to 0, and attachFlightAbort's
|
|
595
|
+
// committed guard (!persisted || !committed) cancels the queued flight
|
|
596
|
+
// while leaving a committed keyed flight to persist (round 15 #2).
|
|
597
|
+
const consumed = await consumeFlight(host, existing, request, true, race, true);
|
|
598
|
+
capturedReservation = consumed.reservation;
|
|
599
|
+
// A KEYED follower that coalesced onto the leader's flight must
|
|
600
|
+
// inherit the leader's persistence outcome before reporting success.
|
|
601
|
+
// The shared pipeline settling is NOT the leader's idempotency.put:
|
|
602
|
+
// the leader detaches (consumeFlight) BEFORE its put, so without this
|
|
603
|
+
// await a keyed follower could return success (and run its OWN
|
|
604
|
+
// idempotency.put), keeping its cross-namespace reservation, while the
|
|
605
|
+
// leader's put later FAILS — a phantom success that a same-key retry
|
|
606
|
+
// would then diverge from. Await the joined flight's `persisted` gate
|
|
607
|
+
// so a keyed join resolves only after the leader's put succeeds and
|
|
608
|
+
// REJECTS (releasing this caller's reservation via the outer catch,
|
|
609
|
+
// and skipping its own put) with the leader's exact error when the
|
|
610
|
+
// put fails — identical to the leader's put-failure behavior (round
|
|
611
|
+
// 13 #1). Race this persistence wait with the follower's OWN abort
|
|
612
|
+
// signal (round 14 #1/#4): a keyed follower whose HTTP/MCP client
|
|
613
|
+
// disconnects while the leader's put is still pending must receive
|
|
614
|
+
// its own AbortError PROMPTLY rather than block until the put settles
|
|
615
|
+
// (and, on put failure, get the store error instead of AbortError).
|
|
616
|
+
// The follower already detached from the flight inside consumeFlight
|
|
617
|
+
// (its non-racing await ran to the shared settle), so bailing here
|
|
618
|
+
// never decrements the leader's refcount or cancels its controller —
|
|
619
|
+
// the leader's persistence continues for the flight's other
|
|
620
|
+
// consumers. On abort the outer catch releases ONLY this follower's
|
|
621
|
+
// reservation. Unkeyed joins (race=true) keep existing behavior: they
|
|
622
|
+
// consumed the shared result and never depend on another caller's
|
|
623
|
+
// persistence, so they never block on `persisted`.
|
|
624
|
+
if (keyed) {
|
|
625
|
+
if (existing.persisted) {
|
|
626
|
+
await raceAbort(existing.persisted.promise, request.abortSignal);
|
|
627
|
+
} else {
|
|
628
|
+
// The joined flight was started by an UNKEYED leader, so it
|
|
629
|
+
// carries no `persisted` gate. The non-racing consume (race=false
|
|
630
|
+
// for a keyed caller) never observed this follower's abort, so a
|
|
631
|
+
// keyed follower that disconnected while the shared pipeline was
|
|
632
|
+
// still running would otherwise return success here and let
|
|
633
|
+
// handleIdempotentRead persist its key + keep its recorded
|
|
634
|
+
// cross-namespace budget event. Recheck the abort before
|
|
635
|
+
// returning so it rejects with AbortError instead: the outer
|
|
636
|
+
// catch releases this follower's reservation and execute()
|
|
637
|
+
// throwing skips its own idempotency.put — matching the
|
|
638
|
+
// keyed-follower-on-keyed-leader persistence path (round 16 #1).
|
|
639
|
+
throwIfAborted(request.abortSignal);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
return consumed.response;
|
|
643
|
+
}
|
|
644
|
+
// No LIVE flight to join. If the caller already disconnected before we
|
|
645
|
+
// committed any work, reject at admission — creating the flight starts
|
|
646
|
+
// the pipeline (queue + execute + persist) and reserves a cross-namespace
|
|
647
|
+
// budget event. For a keyed leader `race` is false, so without this the
|
|
648
|
+
// caller would burn a full recall + budget event before the final
|
|
649
|
+
// post-consume abort check rejects, even though it left before admission
|
|
650
|
+
// and no follower is here to keep the flight alive. The old width-1
|
|
651
|
+
// budget lock rejected before starting work; preserve that (#1906 r9).
|
|
652
|
+
throwIfAborted(request.abortSignal);
|
|
653
|
+
const flight = createAndStartFlight(host, normalizedRequest, flightKey, principalKey, keyed);
|
|
654
|
+
ownedFlight = flight;
|
|
655
|
+
// The leader's own budget event is reserved inside the pipeline, so it
|
|
656
|
+
// must NOT record again here. `cancelOnAbort=true` even for a keyed
|
|
657
|
+
// leader (race=false): while the flight is only QUEUED for a slot and
|
|
658
|
+
// this is its sole caller, the leader's disconnect cancels the
|
|
659
|
+
// not-yet-committed pipeline (attachFlightAbort's committed guard keeps
|
|
660
|
+
// a post-commit keyed flight persisting, and any additional live caller
|
|
661
|
+
// keeps live > 0 so the shared flight survives) (round 14 #3).
|
|
662
|
+
const consumed = await consumeFlight(host, flight, request, false, race, true);
|
|
663
|
+
capturedReservation = consumed.reservation;
|
|
664
|
+
return consumed.response;
|
|
665
|
+
},
|
|
666
|
+
});
|
|
667
|
+
} catch (err) {
|
|
668
|
+
// A failure AFTER the caller reserved (idempotency put, or any post-
|
|
669
|
+
// execute step in handleIdempotentRead) releases the exact reservation.
|
|
670
|
+
// If execute() rejected before reserving — leader abort mid-pipeline, or
|
|
671
|
+
// a pipeline failure already rolled back inside executeRecall/consumeFlight
|
|
672
|
+
// — capturedReservation is undefined, so this is a no-op (round 3 #3).
|
|
673
|
+
if (capturedReservation) host.budget.release(capturedReservation);
|
|
674
|
+
// Tell keyed followers coalescing via the existing-join (they await this
|
|
675
|
+
// flight's `persisted` gate) that persistence failed so they behave
|
|
676
|
+
// identically to this leader (release + reject) — no phantom success
|
|
677
|
+
// (round 7 #1; keyed followers moved to the existing-join in round 12 #1).
|
|
678
|
+
ownedFlight?.persisted?.reject(err);
|
|
679
|
+
throw err;
|
|
680
|
+
}
|
|
681
|
+
// Leader persisted successfully — resolve the gate so keyed followers
|
|
682
|
+
// awaiting the put return success.
|
|
683
|
+
ownedFlight?.persisted?.resolve();
|
|
684
|
+
try {
|
|
685
|
+
throwIfAborted(request.abortSignal);
|
|
686
|
+
} catch (err) {
|
|
687
|
+
// Abort landed after consumption but before delivery. A NON-persisted
|
|
688
|
+
// (unkeyed) recall's completed result is discarded (no replay), so release
|
|
689
|
+
// its reservation rather than leak quota (round 6 #2); a keyed recall
|
|
690
|
+
// persisted its result, so its budget event legitimately stands (round 5 #1).
|
|
691
|
+
if (!keyed && capturedReservation) {
|
|
692
|
+
host.budget.release(capturedReservation);
|
|
693
|
+
}
|
|
694
|
+
throw err;
|
|
695
|
+
}
|
|
696
|
+
return response;
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
/**
|
|
700
|
+
* Top-level recall coordination (issue #1906): dispatch a validated recall to
|
|
701
|
+
* either the non-coalesced per-request path (single-flight disabled) or the
|
|
702
|
+
* single-flight leader/follower coalescing path. `singleFlight` is resolved by
|
|
703
|
+
* the caller through the shared access-setup capability projection so the
|
|
704
|
+
* config flag is read only in capabilities.ts (#1523 scattered-gate ratchet).
|
|
705
|
+
*/
|
|
706
|
+
export function coordinateRecall(
|
|
707
|
+
host: RecallCoordinatorHost,
|
|
708
|
+
request: EngramAccessRecallRequest,
|
|
709
|
+
normalizedRequest: EngramAccessRecallRequest,
|
|
710
|
+
requestFingerprint: Omit<EngramAccessRecallRequest, "abortSignal">,
|
|
711
|
+
principalKey: string,
|
|
712
|
+
singleFlight: boolean,
|
|
713
|
+
): Promise<EngramAccessRecallResponse> {
|
|
714
|
+
if (!singleFlight) {
|
|
715
|
+
// No coalescing: per-request execution under a concurrency slot.
|
|
716
|
+
return withRecallConcurrency(
|
|
717
|
+
host,
|
|
718
|
+
principalKey,
|
|
719
|
+
request.abortSignal,
|
|
720
|
+
(queueWaitMs) =>
|
|
721
|
+
runRecallDirect(host, request, normalizedRequest, requestFingerprint, queueWaitMs),
|
|
722
|
+
);
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
// The flight key represents the recall WORK — the query + options that shape
|
|
726
|
+
// the result — NOT the persistence key. `idempotencyKey` only selects an
|
|
727
|
+
// idempotency-store slot; it never changes the computed result. Excluding it
|
|
728
|
+
// lets identical recalls that arrive with DISTINCT per-request idempotency
|
|
729
|
+
// keys (a common transport-retry pattern) coalesce onto ONE pipeline + slot
|
|
730
|
+
// instead of each key spawning its own (round 11). Contract: EVERY keyed
|
|
731
|
+
// caller enters the idempotency guard first (round 12 #1) and persists the
|
|
732
|
+
// shared result under ITS OWN key, so a same-key retry always replays from
|
|
733
|
+
// the store; distinct keys on identical work still coalesce onto one pipeline.
|
|
734
|
+
const { idempotencyKey: _flightKeyOmitIdemKey, ...flightFingerprint } = requestFingerprint;
|
|
735
|
+
const flightKey = `${principalKey}\u0000${hashAccessIdempotencyPayload({
|
|
736
|
+
operation: "recall",
|
|
737
|
+
request: flightFingerprint,
|
|
738
|
+
})}`;
|
|
739
|
+
// UNKEYED follower fast-path (#1906 review #2): join an in-flight identical
|
|
740
|
+
// recall WITHOUT acquiring a concurrency slot. Because the leader registers
|
|
741
|
+
// its flight synchronously (below, before any await), every later identical
|
|
742
|
+
// arrival coalesces here — even when the concurrency cap is below the number
|
|
743
|
+
// of concurrent callers. Followers never wait for, or consume, a slot.
|
|
744
|
+
//
|
|
745
|
+
// KEYED callers must NOT take this fast-path: they enter the idempotency
|
|
746
|
+
// guard FIRST (leadRecallFlight -> handleIdempotentRead) so a stored response
|
|
747
|
+
// REPLAYS and a reused key with a different payload raises a CONFLICT, instead
|
|
748
|
+
// of silently joining the flight and skipping the store check (round 12 #1).
|
|
749
|
+
// On a store MISS a keyed caller still coalesces onto a live flight via
|
|
750
|
+
// leadRecallFlight's existing-join, then persists under its own key.
|
|
751
|
+
const keyed = !!request.idempotencyKey?.trim();
|
|
752
|
+
const existing = host.recallInFlight.get(flightKey);
|
|
753
|
+
// Skip a flight already cancelled (all its callers aborted) — it will
|
|
754
|
+
// reject with AbortError; lead a fresh flight instead (round 3 #2).
|
|
755
|
+
if (!keyed && existing && !existing.controller.signal.aborted) {
|
|
756
|
+
// A caller that already disconnected must NOT join a live flight: joining
|
|
757
|
+
// records its own cross-namespace budget event before the late abort check.
|
|
758
|
+
// Reject at admission; the existing flight continues for its other live
|
|
759
|
+
// consumers (round 10 #1).
|
|
760
|
+
throwIfAborted(request.abortSignal);
|
|
761
|
+
return followRecallFlight(host, existing, request);
|
|
762
|
+
}
|
|
763
|
+
// We are the leader: leadRecallFlight registers the flight synchronously in
|
|
764
|
+
// this same turn, then acquires a slot to run the one shared pipeline.
|
|
765
|
+
return leadRecallFlight(
|
|
766
|
+
host,
|
|
767
|
+
request,
|
|
768
|
+
normalizedRequest,
|
|
769
|
+
requestFingerprint,
|
|
770
|
+
flightKey,
|
|
771
|
+
principalKey,
|
|
772
|
+
);
|
|
773
|
+
}
|