@remnic/core 9.7.15 → 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 +85 -71
- package/dist/access-audit.js +2 -2
- package/dist/access-boundary.d.ts +35 -17
- package/dist/access-boundary.js +86 -74
- package/dist/access-citation.d.ts +28 -0
- package/dist/access-citation.js +9 -0
- package/dist/access-cli.js +194 -178
- 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 +100 -87
- package/dist/access-identity-continuity-surface.d.ts +13 -8
- package/dist/access-identity-continuity-surface.js +85 -71
- package/dist/access-lcm-surface.d.ts +16 -9
- package/dist/access-lcm-surface.js +85 -71
- package/dist/access-mcp.d.ts +23 -16
- package/dist/access-mcp.js +96 -84
- 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 +85 -71
- package/dist/access-operations-batch.js +92 -80
- package/dist/access-operations.d.ts +29 -22
- package/dist/access-operations.js +94 -82
- 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 +85 -71
- package/dist/access-schema.d.ts +98 -98
- package/dist/access-schema.js +8 -6
- package/dist/{access-service-DpcYZ9Nl.d.ts → access-service-DEL4qCrc.d.ts} +25 -32
- package/dist/access-service.d.ts +13 -6
- package/dist/access-service.js +89 -72
- 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 +34 -24
- 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/{catalog-C9444P10.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 +43 -34
- 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-QKQYXZVS.js → chunk-2EJOEICD.js} +1819 -1481
- package/dist/chunk-2EJOEICD.js.map +1 -0
- package/dist/{chunk-L2B3EE7B.js → chunk-2QMKMVHH.js} +2 -2
- package/dist/{chunk-VJVNLNDQ.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-HDTQVNWD.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-LRNMRXJO.js → chunk-3Y224NYC.js} +3 -3
- package/dist/{chunk-3IY64MV6.js → chunk-44XZ75OQ.js} +44 -10
- package/dist/chunk-44XZ75OQ.js.map +1 -0
- package/dist/{chunk-VFSP73LP.js → chunk-45GF7Y3V.js} +2 -2
- package/dist/{chunk-K7LOWSLU.js → chunk-4BJQODZF.js} +2479 -1520
- package/dist/chunk-4BJQODZF.js.map +1 -0
- package/dist/{chunk-JREB6UFH.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-2AZXIZEN.js → chunk-5Q7EVV4X.js} +6 -6
- package/dist/{chunk-LC7OODWZ.js → chunk-5SB7SC2G.js} +80 -49
- package/dist/chunk-5SB7SC2G.js.map +1 -0
- 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-FDCTQWLW.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-OVJ2HIPE.js → chunk-76GLCM57.js} +158 -125
- 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-ZHIVCODT.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-A5UXZRRM.js → chunk-AJ7QCSIS.js} +2 -2
- 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-74F5STS4.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-T7Y5KPLN.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-EHCONI6E.js → chunk-CQMEM5CC.js} +2 -2
- package/dist/{chunk-PBNZVPFS.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-INELTPRG.js → chunk-EEC7UJPX.js} +103 -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-DZKHSDOM.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-DMSDUGDM.js → chunk-F7GAIWFA.js} +20 -20
- package/dist/{chunk-G6XXLKC5.js → chunk-FFPJINJE.js} +6 -6
- 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-G4CN3ZXL.js → chunk-FUTF72MJ.js} +15 -15
- package/dist/chunk-GCASGYIO.js +71 -0
- package/dist/chunk-GCASGYIO.js.map +1 -0
- package/dist/{chunk-HF77M34J.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-UDQUSU27.js → chunk-HNZKVLAN.js} +2 -2
- package/dist/{chunk-5EZXHU36.js → chunk-HYQJQGD3.js} +2 -2
- package/dist/{chunk-OAZVR2BV.js → chunk-IDZFBSHN.js} +8 -6
- package/dist/{chunk-OAZVR2BV.js.map → chunk-IDZFBSHN.js.map} +1 -1
- package/dist/{chunk-PLQE6MJA.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-DCFV7A7H.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-E6CBU7XP.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-KDXVOFYY.js → chunk-KAVBJSBQ.js} +4 -4
- package/dist/{chunk-BS4SGLWV.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-2S6QHZGJ.js → chunk-L2DPF4DF.js} +1 -1
- 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-QQGPUKMT.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-Q5WG43OP.js → chunk-MYFQ3ED4.js} +7 -7
- 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-VDW4VU7B.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-DYP3YYJJ.js → chunk-QJAQNXWI.js} +39 -5
- package/dist/chunk-QJAQNXWI.js.map +1 -0
- package/dist/{chunk-3D6AFGQR.js → chunk-QVT3E4CE.js} +7 -7
- package/dist/{chunk-FIJUY7GG.js → chunk-R26ZMXR2.js} +23 -23
- package/dist/{chunk-FIJUY7GG.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-FNZQGN76.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-LZOV7MX7.js → chunk-TDTXKOAJ.js} +6474 -5747
- 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-DPAENM7O.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-AJLLIIML.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-RO4LQGT3.js → chunk-WON4APQY.js} +4 -4
- package/dist/{chunk-PQVK2S3J.js → chunk-WZFAPHIK.js} +6 -6
- package/dist/{chunk-KQPJLK3X.js → chunk-XL24QQ63.js} +2 -2
- package/dist/{chunk-RVZRYUQH.js → chunk-YROFNEG5.js} +7 -7
- package/dist/{chunk-RAR2BSEM.js → chunk-YV32N67O.js} +1 -1
- package/dist/chunk-YV32N67O.js.map +1 -0
- package/dist/{chunk-PBSAPHHA.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-Cd5fMmhq.d.ts → cli-C_pqqTCw.d.ts} +28 -12
- package/dist/cli.d.ts +16 -9
- package/dist/cli.js +142 -127
- package/dist/compounding/engine.d.ts +5 -2
- package/dist/compounding/engine.js +36 -26
- 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 +36 -26
- 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 +41 -32
- package/dist/consolidation-provenance-check.d.ts +5 -2
- package/dist/consolidation-undo.d.ts +5 -2
- 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 +35 -26
- 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-IOGBBAGC.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 +3 -1
- 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 +473 -464
- package/dist/index.js +287 -239
- 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 +35 -25
- 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 +37 -25
- package/dist/maintenance/rebuild-memory-projection.js +38 -28
- 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 +3 -1
- 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 +51 -42
- 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 +24 -20
- package/dist/namespaces/storage.d.ts +24 -3
- package/dist/namespaces/storage.js +35 -27
- 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 +69 -54
- 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 +44 -31
- package/dist/{orchestrator-Bp_jeBHK.d.ts → orchestrator-CQJ8U7En.d.ts} +85 -79
- package/dist/orchestrator.d.ts +13 -8
- package/dist/orchestrator.js +194 -177
- package/dist/patterns-cli.d.ts +3 -1
- package/dist/{pipeline-BAj5bx7g.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-_MDSlj1m.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 +7 -3
- 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 +98 -98
- 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 +18 -16
- package/dist/search/index.d.ts +3 -1
- package/dist/search/index.js +22 -20
- 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 +16 -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-C2m5eHHE.d.ts → semantic-consolidation-DILZEQq3.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +4 -2
- package/dist/semantic-consolidation.js +38 -29
- package/dist/semantic-rule-promotion.js +34 -24
- package/dist/semantic-rule-verifier.d.ts +3 -1
- package/dist/semantic-rule-verifier.js +35 -25
- 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 +11 -9
- package/dist/shared-context/manager.js +3 -3
- package/dist/signal.d.ts +3 -1
- package/dist/{storage-hr_Y2z5R.d.ts → storage-NIyKYD8g.d.ts} +489 -110
- package/dist/storage-guards.js +2 -2
- package/dist/storage.d.ts +6 -3
- package/dist/storage.js +38 -26
- 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 +3 -3
- package/dist/transfer/types.d.ts +90 -90
- 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-Cg8q7W7_.d.ts → types-D_fG2ix8.d.ts} +39 -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 +36 -26
- 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 +113 -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/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-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 +43 -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 +574 -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 +168 -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 +160 -149
- 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.ts +47 -47
- 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 +13 -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 +882 -890
- 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 +51 -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-3IY64MV6.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-BS4SGLWV.js.map +0 -1
- package/dist/chunk-DCFV7A7H.js.map +0 -1
- package/dist/chunk-DYP3YYJJ.js.map +0 -1
- package/dist/chunk-E5BK6CGV.js +0 -335
- package/dist/chunk-E5BK6CGV.js.map +0 -1
- package/dist/chunk-FTYDWKO6.js.map +0 -1
- package/dist/chunk-GWTFLF2P.js.map +0 -1
- package/dist/chunk-IKQTFQMI.js.map +0 -1
- package/dist/chunk-INELTPRG.js.map +0 -1
- package/dist/chunk-J2HSAU72.js.map +0 -1
- package/dist/chunk-JREB6UFH.js.map +0 -1
- package/dist/chunk-K7LOWSLU.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-LZOV7MX7.js.map +0 -1
- package/dist/chunk-NWTGD4AN.js.map +0 -1
- package/dist/chunk-ODPLEWB6.js.map +0 -1
- package/dist/chunk-OVJ2HIPE.js.map +0 -1
- package/dist/chunk-PBSAPHHA.js.map +0 -1
- package/dist/chunk-PHK3HARR.js +0 -32
- package/dist/chunk-PHK3HARR.js.map +0 -1
- package/dist/chunk-PLQE6MJA.js.map +0 -1
- package/dist/chunk-QKQYXZVS.js.map +0 -1
- package/dist/chunk-QQGPUKMT.js.map +0 -1
- package/dist/chunk-RANHFI3P.js +0 -8
- package/dist/chunk-RANHFI3P.js.map +0 -1
- package/dist/chunk-RAR2BSEM.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-T7Y5KPLN.js.map +0 -1
- package/dist/chunk-TXLGHDHS.js.map +0 -1
- package/dist/chunk-VDW4VU7B.js.map +0 -1
- package/dist/chunk-VSMRDBFT.js +0 -17
- package/dist/chunk-VSMRDBFT.js.map +0 -1
- package/dist/chunk-X64YLC24.js.map +0 -1
- package/dist/chunk-XDSXEKYK.js +0 -118
- package/dist/chunk-XDSXEKYK.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-IOGBBAGC.js.map → access-recall-response.js.map} +0 -0
- /package/dist/{resolution-VH4NGENZ.js.map → bounded-jsonl-state.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-VJVNLNDQ.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-HDTQVNWD.js.map → chunk-3QAH2S33.js.map} +0 -0
- /package/dist/{chunk-LRNMRXJO.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-2AZXIZEN.js.map → chunk-5Q7EVV4X.js.map} +0 -0
- /package/dist/{chunk-PUBTHW5O.js.map → chunk-6DRPPQEJ.js.map} +0 -0
- /package/dist/{chunk-FDCTQWLW.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-ZHIVCODT.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-A5UXZRRM.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-74F5STS4.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-EHCONI6E.js.map → chunk-CQMEM5CC.js.map} +0 -0
- /package/dist/{chunk-PBNZVPFS.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-DZKHSDOM.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-DMSDUGDM.js.map → chunk-F7GAIWFA.js.map} +0 -0
- /package/dist/{chunk-G6XXLKC5.js.map → chunk-FFPJINJE.js.map} +0 -0
- /package/dist/{chunk-G4CN3ZXL.js.map → chunk-FUTF72MJ.js.map} +0 -0
- /package/dist/{chunk-HF77M34J.js.map → chunk-GFPZS3F5.js.map} +0 -0
- /package/dist/{chunk-G6NKALRN.js.map → chunk-H4WG3UQZ.js.map} +0 -0
- /package/dist/{chunk-UDQUSU27.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-E6CBU7XP.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-KDXVOFYY.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-2S6QHZGJ.js.map → chunk-L2DPF4DF.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-Q5WG43OP.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-FNZQGN76.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-DPAENM7O.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-AJLLIIML.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-RO4LQGT3.js.map → chunk-WON4APQY.js.map} +0 -0
- /package/dist/{chunk-PQVK2S3J.js.map → chunk-WZFAPHIK.js.map} +0 -0
- /package/dist/{chunk-KQPJLK3X.js.map → chunk-XL24QQ63.js.map} +0 -0
- /package/dist/{chunk-RVZRYUQH.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,316 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
import { mkdir, mkdtemp, readdir, readFile, rm, symlink, writeFile } from "node:fs/promises";
|
|
4
|
+
import os from "node:os";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import test from "node:test";
|
|
7
|
+
import {
|
|
8
|
+
drainPendingImpressionsForOfflineSync,
|
|
9
|
+
drainPendingLifecycleForOfflineSync,
|
|
10
|
+
getOfflineSyncStorage,
|
|
11
|
+
} from "./offline-sync-impression-drain.js";
|
|
12
|
+
import { isEncryptedFile } from "./secure-store/secure-fs.js";
|
|
13
|
+
import { StorageManager } from "./storage.js";
|
|
14
|
+
|
|
15
|
+
test("retries deferred drains and succeeds when the lock is released", async () => {
|
|
16
|
+
let calls = 0;
|
|
17
|
+
await drainPendingImpressionsForOfflineSync(async () => {
|
|
18
|
+
calls += 1;
|
|
19
|
+
return { pendingDeferred: calls < 2 };
|
|
20
|
+
});
|
|
21
|
+
assert.equal(calls, 2);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test("retries a transient drain error before succeeding", async () => {
|
|
25
|
+
let calls = 0;
|
|
26
|
+
await drainPendingImpressionsForOfflineSync(async () => {
|
|
27
|
+
calls += 1;
|
|
28
|
+
if (calls === 1) throw new Error("temporary lock failure");
|
|
29
|
+
return { pendingDeferred: false };
|
|
30
|
+
});
|
|
31
|
+
assert.equal(calls, 2);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test("aborts after repeated deferrals instead of producing an incomplete snapshot", async () => {
|
|
35
|
+
let calls = 0;
|
|
36
|
+
await assert.rejects(
|
|
37
|
+
drainPendingImpressionsForOfflineSync(async () => {
|
|
38
|
+
calls += 1;
|
|
39
|
+
return { pendingDeferred: true };
|
|
40
|
+
}),
|
|
41
|
+
/could not fold pending recall impressions after 3 attempts/,
|
|
42
|
+
);
|
|
43
|
+
assert.equal(calls, 3);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const LIFECYCLE_LEDGER_REL = "state/memory-lifecycle-ledger.jsonl";
|
|
47
|
+
const LIFECYCLE_PENDING_REL = `${LIFECYCLE_LEDGER_REL}.pending.d`;
|
|
48
|
+
|
|
49
|
+
// Seed one durable pending lifecycle spill exactly as appendLifecycleEventsSerialized
|
|
50
|
+
// does when the ledger lock is held (#2033): a `<uuid>.jsonl` file inside the
|
|
51
|
+
// offline-sync-EXCLUDED pending dir under `stateRel`. The nonce proves this row
|
|
52
|
+
// was folded rather than dropped by the sync exclude glob.
|
|
53
|
+
async function seedPendingLifecycle(root: string, stateRel: string): Promise<string> {
|
|
54
|
+
const nonce = randomUUID();
|
|
55
|
+
const pendingDir = path.join(root, stateRel, "memory-lifecycle-ledger.jsonl.pending.d");
|
|
56
|
+
await mkdir(pendingDir, { recursive: true });
|
|
57
|
+
const line = `${JSON.stringify({ type: "promotion", memoryId: "mem-1", timestamp: "2026-01-01T00:00:00.000Z", nonce })}\n`;
|
|
58
|
+
await writeFile(path.join(pendingDir, `${randomUUID()}.jsonl`), line, "utf-8");
|
|
59
|
+
return nonce;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
test("drainPendingLifecycleForOfflineSync folds root and per-namespace pending spills (#2033)", async () => {
|
|
63
|
+
const root = await mkdtemp(path.join(os.tmpdir(), "remnic-lifecycle-drain-"));
|
|
64
|
+
try {
|
|
65
|
+
const rootNonce = await seedPendingLifecycle(root, "state");
|
|
66
|
+
const nsNonce = await seedPendingLifecycle(root, "namespaces/team/state");
|
|
67
|
+
|
|
68
|
+
await drainPendingLifecycleForOfflineSync(root);
|
|
69
|
+
|
|
70
|
+
const rootPending = await readdir(path.join(root, LIFECYCLE_PENDING_REL)).catch(() => [] as string[]);
|
|
71
|
+
assert.deepEqual(rootPending, [], "root pending spills must be folded and finalized");
|
|
72
|
+
const rootActive = await readFile(path.join(root, LIFECYCLE_LEDGER_REL), "utf-8");
|
|
73
|
+
assert.ok(rootActive.includes(rootNonce), "root lifecycle row must land in the synced active ledger");
|
|
74
|
+
|
|
75
|
+
const nsPending = await readdir(
|
|
76
|
+
path.join(root, "namespaces/team", LIFECYCLE_PENDING_REL),
|
|
77
|
+
).catch(() => [] as string[]);
|
|
78
|
+
assert.deepEqual(nsPending, [], "per-namespace pending spills must be folded and finalized");
|
|
79
|
+
const nsActive = await readFile(
|
|
80
|
+
path.join(root, "namespaces/team", LIFECYCLE_LEDGER_REL),
|
|
81
|
+
"utf-8",
|
|
82
|
+
);
|
|
83
|
+
assert.ok(nsActive.includes(nsNonce), "per-namespace lifecycle row must land in its active ledger");
|
|
84
|
+
} finally {
|
|
85
|
+
await rm(root, { recursive: true, force: true });
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test("drains encrypted lifecycle spills through secure storage (#2033)", async () => {
|
|
90
|
+
const root = await mkdtemp(path.join(os.tmpdir(), "remnic-lifecycle-drain-secure-"));
|
|
91
|
+
const key = Buffer.alloc(32, 17);
|
|
92
|
+
const storage = new StorageManager(root);
|
|
93
|
+
storage.setSecureStoreRequired(true);
|
|
94
|
+
storage.setSecureStoreKey(key);
|
|
95
|
+
try {
|
|
96
|
+
const nonce = randomUUID();
|
|
97
|
+
const pendingDir = path.join(root, LIFECYCLE_PENDING_REL);
|
|
98
|
+
const pendingPath = path.join(pendingDir, `${randomUUID()}.jsonl`);
|
|
99
|
+
await mkdir(pendingDir, { recursive: true });
|
|
100
|
+
await storage.writeMemoryLifecycleLedgerContent(
|
|
101
|
+
`${JSON.stringify({
|
|
102
|
+
type: "promotion",
|
|
103
|
+
memoryId: "mem-secure",
|
|
104
|
+
timestamp: "2026-01-01T00:00:00.000Z",
|
|
105
|
+
nonce,
|
|
106
|
+
})}\n`,
|
|
107
|
+
pendingPath,
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
await drainPendingLifecycleForOfflineSync(
|
|
111
|
+
root,
|
|
112
|
+
(ledgerPath) => storage.drainPendingMemoryLifecycleEventsForSyncAt(ledgerPath),
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
assert.deepEqual(await readdir(pendingDir), []);
|
|
116
|
+
assert.ok(
|
|
117
|
+
isEncryptedFile(await readFile(path.join(root, LIFECYCLE_LEDGER_REL))),
|
|
118
|
+
"the active ledger must remain encrypted",
|
|
119
|
+
);
|
|
120
|
+
const activePlaintext = await storage.readMemoryLifecycleLedgerRawBufferForCompaction();
|
|
121
|
+
assert.ok(activePlaintext.toString("utf-8").includes(nonce));
|
|
122
|
+
} finally {
|
|
123
|
+
await rm(root, { recursive: true, force: true });
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
test("drainPendingLifecycleForOfflineSync aborts when pending rows cannot be folded (#2033)", async () => {
|
|
128
|
+
const root = await mkdtemp(path.join(os.tmpdir(), "remnic-lifecycle-drain-abort-"));
|
|
129
|
+
try {
|
|
130
|
+
await seedPendingLifecycle(root, "state");
|
|
131
|
+
// The active ledger path is a DIRECTORY, so the fold's append fails on every
|
|
132
|
+
// attempt: the durable spill can never be committed, so the drain aborts
|
|
133
|
+
// rather than let a caller build a snapshot that silently omits it.
|
|
134
|
+
await mkdir(path.join(root, LIFECYCLE_LEDGER_REL), { recursive: true });
|
|
135
|
+
|
|
136
|
+
await assert.rejects(
|
|
137
|
+
drainPendingLifecycleForOfflineSync(root),
|
|
138
|
+
(err: unknown) => {
|
|
139
|
+
assert.ok(err instanceof Error);
|
|
140
|
+
assert.match(
|
|
141
|
+
err.message,
|
|
142
|
+
/lifecycle drain could not fold pending memory-lifecycle events after 3 attempts.*aborting snapshot/s,
|
|
143
|
+
);
|
|
144
|
+
assert.ok(
|
|
145
|
+
!err.message.includes(root),
|
|
146
|
+
"abort error must not leak the ledger's absolute path (#2033)",
|
|
147
|
+
);
|
|
148
|
+
return true;
|
|
149
|
+
},
|
|
150
|
+
);
|
|
151
|
+
} finally {
|
|
152
|
+
await rm(root, { recursive: true, force: true });
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
test("aborted impression drain redacts the underlying error path (#2033)", async () => {
|
|
157
|
+
// A persona path standing in for a real operator's memory dir. displayErrorDetail
|
|
158
|
+
// must reduce the thrown fs error to its class + errno code so the absolute path
|
|
159
|
+
// never reaches CLI stderr / the offline snapshot failure.
|
|
160
|
+
const secretPath = "/home/user/.remnic/state/recall_impressions.jsonl";
|
|
161
|
+
await assert.rejects(
|
|
162
|
+
drainPendingImpressionsForOfflineSync(async () => {
|
|
163
|
+
const err = new Error(`EACCES: permission denied, open '${secretPath}'`);
|
|
164
|
+
(err as NodeJS.ErrnoException).code = "EACCES";
|
|
165
|
+
throw err;
|
|
166
|
+
}),
|
|
167
|
+
(err: unknown) => {
|
|
168
|
+
assert.ok(err instanceof Error);
|
|
169
|
+
assert.ok(!err.message.includes(secretPath), "raw fs path must not leak into the abort error");
|
|
170
|
+
assert.match(err.message, /could not fold pending recall impressions after 3 attempts/);
|
|
171
|
+
assert.match(err.message, /EACCES/, "the path-free error class + code still surfaces");
|
|
172
|
+
return true;
|
|
173
|
+
},
|
|
174
|
+
);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
test("drainPendingLifecycleForOfflineSync skips a symlinked namespace child (#2033 containment)", async () => {
|
|
178
|
+
const root = await mkdtemp(path.join(os.tmpdir(), "remnic-lifecycle-drain-symlink-child-"));
|
|
179
|
+
const outside = await mkdtemp(path.join(os.tmpdir(), "remnic-lifecycle-drain-outside-"));
|
|
180
|
+
try {
|
|
181
|
+
const rootNonce = await seedPendingLifecycle(root, "state");
|
|
182
|
+
const teamNonce = await seedPendingLifecycle(root, "namespaces/team/state");
|
|
183
|
+
// A poisoned namespace child symlinked outside the memory root, carrying its
|
|
184
|
+
// own pending spill. The drain must NOT fold through it (no ledger appended
|
|
185
|
+
// outside memoryDir) yet still fold the root and the legit namespace.
|
|
186
|
+
await seedPendingLifecycle(outside, "state");
|
|
187
|
+
await mkdir(path.join(root, "namespaces"), { recursive: true });
|
|
188
|
+
await symlink(outside, path.join(root, "namespaces", "evil"));
|
|
189
|
+
|
|
190
|
+
await drainPendingLifecycleForOfflineSync(root);
|
|
191
|
+
|
|
192
|
+
assert.deepEqual(await readdir(path.join(root, LIFECYCLE_PENDING_REL)).catch(() => [] as string[]), []);
|
|
193
|
+
assert.ok((await readFile(path.join(root, LIFECYCLE_LEDGER_REL), "utf-8")).includes(rootNonce));
|
|
194
|
+
assert.ok(
|
|
195
|
+
(await readFile(path.join(root, "namespaces/team", LIFECYCLE_LEDGER_REL), "utf-8")).includes(teamNonce),
|
|
196
|
+
);
|
|
197
|
+
// The escaping child's spill is left untouched and no ledger was written
|
|
198
|
+
// through the link.
|
|
199
|
+
assert.equal(
|
|
200
|
+
(await readdir(path.join(outside, LIFECYCLE_PENDING_REL))).length,
|
|
201
|
+
1,
|
|
202
|
+
"escaping namespace spill must be left untouched",
|
|
203
|
+
);
|
|
204
|
+
await assert.rejects(
|
|
205
|
+
() => readFile(path.join(outside, LIFECYCLE_LEDGER_REL), "utf-8"),
|
|
206
|
+
/ENOENT/,
|
|
207
|
+
);
|
|
208
|
+
} finally {
|
|
209
|
+
await rm(root, { recursive: true, force: true });
|
|
210
|
+
await rm(outside, { recursive: true, force: true });
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
test("drainPendingLifecycleForOfflineSync refuses a symlinked namespaces base (#2033 containment)", async () => {
|
|
215
|
+
const root = await mkdtemp(path.join(os.tmpdir(), "remnic-lifecycle-drain-symlink-base-"));
|
|
216
|
+
const outside = await mkdtemp(path.join(os.tmpdir(), "remnic-lifecycle-drain-base-outside-"));
|
|
217
|
+
try {
|
|
218
|
+
const rootNonce = await seedPendingLifecycle(root, "state");
|
|
219
|
+
// A legit-looking namespace living under the symlinked base target.
|
|
220
|
+
await seedPendingLifecycle(outside, "team/state");
|
|
221
|
+
await symlink(outside, path.join(root, "namespaces"));
|
|
222
|
+
|
|
223
|
+
await drainPendingLifecycleForOfflineSync(root);
|
|
224
|
+
|
|
225
|
+
// The root ledger is still folded through the real state dir.
|
|
226
|
+
assert.ok((await readFile(path.join(root, LIFECYCLE_LEDGER_REL), "utf-8")).includes(rootNonce));
|
|
227
|
+
// The symlinked base is refused wholesale: nothing under it is drained.
|
|
228
|
+
assert.equal(
|
|
229
|
+
(await readdir(path.join(outside, "team", "state", "memory-lifecycle-ledger.jsonl.pending.d"))).length,
|
|
230
|
+
1,
|
|
231
|
+
"namespaces base symlink must be refused, leaving its spills untouched",
|
|
232
|
+
);
|
|
233
|
+
await assert.rejects(
|
|
234
|
+
() => readFile(path.join(outside, "team", LIFECYCLE_LEDGER_REL), "utf-8"),
|
|
235
|
+
/ENOENT/,
|
|
236
|
+
);
|
|
237
|
+
} finally {
|
|
238
|
+
await rm(root, { recursive: true, force: true });
|
|
239
|
+
await rm(outside, { recursive: true, force: true });
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
type FakeLifecycleStorage = {
|
|
244
|
+
dir: string;
|
|
245
|
+
drainPendingMemoryLifecycleEventsForSync(): Promise<{ folded: boolean; pendingDeferred: boolean }>;
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
function fakeOfflineOrchestrator(memoryRoot: string, namespaceDirs: Record<string, string>) {
|
|
249
|
+
const lifecycleDrains: string[] = [];
|
|
250
|
+
let impressionDrains = 0;
|
|
251
|
+
const storages: Record<string, FakeLifecycleStorage> = {};
|
|
252
|
+
for (const [name, dir] of Object.entries(namespaceDirs)) {
|
|
253
|
+
storages[name] = {
|
|
254
|
+
dir,
|
|
255
|
+
drainPendingMemoryLifecycleEventsForSync: async () => {
|
|
256
|
+
lifecycleDrains.push(name);
|
|
257
|
+
return { folded: false, pendingDeferred: false };
|
|
258
|
+
},
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
const orchestrator = {
|
|
262
|
+
config: { memoryDir: memoryRoot },
|
|
263
|
+
drainPendingRecallImpressions: async () => {
|
|
264
|
+
impressionDrains += 1;
|
|
265
|
+
return { pendingDeferred: false };
|
|
266
|
+
},
|
|
267
|
+
getStorage: async (ns: string) => {
|
|
268
|
+
const storage = storages[ns];
|
|
269
|
+
if (!storage) throw new Error(`no fake storage for namespace ${ns}`);
|
|
270
|
+
return storage;
|
|
271
|
+
},
|
|
272
|
+
listOfflineSyncNamespaces: async () => Object.keys(namespaceDirs).filter((n) => n !== "root"),
|
|
273
|
+
};
|
|
274
|
+
return { orchestrator, lifecycleDrains, impressions: () => impressionDrains };
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
test("getOfflineSyncStorage drains every namespace ledger for a root snapshot (#2033)", async () => {
|
|
278
|
+
const memoryRoot = path.join(os.tmpdir(), "remnic-root-drain-fanout");
|
|
279
|
+
const { orchestrator, lifecycleDrains, impressions } = fakeOfflineOrchestrator(memoryRoot, {
|
|
280
|
+
root: memoryRoot,
|
|
281
|
+
team: path.join(memoryRoot, "namespaces", "team"),
|
|
282
|
+
ops: path.join(memoryRoot, "namespaces", "ops"),
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
await getOfflineSyncStorage(orchestrator, "root");
|
|
286
|
+
|
|
287
|
+
assert.deepEqual(lifecycleDrains, ["root", "team", "ops"], "root snapshot folds root + every namespace ledger");
|
|
288
|
+
assert.equal(impressions(), 1, "global impressions are folded for a root snapshot");
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
test("getOfflineSyncStorage folds only the namespace's own ledger for a namespace snapshot (#2033)", async () => {
|
|
292
|
+
const memoryRoot = path.join(os.tmpdir(), "remnic-ns-drain-scope");
|
|
293
|
+
const { orchestrator, lifecycleDrains, impressions } = fakeOfflineOrchestrator(memoryRoot, {
|
|
294
|
+
root: memoryRoot,
|
|
295
|
+
team: path.join(memoryRoot, "namespaces", "team"),
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
await getOfflineSyncStorage(orchestrator, "team");
|
|
299
|
+
|
|
300
|
+
assert.deepEqual(lifecycleDrains, ["team"], "namespace snapshot folds only its own ledger");
|
|
301
|
+
assert.equal(impressions(), 0, "global impressions are left pending for the root sync");
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
test("getOfflineSyncStorage never double-folds the root ledger when it is listed as a namespace (#2033)", async () => {
|
|
305
|
+
const memoryRoot = path.join(os.tmpdir(), "remnic-root-drain-dedup");
|
|
306
|
+
const { orchestrator, lifecycleDrains } = fakeOfflineOrchestrator(memoryRoot, {
|
|
307
|
+
root: memoryRoot,
|
|
308
|
+
// A listing that also surfaces the default namespace pointing back at root.
|
|
309
|
+
default: memoryRoot,
|
|
310
|
+
team: path.join(memoryRoot, "namespaces", "team"),
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
await getOfflineSyncStorage(orchestrator, "root");
|
|
314
|
+
|
|
315
|
+
assert.deepEqual(lifecycleDrains, ["root", "team"], "root ledger is folded exactly once");
|
|
316
|
+
});
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { lstat, realpath } from "node:fs/promises";
|
|
4
|
+
import {
|
|
5
|
+
drainPendingLifecycleForSyncOrThrow,
|
|
6
|
+
drainPendingLifecycleLedgerForSync,
|
|
7
|
+
type LifecyclePendingIo,
|
|
8
|
+
} from "./storage/memory-lifecycle-ledger-access.js";
|
|
9
|
+
import { writeFileAtomically } from "./maintenance/atomic-file.js";
|
|
10
|
+
import { log } from "./logger.js";
|
|
11
|
+
import { isErrnoCode } from "./utils/errno.js";
|
|
12
|
+
import { assertPathInsideRoot, pathIsInside } from "./utils/path-containment.js";
|
|
13
|
+
import { displayErrorDetail } from "./runtime/better-sqlite.js";
|
|
14
|
+
import { getConfiguredNamespaces } from "./scopes/scope-plan.js";
|
|
15
|
+
import type { PluginConfig } from "./types.js";
|
|
16
|
+
|
|
17
|
+
type PendingImpressionDrain = () => Promise<{ pendingDeferred: boolean }>;
|
|
18
|
+
|
|
19
|
+
type PendingLifecycleDrain = {
|
|
20
|
+
drainPendingMemoryLifecycleEventsForSync(): Promise<{ folded: boolean; pendingDeferred: boolean }>;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
type LifecycleDrainAtPath = (
|
|
24
|
+
ledgerPath: string,
|
|
25
|
+
) => Promise<{ folded: boolean; pendingDeferred: boolean }>;
|
|
26
|
+
|
|
27
|
+
type PendingImpressionHost = {
|
|
28
|
+
drainPendingRecallImpressions(): Promise<{ pendingDeferred: boolean }>;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Fold pending recall-impression spills before building an offline-sync snapshot.
|
|
32
|
+
* A deferred or failed drain must abort the snapshot rather than silently omit
|
|
33
|
+
* durable rows from the sync payload.
|
|
34
|
+
*/
|
|
35
|
+
export async function drainPendingImpressionsForOfflineSync(
|
|
36
|
+
host: PendingImpressionDrain,
|
|
37
|
+
): Promise<void> {
|
|
38
|
+
const maxAttempts = 3;
|
|
39
|
+
let lastError: unknown;
|
|
40
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
41
|
+
try {
|
|
42
|
+
const result = await host();
|
|
43
|
+
if (!result.pendingDeferred) return;
|
|
44
|
+
lastError = undefined;
|
|
45
|
+
} catch (error) {
|
|
46
|
+
lastError = error;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const detail = lastError
|
|
50
|
+
? `: ${displayErrorDetail(lastError) || "unknown error"}`
|
|
51
|
+
: " (rotation lock held by a peer)";
|
|
52
|
+
throw new Error(
|
|
53
|
+
`offline-sync impression drain could not fold pending recall impressions after ${maxAttempts} attempts${detail}; aborting snapshot so the pending rows are not silently excluded (#2033)`,
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
export async function getOfflineSyncStorage<T extends PendingLifecycleDrain & { dir: string }>(
|
|
59
|
+
orchestrator: PendingImpressionHost & {
|
|
60
|
+
config: { memoryDir: string };
|
|
61
|
+
getStorage(namespace: string): Promise<T>;
|
|
62
|
+
listOfflineSyncNamespaces?(): Promise<string[]>;
|
|
63
|
+
},
|
|
64
|
+
namespace: string,
|
|
65
|
+
): Promise<T> {
|
|
66
|
+
const storage = await orchestrator.getStorage(namespace);
|
|
67
|
+
const memoryRoot = path.resolve(orchestrator.config.memoryDir);
|
|
68
|
+
// Recall impressions are global: the orchestrator's single LastRecallStore
|
|
69
|
+
// roots at config.memoryDir, so the active recall_impressions.jsonl lives at
|
|
70
|
+
// <memoryDir>/state/. Fold the global pending queue ONLY when THIS snapshot's
|
|
71
|
+
// root actually contains that active file - a root snapshot. A namespace
|
|
72
|
+
// snapshot (storage.dir under namespaces/<token>/) cannot carry it, so
|
|
73
|
+
// draining there would empty the durable pending queue into a file this
|
|
74
|
+
// snapshot omits and strand the row until a root sync; leave it pending for
|
|
75
|
+
// the root sync instead (#2033).
|
|
76
|
+
const impressionsFile = path.join(memoryRoot, "state", "recall_impressions.jsonl");
|
|
77
|
+
if (pathIsInside(path.resolve(storage.dir), impressionsFile)) {
|
|
78
|
+
await drainPendingImpressionsForOfflineSync(() => orchestrator.drainPendingRecallImpressions());
|
|
79
|
+
}
|
|
80
|
+
await drainPendingLifecycleForSyncOrThrow(() => storage.drainPendingMemoryLifecycleEventsForSync());
|
|
81
|
+
// Root snapshot: buildOfflineSyncSnapshot walks `namespaces/<ns>/state/` for
|
|
82
|
+
// every namespace under the memory root and INCLUDES each namespace's active
|
|
83
|
+
// lifecycle ledger, but the per-namespace pending spill dirs are offline-sync
|
|
84
|
+
// EXCLUDED. Draining only the root ledger above would let a root snapshot omit
|
|
85
|
+
// append-only rows still sitting in a namespace's spill queue, so fold every
|
|
86
|
+
// namespace ledger too - each through its OWN namespace storage so secure-store
|
|
87
|
+
// AAD stays namespace-scoped (#2033, matching the CLI all-ledger drain). A
|
|
88
|
+
// namespace snapshot folds only its own ledger, already done above.
|
|
89
|
+
if (path.resolve(storage.dir) === memoryRoot && orchestrator.listOfflineSyncNamespaces) {
|
|
90
|
+
const drained = new Set<string>([memoryRoot]);
|
|
91
|
+
for (const ns of await orchestrator.listOfflineSyncNamespaces()) {
|
|
92
|
+
const nsStorage = await orchestrator.getStorage(ns);
|
|
93
|
+
const nsDir = path.resolve(nsStorage.dir);
|
|
94
|
+
if (drained.has(nsDir)) continue;
|
|
95
|
+
drained.add(nsDir);
|
|
96
|
+
await drainPendingLifecycleForSyncOrThrow(() => nsStorage.drainPendingMemoryLifecycleEventsForSync());
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return storage;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
type OfflineSyncNamespaceHost = {
|
|
103
|
+
config: PluginConfig;
|
|
104
|
+
namespaceCatalog: { listNamespaces(): Promise<Array<{ namespace: string }>> };
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Every namespace whose lifecycle ledger a ROOT offline snapshot enumerates.
|
|
109
|
+
* Configured namespaces plus catalog-discovered ones; the catalog is queried
|
|
110
|
+
* best-effort so a catalog read failure still drains the configured set (#2033).
|
|
111
|
+
*/
|
|
112
|
+
export async function listOfflineSyncNamespaces(host: OfflineSyncNamespaceHost): Promise<string[]> {
|
|
113
|
+
const names = new Set<string>(getConfiguredNamespaces(host.config));
|
|
114
|
+
try {
|
|
115
|
+
for (const ledgerPath of await offlineSyncLifecycleLedgerPaths(host.config.memoryDir)) {
|
|
116
|
+
const namespaceDir = path.dirname(path.dirname(ledgerPath));
|
|
117
|
+
if (path.basename(path.dirname(namespaceDir)) === "namespaces") {
|
|
118
|
+
names.add(path.basename(namespaceDir));
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
} catch {
|
|
122
|
+
// best-effort: a filesystem scan failure must not block configured/catalog namespaces
|
|
123
|
+
}
|
|
124
|
+
try {
|
|
125
|
+
for (const record of await host.namespaceCatalog.listNamespaces()) {
|
|
126
|
+
names.add(record.namespace);
|
|
127
|
+
}
|
|
128
|
+
} catch {
|
|
129
|
+
// best-effort: fall back to the configured and filesystem namespace sets
|
|
130
|
+
}
|
|
131
|
+
return [...names];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Resolve the offline-sync storage for a snapshot, folding pending spills first.
|
|
136
|
+
* For a root snapshot this also folds every namespace lifecycle ledger the
|
|
137
|
+
* snapshot will enumerate, so append-only rows in a namespace spill queue are
|
|
138
|
+
* never omitted (#2033).
|
|
139
|
+
*/
|
|
140
|
+
export function offlineSyncStorageForSnapshot<T extends PendingLifecycleDrain & { dir: string }>(
|
|
141
|
+
host: PendingImpressionHost &
|
|
142
|
+
OfflineSyncNamespaceHost & {
|
|
143
|
+
getStorage(namespace: string): Promise<T>;
|
|
144
|
+
},
|
|
145
|
+
namespace: string,
|
|
146
|
+
): Promise<T> {
|
|
147
|
+
return getOfflineSyncStorage(
|
|
148
|
+
{
|
|
149
|
+
config: { memoryDir: host.config.memoryDir },
|
|
150
|
+
drainPendingRecallImpressions: () => host.drainPendingRecallImpressions(),
|
|
151
|
+
getStorage: (ns: string) => host.getStorage(ns),
|
|
152
|
+
listOfflineSyncNamespaces: () => listOfflineSyncNamespaces(host),
|
|
153
|
+
},
|
|
154
|
+
namespace,
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const LIFECYCLE_LEDGER_FILE = "memory-lifecycle-ledger.jsonl";
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Plaintext filesystem IO for a standalone (CLI) offline-sync lifecycle drain.
|
|
162
|
+
* A standalone offline cache is plaintext - exactly like its LastRecallStore
|
|
163
|
+
* impression drain - so spills read/append as UTF-8. `writeSecure` keeps the
|
|
164
|
+
* atomic temp+rename the pending contract requires (#2033); a pure drain never
|
|
165
|
+
* spills a new event, but the interface demands an atomic writer.
|
|
166
|
+
*/
|
|
167
|
+
function plaintextLifecyclePendingIo(): LifecyclePendingIo {
|
|
168
|
+
return {
|
|
169
|
+
writeSecure: async (filePath, payload) => {
|
|
170
|
+
await writeFileAtomically(filePath, payload);
|
|
171
|
+
},
|
|
172
|
+
readSecure: (filePath) => fs.promises.readFile(filePath, "utf8"),
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Lifecycle ledger paths under a standalone memory dir: the root `state/` ledger
|
|
178
|
+
* plus every per-namespace `namespaces/<ns>/state/` ledger (#2033). Offline sync
|
|
179
|
+
* pushes the whole memory dir, so every namespace's ledger can carry pending
|
|
180
|
+
* spills that must be folded first.
|
|
181
|
+
*/
|
|
182
|
+
async function offlineSyncLifecycleLedgerPaths(memoryDir: string): Promise<string[]> {
|
|
183
|
+
const paths = [path.join(memoryDir, "state", LIFECYCLE_LEDGER_FILE)];
|
|
184
|
+
const namespacesBase = path.join(memoryDir, "namespaces");
|
|
185
|
+
// Symlink/traversal containment (#2033): a symlinked <memoryDir>/namespaces
|
|
186
|
+
// (or a symlinked child) must not redirect the pre-sync drain - and the
|
|
187
|
+
// ledger appends/mkdirs it drives - outside memoryDir. Resolve the memory
|
|
188
|
+
// root and the scan base through realpath, reject a symlinked/escaping/
|
|
189
|
+
// non-directory base, and skip any symlinked/escaping child, mirroring the
|
|
190
|
+
// lifecycle-compaction scanner (orchestration/maintenance.ts) and the
|
|
191
|
+
// memory-store walkers (utils/path-containment). A rejected base is
|
|
192
|
+
// non-fatal: drain the root ledger only, never through the poisoned link.
|
|
193
|
+
let memoryDirReal: string;
|
|
194
|
+
try {
|
|
195
|
+
memoryDirReal = await realpath(memoryDir);
|
|
196
|
+
const baseStat = await lstat(namespacesBase);
|
|
197
|
+
if (baseStat.isSymbolicLink() || !baseStat.isDirectory()) {
|
|
198
|
+
throw new Error("namespaces base is a symlink or not a directory");
|
|
199
|
+
}
|
|
200
|
+
assertPathInsideRoot(memoryDirReal, await realpath(namespacesBase), namespacesBase);
|
|
201
|
+
} catch (err) {
|
|
202
|
+
if (!isErrnoCode(err, "ENOENT")) {
|
|
203
|
+
log.debug(`offline-sync lifecycle drain: namespaces base rejected (non-fatal): ${err}`);
|
|
204
|
+
}
|
|
205
|
+
return paths;
|
|
206
|
+
}
|
|
207
|
+
let entries: fs.Dirent[];
|
|
208
|
+
try {
|
|
209
|
+
entries = fs.readdirSync(namespacesBase, { withFileTypes: true });
|
|
210
|
+
} catch (err) {
|
|
211
|
+
if (!isErrnoCode(err, "ENOENT")) {
|
|
212
|
+
log.debug(`offline-sync lifecycle drain: namespaces dir scan failed (non-fatal): ${err}`);
|
|
213
|
+
}
|
|
214
|
+
return paths;
|
|
215
|
+
}
|
|
216
|
+
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
217
|
+
if (!entry.isDirectory() || entry.isSymbolicLink()) continue;
|
|
218
|
+
const childPath = path.join(namespacesBase, entry.name);
|
|
219
|
+
try {
|
|
220
|
+
assertPathInsideRoot(memoryDirReal, await realpath(childPath), childPath);
|
|
221
|
+
} catch (err) {
|
|
222
|
+
log.debug(`offline-sync lifecycle drain: skipping out-of-root namespace dir ${childPath}: ${err}`);
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
paths.push(path.join(childPath, "state", LIFECYCLE_LEDGER_FILE));
|
|
226
|
+
}
|
|
227
|
+
return paths;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Fold pending memory-lifecycle spills into each active ledger under `memoryDir`
|
|
232
|
+
* before a standalone (CLI) offline-sync snapshot (#2033). Mirrors the
|
|
233
|
+
* access-service snapshot entrypoints, which drain lifecycle pending first: the
|
|
234
|
+
* default sync exclude globs keep `memory-lifecycle-ledger.jsonl.pending.d` out
|
|
235
|
+
* of the push, so an append-only row (promotion/import/explicit capture) that
|
|
236
|
+
* spilled while the ledger lock was held would be silently dropped if the local
|
|
237
|
+
* node were discarded before maintenance folds it. A deferred drain (lock held
|
|
238
|
+
* by a peer) or a repeatedly failing fold ABORTS via
|
|
239
|
+
* {@link drainPendingLifecycleForSyncOrThrow} rather than building/pushing a
|
|
240
|
+
* snapshot that omits durable rows. Fast no-op per ledger with no pending dir.
|
|
241
|
+
*/
|
|
242
|
+
export async function drainPendingLifecycleForOfflineSync(
|
|
243
|
+
memoryDir: string,
|
|
244
|
+
drainAtPath: LifecycleDrainAtPath = (ledgerPath) => {
|
|
245
|
+
const io = plaintextLifecyclePendingIo();
|
|
246
|
+
const stateDir = path.dirname(ledgerPath);
|
|
247
|
+
return drainPendingLifecycleLedgerForSync(
|
|
248
|
+
ledgerPath,
|
|
249
|
+
io,
|
|
250
|
+
(payload) => fs.promises.appendFile(ledgerPath, payload),
|
|
251
|
+
async () => {
|
|
252
|
+
await fs.promises.mkdir(stateDir, { recursive: true });
|
|
253
|
+
},
|
|
254
|
+
);
|
|
255
|
+
},
|
|
256
|
+
): Promise<void> {
|
|
257
|
+
for (const ledgerPath of await offlineSyncLifecycleLedgerPaths(memoryDir)) {
|
|
258
|
+
await drainPendingLifecycleForSyncOrThrow(() => drainAtPath(ledgerPath));
|
|
259
|
+
}
|
|
260
|
+
}
|
package/src/offline-sync.test.ts
CHANGED
|
@@ -297,6 +297,16 @@ test("offline sync includes durable runtime state and excludes only transient sy
|
|
|
297
297
|
await write(root, "state/memory-projection.sqlite-shm", "projection-shm");
|
|
298
298
|
await write(root, "state/memory-projection.sqlite-wal", "projection-wal");
|
|
299
299
|
await write(root, "state/recall_impressions.jsonl", "impressions");
|
|
300
|
+
// Rotated archive (issue #1910) must be excluded from the push snapshot
|
|
301
|
+
// while the active file stays remote-authoritative.
|
|
302
|
+
await write(root, "state/recall_impressions.jsonl.1", "rotated-impressions");
|
|
303
|
+
// Node-local lifecycle coordination files must never cross offline sync.
|
|
304
|
+
await write(root, "state/memory-lifecycle-ledger.jsonl.lock", "lock");
|
|
305
|
+
await write(
|
|
306
|
+
root,
|
|
307
|
+
"state/memory-lifecycle-ledger.jsonl.pending.d/event-1.json",
|
|
308
|
+
"pending",
|
|
309
|
+
);
|
|
300
310
|
await write(root, "namespaces/generalist-project-origin-6ebeaa54/state/last_intent.json", "intent");
|
|
301
311
|
await write(root, "namespaces/generalist-project-origin-6ebeaa54/state/entity-mention-index.json", "entities");
|
|
302
312
|
await write(root, "namespaces/generalist-project-origin-6ebeaa54/state/.memory-status-version.log", "version");
|
|
@@ -341,6 +351,22 @@ test("offline sync includes durable runtime state and excludes only transient sy
|
|
|
341
351
|
}),
|
|
342
352
|
/offline sync file content path is excluded: state\/buffer\.json\.tmp-123-456/,
|
|
343
353
|
);
|
|
354
|
+
await assert.rejects(
|
|
355
|
+
() =>
|
|
356
|
+
readOfflineSyncFileContentChunk({
|
|
357
|
+
root,
|
|
358
|
+
path: "state/memory-lifecycle-ledger.jsonl.lock",
|
|
359
|
+
}),
|
|
360
|
+
/offline sync file content path is excluded: state\/memory-lifecycle-ledger\.jsonl\.lock/,
|
|
361
|
+
);
|
|
362
|
+
await assert.rejects(
|
|
363
|
+
() =>
|
|
364
|
+
readOfflineSyncFileContentChunk({
|
|
365
|
+
root,
|
|
366
|
+
path: "state/memory-lifecycle-ledger.jsonl.pending.d/event-1.json",
|
|
367
|
+
}),
|
|
368
|
+
/offline sync file content path is excluded: state\/memory-lifecycle-ledger\.jsonl\.pending\.d\/event-1\.json/,
|
|
369
|
+
);
|
|
344
370
|
const namespaced = await buildOfflineSyncSnapshotForPaths({
|
|
345
371
|
root,
|
|
346
372
|
sourceId: "remote",
|
|
@@ -363,11 +389,12 @@ test("offline sync includes durable runtime state and excludes only transient sy
|
|
|
363
389
|
}],
|
|
364
390
|
});
|
|
365
391
|
|
|
366
|
-
//
|
|
367
|
-
// artifacts
|
|
368
|
-
//
|
|
369
|
-
//
|
|
370
|
-
|
|
392
|
+
// 21 = the 13 durable local-only files plus the 8 node-local excluded
|
|
393
|
+
// artifacts (the 6 prior ones plus the lifecycle lock and pending spill
|
|
394
|
+
// file), which the corrected apply-side view (#1793 review) now SEES and
|
|
395
|
+
// deliberately leaves untouched (counted as skipped) instead of hiding
|
|
396
|
+
// from enumeration entirely.
|
|
397
|
+
assert.equal(pull.skipped, 21);
|
|
371
398
|
assert.equal(await readUtf8(root, "state/memory-lifecycle-ledger.jsonl"), "ledger");
|
|
372
399
|
} finally {
|
|
373
400
|
await rm(root, { recursive: true, force: true });
|
package/src/offline-sync.ts
CHANGED
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
type SafeArchiveRoot,
|
|
27
27
|
} from "./transfer/fs-utils.js";
|
|
28
28
|
import { parseFlexibleIsoTimestamp } from "./utils/iso-timestamp.js";
|
|
29
|
+
import { DEFAULT_OFFLINE_SYNC_EXCLUDE_GLOBS } from "./offline-sync-exclude-globs.js";
|
|
29
30
|
|
|
30
31
|
export const OFFLINE_SYNC_SNAPSHOT_FORMAT = "remnic.offline-sync.snapshot.v1";
|
|
31
32
|
export const OFFLINE_SYNC_CHANGESET_FORMAT = "remnic.offline-sync.changeset.v1";
|
|
@@ -198,20 +199,6 @@ const EXCLUDED_FILE_PREFIXES = [
|
|
|
198
199
|
".remnic-sync.",
|
|
199
200
|
".remnic-sync-state.",
|
|
200
201
|
];
|
|
201
|
-
// Issue #1786: node-local runtime state that each node rebuilds from synced
|
|
202
|
-
// records. Pushing these wastes bandwidth, corrupts the remote's live state
|
|
203
|
-
// dir, and trips the large-file push retry loop on a live SQLite database.
|
|
204
|
-
const DEFAULT_OFFLINE_SYNC_EXCLUDE_GLOBS: readonly string[] = [
|
|
205
|
-
// Leading `**/` matches zero or more segments, so each pattern covers both
|
|
206
|
-
// the root `state/` dir AND per-namespace `namespaces/<ns>/state/` dirs
|
|
207
|
-
// (Cursor review on PR #1793: multi-namespace deployments previously kept
|
|
208
|
-
// pushing their namespaced live sqlite files).
|
|
209
|
-
"**/state/*.sqlite",
|
|
210
|
-
"**/state/*.sqlite-*",
|
|
211
|
-
"**/state/index_tags.json",
|
|
212
|
-
"**/state/entity-mention-index.json",
|
|
213
|
-
"**/state/memory-governance/runs/**",
|
|
214
|
-
];
|
|
215
202
|
|
|
216
203
|
/**
|
|
217
204
|
* Convert a tiny subset of glob syntax (`*`, `**`, `?`, literal text) into a
|
package/src/operator-toolkit.ts
CHANGED
|
@@ -1987,7 +1987,7 @@ function summarizeSecurityMitigations(
|
|
|
1987
1987
|
| "recallAuditAnomalyRepeatQueryLimit"
|
|
1988
1988
|
| "recallAuditAnomalyNamespaceWalkLimit"
|
|
1989
1989
|
| "recallAuditAnomalyHighCardinalityLimit"
|
|
1990
|
-
| "recallAuditAnomalyRapidFireLimit"
|
|
1990
|
+
| "recallAuditAnomalyRapidFireLimit" | "recallSingleFlightEnabled"
|
|
1991
1991
|
>,
|
|
1992
1992
|
): OperatorDoctorCheck {
|
|
1993
1993
|
// Resolve access-setup gates once (#1566 Cluster B).
|