@remnic/core 9.7.15 → 9.9.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-DbZ1G3zV.d.ts} +29 -36
- 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-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-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-QKQYXZVS.js → chunk-BI2OJF6J.js} +1819 -1481
- package/dist/chunk-BI2OJF6J.js.map +1 -0
- 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-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-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-OAZVR2BV.js → chunk-OGCAYLNA.js} +8 -6
- package/dist/{chunk-OAZVR2BV.js.map → chunk-OGCAYLNA.js.map} +1 -1
- 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-PJSK6OJM.js +201 -0
- package/dist/chunk-PJSK6OJM.js.map +1 -0
- package/dist/{chunk-OVJ2HIPE.js → chunk-PMUD7ERF.js} +158 -125
- package/dist/chunk-PMUD7ERF.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-SK7AMF2J.js +168 -0
- package/dist/chunk-SK7AMF2J.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-LZOV7MX7.js → chunk-XQDRKZ7V.js} +6476 -5747
- package/dist/chunk-XQDRKZ7V.js.map +1 -0
- 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/{chunk-DCFV7A7H.js → chunk-ZVAYK7GU.js} +101 -91
- package/dist/chunk-ZVAYK7GU.js.map +1 -0
- package/dist/{cli-Cd5fMmhq.d.ts → cli-5tNLVTvJ.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 +94 -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 +172 -0
- package/src/access-observe-write-surface.ts +137 -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 +186 -179
- 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 +245 -0
- package/src/write-quarantine.ts +290 -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
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/wearables/cleanup.ts","../src/wearables/sync-state.ts","../src/wearables/trust.ts","../src/wearables/memory-gen.ts","../src/wearables/pipeline.ts"],"sourcesContent":["/**\n * Wearable transcript cleanup — deterministic, zero-LLM normalization.\n *\n * ASR output from always-on wearables is noisy: fragmented utterances,\n * filler tokens, stuttered repeats, and occasional pure garbage. This\n * module cleans a conversation in place-order without changing meaning:\n * everything here is conservative and reversible by re-syncing.\n */\n\nimport type {\n WearableCleanupSettings,\n WearableConversation,\n WearableTranscriptSegment,\n} from \"./types.js\";\n\nexport interface CleanupResult {\n conversation: WearableConversation;\n /** Segments removed by the low-quality heuristic. */\n droppedSegments: number;\n /** Segments merged into a predecessor. */\n mergedSegments: number;\n}\n\n/** Merge consecutive same-speaker segments when gaps are below this. */\nconst MERGE_GAP_MS = 30_000;\n\n/**\n * Speaker labels that carry no real diarization signal. Bee (and other\n * providers that fall back to a placeholder) emit \"Unknown\"/\"unknown\"\n * or an empty string when diarization is unavailable; merging on such a\n * label would collapse an entire conversation into one segment (issue #1811).\n */\nconst GENERIC_SPEAKER_PATTERN = /^unknown$/i;\n\n/**\n * Standalone filler tokens stripped when `stripFillers` is on. Matched\n * case-insensitively on word boundaries, only as whole tokens — \"um\"\n * inside \"umbrella\" is never touched. Deliberately short, low-risk\n * list; meaning-bearing hedges (\"like\", \"well\") are NOT stripped.\n */\nconst FILLER_TOKENS = [\"um\", \"uh\", \"uhm\", \"umm\", \"uhh\", \"erm\", \"hmm\", \"mhm\"];\n\nconst FILLER_PATTERN = new RegExp(\n // Leading/trailing punctuation around the filler collapses with it so\n // \"Um, so we should\" -> \"so we should\" rather than \", so we should\".\n `(?:^|\\\\s)(?:${FILLER_TOKENS.join(\"|\")})[,.]?(?=\\\\s|$)`,\n \"gi\",\n);\n\n/** Apply configured cleanup passes to one conversation. */\nexport function cleanConversation(\n conversation: WearableConversation,\n settings: WearableCleanupSettings,\n): CleanupResult {\n let segments = conversation.segments.map((segment) => ({ ...segment }));\n let droppedSegments = 0;\n let mergedSegments = 0;\n // Optional on the type so other connectors keep the legacy no-op\n // default; absent means \"off\" (unchanged merge behavior).\n const preserveBoundaries = settings.preserveUtteranceBoundaries === true;\n\n if (settings.stripFillers) {\n for (const segment of segments) {\n segment.text = stripFillerTokens(segment.text);\n }\n }\n\n if (settings.collapseRepeats) {\n for (const segment of segments) {\n segment.text = collapseImmediateRepeats(segment.text);\n }\n }\n\n for (const segment of segments) {\n segment.text = normalizeWhitespace(segment.text);\n }\n\n if (settings.dropLowQuality) {\n const kept: WearableTranscriptSegment[] = [];\n for (const segment of segments) {\n if (isLowQualitySegment(segment.text)) {\n droppedSegments += 1;\n } else {\n kept.push(segment);\n }\n }\n segments = kept;\n } else {\n // Even without the quality heuristic, segments whose text became\n // empty after filler stripping carry no information.\n const kept = segments.filter((segment) => segment.text.length > 0);\n droppedSegments += segments.length - kept.length;\n segments = kept;\n }\n\n if (settings.mergeSameSpeaker) {\n const merged: WearableTranscriptSegment[] = [];\n for (const segment of segments) {\n const previous = merged[merged.length - 1];\n if (previous && canMerge(previous, segment, preserveBoundaries)) {\n previous.text = `${previous.text} ${segment.text}`.trim();\n if (segment.endIso) previous.endIso = segment.endIso;\n mergedSegments += 1;\n } else {\n merged.push(segment);\n }\n }\n segments = merged;\n }\n\n return {\n conversation: { ...conversation, segments },\n droppedSegments,\n mergedSegments,\n };\n}\n\nfunction canMerge(\n previous: WearableTranscriptSegment,\n next: WearableTranscriptSegment,\n preserveUtteranceBoundaries: boolean,\n): boolean {\n if (previous.speakerKey !== next.speakerKey) return false;\n // A generic/low-confidence speaker label (\"Unknown\", empty) carries no\n // real diarization: merging on it collapses unrelated utterances. When\n // the source opts into boundary preservation, refuse to merge across\n // such a label (issue #1811). The keys are equal here, so checking one\n // suffices; diarized labels still merge normally.\n if (preserveUtteranceBoundaries) {\n const label = previous.speakerKey.trim();\n if (label.length === 0 || GENERIC_SPEAKER_PATTERN.test(label)) return false;\n }\n const previousEnd = previous.endIso ? Date.parse(previous.endIso) : NaN;\n const nextStart = next.startIso ? Date.parse(next.startIso) : NaN;\n // Without timestamps, adjacency is the only signal — still merge.\n if (Number.isNaN(previousEnd) || Number.isNaN(nextStart)) return true;\n return nextStart - previousEnd <= MERGE_GAP_MS;\n}\n\nexport function stripFillerTokens(text: string): string {\n return normalizeWhitespace(text.replace(FILLER_PATTERN, \" \"));\n}\n\n/**\n * Collapse immediate word/phrase stutters: \"I I I think\" -> \"I think\",\n * \"we should we should go\" -> \"we should go\". Only collapses *adjacent*\n * repeats (up to 4-word phrases) so intentional repetition across a\n * sentence is preserved.\n */\nexport function collapseImmediateRepeats(text: string): string {\n const words = text.split(/\\s+/).filter((word) => word.length > 0);\n if (words.length < 2) return text.trim();\n const out: string[] = [];\n let index = 0;\n while (index < words.length) {\n out.push(words[index]);\n index += 1;\n // Greedily consume every adjacent repeat of the phrase that just\n // ended at the output tail (largest phrase first, then re-check so\n // \"I I I think\" fully collapses to \"I think\").\n let matched = true;\n while (matched) {\n matched = false;\n for (let size = 4; size >= 1; size--) {\n if (out.length < size || index + size > words.length) continue;\n const tail = out.slice(-size).join(\" \").toLowerCase();\n // Spoken digit sequences legitimately repeat (\"555 555 1234\");\n // never collapse a phrase that carries no letters.\n if (!/\\p{L}/u.test(tail)) continue;\n const ahead = words.slice(index, index + size).join(\" \").toLowerCase();\n if (tail === ahead) {\n index += size;\n matched = true;\n break;\n }\n }\n }\n }\n return out.join(\" \");\n}\n\n/**\n * Heuristic ASR-garbage detector. Intentionally conservative: it only\n * drops segments that carry no plausible information.\n */\nexport function isLowQualitySegment(text: string): boolean {\n const trimmed = text.trim();\n if (trimmed.length === 0) return true;\n // Single repeated character runs (\"aaaaaa\", \"######\").\n if (/^(.)\\1{4,}$/.test(trimmed)) return true;\n // Mostly non-letter content with no digits (timestamps/amounts are\n // information; \"%$#@!\" is not).\n const letters = trimmed.replace(/[^\\p{L}\\p{N}]/gu, \"\");\n if (letters.length === 0) return true;\n if (trimmed.length >= 12 && letters.length / trimmed.length < 0.3) {\n return true;\n }\n // One identical token repeated many times (\"yeah yeah yeah yeah yeah\").\n const words = trimmed.toLowerCase().split(/\\s+/);\n if (words.length >= 5) {\n const unique = new Set(words);\n if (unique.size === 1) return true;\n }\n return false;\n}\n\nexport function normalizeWhitespace(text: string): string {\n return text.replace(/\\s+/g, \" \").trim();\n}\n","/**\n * Wearable sync-state ledger — per-source bookkeeping for incremental\n * syncs, stored at `state/wearables/sync.json`.\n *\n * State is written only AFTER a source's transcripts (and any memories)\n * were persisted successfully, so a failed sync never advances the\n * watermark past data that didn't land.\n */\n\nimport { promises as fsPromises } from \"node:fs\";\nimport * as path from \"node:path\";\n\nexport interface WearableSourceSyncState {\n /** ISO timestamp of the last successful sync run. */\n lastSyncAt: string;\n /** Most recent day (YYYY-MM-DD) that was synced. */\n lastDateSynced: string;\n /** Body hashes of the last-written day files, keyed by date. */\n dayHashes: Record<string, string>;\n /**\n * Body hashes of days whose memory-extraction pass completed without\n * warnings, keyed by date. A day whose entry is missing or stale\n * re-extracts on the next sync even when its transcript is unchanged\n * — this is how a memory pass that failed mid-run (transcript stored,\n * memories incomplete) self-heals. Absent on records written before\n * this field existed.\n */\n memoryDayHashes?: Record<string, string>;\n /** Native-memory ids already imported (bounded, newest kept). */\n importedNativeMemoryIds: string[];\n}\n\nexport interface WearableSyncStateFile {\n version: 1;\n sources: Record<string, WearableSourceSyncState>;\n}\n\n/** Cap on remembered native-memory ids per source. */\nconst MAX_TRACKED_NATIVE_IDS = 5_000;\n/** Cap on remembered day hashes per source (~2 years of days). */\nconst MAX_TRACKED_DAY_HASHES = 800;\n\nexport function syncStateFilePath(memoryDir: string): string {\n return path.join(memoryDir, \"state\", \"wearables\", \"sync.json\");\n}\n\nexport function emptySyncState(): WearableSyncStateFile {\n return { version: 1, sources: {} };\n}\n\nexport async function loadSyncState(\n memoryDir: string,\n): Promise<WearableSyncStateFile> {\n const filePath = syncStateFilePath(memoryDir);\n let raw: string;\n try {\n raw = await fsPromises.readFile(filePath, \"utf-8\");\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n return emptySyncState();\n }\n throw err;\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n // A corrupt state file should not brick syncing forever; treat it\n // as a cold start (the worst case is re-syncing days we already\n // have, which the day-hash skip makes cheap and idempotent).\n return emptySyncState();\n }\n if (\n typeof parsed !== \"object\" ||\n parsed === null ||\n Array.isArray(parsed) ||\n typeof (parsed as WearableSyncStateFile).sources !== \"object\" ||\n (parsed as WearableSyncStateFile).sources === null\n ) {\n return emptySyncState();\n }\n return { version: 1, sources: (parsed as WearableSyncStateFile).sources };\n}\n\nexport async function saveSyncState(\n memoryDir: string,\n state: WearableSyncStateFile,\n): Promise<void> {\n const filePath = syncStateFilePath(memoryDir);\n await fsPromises.mkdir(path.dirname(filePath), { recursive: true });\n const tmpPath = `${filePath}.tmp-${process.pid}-${Date.now().toString(36)}`;\n await fsPromises.writeFile(\n tmpPath,\n `${JSON.stringify(state, null, 2)}\\n`,\n \"utf-8\",\n );\n try {\n await fsPromises.rename(tmpPath, filePath);\n } catch (err) {\n await fsPromises.unlink(tmpPath).catch(() => undefined);\n throw err;\n }\n}\n\n/** Merge a completed source sync into the state file shape. */\nexport function updateSourceSyncState(\n state: WearableSyncStateFile,\n sourceId: string,\n update: {\n syncedAt: string;\n days: string[];\n dayHashes: Record<string, string>;\n /** Days whose memory pass completed cleanly this run. */\n memoryDayHashes?: Record<string, string>;\n /**\n * Days whose memory pass ran this sync but did NOT complete\n * cleanly. Their previous completion records are removed so a\n * stale hash from an earlier clean pass can never mask the\n * failure on the next sync.\n */\n clearMemoryDays?: string[];\n importedNativeMemoryIds?: string[];\n },\n): WearableSyncStateFile {\n const previous = state.sources[sourceId];\n const mergedHashes: Record<string, string> = {\n ...(previous?.dayHashes ?? {}),\n ...update.dayHashes,\n };\n // Bound the hash map: keep the lexicographically-largest (most\n // recent) dates, which sort naturally for YYYY-MM-DD keys.\n const hashKeys = Object.keys(mergedHashes).sort();\n while (hashKeys.length > MAX_TRACKED_DAY_HASHES) {\n const oldest = hashKeys.shift();\n if (oldest === undefined) break;\n delete mergedHashes[oldest];\n }\n\n const mergedMemoryHashes: Record<string, string> = {\n ...(previous?.memoryDayHashes ?? {}),\n ...(update.memoryDayHashes ?? {}),\n };\n for (const day of update.clearMemoryDays ?? []) {\n if (!(day in (update.memoryDayHashes ?? {}))) {\n delete mergedMemoryHashes[day];\n }\n }\n const memoryHashKeys = Object.keys(mergedMemoryHashes).sort();\n while (memoryHashKeys.length > MAX_TRACKED_DAY_HASHES) {\n const oldest = memoryHashKeys.shift();\n if (oldest === undefined) break;\n delete mergedMemoryHashes[oldest];\n }\n\n const mergedNativeIds = [\n ...(previous?.importedNativeMemoryIds ?? []),\n ...(update.importedNativeMemoryIds ?? []),\n ];\n const dedupedNativeIds = [...new Set(mergedNativeIds)];\n const boundedNativeIds =\n dedupedNativeIds.length > MAX_TRACKED_NATIVE_IDS\n ? dedupedNativeIds.slice(dedupedNativeIds.length - MAX_TRACKED_NATIVE_IDS)\n : dedupedNativeIds;\n\n const sortedDays = [...update.days].sort();\n const latestDay = sortedDays[sortedDays.length - 1];\n const lastDateSynced =\n latestDay !== undefined &&\n (!previous || previous.lastDateSynced < latestDay)\n ? latestDay\n : previous?.lastDateSynced ?? latestDay ?? \"\";\n\n return {\n version: 1,\n sources: {\n ...state.sources,\n [sourceId]: {\n lastSyncAt: update.syncedAt,\n lastDateSynced,\n dayHashes: mergedHashes,\n memoryDayHashes: mergedMemoryHashes,\n importedNativeMemoryIds: boundedNativeIds,\n },\n },\n };\n}\n","/**\n * Wearable memory trust scoring — the \"smart\" memoryMode engine.\n *\n * Grounded in how production memory systems handle noisy ingest:\n *\n * - **LLM-as-judge gating** (Remnic's own extraction judge,\n * `judgeFactDurability`): an LLM verdict on durability decides\n * accept / defer / reject before anything persists.\n * - **Provenance priors**: each source carries a configurable trust\n * prior (`sourceTrust`) — a noisy ASR channel contributes less\n * confidence than a clean one (provenance-weighted fusion).\n * - **Corroboration**: independent agreement raises trust. A fact\n * supported by a second wearable that recorded the same day, or by\n * an existing active memory, is far less likely to be an ASR\n * artifact (ensemble agreement / self-consistency).\n *\n * The combined score maps to a three-way decision:\n *\n * trust >= autoApproveTrust -> written ACTIVE\n * trust >= reviewTrust -> written pending_review\n * below -> dropped\n *\n * with the judge able to short-circuit (reject -> drop,\n * defer -> pending_review regardless of score). The score, verdict,\n * and corroboration evidence persist on the memory (confidence +\n * structuredAttributes + verificationState), so Remnic's existing\n * trust machinery — memory-worth outcome counters, pattern\n * reinforcement, temporal supersession, contradiction scans — keeps\n * calibrating these memories after they land.\n */\n\nimport {\n countRecallTokenOverlap,\n normalizeRecallTokens,\n} from \"../recall-tokenization.js\";\n\n/** Judge adjustments and corroboration boosts (documented, fixed). */\nexport const TRUST_JUDGE_ACCEPT_BOOST = 0.15;\nexport const TRUST_CROSS_SOURCE_BOOST = 0.15;\nexport const TRUST_SUPPORTING_MEMORY_BOOST = 0.1;\n\n/** Minimum distinct tokens before similarity is meaningful. */\nconst MIN_FACT_TOKENS = 4;\n/** Fact-token coverage required to call a day-text corroborating. */\nconst CROSS_SOURCE_COVERAGE = 0.6;\n/** Fact-token coverage required to call an existing memory supporting. */\nconst MEMORY_SUPPORT_COVERAGE = 0.7;\n/** Bound on existing memories scanned per fact batch. */\nconst MAX_MEMORIES_SCANNED = 5_000;\n\nexport interface TrustEvidence {\n /** Other-source ids whose same-day content corroborates the fact. */\n corroboratedBySources: string[];\n /** Id of an existing active memory whose content supports the fact. */\n supportingMemoryId?: string;\n}\n\nexport interface TrustScoreInput {\n /** Extraction confidence for the fact (defaults to 0.7 when absent). */\n extractionConfidence: number | undefined;\n /** Per-source trust prior from config (0..1). */\n sourceTrust: number;\n /** Judge verdict kind when a judge ran; undefined when unavailable. */\n judgeVerdict?: \"accept\" | \"reject\" | \"defer\";\n evidence: TrustEvidence;\n}\n\nexport function computeTrustScore(input: TrustScoreInput): number {\n const confidence =\n typeof input.extractionConfidence === \"number\" &&\n Number.isFinite(input.extractionConfidence)\n ? Math.min(1, Math.max(0, input.extractionConfidence))\n : 0.7;\n let trust = confidence * Math.min(1, Math.max(0, input.sourceTrust));\n if (input.judgeVerdict === \"accept\") trust += TRUST_JUDGE_ACCEPT_BOOST;\n if (input.evidence.corroboratedBySources.length > 0) {\n trust += TRUST_CROSS_SOURCE_BOOST;\n }\n if (input.evidence.supportingMemoryId !== undefined) {\n trust += TRUST_SUPPORTING_MEMORY_BOOST;\n }\n return Math.min(1, Math.max(0, trust));\n}\n\nexport interface CorroborationContext {\n /**\n * Same-day transcript bodies from OTHER sources, keyed by source id.\n * Pre-tokenized once per sync (day bodies are large).\n */\n otherSourceDayTokens: Map<string, Set<string>>;\n /** Existing active memories: id + content. */\n existingMemories: Array<{ id: string; content: string }>;\n}\n\n/** Tokenize a day body once for repeated per-fact coverage checks. */\nexport function tokenizeDayBody(body: string): Set<string> {\n return new Set(normalizeRecallTokens(body));\n}\n\n/**\n * Find corroborating evidence for one fact. Deterministic and local:\n * token-coverage similarity via the shared recall tokenizer — no LLM\n * cost on the corroboration path.\n */\nexport function findCorroboration(\n factText: string,\n context: CorroborationContext,\n): TrustEvidence {\n const factTokens = normalizeRecallTokens(factText);\n const evidence: TrustEvidence = { corroboratedBySources: [] };\n if (factTokens.length < MIN_FACT_TOKENS) return evidence;\n const factTokenSet = new Set(factTokens);\n\n for (const [sourceId, dayTokens] of context.otherSourceDayTokens) {\n let matches = 0;\n for (const token of factTokenSet) {\n if (dayTokens.has(token)) matches += 1;\n }\n if (matches / factTokenSet.size >= CROSS_SOURCE_COVERAGE) {\n evidence.corroboratedBySources.push(sourceId);\n }\n }\n evidence.corroboratedBySources.sort();\n\n let scanned = 0;\n for (const memory of context.existingMemories) {\n if (scanned >= MAX_MEMORIES_SCANNED) break;\n scanned += 1;\n const matches = countRecallTokenOverlap(factTokenSet, memory.content);\n if (matches / factTokenSet.size >= MEMORY_SUPPORT_COVERAGE) {\n evidence.supportingMemoryId = memory.id;\n break;\n }\n }\n return evidence;\n}\n\nexport interface SmartDecision {\n outcome: \"active\" | \"review\" | \"drop\";\n reason:\n | \"judge-rejected\"\n | \"judge-deferred\"\n | \"auto-approved\"\n | \"queued-for-review\"\n | \"below-trust\";\n trust: number;\n}\n\n/** Map judge verdict + trust score to the smart-mode decision. */\nexport function decideSmart(\n trust: number,\n judgeVerdict: \"accept\" | \"reject\" | \"defer\" | undefined,\n thresholds: { autoApproveTrust: number; reviewTrust: number },\n): SmartDecision {\n if (judgeVerdict === \"reject\") {\n return { outcome: \"drop\", reason: \"judge-rejected\", trust };\n }\n if (judgeVerdict === \"defer\") {\n return { outcome: \"review\", reason: \"judge-deferred\", trust };\n }\n if (trust >= thresholds.autoApproveTrust) {\n return { outcome: \"active\", reason: \"auto-approved\", trust };\n }\n if (trust >= thresholds.reviewTrust) {\n return { outcome: \"review\", reason: \"queued-for-review\", trust };\n }\n return { outcome: \"drop\", reason: \"below-trust\", trust };\n}\n","/**\n * Wearable memory generation — trust-gated extraction from cleaned day\n * transcripts.\n *\n * Wearable ASR quality varies wildly between providers and rooms, so\n * unlike live-session extraction this path is gated per source:\n *\n * - memoryMode \"off\" -> never runs\n * - memoryMode \"review\" -> candidates land with status\n * \"pending_review\" (operator approves via\n * the existing review-queue surfaces)\n * - memoryMode \"auto\" -> candidates that pass every gate land\n * active\n *\n * Deterministic gates (applied in order, all modes except \"off\"):\n * 1. category gate — procedure / reasoning_trace candidates are\n * skipped (they need richer persistence than\n * this path provides)\n * 2. confidence floor — `minConfidence`\n * 3. importance floor — local `scoreImportance` >= `minImportance`\n * 4. dedup — storage content-hash index + intra-run set\n * 5. day cap — top `maxMemoriesPerDay` by importance score\n * (0 disables the cap)\n *\n * The extraction engine itself is injected so this module stays free of\n * LLM-client construction; callers hand in `orchestrator`-owned or\n * standalone engines alike.\n */\n\nimport { scoreImportance } from \"../importance.js\";\nimport type { MemoryWriteResult } from \"../storage.js\";\nimport type { JudgeBatchResult, JudgeCandidate } from \"../extraction-judge.js\";\nimport { getVerdictKind } from \"../extraction-judge.js\";\nimport { describeErrorForOperator } from \"./errors.js\";\nimport {\n computeTrustScore,\n decideSmart,\n findCorroboration,\n type CorroborationContext,\n type TrustEvidence,\n} from \"./trust.js\";\nimport type {\n BufferTurn,\n ExtractedFact,\n ExtractionResult,\n ImportanceLevel,\n ImportanceScore,\n MemoryCategory,\n MemoryStatus,\n} from \"../types.js\";\nimport { resolveSpeaker, type SpeakerRegistry } from \"./speakers.js\";\nimport type {\n WearableConversation,\n WearableMemoryMode,\n WearableNativeMemory,\n WearableSourceSettings,\n} from \"./types.js\";\n\n/**\n * Memory status used for a given memory mode. Least-privilege default:\n * anything that is not explicitly \"auto\" lands in the review queue\n * rather than active recall.\n */\nexport function memoryStatusForMode(\n mode: WearableMemoryMode,\n): Extract<MemoryStatus, \"active\" | \"pending_review\"> {\n return mode === \"auto\" || mode === \"smart\" ? \"active\" : \"pending_review\";\n}\n\n/** Narrow writer interface satisfied by `StorageManager`. */\nexport interface WearableMemoryWriter {\n writeMemory(\n category: MemoryCategory,\n content: string,\n options: {\n confidence?: number;\n tags?: string[];\n source?: string;\n importance?: ImportanceScore;\n validAt?: string;\n structuredAttributes?: Record<string, string>;\n contentHashSource?: string;\n status?: MemoryStatus;\n memoryKind?: \"episode\" | \"note\" | \"box\" | \"dream\" | \"procedural\";\n },\n ): Promise<MemoryWriteResult>;\n hasFactContentHash(content: string): Promise<boolean>;\n /**\n * Locate an earlier wearable write of the same content (any status).\n * Optional: enables in-place promotion when re-scoring with stronger\n * evidence.\n */\n findWearableMemoryByContent?(\n content: string,\n ): Promise<{ id: string; status: MemoryStatus | undefined } | null>;\n /**\n * Promote a pending_review wearable memory to active, merging trust\n * evidence. Returns false when missing or no longer pending.\n */\n promoteWearableMemory?(\n id: string,\n attributeUpdates: Record<string, string>,\n confidence?: number,\n ): Promise<boolean>;\n /**\n * Demote a pending_review wearable memory to rejected on an explicit\n * judge-reject re-verdict. Returns false when missing or no longer\n * pending. Active rows are never auto-demoted.\n */\n demoteWearableMemory?(\n id: string,\n attributeUpdates: Record<string, string>,\n ): Promise<boolean>;\n}\n\nexport interface WearableMemoryGenDeps {\n extract(turns: BufferTurn[]): Promise<ExtractionResult>;\n writer: WearableMemoryWriter;\n /**\n * LLM-as-judge batch evaluation (the existing extraction judge).\n * Absent when no judge is wired (degraded smart mode: trust scoring\n * runs on confidence x sourceTrust + corroboration alone).\n */\n judgeFacts?(candidates: JudgeCandidate[]): Promise<JudgeBatchResult>;\n /**\n * Corroboration evidence for smart mode: other sources' same-day\n * transcript tokens + existing active memories. Absent disables\n * corroboration boosts.\n */\n corroboration?: CorroborationContext;\n}\n\nexport interface WearableMemoryGenResult {\n created: number;\n /**\n * Writes the #1579 tombstone chokepoint downgraded to pending_review (no\n * active copy). Surfaced distinctly from `created` so sync summaries and\n * callers don't count blocked content as successfully created (#1645).\n */\n tombstoneBlocked: number;\n /** Earlier borderline writes promoted to active by new evidence. */\n promoted: number;\n /** Earlier pending writes retired by a fresh judge-reject verdict. */\n demoted: number;\n skipped: number;\n skippedByReason: Record<string, number>;\n /** Non-fatal problems (e.g. the extraction engine erroring). */\n warnings: string[];\n /**\n * True when every conversation was extracted (the pass may still\n * carry degraded-mode warnings, e.g. judge unavailable). False only\n * when extraction itself aborted mid-day — the signal callers use to\n * re-run the pass on the next sync. A degraded-but-complete pass\n * must NOT re-run forever: its facts are already written and dedup\n * would suppress improvements anyway.\n */\n completed: boolean;\n}\n\nexport const WEARABLE_SOURCE_PREFIX = \"wearable\";\n\nexport function wearableSourceLabel(sourceId: string): string {\n return `${WEARABLE_SOURCE_PREFIX}:${sourceId}`;\n}\n\nexport function wearableDayTag(date: string): string {\n return `wearable-day:${date}`;\n}\n\nconst IMPORTANCE_RANK: Record<ImportanceLevel, number> = {\n trivial: 0,\n low: 1,\n normal: 2,\n high: 3,\n critical: 4,\n};\n\n/** Max characters of transcript per extraction turn. */\nconst MAX_EXTRACTION_CHUNK_CHARS = 6_000;\n/** Skip extraction for conversations with less substance than this. */\nconst MIN_CONVERSATION_CHARS = 80;\n\n/**\n * Render a cleaned conversation into extraction-ready turns. Each turn\n * carries a labeled multi-speaker transcript block; the wearer is\n * marked \"(you)\" so first-person facts attribute correctly.\n */\nexport function buildExtractionTurns(\n sourceId: string,\n date: string,\n conversation: WearableConversation,\n registry: SpeakerRegistry,\n): BufferTurn[] {\n const headerParts = [\n `Wearable transcript (${sourceId}) — ${date}`,\n conversation.title ? `\"${conversation.title}\"` : undefined,\n conversation.location ? `at ${conversation.location}` : undefined,\n ].filter((part): part is string => typeof part === \"string\");\n const header = `[${headerParts.join(\" — \")}]`;\n\n const lines: string[] = [];\n for (const segment of conversation.segments) {\n const { label } = resolveSpeaker(sourceId, segment, registry);\n lines.push(`${label}: ${segment.text}`);\n }\n const transcript = lines.join(\"\\n\");\n if (transcript.trim().length < MIN_CONVERSATION_CHARS) return [];\n\n const sessionKey = `wearables:${sourceId}:${date}:${conversation.id}`;\n const timestamp = conversation.startIso;\n const turns: BufferTurn[] = [];\n let chunkLines: string[] = [];\n let chunkChars = 0;\n const flush = () => {\n if (chunkLines.length === 0) return;\n turns.push({\n role: \"user\",\n content: `${header}\\n${chunkLines.join(\"\\n\")}`,\n timestamp,\n sourceValidAt: timestamp,\n sessionKey,\n });\n chunkLines = [];\n chunkChars = 0;\n };\n for (const line of transcript.split(\"\\n\")) {\n if (chunkChars + line.length + 1 > MAX_EXTRACTION_CHUNK_CHARS) flush();\n chunkLines.push(line);\n chunkChars += line.length + 1;\n }\n flush();\n return turns;\n}\n\ninterface GatedCandidate {\n fact: ExtractedFact;\n importance: ImportanceScore;\n conversation: WearableConversation;\n}\n\ninterface ScoredCandidate {\n trust: number;\n verdict?: \"accept\" | \"reject\" | \"defer\";\n evidence: TrustEvidence;\n}\n\n/**\n * Smart-mode scoring: one judge batch call for the whole day, then\n * per-fact trust = confidence x sourceTrust + judge/corroboration\n * boosts. A judge failure degrades gracefully (warned once; scoring\n * continues on confidence + corroboration alone).\n */\nasync function scoreCandidates(\n novel: GatedCandidate[],\n settings: WearableSourceSettings,\n deps: WearableMemoryGenDeps,\n result: WearableMemoryGenResult,\n): Promise<Map<number, ScoredCandidate>> {\n const scored = new Map<number, ScoredCandidate>();\n if (novel.length === 0) return scored;\n\n let verdicts: Map<number, \"accept\" | \"reject\" | \"defer\"> | undefined;\n if (deps.judgeFacts) {\n const judgeCandidates: JudgeCandidate[] = novel.map((candidate) => ({\n text: candidate.fact.content,\n category: candidate.fact.category,\n confidence:\n typeof candidate.fact.confidence === \"number\"\n ? candidate.fact.confidence\n : 0.7,\n tags: candidate.fact.tags ?? [],\n importanceLevel: candidate.importance.level,\n }));\n try {\n const judgeResult = await deps.judgeFacts(judgeCandidates);\n verdicts = new Map();\n for (const [index, verdict] of judgeResult.verdicts) {\n verdicts.set(index, getVerdictKind(verdict));\n }\n } catch (err) {\n result.warnings.push(\n `extraction judge unavailable for this pass: ${describeErrorForOperator(err)} — trust scoring continued without judge verdicts`,\n );\n }\n }\n\n const corroboration: CorroborationContext = deps.corroboration ?? {\n otherSourceDayTokens: new Map(),\n existingMemories: [],\n };\n novel.forEach((candidate, index) => {\n const evidence = findCorroboration(candidate.fact.content, corroboration);\n const verdict = verdicts?.get(index);\n const trust = computeTrustScore({\n extractionConfidence: candidate.fact.confidence,\n sourceTrust: settings.sourceTrust,\n judgeVerdict: verdict,\n evidence,\n });\n scored.set(index, { trust, ...(verdict !== undefined ? { verdict } : {}), evidence });\n });\n return scored;\n}\n\n/**\n * Run extraction + gates over a day's conversations and persist the\n * survivors. Returns counts for the sync summary.\n */\nexport async function generateWearableMemories(\n sourceId: string,\n date: string,\n conversations: WearableConversation[],\n settings: WearableSourceSettings,\n registry: SpeakerRegistry,\n deps: WearableMemoryGenDeps,\n): Promise<WearableMemoryGenResult> {\n const result: WearableMemoryGenResult = {\n created: 0,\n tombstoneBlocked: 0,\n promoted: 0,\n demoted: 0,\n skipped: 0,\n skippedByReason: {},\n warnings: [],\n completed: true,\n };\n if (settings.memoryMode === \"off\") return result;\n\n const skip = (reason: string, count = 1): void => {\n result.skipped += count;\n result.skippedByReason[reason] =\n (result.skippedByReason[reason] ?? 0) + count;\n };\n\n const candidates: GatedCandidate[] = [];\n const seenContent = new Set<string>();\n\n for (const conversation of conversations) {\n const turns = buildExtractionTurns(sourceId, date, conversation, registry);\n if (turns.length === 0) continue;\n let extraction: ExtractionResult;\n try {\n extraction = await deps.extract(turns);\n } catch (err) {\n // One failing extraction call almost always means every call will\n // fail (missing key, provider outage) — stop hammering the engine\n // and surface a single actionable warning instead of one per\n // conversation. Candidates gathered before the failure still\n // persist below.\n result.warnings.push(\n `extraction failed for ${sourceId}/${date} (conversation ${conversation.id}): ${describeErrorForOperator(err)} — the memory pass for this day retries on the next sync`,\n );\n result.completed = false;\n break;\n }\n for (const fact of extraction.facts) {\n const content = fact.content?.trim();\n if (!content) {\n skip(\"empty\");\n continue;\n }\n if (fact.category === \"procedure\" || fact.category === \"reasoning_trace\") {\n skip(\"unsupported-category\");\n continue;\n }\n // In smart mode the trust bands subsume the hard confidence\n // floor — a borderline fact belongs in the review band, not on\n // the floor. The pre-filter applies to review/auto modes only.\n if (\n settings.memoryMode !== \"smart\" &&\n typeof fact.confidence === \"number\" &&\n fact.confidence < settings.minConfidence\n ) {\n skip(\"below-confidence\");\n continue;\n }\n const importance = scoreImportance(content, fact.category, fact.tags ?? []);\n if (\n IMPORTANCE_RANK[importance.level] <\n IMPORTANCE_RANK[settings.minImportance]\n ) {\n skip(\"below-importance\");\n continue;\n }\n const dedupKey = content.toLowerCase();\n if (seenContent.has(dedupKey)) {\n skip(\"duplicate-in-run\");\n continue;\n }\n seenContent.add(dedupKey);\n candidates.push({ fact: { ...fact, content }, importance, conversation });\n }\n }\n\n // Drop candidates that already exist in storage BEFORE applying the\n // day cap so duplicates never consume cap slots that novel,\n // lower-scoring candidates should get (Codex P2 on PR #1458). In\n // smart mode a duplicate of a PENDING_REVIEW write is kept aside as\n // a promotion candidate — corroboration that arrives after the\n // original borderline write (another device syncing the same day)\n // must be able to promote it in place (Cursor review on PR #1462).\n const novel: GatedCandidate[] = [];\n const promotable: GatedCandidate[] = [];\n for (const candidate of candidates) {\n if (await deps.writer.hasFactContentHash(candidate.fact.content)) {\n if (\n settings.memoryMode === \"smart\" &&\n deps.writer.findWearableMemoryByContent !== undefined &&\n deps.writer.promoteWearableMemory !== undefined\n ) {\n promotable.push(candidate);\n } else {\n skip(\"duplicate-existing\");\n }\n continue;\n }\n novel.push(candidate);\n }\n\n // Re-score promotion candidates with TODAY'S evidence; promote the\n // ones that now clear the auto threshold. Never consumes day-cap\n // slots (no new memory is written).\n if (promotable.length > 0) {\n const promoteScores = await scoreCandidates(promotable, settings, deps, result);\n for (const [index, candidate] of promotable.entries()) {\n const scored = promoteScores.get(index);\n const decision = scored\n ? decideSmart(scored.trust, scored.verdict, settings)\n : undefined;\n if (!scored || !decision) {\n skip(\"duplicate-existing\");\n continue;\n }\n // A fresh judge-REJECT retires the stored row — but only a\n // pending_review one. Active rows are never auto-demoted: an\n // operator approval or accrued recall signals must not be\n // overturned by one later LLM verdict; contradiction scans and\n // supersession own active-row retirement (Cursor review on PR\n // #1462, round 7).\n if (scored.verdict === \"reject\") {\n if (deps.writer.demoteWearableMemory !== undefined) {\n const existingForDemote = await deps.writer.findWearableMemoryByContent!(\n candidate.fact.content,\n );\n if (\n existingForDemote &&\n existingForDemote.status === \"pending_review\" &&\n (await deps.writer.demoteWearableMemory(existingForDemote.id, {\n trustScore: scored.trust.toFixed(3),\n trustDecision: \"demoted-by-rejection\",\n judgeVerdict: \"reject\",\n }))\n ) {\n result.demoted += 1;\n continue;\n }\n }\n skip(\"duplicate-existing\");\n continue;\n }\n if (decision.outcome !== \"active\") {\n skip(\"duplicate-existing\");\n continue;\n }\n const existing = await deps.writer.findWearableMemoryByContent!(\n candidate.fact.content,\n );\n if (!existing || existing.status !== \"pending_review\") {\n skip(\"duplicate-existing\");\n continue;\n }\n const promoted = await deps.writer.promoteWearableMemory!(\n existing.id,\n {\n trustScore: scored.trust.toFixed(3),\n trustDecision: \"promoted-by-corroboration\",\n ...(scored.verdict !== undefined ? { judgeVerdict: scored.verdict } : {}),\n ...(scored.evidence.corroboratedBySources.length > 0\n ? { corroboratedBySources: scored.evidence.corroboratedBySources.join(\",\") }\n : {}),\n ...(scored.evidence.supportingMemoryId !== undefined\n ? { supportingMemoryId: scored.evidence.supportingMemoryId }\n : {}),\n },\n scored.trust,\n );\n if (promoted) {\n result.promoted += 1;\n } else {\n skip(\"duplicate-existing\");\n }\n }\n }\n\n // Smart mode: judge + trust scoring decide active/review/drop per\n // fact. The judge runs ONE batch call for the whole day; trust\n // combines extraction confidence x sourceTrust with corroboration\n // boosts (cross-device agreement, existing-memory support).\n let trustById = new Map<number, ScoredCandidate>();\n if (settings.memoryMode === \"smart\") {\n trustById = await scoreCandidates(novel, settings, deps, result);\n }\n\n // Smart decisions run BEFORE the day cap so dropped facts (judge\n // rejections, below-trust) never consume cap slots that surviving\n // candidates ranked past position N should get (Cursor review on PR\n // #1462).\n interface Writable {\n candidate: GatedCandidate;\n index: number;\n status: MemoryStatus;\n trustAttributes: Record<string, string>;\n }\n const modeStatus = memoryStatusForMode(settings.memoryMode);\n const writable: Writable[] = [];\n novel.forEach((candidate, index) => {\n if (settings.memoryMode !== \"smart\") {\n writable.push({ candidate, index, status: modeStatus, trustAttributes: {} });\n return;\n }\n const scored = trustById.get(index);\n if (!scored) return;\n const decision = decideSmart(scored.trust, scored.verdict, settings);\n if (decision.outcome === \"drop\") {\n skip(decision.reason);\n return;\n }\n writable.push({\n candidate,\n index,\n status: decision.outcome === \"active\" ? \"active\" : \"pending_review\",\n trustAttributes: {\n trustScore: scored.trust.toFixed(3),\n trustDecision: decision.reason,\n ...(scored.verdict !== undefined ? { judgeVerdict: scored.verdict } : {}),\n ...(scored.evidence.corroboratedBySources.length > 0\n ? { corroboratedBySources: scored.evidence.corroboratedBySources.join(\",\") }\n : {}),\n ...(scored.evidence.supportingMemoryId !== undefined\n ? { supportingMemoryId: scored.evidence.supportingMemoryId }\n : {}),\n },\n });\n });\n\n // Day cap over the SURVIVORS: strongest by trust in smart mode, by\n // importance otherwise. Stable ordering with a content tiebreak.\n const strength = (entry: Writable): number =>\n settings.memoryMode === \"smart\"\n ? trustById.get(entry.index)?.trust ?? 0\n : entry.candidate.importance.score;\n writable.sort((a, b) => {\n const sa = strength(a);\n const sb = strength(b);\n if (sa > sb) return -1;\n if (sa < sb) return 1;\n if (a.candidate.fact.content < b.candidate.fact.content) return -1;\n if (a.candidate.fact.content > b.candidate.fact.content) return 1;\n return 0;\n });\n const cap = settings.maxMemoriesPerDay;\n const kept = cap > 0 ? writable.slice(0, cap) : writable;\n if (writable.length > kept.length) {\n skip(\"over-day-cap\", writable.length - kept.length);\n }\n\n for (const { candidate, index, status, trustAttributes } of kept) {\n const tags = [\n ...new Set([\n ...(candidate.fact.tags ?? []),\n WEARABLE_SOURCE_PREFIX,\n wearableSourceLabel(sourceId),\n wearableDayTag(date),\n ]),\n ];\n const writeResult = await deps.writer.writeMemory(candidate.fact.category, candidate.fact.content, {\n confidence:\n settings.memoryMode === \"smart\"\n ? trustById.get(index)?.trust\n : candidate.fact.confidence,\n tags,\n source: wearableSourceLabel(sourceId),\n importance: candidate.importance,\n validAt: candidate.conversation.startIso,\n structuredAttributes: {\n ...(candidate.fact.structuredAttributes ?? {}),\n wearableSource: sourceId,\n wearableDate: date,\n wearableConversationId: candidate.conversation.id,\n ...trustAttributes,\n },\n contentHashSource: candidate.fact.content,\n status,\n });\n // #1645: a tombstone-blocked wearable write lands pending_review (no active\n // copy) — count it as blocked, NOT created, so the sync summary and callers\n // don't report blocked content as successfully created active memories.\n if (writeResult.tombstoneBlocked) {\n result.tombstoneBlocked += 1;\n } else {\n result.created += 1;\n }\n }\n return result;\n}\n\n/**\n * Write one compact daily-digest memory summarizing the day's recorded\n * conversations. Deterministic (no LLM): titles, time ranges, speaker\n * counts. Gated by `wearables.digestEnabled`.\n */\nexport async function writeDailyDigestMemory(\n sourceId: string,\n date: string,\n conversations: WearableConversation[],\n settings: WearableSourceSettings,\n registry: SpeakerRegistry,\n writer: WearableMemoryWriter,\n): Promise<boolean> {\n if (settings.memoryMode === \"off\") return false;\n if (conversations.length === 0) return false;\n const lines = conversations.map((conversation) => {\n const title = conversation.title?.trim() || \"Untitled conversation\";\n const speakers = new Set(\n conversation.segments.map(\n (segment) => resolveSpeaker(sourceId, segment, registry).label,\n ),\n );\n return `- ${title} (${speakers.size} speaker${speakers.size === 1 ? \"\" : \"s\"})`;\n });\n const content =\n `Wearable day digest — ${sourceId}, ${date}: ` +\n `${conversations.length} recorded conversation${conversations.length === 1 ? \"\" : \"s\"}.\\n` +\n lines.join(\"\\n\");\n if (await writer.hasFactContentHash(content)) return false;\n await writer.writeMemory(\"moment\", content, {\n confidence: 0.9,\n tags: [\n WEARABLE_SOURCE_PREFIX,\n wearableSourceLabel(sourceId),\n wearableDayTag(date),\n \"daily-digest\",\n ],\n source: wearableSourceLabel(sourceId),\n importance: scoreImportance(content, \"moment\", [\"daily-digest\"]),\n validAt: `${date}T00:00:00.000Z`,\n structuredAttributes: {\n wearableSource: sourceId,\n wearableDate: date,\n },\n contentHashSource: content,\n status: memoryStatusForMode(settings.memoryMode),\n memoryKind: \"episode\",\n });\n return true;\n}\n\n/**\n * Import provider-extracted memories (Bee facts, Omi memories) into the\n * review queue. Always `pending_review` regardless of memoryMode — the\n * provider's extraction quality is outside Remnic's control.\n */\n/** Native-source trust prior reduction (provider extraction quality). */\nconst NATIVE_TRUST_FACTOR = 0.9;\n\nexport async function importNativeMemories(\n sourceId: string,\n memories: WearableNativeMemory[],\n alreadyImportedIds: ReadonlySet<string>,\n settings: WearableSourceSettings,\n deps: WearableMemoryGenDeps,\n): Promise<{ imported: number; tombstoneBlocked: number; importedIds: string[]; warnings: string[] }> {\n let imported = 0;\n let tombstoneBlocked = 0;\n const importedIds: string[] = [];\n const warnings: string[] = [];\n const seenContent = new Set<string>();\n const smart = settings.importNativeMemories === \"smart\";\n\n // Smart path: one judge batch over the novel items, like transcript\n // facts, with a reduced source prior — provider extraction quality is\n // outside Remnic's control.\n const novel: WearableNativeMemory[] = [];\n for (const memory of memories) {\n const content = memory.content?.trim();\n if (!content) continue;\n if (alreadyImportedIds.has(memory.id)) continue;\n // Intra-run + cross-run dedup: the storage hash index only learns a\n // fact after its write lands, so same-content items within one page\n // batch need the local set.\n if (seenContent.has(content) || (await deps.writer.hasFactContentHash(content))) {\n importedIds.push(memory.id);\n continue;\n }\n seenContent.add(content);\n novel.push({ ...memory, content });\n }\n\n let verdicts: Map<number, \"accept\" | \"reject\" | \"defer\"> | undefined;\n if (smart && deps.judgeFacts && novel.length > 0) {\n try {\n const judgeResult = await deps.judgeFacts(\n novel.map((memory) => ({\n text: memory.content,\n category: \"fact\",\n confidence: 0.7,\n tags: memory.tags ?? [],\n })),\n );\n verdicts = new Map();\n for (const [index, verdict] of judgeResult.verdicts) {\n verdicts.set(index, getVerdictKind(verdict));\n }\n } catch (err) {\n warnings.push(\n `extraction judge unavailable for native import: ${describeErrorForOperator(err)} — trust scoring continued without judge verdicts`,\n );\n }\n }\n const corroboration: CorroborationContext = deps.corroboration ?? {\n otherSourceDayTokens: new Map(),\n existingMemories: [],\n };\n\n for (const [index, memory] of novel.entries()) {\n const content = memory.content;\n let status: MemoryStatus = \"pending_review\";\n let trustAttributes: Record<string, string> = {};\n let confidence = 0.6;\n if (smart) {\n const evidence = findCorroboration(content, corroboration);\n const verdict = verdicts?.get(index);\n const trust = computeTrustScore({\n extractionConfidence: undefined,\n sourceTrust: settings.sourceTrust * NATIVE_TRUST_FACTOR,\n judgeVerdict: verdict,\n evidence,\n });\n const decision = decideSmart(trust, verdict, settings);\n if (decision.outcome === \"drop\") {\n // Deliberately NOT recorded in importedIds: a dropped native\n // fact re-fetches and re-scores on later syncs, so corpus or\n // corroboration support that arrives later can still admit it.\n // The judge verdict cache keeps repeated rejections cheap\n // (Cursor review on PR #1462).\n continue;\n }\n status = decision.outcome === \"active\" ? \"active\" : \"pending_review\";\n confidence = trust;\n trustAttributes = {\n trustScore: trust.toFixed(3),\n trustDecision: decision.reason,\n ...(verdict !== undefined ? { judgeVerdict: verdict } : {}),\n ...(evidence.corroboratedBySources.length > 0\n ? { corroboratedBySources: evidence.corroboratedBySources.join(\",\") }\n : {}),\n ...(evidence.supportingMemoryId !== undefined\n ? { supportingMemoryId: evidence.supportingMemoryId }\n : {}),\n };\n }\n const nativeWriteResult = await deps.writer.writeMemory(\"fact\", content, {\n confidence,\n tags: [\n ...new Set([\n ...(memory.tags ?? []),\n WEARABLE_SOURCE_PREFIX,\n wearableSourceLabel(sourceId),\n \"native-import\",\n ]),\n ],\n source: `${wearableSourceLabel(sourceId)}:native`,\n importance: scoreImportance(content, \"fact\", memory.tags ?? []),\n validAt: memory.createdIso,\n structuredAttributes: {\n wearableSource: sourceId,\n wearableNativeId: memory.id,\n ...trustAttributes,\n },\n contentHashSource: content,\n status,\n });\n // #1645: a tombstone-blocked native import lands pending_review (no active\n // copy) — count it as blocked, NOT imported. Still record the provider id in\n // importedIds so the next sync doesn't re-import and duplicate the pending\n // row; the block is permanent for this content.\n if (nativeWriteResult.tombstoneBlocked) {\n tombstoneBlocked += 1;\n } else {\n imported += 1;\n }\n importedIds.push(memory.id);\n }\n return { imported, tombstoneBlocked, importedIds, warnings };\n}\n","/**\n * Wearable sync pipeline — pull → clean → label → correct → store →\n * (optionally) remember, for one source.\n *\n * Stage order per conversation is deliberate:\n * 1. off-the-record elision (before anything can persist the span)\n * 2. cleanup (merging first lets redaction see numbers\n * that ASR split across segments)\n * 3. redaction (built-in + user patterns)\n * 4. corrections (user-specific word fixes)\n *\n * Day files are rebuilt idempotently; the per-day body hash recorded in\n * sync state lets unchanged days skip both the rewrite and the\n * (expensive) memory extraction. Sync state advances only after every\n * write for the run has succeeded.\n */\n\nimport { cleanConversation } from \"./cleanup.js\";\nimport { describeErrorForOperator, WearablesInputError } from \"./errors.js\";\nimport {\n applyCorrections,\n compileCorrectionRules,\n loadCorrectionsFile,\n type CompiledCorrectionRule,\n} from \"./corrections.js\";\nimport {\n composeDayTranscriptBody,\n composeDayTranscriptMeta,\n hashTranscriptBody,\n isValidTranscriptDate,\n serializeDayTranscript,\n} from \"./day-store.js\";\nimport {\n generateWearableMemories,\n importNativeMemories,\n writeDailyDigestMemory,\n type WearableMemoryGenDeps,\n} from \"./memory-gen.js\";\nimport { tokenizeDayBody, type CorroborationContext } from \"./trust.js\";\nimport { applyOffTheRecord, compileRedactionPatterns, redactText } from \"./redaction.js\";\nimport { loadSpeakerRegistry } from \"./speakers.js\";\nimport {\n loadSyncState,\n saveSyncState,\n updateSourceSyncState,\n} from \"./sync-state.js\";\nimport type {\n WearableConversation,\n WearableSourceConnector,\n WearableSourceSettings,\n WearableSyncSummary,\n WearablesConfig,\n} from \"./types.js\";\n\n/**\n * Pathological-provider backstop on pagination loops. Day fetches are\n * intentionally UNLIMITED for real data — a full day must never be\n * truncated — so runaway protection comes from cursor-cycle detection\n * plus this far-out-of-band ceiling, not from a content-sized cap.\n */\nconst PAGE_SAFETY_CEILING = 10_000;\n/** Default lookback window (today + yesterday) for unscoped syncs. */\nconst DEFAULT_SYNC_DAYS = 2;\nconst MAX_SYNC_DAYS = 90;\n\nexport interface WearableSyncOptions {\n /** Sync exactly this day (YYYY-MM-DD). Overrides `days`. */\n date?: string;\n /** Lookback window in days ending today (default 2, max 90). */\n days?: number;\n /** Re-run memory extraction even for unchanged days. */\n forceMemories?: boolean;\n signal?: AbortSignal;\n}\n\nexport interface WearableSyncDeps {\n /** Memory dir for state files (speakers, corrections, sync ledger). */\n memoryDir: string;\n /** Read the stored content hash for a day file, if present. */\n readDayContentHash(sourceId: string, date: string): Promise<string | null>;\n /** Persist a serialized day-transcript file (atomic). */\n writeDayTranscript(\n sourceId: string,\n date: string,\n serialized: string,\n ): Promise<void>;\n /**\n * Optional hook fired once after the sync wrote ANYTHING the search\n * index should see: day transcripts, created memories, in-place\n * promotions, or native imports. (A cross-source invalidation can\n * promote memories on a run with zero transcript writes — the index\n * must still refresh.)\n */\n afterWrites?(): Promise<void>;\n /**\n * Memory-generation dependencies, or null when no extraction engine\n * is available in this context (transcripts still sync; memory\n * creation is skipped with a warning when the mode wanted it).\n */\n memoryGen: WearableMemoryGenDeps | null;\n /**\n * Same-day transcript bodies from OTHER sources, for cross-device\n * corroboration in smart mode. Absent disables the boost.\n */\n readOtherSourceDayBodies?(\n date: string,\n excludeSource: string,\n ): Promise<Map<string, string>>;\n /**\n * Existing memories usable as support evidence: status \"active\" or\n * \"pending_review\" (explicit allow-list — a borderline fact observed\n * again on a later day is repetition signal, and the +0.10 boost is\n * how it earns promotion). Rejected/quarantined/superseded/archived/\n * forgotten rows are never support evidence.\n */\n listSupportMemories?(): Promise<Array<{ id: string; content: string }>>;\n /** Clock injection for tests. */\n now?: () => Date;\n}\n\n/** Format a Date as YYYY-MM-DD in the given IANA timezone. */\nexport function dateInTimezone(date: Date, timezone: string): string {\n try {\n const parts = new Intl.DateTimeFormat(\"en-CA\", {\n timeZone: timezone,\n year: \"numeric\",\n month: \"2-digit\",\n day: \"2-digit\",\n }).formatToParts(date);\n const get = (type: string) =>\n parts.find((part) => part.type === type)?.value ?? \"\";\n return `${get(\"year\")}-${get(\"month\")}-${get(\"day\")}`;\n } catch {\n return date.toISOString().slice(0, 10);\n }\n}\n\n/** Resolve the list of days to sync, oldest first. */\nexport function resolveSyncDates(\n options: WearableSyncOptions,\n timezone: string,\n now: Date,\n): string[] {\n if (options.date !== undefined) {\n if (!isValidTranscriptDate(options.date)) {\n throw new WearablesInputError(\n `wearables sync: invalid date '${options.date}' — expected YYYY-MM-DD`,\n );\n }\n return [options.date];\n }\n let days = DEFAULT_SYNC_DAYS;\n if (options.days !== undefined) {\n if (\n !Number.isFinite(options.days) ||\n !Number.isInteger(options.days) ||\n options.days < 1 ||\n options.days > MAX_SYNC_DAYS\n ) {\n throw new WearablesInputError(\n `wearables sync: invalid days '${options.days}' — expected an integer between 1 and ${MAX_SYNC_DAYS}`,\n );\n }\n days = options.days;\n }\n // Walk back by CALENDAR days from today's local date — subtracting\n // fixed 24h intervals from the wall clock can skip a local day\n // around DST transitions (Codex P2 on PR #1458).\n const dates: string[] = [];\n let cursor = dateInTimezone(now, timezone);\n for (let count = 0; count < days; count++) {\n dates.unshift(cursor);\n cursor = previousIsoDate(cursor);\n }\n return dates;\n}\n\n/** Previous calendar date in pure date arithmetic (no DST exposure). */\nfunction previousIsoDate(date: string): string {\n const parsed = new Date(`${date}T00:00:00Z`);\n parsed.setUTCDate(parsed.getUTCDate() - 1);\n return parsed.toISOString().slice(0, 10);\n}\n\nasync function fetchAllConversationsForDate(\n connector: WearableSourceConnector,\n date: string,\n timezone: string,\n signal: AbortSignal | undefined,\n warnings: string[],\n): Promise<{ conversations: WearableConversation[]; partial: boolean }> {\n // Keyed by conversation id: a looping or overlapping provider can\n // re-serve rows it already returned, and appending blindly would\n // store the same conversation twice in the day file (Cursor review\n // on PR #1464). Map keeps first-seen order; a re-served id replaces\n // its entry in place, so the provider's LATEST version of a\n // conversation wins — exactly what the current-day refresh wants.\n const byId = new Map<string, WearableConversation>();\n let cursor: string | null | undefined = undefined;\n const seenCursors = new Set<string>();\n const collect = () => [...byId.values()];\n for (let page = 0; page < PAGE_SAFETY_CEILING; page++) {\n const result = await connector.fetchConversations({\n date,\n timezone,\n cursor,\n signal,\n });\n for (const conversation of result.conversations) {\n byId.set(conversation.id, conversation);\n }\n if (!result.nextCursor) return { conversations: collect(), partial: false };\n // A repeated cursor means the provider's pagination is looping —\n // following it again would refetch the same page forever.\n if (seenCursors.has(result.nextCursor)) {\n warnings.push(\n `${connector.id}: provider pagination repeated cursor on ${date} — stopped to avoid an infinite loop; day may be partially synced (every sync refetches and re-warns while the provider misbehaves)`,\n );\n return { conversations: collect(), partial: true };\n }\n seenCursors.add(result.nextCursor);\n cursor = result.nextCursor;\n }\n warnings.push(\n `${connector.id}: stopped paginating ${date} after the ${PAGE_SAFETY_CEILING}-page safety ceiling — day may be partially synced (every sync refetches and re-warns while this persists)`,\n );\n return { conversations: collect(), partial: true };\n}\n\n/** Visible marker appended to day files whose fetch hit the page cap. */\nconst PARTIAL_DAY_MARKER =\n \"\\n*Note: pagination safety cap reached during sync — this day may be incomplete.*\\n\";\n\n/**\n * Explicit replacement body for a day whose provider data exists but\n * whose every segment was elided or dropped (all off-the-record, all\n * ASR garbage). Written so previously-stored content for the day stops\n * being searchable instead of lingering as a stale transcript.\n */\nfunction emptyDayBody(sourceId: string, date: string): string {\n return (\n `# ${sourceId} transcript — ${date}\\n\\n` +\n \"_No storable conversation content for this day (all segments were elided or dropped)._\\n\"\n );\n}\n\ninterface CleanedDay {\n conversations: WearableConversation[];\n segmentsKept: number;\n segmentsDropped: number;\n redactions: number;\n correctionsApplied: number;\n}\n\nfunction cleanDay(\n raw: WearableConversation[],\n sourceId: string,\n settings: WearableSourceSettings,\n config: WearablesConfig,\n userRedaction: RegExp[],\n correctionRules: CompiledCorrectionRule[],\n): CleanedDay {\n const { offTheRecordEnabled, redactionEnabled } = config;\n const out: CleanedDay = {\n conversations: [],\n segmentsKept: 0,\n segmentsDropped: 0,\n redactions: 0,\n correctionsApplied: 0,\n };\n for (const conversation of raw) {\n let current = conversation;\n if (offTheRecordEnabled) {\n const otr = applyOffTheRecord(current);\n current = otr.conversation;\n out.segmentsDropped += otr.droppedSegments;\n }\n const cleaned = cleanConversation(current, settings.cleanup);\n current = cleaned.conversation;\n out.segmentsDropped += cleaned.droppedSegments;\n\n const segments = current.segments.map((segment) => {\n let text = segment.text;\n if (redactionEnabled) {\n const redacted = redactText(text, userRedaction);\n text = redacted.text;\n out.redactions += redacted.redactions;\n }\n const corrected = applyCorrections(text, correctionRules, sourceId);\n out.correctionsApplied += corrected.applied;\n return { ...segment, text: corrected.text };\n });\n current = { ...current, segments };\n\n if (current.segments.length > 0) {\n out.conversations.push(current);\n out.segmentsKept += current.segments.length;\n }\n }\n return out;\n}\n\n/** Sync one source. */\nexport async function syncWearableSource(\n connector: WearableSourceConnector,\n settings: WearableSourceSettings,\n config: WearablesConfig,\n options: WearableSyncOptions,\n deps: WearableSyncDeps,\n): Promise<WearableSyncSummary> {\n const now = deps.now ? deps.now() : new Date();\n const timezone = config.timezone ?? defaultTimezone();\n const dates = resolveSyncDates(options, timezone, now);\n\n const summary: WearableSyncSummary = {\n source: connector.id,\n days: dates,\n conversations: 0,\n segmentsKept: 0,\n segmentsDropped: 0,\n redactions: 0,\n correctionsApplied: 0,\n transcriptsWritten: [],\n memoriesCreated: 0,\n memoriesPromoted: 0,\n memoriesDemoted: 0,\n memoriesSkipped: 0,\n memoriesBlocked: 0,\n nativeMemoriesImported: 0,\n warnings: [],\n };\n\n const registry = await loadSpeakerRegistry(deps.memoryDir);\n const stateRules = await loadCorrectionsFile(deps.memoryDir);\n const correctionRules = [\n ...compileCorrectionRules(config.corrections, \"wearables.corrections\"),\n ...compileCorrectionRules(stateRules, \"state corrections\"),\n ];\n const userRedaction = compileRedactionPatterns(config.redactionPatterns);\n\n let syncState = await loadSyncState(deps.memoryDir);\n const previousState = syncState.sources[connector.id];\n const dayHashes: Record<string, string> = {};\n const memoryDayHashes: Record<string, string> = {};\n const failedMemoryDays: string[] = [];\n const importedNativeIds: string[] = [];\n\n for (const date of dates) {\n const fetched = await fetchAllConversationsForDate(\n connector,\n date,\n timezone,\n options.signal,\n summary.warnings,\n );\n const cleaned = cleanDay(\n fetched.conversations,\n connector.id,\n settings,\n config,\n userRedaction,\n correctionRules,\n );\n summary.conversations += cleaned.conversations.length;\n summary.segmentsKept += cleaned.segmentsKept;\n summary.segmentsDropped += cleaned.segmentsDropped;\n summary.redactions += cleaned.redactions;\n summary.correctionsApplied += cleaned.correctionsApplied;\n\n if (fetched.conversations.length === 0) {\n // No provider data at all. A transient provider hiccup can\n // legitimately produce an empty result, so an existing stored\n // transcript is never auto-deleted here — surface it instead.\n const existing = await deps.readDayContentHash(connector.id, date);\n if (existing !== null) {\n summary.warnings.push(\n `${connector.id}: provider returned no conversations for ${date} but a stored transcript exists — leaving it in place; delete the day file manually if the recordings were intentionally removed upstream`,\n );\n }\n continue;\n }\n\n // Provider data exists but cleanup/off-the-record elided all of it:\n // replace any stored transcript with an explicit empty-day file so\n // elided content stops being stored and searchable (Codex P2 on PR\n // #1458).\n const allElided = cleaned.conversations.length === 0;\n let body = allElided\n ? emptyDayBody(connector.id, date)\n : composeDayTranscriptBody(\n connector.id,\n date,\n timezone,\n cleaned.conversations,\n registry,\n );\n if (fetched.partial && !allElided) {\n body += PARTIAL_DAY_MARKER;\n }\n const bodyHash = hashTranscriptBody(body);\n // The on-disk file is the authority for the skip decision — a hash\n // remembered in sync state must never suppress recreating a day\n // file that was deleted or lost (Cursor review on PR #1458). The\n // state's dayHashes remain as bookkeeping only.\n const existingHash = await deps.readDayContentHash(connector.id, date);\n const changed = existingHash !== bodyHash;\n // An all-elided day only writes a replacement over an existing\n // file; it never creates an empty-day file from nothing.\n const shouldWrite = changed && (!allElided || existingHash !== null);\n\n if (shouldWrite) {\n const meta = composeDayTranscriptMeta(\n connector.id,\n date,\n timezone,\n cleaned.conversations,\n registry,\n body,\n now.toISOString(),\n );\n await deps.writeDayTranscript(\n connector.id,\n date,\n serializeDayTranscript(meta, body),\n );\n summary.transcriptsWritten.push(date);\n }\n dayHashes[date] = bodyHash;\n\n if (allElided) continue;\n\n const needsSmartContext =\n settings.memoryMode === \"smart\" || settings.importNativeMemories === \"smart\";\n\n // The memory pass runs when the day changed, when forced, or when\n // the last pass for this exact content didn't complete cleanly —\n // a sync that stored the transcript but failed mid-memory-write\n // self-heals on the next run instead of being frozen out by the\n // unchanged-day skip (Cursor review on PR #1458).\n const memoryPassComplete =\n previousState?.memoryDayHashes?.[date] === bodyHash;\n if (\n settings.memoryMode !== \"off\" &&\n (changed || options.forceMemories === true || !memoryPassComplete)\n ) {\n if (!deps.memoryGen) {\n summary.warnings.push(\n `${connector.id}: memoryMode is '${settings.memoryMode}' but no extraction engine is available in this context — transcripts synced, memories skipped`,\n );\n } else {\n // The whole memory pass (extraction, fact writes, digest) is\n // warn-and-retry rather than abort: the transcript is already\n // stored, and aborting here would leave any stale completion\n // record from an earlier clean run in place to mask the\n // failure (Kilo review on PR #1458 for the digest case; fact\n // writes share the same failure class). A clean pass records\n // completion; anything else clears it so the next sync\n // re-runs the day.\n let passClean = false;\n try {\n const corroboration = needsSmartContext\n ? await buildCorroborationContext(connector.id, date, deps)\n : undefined;\n const dayMemoryGen: WearableMemoryGenDeps = {\n ...deps.memoryGen,\n ...(corroboration !== undefined ? { corroboration } : {}),\n };\n const generated = await generateWearableMemories(\n connector.id,\n date,\n cleaned.conversations,\n settings,\n registry,\n dayMemoryGen,\n );\n summary.memoriesCreated += generated.created;\n summary.memoriesPromoted += generated.promoted;\n summary.memoriesDemoted += generated.demoted;\n summary.memoriesSkipped += generated.skipped;\n summary.memoriesBlocked += generated.tombstoneBlocked;\n summary.warnings.push(...generated.warnings);\n // Degraded-but-complete passes (e.g. judge unavailable) still\n // record completion — only an aborted extraction should force\n // the day to re-run on the next sync (Cursor review on PR\n // #1462).\n passClean = generated.completed;\n const { digestEnabled } = config;\n if (digestEnabled) {\n const wrote = await writeDailyDigestMemory(\n connector.id,\n date,\n cleaned.conversations,\n settings,\n registry,\n deps.memoryGen.writer,\n );\n if (wrote) summary.memoriesCreated += 1;\n }\n } catch (err) {\n passClean = false;\n summary.warnings.push(\n `${connector.id}: memory pass failed for ${date}: ${describeErrorForOperator(err)} — retries on the next sync`,\n );\n }\n if (passClean) {\n memoryDayHashes[date] = bodyHash;\n } else {\n failedMemoryDays.push(date);\n }\n }\n } else if (settings.memoryMode !== \"off\" && memoryPassComplete) {\n // Carry the completion record forward for unchanged days.\n memoryDayHashes[date] = bodyHash;\n }\n }\n\n if (\n settings.importNativeMemories !== \"off\" &&\n typeof connector.fetchNativeMemories === \"function\"\n ) {\n if (!deps.memoryGen) {\n summary.warnings.push(\n `${connector.id}: importNativeMemories is enabled but no memory writer is available in this context`,\n );\n } else {\n const alreadyImported = new Set(\n previousState?.importedNativeMemoryIds ?? [],\n );\n // Native memories carry no day, so same-day cross-device\n // corroboration does not apply to them — scoring a provider fact\n // against an arbitrary day's tokens would be wrong-day evidence\n // (Cursor review on PR #1462). They keep only the day-independent\n // existing-memory support boost.\n const nativeCorroboration =\n settings.importNativeMemories === \"smart\"\n ? {\n otherSourceDayTokens: new Map<string, Set<string>>(),\n existingMemories: deps.listSupportMemories\n ? await deps.listSupportMemories()\n : [],\n }\n : undefined;\n const nativeMemoryGen: WearableMemoryGenDeps = {\n ...deps.memoryGen,\n ...(nativeCorroboration !== undefined\n ? { corroboration: nativeCorroboration }\n : {}),\n };\n let cursor: string | null | undefined = undefined;\n const seenNativeCursors = new Set<string>();\n for (let page = 0; page < PAGE_SAFETY_CEILING; page++) {\n const result = await connector.fetchNativeMemories({\n cursor,\n signal: options.signal,\n });\n const imported = await importNativeMemories(\n connector.id,\n result.memories,\n alreadyImported,\n settings,\n nativeMemoryGen,\n );\n summary.warnings.push(...imported.warnings);\n summary.nativeMemoriesImported += imported.imported;\n summary.memoriesBlocked += imported.tombstoneBlocked;\n importedNativeIds.push(...imported.importedIds);\n for (const id of imported.importedIds) alreadyImported.add(id);\n if (!result.nextCursor) break;\n if (seenNativeCursors.has(result.nextCursor)) {\n summary.warnings.push(\n `${connector.id}: provider pagination repeated cursor during native-memory import — stopped to avoid an infinite loop; remaining items import on the next sync`,\n );\n break;\n }\n seenNativeCursors.add(result.nextCursor);\n cursor = result.nextCursor;\n if (page === PAGE_SAFETY_CEILING - 1) {\n summary.warnings.push(\n `${connector.id}: stopped native-memory import at the ${PAGE_SAFETY_CEILING}-page safety ceiling — remaining items import on the next sync`,\n );\n }\n }\n }\n }\n\n const wroteAnything =\n summary.transcriptsWritten.length > 0 ||\n summary.memoriesCreated > 0 ||\n summary.memoriesPromoted > 0 ||\n summary.memoriesDemoted > 0 ||\n summary.memoriesBlocked > 0 ||\n summary.nativeMemoriesImported > 0;\n if (wroteAnything && deps.afterWrites) {\n try {\n await deps.afterWrites();\n } catch (err) {\n summary.warnings.push(\n `search reindex failed (writes are stored and will index on the next update): ${describeErrorForOperator(err)}`,\n );\n }\n }\n\n // Watermark advances only now — after transcript writes, memory\n // writes, and native imports all succeeded.\n syncState = updateSourceSyncState(syncState, connector.id, {\n syncedAt: now.toISOString(),\n days: dates,\n dayHashes,\n memoryDayHashes,\n clearMemoryDays: failedMemoryDays,\n importedNativeMemoryIds: importedNativeIds,\n });\n // New same-day evidence invalidates OTHER sources' memory-pass\n // completion for the days this source just (re)wrote: their next\n // sync re-scores with this transcript available, and the promotion\n // path upgrades earlier borderline writes in place (Cursor review on\n // PR #1462).\n if (summary.transcriptsWritten.length > 0) {\n const cleared: typeof syncState.sources = {};\n for (const [otherId, otherState] of Object.entries(syncState.sources)) {\n if (otherId === connector.id || otherState.memoryDayHashes === undefined) {\n cleared[otherId] = otherState;\n continue;\n }\n const memoryDays = { ...otherState.memoryDayHashes };\n let touched = false;\n for (const date of summary.transcriptsWritten) {\n if (date in memoryDays) {\n delete memoryDays[date];\n touched = true;\n }\n }\n cleared[otherId] = touched\n ? { ...otherState, memoryDayHashes: memoryDays }\n : otherState;\n }\n syncState = { version: 1, sources: cleared };\n }\n await saveSyncState(deps.memoryDir, syncState);\n\n return summary;\n}\n\n/**\n * Assemble smart-mode corroboration evidence: other sources' same-day\n * transcript tokens + existing active memories. The memory list loads\n * fresh per day (not per run) so facts written on earlier days of a\n * multi-day backfill are visible as support evidence on later days —\n * the underlying readAllMemories is cached in storage and invalidated\n * by writes, so the per-day refresh is cheap (Cursor review on PR\n * #1462).\n */\nasync function buildCorroborationContext(\n sourceId: string,\n date: string,\n deps: WearableSyncDeps,\n): Promise<CorroborationContext> {\n const otherSourceDayTokens = new Map<string, Set<string>>();\n if (deps.readOtherSourceDayBodies) {\n const bodies = await deps.readOtherSourceDayBodies(date, sourceId);\n for (const [otherSource, body] of bodies) {\n otherSourceDayTokens.set(otherSource, tokenizeDayBody(body));\n }\n }\n const existingMemories = deps.listSupportMemories\n ? await deps.listSupportMemories()\n : [];\n return { otherSourceDayTokens, existingMemories };\n}\n\nexport function defaultTimezone(): string {\n try {\n return Intl.DateTimeFormat().resolvedOptions().timeZone || \"UTC\";\n } catch {\n return \"UTC\";\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/serialize-mutations.ts"],"sourcesContent":["// ---------------------------------------------------------------------------\n// Shared serialized-mutation utilities for TOCTOU hotspots (issue #1524).\n//\n// Two complementary primitives that the namespace catalog (`queueCritical` +\n// `withHeldCatalogLock`), the storage router's resolve-hook serialization, and\n// the summary-snapshot writer each re-implement today:\n//\n// 1. `serializeMutations(key, task)` — keyed IN-PROCESS async serialization\n// that recovers after a rejection (CLAUDE.md rule #40). One failed task\n// never poisons the tasks queued behind it; the failed task's error is\n// still surfaced to ITS caller.\n//\n// 2. `withHeldFileLock(lockPath, opts, task)` — a held CROSS-PROCESS file\n// lock with replacement-safe stale breaking (the NG7Bg invariant from\n// #1506 round 28) and ownership-checked release.\n//\n// This is the UTILITY module only. Per-issue PR split: one PR for the utility\n// + tests (this file), then one PR per adoption hotspot (catalog, router\n// provenance, summary snapshot). No adoptions live here.\n// ---------------------------------------------------------------------------\n\nimport { randomUUID } from \"node:crypto\";\nimport { link, mkdir, open, readFile, rename, stat, unlink, utimes } from \"node:fs/promises\";\nimport path from \"node:path\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 1. serializeMutations — keyed async serialization with rejection recovery\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * One entry in the per-key serialization map. `tail` is the recovered promise\n * the next queued task chains off of; it never rejects (both settle handlers\n * swallow), so a prior task's failure can never break subsequent ones.\n */\ninterface MutationChainEntry {\n tail: Promise<void>;\n}\n\n/**\n * Instance-scoped keyed serializer. Holds the per-key chain map so that all\n * tasks queued under the same key on the SAME serializer run strictly in order.\n *\n * The map is instance-scoped (not module-level) so tests can construct a fresh\n * serializer per case and avoid cross-test contamination, and so adopters that\n * want isolation (e.g. one serializer per storage root) can have it. The free\n * {@link serializeMutations} export delegates to a single shared default\n * instance for callers that want process-wide serialization.\n */\nexport class MutationSerializer {\n private readonly chains = new Map<string, MutationChainEntry>();\n\n /**\n * Run `task` strictly after every other task already queued under `key` on\n * this serializer has settled.\n *\n * Rejection recovery (rule #40, mirroring the catalog's `queueCritical`):\n * if a prior task rejects, later tasks STILL RUN, while the rejecting task's\n * error is surfaced to ITS OWN caller. Concretely, the recovered tail is\n * `run.then(noop, noop)` — never a bare `.then(fn)`, which would let one\n * failure kill every queued task behind it.\n *\n * No unbounded growth: when a chain's last task settles and no newer task\n * chained onto it, its entry is deleted (the storage router's\n * `inFlightResolved` marker-then-clear discipline).\n */\n serialize<T>(key: string, task: () => Promise<T>): Promise<T> {\n if (typeof key !== \"string\" || key.length === 0) {\n throw new TypeError(\"MutationSerializer.serialize: key must be a non-empty string\");\n }\n if (typeof task !== \"function\") {\n throw new TypeError(\"MutationSerializer.serialize: task must be a function returning a promise\");\n }\n\n let entry = this.chains.get(key);\n if (!entry) {\n entry = { tail: Promise.resolve() };\n this.chains.set(key, entry);\n }\n\n // Chain this task off the prior tail. `tail.then(task)` runs task only once\n // the previous task has settled, preserving read-modify-write ordering.\n const run = entry.tail.then(task);\n\n // Recover the tail after a rejection so a failed task never poisons later\n // ones. Both handlers swallow; `run` still carries the original resolution\n // (or rejection) to THIS caller. This is the line a naive `.then(fn)`\n // implementation omits — see the \"naive poison chain\" prove-fail test.\n const recovered = run.then(settleNoop, settleNoop);\n entry.tail = recovered;\n\n // Self-cleaning: once our recovered tail settles, if no newer task chained\n // onto us the entry still points at `recovered` and is safe to delete. A\n // concurrent `serialize()` call enqueues synchronously and would have\n // replaced `entry.tail` BEFORE this microtask runs, so the identity check\n // is race-free (no newer task's entry can be wrongly removed).\n //\n // `recovered` cannot reject in correct operation (both handlers above\n // swallow) and the cleanup body cannot throw — but we attach a rejection\n // handler anyway so that IF the recovery invariant is ever broken, the\n // failure surfaces as a behavioral assertion (skipped tasks) rather than an\n // unhandled-rejection storm that masks which task failed. The handler is a\n // no-op: cleanup only runs on fulfillment.\n void recovered.then(\n () => {\n if (entry && entry.tail === recovered) {\n this.chains.delete(key);\n }\n },\n () => undefined,\n );\n\n return run;\n }\n\n /**\n * Test-only: the number of keys with a not-yet-cleaned chain. Used to assert\n * the no-unbounded-growth invariant. Not part of the public contract.\n */\n pendingKeysForTest(): number {\n return this.chains.size;\n }\n}\n\n/**\n * Recovery handler shared by both settle arms. Named (not inline\n * `() => undefined`) so the chain assignment stays self-documenting in stack\n * traces and the review-patterns poison-chain check can see the chain is\n * recovered, not bare `.then(fn)`.\n */\nfunction settleNoop(): void {\n /* swallow — the original resolution/rejection is carried by `run` */\n}\n\n/**\n * Process-wide default serializer backing the free {@link serializeMutations}\n * export. Lazy so it is only created when first used (tests that construct\n * their own `MutationSerializer` pay nothing).\n */\nlet defaultSerializer: MutationSerializer | undefined;\n\n/**\n * Free-function entry point (issue #1524 signature). Serializes `task` against\n * every other task queued under `key` across the whole process, via a shared\n * default {@link MutationSerializer}. For isolated/testable serialization,\n * construct a `MutationSerializer` directly.\n */\nexport function serializeMutations<T>(key: string, task: () => Promise<T>): Promise<T> {\n if (!defaultSerializer) defaultSerializer = new MutationSerializer();\n return defaultSerializer.serialize(key, task);\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 2. withHeldFileLock — cross-process held file lock with stale breaking\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Options for {@link withHeldFileLock}. */\nexport interface HeldFileLockOptions {\n /**\n * A lock whose mtime is older than this (in ms) is treated as a crashed\n * holder and broken. Required — there is no safe default, since the right\n * value depends on how long the guarded critical section can legitimately\n * run.\n */\n readonly staleMs: number;\n /**\n * Bounded acquisition: give up trying to acquire a busy lock after this long\n * (ms) and invoke `task(false)` best-effort WITHOUT holding the lock, rather\n * than blocking forever or crashing the primary op. Default 5000ms (matches\n * the namespace catalog's `REBUILD_LOCK_MAX_WAIT_MS`).\n */\n readonly maxWaitMs?: number;\n /**\n * Poll interval (ms) while waiting for a busy lock to clear. Default 50ms.\n */\n readonly pollMs?: number;\n /**\n * While WE hold the lock, refresh its mtime on this cadence (ms) so a\n * legitimately long task is not mistaken for a crashed holder and broken out\n * from under. Default `floor(staleMs / 3)` (at least 100ms), mirroring the\n * catalog heartbeat ratio. Must be comfortably below `staleMs`.\n */\n readonly heartbeatMs?: number;\n /**\n * Test seam (NG7Bg, #1506 round 28): fires AFTER a lock is judged stale and\n * BEFORE the re-verify + unlink, simulating a replacement lock being created\n * in the race window. No-op in production.\n */\n readonly onBeforeBreakStaleUnlinkForTest?: () => Promise<void> | void;\n /**\n * Test seam (codex P2): fires AFTER the release rename moves the lock to a\n * trash path and BEFORE the ownership re-verify/restore — simulating a third\n * contender acquiring the (now-empty) lockPath in the race window. No-op in\n * production. Used to prove the pre-check prevents the rename entirely.\n */\n readonly onAfterReleaseRenameForTest?: () => Promise<void> | void;\n /**\n * Best-effort hook for non-fatal lock warnings (heartbeat refresh failure,\n * release-time ownership check failure). Never throws into the caller. If\n * omitted, warnings are swallowed (the lock is advisory; release/heartbeat\n * failures must never crash the guarded op).\n */\n readonly onLockWarning?: (message: string, err: unknown) => void;\n}\n\n/** Default bounded acquisition wait, mirroring the catalog. */\nconst DEFAULT_MAX_WAIT_MS = 5_000;\n/** Default busy-lock poll interval, mirroring the catalog. */\nconst DEFAULT_POLL_MS = 50;\n/** Floor for the derived heartbeat cadence. */\nconst MIN_HEARTBEAT_MS = 100;\n/** Node's setTimeout/setInterval 32-bit signed-int ceiling (2^31 − 1 ms ≈ 24.8\n * days). Delays above this are silently clamped to 1ms by the Node timer, so\n * timer-backed options (pollMs, heartbeatMs) must be rejected at this boundary\n * (chatgpt-codex-connector P2). */\nconst MAX_TIMER_DELAY_MS = 2_147_483_647;\n\n/** Internal handle for a lock we successfully acquired. */\ninterface HeldLock {\n readonly path: string;\n readonly ownerId: string;\n}\n\n/**\n * Run `task` under an exclusive on-disk lock at `lockPath`.\n *\n * Cross-process mutex via `open(lockPath, \"wx\")` (atomic exclusive create).\n * While held, a heartbeat timer refreshes the lock's mtime so a legitimately\n * long task is not mistaken for a crashed holder and broken out from under. A\n * lock older than `opts.staleMs` is treated as stale and broken — but\n * REPLACEMENT-SAFE (NG7Bg): we capture the stale lock's identity (full content\n * line: `<pid> <owner-uuid> <iso>`) when judging it stale, then RE-READ and\n * RE-STAT immediately before `unlink`, deleting only if byte-identical AND\n * still stale. A replacement lock created in the window has a different owner\n * id / timestamp, so its content differs and is left untouched.\n *\n * `task` receives `acquired: boolean` — `true` when we hold the lock, `false`\n * when acquisition timed out (best-effort). The signature takes\n * `(acquired) => Promise<T>` rather than the issue's sketched `() => Promise<T>`\n * so this can be the SINGLE lock home (issue: \"do NOT leave two lock\n * implementations; pick one home\"): the catalog's touch path needs to DROP on\n * timeout, which requires knowing whether the lock was acquired. A caller that\n * ignores the flag is still assignable (`() => Promise<T>` ⊆\n * `(acquired: boolean) => Promise<T>` in TypeScript).\n *\n * Release is ownership-checked: we only `unlink` a lock whose content still\n * identifies THIS acquirer (same owner id), so a replacement created after we\n * stopped heartbeating is never destroyed — mirroring the catalog's\n * `rebuildLockHeldBySelf`.\n *\n * ADOPTION NOTE: lock only the brief final read-merge-write window, never a\n * long scan — a scan-length lock makes concurrent writers time out and\n * silently drop work (catalog round 5, codex/cursor P2).\n */\nexport async function withHeldFileLock<T>(\n lockPath: string,\n opts: HeldFileLockOptions,\n task: (acquired: boolean) => Promise<T>,\n): Promise<T> {\n if (typeof lockPath !== \"string\" || lockPath.length === 0) {\n throw new TypeError(\"withHeldFileLock: lockPath must be a non-empty string\");\n }\n if (typeof opts?.staleMs !== \"number\" || !Number.isFinite(opts.staleMs) || opts.staleMs <= 0) {\n throw new TypeError(\n `withHeldFileLock: opts.staleMs must be a positive finite number ` +\n `(valid range: > 0 ms, finite; got ${formatInvalidNumber(opts?.staleMs)}).`,\n );\n }\n\n // Validate optional timings: a NaN/Infinity here is a real hazard (e.g.\n // `Date.now() + NaN` === NaN, so `Date.now() >= deadline` is always false and\n // the bounded acquire loop would wait forever instead of falling back to\n // best-effort). Reject invalid input rather than silently defaulting it\n // (codex P2 review). Omitting an option still picks its default.\n const maxWaitMs = optionalPositiveMs(opts.maxWaitMs, \"maxWaitMs\", DEFAULT_MAX_WAIT_MS, MAX_TIMER_DELAY_MS);\n const pollMs = optionalPositiveMs(opts.pollMs, \"pollMs\", DEFAULT_POLL_MS, MAX_TIMER_DELAY_MS);\n const heartbeatMs = optionalPositiveMs(\n opts.heartbeatMs,\n \"heartbeatMs\",\n Math.max(MIN_HEARTBEAT_MS, Math.floor(opts.staleMs / 3)),\n MAX_TIMER_DELAY_MS,\n );\n if (heartbeatMs >= opts.staleMs) {\n throw new TypeError(\n `withHeldFileLock: heartbeatMs (${heartbeatMs}) must be below staleMs (${opts.staleMs}) ` +\n `(valid range: > 0 and < staleMs ms) so at least one heartbeat lands per stale window.`,\n );\n }\n if (heartbeatMs > MAX_TIMER_DELAY_MS) {\n throw new TypeError(\n `withHeldFileLock: derived heartbeatMs (${heartbeatMs} = floor(staleMs/3)) exceeds ` +\n `Node's setTimeout ceiling (${MAX_TIMER_DELAY_MS} ms). Use an explicit opts.heartbeatMs ` +\n `at or below ${MAX_TIMER_DELAY_MS} ms.`,\n );\n }\n // Wrap the consumer's warning hook so a throwing callback never turns a\n // non-fatal advisory lock warning into an unhandled rejection (heartbeat\n // catch handler) or overrides the task's result (release path). The option\n // is documented as never throwing into the caller; enforce that here\n // (codex P2 review).\n const rawWarn = opts.onLockWarning;\n const warn = (message: string, err: unknown): void => {\n if (!rawWarn) return;\n try {\n rawWarn(message, err);\n } catch {\n /* swallow — a throwing advisory hook must not crash the guarded op */\n }\n };\n\n // Per-call owner identity. Two withHeldFileLock calls in the SAME process\n // get different ids, so neither mistakes the other's lock for its own\n // (stronger than the catalog's per-instance id, which is what we want for a\n // stateless utility).\n const ownerId = randomUUID();\n const lockDir = path.dirname(lockPath);\n\n const held = await acquireLock(lockPath, lockDir, ownerId, opts, maxWaitMs, pollMs);\n if (!held) {\n // Best-effort: run the task WITHOUT the lock. The caller decides what to\n // do (the catalog touch path will drop its append); we never crash the\n // primary op on contention.\n return task(false);\n }\n\n // Heartbeat: while WE hold the lock, refresh its mtime so age-based stale\n // detection sees an active holder and does not break us out from under\n // (catalog round 5). Failures are swallowed (advisory lock); the timer is\n // always cleared in the finally.\n //\n // OWNERSHIP CHECK (codex P2): if our event loop was paused long enough that\n // another process judged us stale, broke our lock, and created a replacement,\n // we must NOT refresh the replacement's mtime — that would keep a (possibly\n // crashed) replacement looking fresh. Verify lockHeldBySelf before each\n // utimes; if ownership is lost, stop heartbeating (our lock is gone).\n const heartbeat = setInterval(() => {\n lockHeldBySelf(held)\n .then((ours) => {\n if (!ours) return; // broken/replaced — stop refreshing\n return utimes(held.path, new Date(), new Date());\n })\n .catch((err: unknown) => {\n warn(\"withHeldFileLock heartbeat refresh failed\", err);\n });\n }, heartbeatMs);\n // Don't keep the event loop alive solely for the heartbeat.\n heartbeat.unref?.();\n try {\n return await task(true);\n } finally {\n clearInterval(heartbeat);\n await releaseLock(held, warn, opts.onAfterReleaseRenameForTest);\n }\n}\n\n/**\n * Resolve an optional millisecond timing option, REJECTING invalid values\n * (NaN, Infinity, non-positive, or above `maxMs`) rather than silently defaulting\n * them. A NaN or Infinity maxWaitMs would make the bounded acquire loop wait\n * forever (`Date.now() + NaN` is NaN); a non-positive poll/heartbeat makes no\n * sense. Timer-backed options (pollMs, heartbeatMs) are bounded to Node's\n * setTimeout ceiling (`MAX_TIMER_DELAY_MS`): a value above 2^31−1 is silently\n * clamped to 1ms by the timer, turning a typo into tight polling (codex P2).\n * Omitting the option (`undefined`) picks `fallback`. Non-number types are also\n * rejected (defensive against config/env coercion).\n */\nfunction optionalPositiveMs(\n value: number | undefined,\n name: \"maxWaitMs\" | \"pollMs\" | \"heartbeatMs\",\n fallback: number,\n maxMs: number,\n): number {\n if (value === undefined) return fallback;\n if (typeof value !== \"number\" || !Number.isFinite(value) || value <= 0) {\n throw new TypeError(\n `withHeldFileLock: opts.${name} must be a positive finite number ` +\n `(valid range: > 0 ms, finite; got ${formatInvalidNumber(value)}). ` +\n `Omit the option to use the default of ${fallback} ms.`,\n );\n }\n if (value > maxMs) {\n throw new TypeError(\n `withHeldFileLock: opts.${name} (${value} ms) exceeds the ${maxMs} ms ` +\n `ceiling (Node's setTimeout clamps larger delays to 1ms, turning a ` +\n `typo into tight polling). Omit the option to use the default of ${fallback} ms.`,\n );\n }\n return value;\n}\n\n/**\n * Human-readable label for a rejected numeric input. Makes the error message\n * immediately actionable for NaN/Infinity (which print as \"NaN\"/\"Infinity\" via\n * String() but are easier to triage with an explicit sign), and surfaces the\n * actual type for non-number values (defensive against config/env coercion).\n */\nfunction formatInvalidNumber(value: unknown): string {\n if (typeof value === \"number\") {\n if (Number.isNaN(value)) return \"NaN\";\n if (value === Infinity) return \"+Infinity\";\n if (value === -Infinity) return \"-Infinity\";\n return String(value);\n }\n return `${typeof value} ${JSON.stringify(value)}`;\n}\n\n/**\n * Atomically create the lock file, looping until acquired/stale-broken/timeout.\n * Returns the held-lock handle on success, or `undefined` on bounded-timeout.\n * Unexpected FS errors proceed best-effort (return undefined) rather than\n * crashing the guarded op, matching the catalog.\n */\nasync function acquireLock(\n lockPath: string,\n lockDir: string,\n ownerId: string,\n opts: HeldFileLockOptions,\n maxWaitMs: number,\n pollMs: number,\n): Promise<HeldLock | undefined> {\n try {\n await mkdir(lockDir, { recursive: true });\n } catch {\n // Lock-directory setup failure (e.g. an intermediate path is a file, or\n // permissions deny mkdir) must NOT crash the guarded op — the advisory\n // lock contract is best-effort. Return undefined so task(false) runs\n // instead of rejecting (codex P2 review).\n return undefined;\n }\n const deadline = Date.now() + maxWaitMs;\n for (;;) {\n try {\n const handle = await open(lockPath, \"wx\");\n let wroteMeta = true;\n try {\n await handle.writeFile(`${process.pid} ${ownerId} ${new Date().toISOString()}\\n`, \"utf8\");\n } catch {\n // The metadata write failed; the lock file may be empty or partial.\n // Our ownership check on release would NOT find this ownerId, leaving\n // a malformed lock that lingers until stale and blocks other callers\n // out of the mutex (codex P2). Undo our exclusive create and report\n // acquisition failure so the caller runs best-effort instead.\n wroteMeta = false;\n } finally {\n try {\n await handle.close();\n } catch {\n // close() can report a deferred I/O error (e.g. write that appeared\n // to succeed but failed on flush). The lock file may be malformed —\n // treat it as a metadata-write failure so the cleanup path unlinks\n // the orphaned lock (codex P2 review).\n wroteMeta = false;\n }\n }\n if (!wroteMeta) {\n await unlink(lockPath).catch(() => undefined);\n return undefined;\n }\n return { path: lockPath, ownerId };\n } catch (err) {\n if ((err as NodeJS.ErrnoException | undefined)?.code !== \"EEXIST\") {\n // Unexpected FS error — proceed best-effort without the lock.\n return undefined;\n }\n // Lock exists: break it if stale, then poll. breakStaleLock is\n // replacement-safe (NG7Bg) and never throws.\n await breakStaleLock(lockPath, opts.staleMs, opts.onBeforeBreakStaleUnlinkForTest);\n if (Date.now() >= deadline) return undefined;\n // Cap the sleep to the remaining budget so a large pollMs cannot block\n // acquisition far past maxWaitMs (e.g. maxWaitMs=1000, pollMs=60000\n // would otherwise block ~60s instead of 1s — codex P2).\n await sleep(Math.min(pollMs, deadline - Date.now()));\n }\n }\n}\n\n/**\n * Replacement-safe stale-lock breaking (NG7Bg, #1506 round 28). Capture the\n * lock's identity when judging it stale, then ATOMICALLY rename it to a unique\n * trash path and verify the moved content matches. A replacement lock created\n * in the race window is either left untouched (different identity at\n * lockPath, so the rename moves the stale lock — not the replacement) or\n * restored (if the rename accidentally moves a replacement, the verify\n * detects the mismatch and renames it back).\n *\n * ATOMICITY (codex P2): `rename` is atomic on POSIX — only ONE contender can\n * successfully rename a given file. This eliminates the TOCTOU between the\n * identity/stat checks and the deletion that a bare `unlink` leaves open:\n * without rename, contender A could verify identity X, pause, then unlink\n * contender B's freshly acquired replacement Y. With rename, A moves whatever\n * is at lockPath, then checks: if it is X, A broke the stale lock; if it is\n * not X (a replacement appeared between A's last check and the rename), A\n * restores it.\n */\nasync function breakStaleLock(\n lockPath: string,\n staleMs: number,\n onBeforeBreakStaleUnlinkForTest: (() => Promise<void> | void) | undefined,\n): Promise<void> {\n let staleIdentity: string;\n try {\n const info = await stat(lockPath);\n if (Date.now() - info.mtimeMs <= staleMs) {\n // Not stale (a live holder's heartbeat keeps it fresh) — leave it.\n return;\n }\n staleIdentity = await readFile(lockPath, \"utf8\");\n } catch {\n // Lock vanished (released by holder) or stat/read failed — nothing to do.\n return;\n }\n // Test seam: simulate a replacement lock being created in the race window\n // between the staleness judgment and the atomic break. No-op in production.\n if (onBeforeBreakStaleUnlinkForTest) {\n await onBeforeBreakStaleUnlinkForTest();\n }\n try {\n // Re-validate immediately before breaking: the lock must still carry the\n // SAME identity AND still be stale.\n const current = await readFile(lockPath, \"utf8\");\n if (current !== staleIdentity) return; // replaced — leave the fresh lock\n const recheck = await stat(lockPath);\n if (Date.now() - recheck.mtimeMs <= staleMs) return; // heartbeat refreshed it\n\n // ATOMIC BREAK: rename is atomic on POSIX. Only one contender succeeds;\n // others get ENOENT (the file is already gone). After the rename, verify\n // the moved content: if it matches staleIdentity we broke the right lock;\n // if it does not, a replacement appeared in the window and we restore it.\n const trashPath = `${lockPath}.breaking.${process.pid}.${Date.now()}`;\n await rename(lockPath, trashPath);\n try {\n const moved = await readFile(trashPath, \"utf8\");\n if (moved !== staleIdentity) {\n // We accidentally moved a replacement lock (created between our last\n // check and the rename). Restore it so the replacement holder's lock\n // survives. Use link (not rename) to AVOID overwriting a fresh lock\n // that a third contender may have acquired at lockPath while the file\n // was in trash: link fails with EEXIST if lockPath exists, leaving\n // the third contender's lock intact (codex P2 review).\n try {\n await link(trashPath, lockPath);\n // link succeeded — remove the redundant trash hard link. The lock\n // now lives only at lockPath.\n await unlink(trashPath).catch(() => undefined);\n } catch {\n // lockPath already exists (a third contender acquired it). Do NOT\n // unlink the moved file — it may be a LIVE lock whose holder is\n // still in its critical section. Destroying it would leave the\n // holder running with no visible lock, breaking mutual exclusion\n // (codex P2). Leave it in trash as a breadcrumb; it is not at\n // lockPath so it does not block other contenders.\n }\n } else {\n // Content matches — but verify the moved file is STILL stale. The\n // original holder may have resumed and heartbeated between our\n // pre-rename stat() and the rename, refreshing the mtime. If so, the\n // holder is live: restore the lock instead of deleting it (codex P2).\n const movedStat = await stat(trashPath);\n if (Date.now() - movedStat.mtimeMs <= staleMs) {\n // Mtime was refreshed — the holder resumed. Restore the lock.\n try {\n await link(trashPath, lockPath);\n await unlink(trashPath).catch(() => undefined);\n } catch {\n // lockPath already exists — another contender acquired it. Do NOT\n // unlink the moved file (it may be a live lock). Leave it in trash.\n }\n } else {\n // Still stale — we broke the right lock. Clean up the trash.\n await unlink(trashPath).catch(() => undefined);\n }\n }\n } catch {\n // Could not read the trash file — clean it up best-effort.\n await unlink(trashPath).catch(() => undefined);\n }\n } catch {\n // The lock changed/vanished between checks — another process handled it.\n }\n}\n\n/**\n * Release the lock ONLY if its content still identifies THIS acquirer (same\n * owner id). Two-stage ownership check:\n *\n * 1. PRE-CHECK (chatgpt-codex-connector P2): read lockPath BEFORE renaming.\n * If the lock is already a replacement (a contender broke our stale lock),\n * return WITHOUT renaming — renaming a replacement out of lockPath leaves\n * it empty, letting a third contender acquire while the replacement holder\n * is still active. The replacement is safe at lockPath; leave it alone.\n *\n * 2. ATOMIC CLAIM: if the pre-check saw our ownerId, rename lockPath→trash\n * (POSIX-atomic) and re-verify on the moved file. A replacement could\n * appear between the pre-check and the rename; if the moved file is no\n * longer ours, restore it via link (non-overwriting). This ties the\n * ownership check to the deletion so a bare readFile-then-unlink TOCTOU\n * cannot delete a fresh replacement (codex P2).\n */\nasync function releaseLock(\n held: HeldLock,\n warn: (message: string, err: unknown) => void,\n onAfterReleaseRenameForTest: (() => Promise<void> | void) | undefined,\n): Promise<void> {\n try {\n // PRE-CHECK (chatgpt-codex-connector P2): read lockPath before renaming. If\n // the lock is no longer ours, a contender broke our stale lock and created a\n // replacement. Return WITHOUT renaming — renaming the replacement out of\n // lockPath leaves it empty, so a third contender could acquire while the\n // replacement holder is still active. The replacement is safe at lockPath.\n let precheck: string;\n try {\n precheck = await readFile(held.path, \"utf8\");\n } catch {\n return; // lock vanished — nothing to release.\n }\n if (!precheck.includes(held.ownerId)) {\n return; // replacement lock — leave it untouched for its holder.\n }\n // It was ours when we read it. Atomically claim via rename, then re-verify\n // on the moved file: a replacement could appear between the pre-check read\n // above and this rename.\n const trashPath = `${held.path}.releasing.${process.pid}.${Date.now()}`;\n await rename(held.path, trashPath);\n // Test seam: simulate a third contender acquiring the now-empty lockPath\n // in the rename-to-restore window. No-op in production.\n if (onAfterReleaseRenameForTest) {\n await onAfterReleaseRenameForTest();\n }\n try {\n const moved = await readFile(trashPath, \"utf8\");\n if (moved.includes(held.ownerId)) {\n // Still our lock — safe to delete.\n await unlink(trashPath).catch(() => undefined);\n } else {\n // Not ours: a replacement appeared between the pre-check and the rename.\n // Restore it via link (non-overwriting — if lockPath already has a newer\n // lock, leave it).\n try {\n await link(trashPath, held.path);\n } catch {\n // lockPath already exists — a newer holder is active. Leave the\n // moved file in trash rather than destroying a live lock (codex P2).\n return;\n }\n await unlink(trashPath).catch(() => undefined);\n }\n } catch {\n // Could not read the moved file — clean it up best-effort.\n await unlink(trashPath).catch(() => undefined);\n }\n } catch (err) {\n // Best-effort release; a stale lock will be broken on the next acquire.\n warn(\"withHeldFileLock release failed\", err);\n }\n}\n\n/**\n * Whether the lock file at `held.path` was written by THIS acquirer (same owner\n * id). Reads the content and matches the `<pid> <owner-uuid>` prefix; the iso\n * timestamp varies so it is not part of the identity check.\n */\nasync function lockHeldBySelf(held: HeldLock): Promise<boolean> {\n try {\n const body = await readFile(held.path, \"utf8\");\n const parts = body.trim().split(/\\s+/);\n const fileOwner = parts[1];\n return typeof fileOwner === \"string\" && fileOwner === held.ownerId;\n } catch {\n return false;\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n // Manual deferred instead of Promise.withResolvers (ES2024) — plugin-openclaw's\n // standalone tsconfig targets ES2022 lib and this module is reachable from its\n // type graph, so withResolvers would TS2550 there (same fix as\n // extraction-faithfulness.ts:467).\n return new Promise<void>((resolve) => {\n // NOT unref'd: this polls inside an awaited acquire loop, so the caller's\n // await chain keeps the loop alive; unref would let Node exit mid-poll when\n // nothing else is pending (the heartbeat interval IS unref'd separately).\n setTimeout(resolve, ms);\n });\n}\n"],"mappings":"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","names":[]}
|