@remnic/core 10.0.84 → 10.0.86
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/access-admin-ops-surface.js +90 -88
- package/dist/access-authorization-probe.js +91 -89
- package/dist/access-boundary.d.ts.map +1 -1
- package/dist/access-boundary.js +90 -88
- package/dist/access-cli.js +198 -194
- package/dist/access-cli.js.map +1 -1
- package/dist/access-errors.d.ts +14 -0
- package/dist/access-errors.d.ts.map +1 -1
- package/dist/access-errors.js +5 -1
- package/dist/access-extraction-force-flush.js +90 -88
- package/dist/access-http-briefing.js +91 -89
- package/dist/access-http-query.js +92 -90
- package/dist/access-http.d.ts +12 -0
- package/dist/access-http.d.ts.map +1 -1
- package/dist/access-http.js +119 -116
- package/dist/access-identity-continuity-surface.js +90 -88
- package/dist/access-lcm-surface.js +90 -88
- package/dist/access-mcp-frames.d.ts +29 -0
- package/dist/access-mcp-frames.d.ts.map +1 -0
- package/dist/access-mcp-frames.js +10 -0
- package/dist/access-mcp.d.ts +1 -1
- package/dist/access-mcp.d.ts.map +1 -1
- package/dist/access-mcp.js +105 -102
- package/dist/access-memory-search-fanout.js +2 -2
- package/dist/access-namespace-preflight.js +90 -88
- package/dist/access-observe-write-category.js +15 -14
- package/dist/access-observe-write-surface.d.ts.map +1 -1
- package/dist/access-observe-write-surface.js +90 -88
- package/dist/access-offline-manifest.js +10 -10
- package/dist/access-operations-batch.js +94 -92
- package/dist/access-operations.js +101 -99
- package/dist/access-recall-concurrency.js +90 -88
- package/dist/access-recall-diagnostics.js +2 -2
- package/dist/access-recall-response.js +90 -88
- package/dist/access-recall-surface.js +90 -88
- package/dist/access-schema.d.ts.map +1 -1
- package/dist/access-schema.js +10 -9
- package/dist/access-service.d.ts +3 -3
- package/dist/access-service.d.ts.map +1 -1
- package/dist/access-service.js +90 -88
- package/dist/access-surface-catalog.js +92 -90
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/access-token-capabilities.js +2 -2
- package/dist/active-recall.js +38 -38
- package/dist/adapters/index.js +7 -7
- package/dist/adapters/registry.js +3 -3
- package/dist/{auto-sync-C7E6G7Y2.js → auto-sync-3AZW7MXI.js} +6 -6
- package/dist/briefing-deadline.d.ts +2 -2
- package/dist/briefing-deadline.d.ts.map +1 -1
- package/dist/briefing-deadline.js +1 -1
- package/dist/briefing.js +25 -25
- package/dist/buffer-admission.d.ts +22 -0
- package/dist/buffer-admission.d.ts.map +1 -0
- package/dist/buffer-admission.js +13 -0
- package/dist/buffer-eviction.d.ts +4 -5
- package/dist/buffer-eviction.d.ts.map +1 -1
- package/dist/buffer-eviction.js +1 -1
- package/dist/buffer-persistence.d.ts +8 -4
- package/dist/buffer-persistence.d.ts.map +1 -1
- package/dist/buffer-persistence.js +1 -1
- package/dist/buffer-turn-helpers.d.ts +12 -0
- package/dist/buffer-turn-helpers.d.ts.map +1 -1
- package/dist/buffer-turn-helpers.js +9 -1
- package/dist/buffer-types.d.ts +24 -1
- package/dist/buffer-types.d.ts.map +1 -1
- package/dist/buffer.d.ts +21 -19
- package/dist/buffer.d.ts.map +1 -1
- package/dist/buffer.js +17 -13
- package/dist/calibration.js +3 -3
- package/dist/{capsule-crypto-YO5QJ6L3.js → capsule-crypto-7FJQINUR.js} +2 -2
- package/dist/capsule-gunzip-KGBDGF7P.js +11 -0
- package/dist/capsule-gunzip-KGBDGF7P.js.map +1 -0
- package/dist/capsule-import-gate.d.ts +11 -0
- package/dist/capsule-import-gate.d.ts.map +1 -0
- package/dist/capsule-import-gate.js +12 -0
- package/dist/capsule-import-gate.js.map +1 -0
- package/dist/{capsule-merge-XVTQJJ6R.js → capsule-merge-2IIXFXN5.js} +5 -11
- package/dist/capsule-merge-2IIXFXN5.js.map +1 -0
- package/dist/causal-behavior.js +2 -2
- package/dist/causal-chain.js +2 -2
- package/dist/causal-consolidation.js +27 -27
- package/dist/causal-retrieval.js +2 -2
- package/dist/causal-trajectory-graph.js +2 -2
- package/dist/causal-trajectory.js +1 -1
- package/dist/{chunk-MSIRVXQ3.js → chunk-2G4TV2ML.js} +12 -12
- package/dist/{chunk-B74NPUHT.js → chunk-2JG2NI7C.js} +54 -54
- package/dist/chunk-2JG2NI7C.js.map +1 -0
- package/dist/{chunk-IR4C3DP2.js → chunk-2K3AUDH7.js} +2 -2
- package/dist/{chunk-2IW5PT7U.js → chunk-2N4OUSIA.js} +2 -2
- package/dist/{chunk-BXLOS5AJ.js → chunk-2NLLXCJG.js} +2 -2
- package/dist/{chunk-QZSIDSB2.js → chunk-2NUDHVYM.js} +2 -2
- package/dist/{chunk-HPFVZPRH.js → chunk-2U4LMSEX.js} +3 -3
- package/dist/{chunk-WHQXWFH7.js → chunk-2XOFVTTT.js} +2 -2
- package/dist/{chunk-I6ORDT54.js → chunk-32CA7B6L.js} +2 -2
- package/dist/{chunk-T77AX6DG.js → chunk-32YX7EJ3.js} +4 -4
- package/dist/{chunk-HLKUZW42.js → chunk-3CTKEXXF.js} +144 -156
- package/dist/chunk-3CTKEXXF.js.map +1 -0
- package/dist/{chunk-HLWXCDUQ.js → chunk-3DAWHP5K.js} +5 -5
- package/dist/{chunk-ZJJFUEPO.js → chunk-3PJEDHLD.js} +2 -2
- package/dist/{chunk-PJYK7HH2.js → chunk-3UZ2VMKD.js} +2 -2
- package/dist/{chunk-IN4OFAHX.js → chunk-3Y5X6YFH.js} +2 -2
- package/dist/{chunk-YUTT4ZTI.js → chunk-45VUHDV2.js} +2 -2
- package/dist/{chunk-T6T2RMWW.js → chunk-4GMI5HFH.js} +12 -12
- package/dist/{chunk-YOEYL6CH.js → chunk-4LCVA2LW.js} +3 -3
- package/dist/{chunk-66JOLMWS.js → chunk-4X7HQKAG.js} +2 -2
- package/dist/{chunk-65SKM4BF.js → chunk-4XYAWK5H.js} +2 -2
- package/dist/{chunk-H7BZBSP6.js → chunk-52II7PB6.js} +4 -4
- package/dist/{chunk-TPX7XXY4.js → chunk-5SOSQTVE.js} +2 -2
- package/dist/{chunk-G3T6YMBO.js → chunk-64S6X4IU.js} +7 -7
- package/dist/{chunk-BK7AJUWB.js → chunk-6BCWFCDG.js} +7 -7
- package/dist/{chunk-V27FK6D6.js → chunk-6XTUZKCZ.js} +2 -2
- package/dist/{chunk-KASJJGRG.js → chunk-6ZELOK6O.js} +3 -8
- package/dist/chunk-6ZELOK6O.js.map +1 -0
- package/dist/{chunk-LECSS7EE.js → chunk-73UZZFJC.js} +3 -3
- package/dist/{chunk-4EACCIPO.js → chunk-77PDJ4OE.js} +3 -3
- package/dist/{chunk-GQZSGXR6.js → chunk-7GSL4LBG.js} +2 -2
- package/dist/{chunk-B6SPPYGJ.js → chunk-7IWRLYFJ.js} +2 -2
- package/dist/{chunk-R45L4TV6.js → chunk-7LCGFUMB.js} +6 -6
- package/dist/{chunk-A7BM2JTH.js → chunk-AJHNXIQU.js} +2 -2
- package/dist/{chunk-2D7BTSDW.js → chunk-ANZZLRUX.js} +2 -2
- package/dist/{chunk-ZXF3O7P4.js → chunk-ARRTLPRC.js} +2 -2
- package/dist/{chunk-S5CQI2KF.js → chunk-B3GKQ6DU.js} +2 -2
- package/dist/{chunk-XRBHIR7Q.js → chunk-B56LORLY.js} +2 -2
- package/dist/{chunk-KO3YBHOV.js → chunk-BIVKPQ6Q.js} +3 -3
- package/dist/{chunk-QZBTIYKD.js → chunk-BLSHFIR6.js} +7 -6
- package/dist/chunk-BLSHFIR6.js.map +1 -0
- package/dist/{chunk-54FDG7K7.js → chunk-C2HORX76.js} +3 -3
- package/dist/{chunk-WAD32CZG.js → chunk-CC4V7HNP.js} +43 -30
- package/dist/chunk-CC4V7HNP.js.map +1 -0
- package/dist/{chunk-LGEH473S.js → chunk-CJCTKL6Y.js} +9 -1
- package/dist/chunk-CJCTKL6Y.js.map +1 -0
- package/dist/{chunk-E33UJHY3.js → chunk-CN7Q3T2J.js} +4 -4
- package/dist/{chunk-YUTG35M4.js → chunk-CYCEROPR.js} +3 -3
- package/dist/{chunk-TFLPDNQV.js → chunk-D5EV6Y2L.js} +3 -3
- package/dist/{chunk-BFBS7OFQ.js → chunk-DC55RIEZ.js} +4 -4
- package/dist/{chunk-B4ZU34JQ.js → chunk-DT7SNJH6.js} +3 -3
- package/dist/{chunk-VLMBSGQF.js → chunk-DZ7DPDVW.js} +10 -8
- package/dist/chunk-DZ7DPDVW.js.map +1 -0
- package/dist/{chunk-FVRTCYZ3.js → chunk-EA2LA5RI.js} +2 -2
- package/dist/{chunk-WBN66HPI.js → chunk-ELHJK7LM.js} +6 -6
- package/dist/{chunk-77R7BQZ2.js → chunk-EQ4U73UH.js} +77 -24
- package/dist/chunk-EQ4U73UH.js.map +1 -0
- package/dist/{chunk-3JPTUCD7.js → chunk-EUBDYOLD.js} +32 -23
- package/dist/chunk-EUBDYOLD.js.map +1 -0
- package/dist/{chunk-YNDLCWXS.js → chunk-EZ25VE3G.js} +4 -4
- package/dist/{chunk-YAUHSNPB.js → chunk-F74G4KIH.js} +2 -2
- package/dist/{chunk-MPGLM2VU.js → chunk-FF3EFLUT.js} +7 -5
- package/dist/chunk-FF3EFLUT.js.map +1 -0
- package/dist/{chunk-BV2BRHD4.js → chunk-FHGWKODN.js} +2 -2
- package/dist/chunk-FKBGK3NC.js +62 -0
- package/dist/chunk-FKBGK3NC.js.map +1 -0
- package/dist/{chunk-X2KO4FK5.js → chunk-FNFURZBZ.js} +5 -5
- package/dist/chunk-FNFURZBZ.js.map +1 -0
- package/dist/{chunk-KESJ5XX3.js → chunk-G54BOKZ6.js} +2 -2
- package/dist/{chunk-YK7GOPIE.js → chunk-G67EUQAB.js} +9 -7
- package/dist/chunk-G67EUQAB.js.map +1 -0
- package/dist/{chunk-K36RMINQ.js → chunk-GOZXQNIM.js} +3 -3
- package/dist/{chunk-OQSSQOKQ.js → chunk-GULUWOA5.js} +2 -2
- package/dist/{chunk-K6RTQZA4.js → chunk-HFUKXOUW.js} +2 -2
- package/dist/{chunk-WV254W4V.js → chunk-HLN2HOXX.js} +2 -2
- package/dist/{chunk-FUOAIJKQ.js → chunk-IBDWYRDR.js} +3 -3
- package/dist/{chunk-Z3DDQXM4.js → chunk-IBGU6AN6.js} +45 -45
- package/dist/chunk-IBGU6AN6.js.map +1 -0
- package/dist/{chunk-AJG2TAMR.js → chunk-IEEV27BC.js} +2 -2
- package/dist/chunk-IGLJNHOX.js +62 -0
- package/dist/chunk-IGLJNHOX.js.map +1 -0
- package/dist/{chunk-LTDLJCMQ.js → chunk-IJ3OEECW.js} +4 -4
- package/dist/{chunk-BK4FBHZ3.js → chunk-IPD5GC7C.js} +3 -3
- package/dist/{chunk-KFLD7ZZG.js → chunk-IUKYFTGW.js} +3 -3
- package/dist/{chunk-GCAQ3VUJ.js → chunk-JM2YZKCQ.js} +2 -2
- package/dist/{chunk-BNQJKWWZ.js → chunk-K3FH3LAQ.js} +4 -4
- package/dist/{chunk-LU66I56Q.js → chunk-KVSOEVAF.js} +61 -12
- package/dist/chunk-KVSOEVAF.js.map +1 -0
- package/dist/chunk-M3BEJJNV.js +31 -0
- package/dist/chunk-M3BEJJNV.js.map +1 -0
- package/dist/{chunk-RZH5RVJC.js → chunk-MTTYIXSU.js} +2 -2
- package/dist/{chunk-XHGYZRVW.js → chunk-NIVKG3DS.js} +5 -5
- package/dist/{chunk-VZELUMKK.js → chunk-NQP4ZYGG.js} +2 -2
- package/dist/{chunk-7PMOCQOL.js → chunk-NT7F7WJQ.js} +192 -63
- package/dist/chunk-NT7F7WJQ.js.map +1 -0
- package/dist/{chunk-YO2JEX2Z.js → chunk-OGBQMY46.js} +2 -2
- package/dist/{chunk-TLHF75OR.js → chunk-OL553AWT.js} +12 -12
- package/dist/{chunk-CLVILSBR.js → chunk-OZNBZJ3S.js} +22 -22
- package/dist/{chunk-VUROWXFL.js → chunk-P452SEKO.js} +2 -2
- package/dist/{chunk-JX3E4XCW.js → chunk-PDOOUXCS.js} +2 -2
- package/dist/{chunk-6QYPL6NI.js → chunk-PKZ274PI.js} +3 -3
- package/dist/{chunk-KJCL2FZO.js → chunk-QD5R6U5J.js} +2 -2
- package/dist/{chunk-JRVMCZE3.js → chunk-QEYTRFR3.js} +2 -2
- package/dist/{chunk-VKDAJJQP.js → chunk-QEZ3DW5O.js} +11 -11
- package/dist/{chunk-WYPCJK6K.js → chunk-QKERFEJS.js} +2 -2
- package/dist/{chunk-BDN3TDGV.js → chunk-QKES7GU6.js} +2 -2
- package/dist/{chunk-PCQWKMOL.js → chunk-QNSZYTSG.js} +2 -2
- package/dist/chunk-QV2VZKD5.js +31 -0
- package/dist/chunk-QV2VZKD5.js.map +1 -0
- package/dist/{chunk-IZJQNDGI.js → chunk-R6HMAIKM.js} +2 -2
- package/dist/{chunk-CIIHIAJ2.js → chunk-ROGO7FRA.js} +6 -5
- package/dist/{chunk-CIIHIAJ2.js.map → chunk-ROGO7FRA.js.map} +1 -1
- package/dist/{chunk-NUSAAN75.js → chunk-ROKDHO74.js} +2 -2
- package/dist/{chunk-D5SSBCYY.js → chunk-RWGRSKN5.js} +7 -5
- package/dist/chunk-RWGRSKN5.js.map +1 -0
- package/dist/{chunk-FF6N7BXC.js → chunk-S45INSV3.js} +4 -4
- package/dist/{chunk-2RUTN7PR.js → chunk-S7GJNA3K.js} +2 -2
- package/dist/{chunk-XT45WCKX.js → chunk-SYKJBS7S.js} +10 -10
- package/dist/{chunk-5BE3FLKL.js → chunk-TAUHAP5J.js} +4 -4
- package/dist/{chunk-RJWL3RHB.js → chunk-TFEHSPGQ.js} +2 -2
- package/dist/{chunk-XYP5WBDO.js → chunk-TQ4SCPGQ.js} +76 -60
- package/dist/chunk-TQ4SCPGQ.js.map +1 -0
- package/dist/{chunk-K3B72DKJ.js → chunk-TRMZHGIX.js} +8 -8
- package/dist/{chunk-WBDIZWJQ.js → chunk-TSS3D7ZY.js} +2 -2
- package/dist/{chunk-6LCWKS62.js → chunk-UAUV3BWS.js} +104 -121
- package/dist/chunk-UAUV3BWS.js.map +1 -0
- package/dist/{chunk-KQUSP6LB.js → chunk-UDKWFDV2.js} +1 -1
- package/dist/chunk-UDKWFDV2.js.map +1 -0
- package/dist/{chunk-HQPFACXO.js → chunk-UH3FPX3L.js} +2 -2
- package/dist/{chunk-GGJFRVRD.js → chunk-US7KPQA5.js} +2 -2
- package/dist/{chunk-FJ2VJTGA.js → chunk-UWRHHRDK.js} +3 -3
- package/dist/{chunk-4KLQI3L2.js → chunk-UXXK523X.js} +40 -2
- package/dist/chunk-UXXK523X.js.map +1 -0
- package/dist/{chunk-SDESKFKT.js → chunk-UYHDMCY2.js} +2 -2
- package/dist/{chunk-3T3VHXUH.js → chunk-VKILERSL.js} +2 -2
- package/dist/{chunk-2TGIKMMZ.js → chunk-WXDTOE6F.js} +2 -2
- package/dist/{chunk-KQLBXUUQ.js → chunk-WYG5UNDY.js} +2 -2
- package/dist/{chunk-DQEMWVMT.js → chunk-X7Y7WX73.js} +1 -1
- package/dist/{chunk-MPDLLLOG.js → chunk-XO23OKMK.js} +9 -5
- package/dist/chunk-XO23OKMK.js.map +1 -0
- package/dist/{chunk-WC475JOG.js → chunk-XU37EJTW.js} +24 -24
- package/dist/chunk-XU37EJTW.js.map +1 -0
- package/dist/{chunk-FZVROZKC.js → chunk-XVZA6VXC.js} +4 -4
- package/dist/{chunk-QA3Y2O6H.js → chunk-YAVIBVCU.js} +2 -2
- package/dist/{chunk-2XJZLSXE.js → chunk-YL4UKMD7.js} +124 -58
- package/dist/chunk-YL4UKMD7.js.map +1 -0
- package/dist/{chunk-VPEIWMUT.js → chunk-YLTU2DC4.js} +2 -2
- package/dist/{chunk-HWHNQVRV.js → chunk-YMJRLT7S.js} +28 -8
- package/dist/chunk-YMJRLT7S.js.map +1 -0
- package/dist/{chunk-EBOHFZI4.js → chunk-YRZPBN46.js} +3 -3
- package/dist/{chunk-FMFCQRDM.js → chunk-ZANNIXXE.js} +3 -3
- package/dist/{chunk-HQGATKG2.js → chunk-ZBFLV657.js} +3 -3
- package/dist/{chunk-6L63IN3M.js → chunk-ZOJUWVAU.js} +1 -1
- package/dist/cli.js +144 -141
- package/dist/coding/export-okf-codegraph.js +24 -24
- package/dist/coding/pre-action-gate.js +2 -2
- package/dist/compounding/engine.js +26 -26
- package/dist/config.js +35 -35
- package/dist/connectors/codex-materialize-runner.js +24 -24
- package/dist/connectors/index.js +28 -28
- package/dist/contradiction/index.js +4 -4
- package/dist/convergence-refresh.js +26 -26
- package/dist/corpus-watermark.js +28 -28
- package/dist/dashboard-runtime.js +2 -2
- package/dist/deep-recall-config.js +2 -2
- package/dist/deep-recall-http-glue.js +12 -12
- package/dist/entity-retrieval.js +25 -25
- package/dist/event-order-recall.js +2 -2
- package/dist/explicit-capture.js +6 -6
- package/dist/external-wiki-access.js +91 -89
- package/dist/extraction-evidence-class.js +2 -2
- package/dist/extraction-quote-grounding.d.ts +5 -1
- package/dist/extraction-quote-grounding.d.ts.map +1 -1
- package/dist/extraction-quote-grounding.js +1 -1
- package/dist/extraction-source-grounding-rules.d.ts +3 -1
- package/dist/extraction-source-grounding-rules.d.ts.map +1 -1
- package/dist/extraction-source-grounding-rules.js +2 -2
- package/dist/extraction-source-grounding.d.ts +1 -1
- package/dist/extraction-source-grounding.d.ts.map +1 -1
- package/dist/extraction-source-grounding.js +5 -5
- package/dist/extraction-span-materialize.js +2 -2
- package/dist/extraction.d.ts.map +1 -1
- package/dist/extraction.js +43 -43
- package/dist/{first-start-migration-QVD22WWS.js → first-start-migration-A6PHIBUQ.js} +4 -4
- package/dist/{graph-edge-decay-CXTNJ7IQ.js → graph-edge-decay-EKWXRBWF.js} +5 -5
- package/dist/graph-edge-decay-EKWXRBWF.js.map +1 -0
- package/dist/graph-jsonl.js +3 -3
- package/dist/graph-snapshot.js +3 -3
- package/dist/graph.js +2 -2
- package/dist/harmonic-retrieval.js +24 -24
- package/dist/index.js +255 -251
- package/dist/lcm/engine.js +2 -2
- package/dist/lcm/index.js +5 -5
- package/dist/local-llm.js +3 -3
- package/dist/location/index.js +28 -28
- package/dist/maintenance/memory-governance.js +24 -24
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +24 -24
- package/dist/maintenance/rebuild-memory-projection-runner.js +26 -26
- package/dist/maintenance/rebuild-memory-projection.js +25 -25
- package/dist/memory-browse-http-glue.js +2 -2
- package/dist/memory-browse-operations.js +91 -89
- package/dist/memory-browse.js +5 -5
- package/dist/memory-subject.js +2 -2
- package/dist/namespaces/migrate.js +25 -25
- package/dist/namespaces/search.d.ts +9 -0
- package/dist/namespaces/search.d.ts.map +1 -1
- package/dist/namespaces/search.js +13 -7
- package/dist/namespaces/storage.js +24 -24
- package/dist/offline-sync-changeset-generations.js +3 -3
- package/dist/offline-sync-embedding-generation.js +2 -2
- package/dist/offline-sync-impression-drain.js +2 -2
- package/dist/offline-sync-snapshot-stream.js +6 -6
- package/dist/offline-sync.js +5 -5
- package/dist/operator-doctor-corpus.js +31 -31
- package/dist/operator-doctor-replica.js +4 -4
- package/dist/operator-toolkit.js +49 -49
- package/dist/orchestration/backlog-scheduler.d.ts +3 -2
- package/dist/orchestration/backlog-scheduler.d.ts.map +1 -1
- package/dist/orchestration/backlog-scheduler.js +209 -205
- package/dist/orchestration/backlog-scheduler.js.map +1 -1
- package/dist/orchestration/buffer-drain-runner.d.ts +6 -1
- package/dist/orchestration/buffer-drain-runner.d.ts.map +1 -1
- package/dist/orchestration/buffer-drain-runner.js +199 -195
- package/dist/orchestration/extraction-persist.d.ts.map +1 -1
- package/dist/orchestration/fact-dedup-window.d.ts +1 -4
- package/dist/orchestration/fact-dedup-window.d.ts.map +1 -1
- package/dist/orchestration/maintenance.js +41 -41
- package/dist/orchestration/turn-ingestion.d.ts +2 -9
- package/dist/orchestration/turn-ingestion.d.ts.map +1 -1
- package/dist/orchestrator.js +198 -194
- package/dist/provenance.js +2 -2
- package/dist/qmd.js +4 -4
- package/dist/recall-navigation-http-glue.js +2 -2
- package/dist/recall-navigation-operations.js +91 -89
- package/dist/recall-navigation.js +90 -88
- package/dist/recall-state-view-admission.js +5 -5
- package/dist/recall-why-service.js +5 -5
- package/dist/reconcile/manifest.js +2 -2
- package/dist/replica-divergence.js +3 -3
- package/dist/{resolution-BNWE5Y25.js → resolution-23ZBDM6A.js} +5 -5
- package/dist/resolution-23ZBDM6A.js.map +1 -0
- package/dist/resume-bundles.js +36 -36
- package/dist/salvage-envelope.js +4 -4
- package/dist/search/factory.js +6 -6
- package/dist/search/index.js +12 -12
- package/dist/semantic-consolidation.js +25 -25
- package/dist/semantic-rule-promotion.js +24 -24
- package/dist/semantic-rule-verifier.js +24 -24
- package/dist/source-agent-qualifier.d.ts +2 -0
- package/dist/source-agent-qualifier.d.ts.map +1 -1
- package/dist/source-agent-qualifier.js +36 -36
- package/dist/standup/build.js +25 -25
- package/dist/storage/buffer-drain-claims.d.ts +18 -6
- package/dist/storage/buffer-drain-claims.d.ts.map +1 -1
- package/dist/storage/buffer-drain-claims.js +2 -2
- package/dist/storage/buffer-session-files.js +2 -2
- package/dist/storage/content-hash-index.d.ts +8 -0
- package/dist/storage/content-hash-index.d.ts.map +1 -1
- package/dist/storage.d.ts +10 -1
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +23 -23
- package/dist/subject-config.js +3 -3
- package/dist/summarizer.js +4 -4
- package/dist/support-passport/index.js +93 -91
- package/dist/tokens.js +3 -3
- package/dist/transfer/autodetect.js +1 -1
- package/dist/transfer/backup.js +2 -2
- package/dist/transfer/capsule-export.js +3 -3
- package/dist/transfer/capsule-gunzip.d.ts +14 -0
- package/dist/transfer/capsule-gunzip.d.ts.map +1 -0
- package/dist/transfer/capsule-import.d.ts.map +1 -1
- package/dist/transfer/capsule-import.js +3 -2
- package/dist/transfer/capsule-merge.d.ts.map +1 -1
- package/dist/transfer/export-okf.js +24 -24
- package/dist/verified-recall.js +24 -24
- package/dist/who-knows-cli.js +26 -26
- package/dist/who-knows.js +25 -25
- package/dist/write-envelope.js +3 -3
- package/package.json +2 -2
- package/src/access-boundary.ts +15 -0
- package/src/access-errors.ts +22 -0
- package/src/access-fleet-wide-work-peer.test.ts +236 -0
- package/src/access-http-peer-fleet-wide.test.ts +192 -0
- package/src/access-http.test.ts +249 -4
- package/src/access-http.ts +114 -39
- package/src/access-mcp-frames.test.ts +47 -0
- package/src/access-mcp-frames.ts +74 -0
- package/src/access-mcp.test.ts +210 -0
- package/src/access-mcp.ts +47 -37
- package/src/access-observe-replay-durability.test.ts +40 -4
- package/src/access-observe-write-surface.ts +4 -4
- package/src/access-operations-batch.ts +23 -12
- package/src/access-proto-injection.test.ts +340 -0
- package/src/access-schema.ts +31 -5
- package/src/access-service-capsule-import.test.ts +235 -0
- package/src/access-service.ts +6 -45
- package/src/backlog-scheduler.test.ts +443 -3
- package/src/briefing-deadline.ts +5 -4
- package/src/buffer-admission.ts +45 -0
- package/src/buffer-eviction-backpressure.test.ts +211 -0
- package/src/buffer-eviction.ts +8 -14
- package/src/buffer-incremental-persistence.test.ts +25 -37
- package/src/buffer-persistence.ts +15 -6
- package/src/buffer-session.test.ts +32 -16
- package/src/buffer-turn-helpers.ts +47 -0
- package/src/buffer-types.ts +28 -1
- package/src/buffer.ts +83 -91
- package/src/capsule-import-gate.ts +109 -0
- package/src/cli.ts +4 -4
- package/src/extraction-quote-grounding.test.ts +125 -0
- package/src/extraction-quote-grounding.ts +99 -25
- package/src/extraction-source-grounding-rules.ts +6 -1
- package/src/extraction-source-grounding.ts +2 -0
- package/src/extraction.ts +3 -4
- package/src/fact-dedup-window.test.ts +103 -20
- package/src/namespaces/search.test.ts +480 -1
- package/src/namespaces/search.ts +93 -10
- package/src/orchestration/backlog-scheduler.ts +13 -12
- package/src/orchestration/buffer-drain-runner.ts +40 -16
- package/src/orchestration/extraction-persist.ts +2 -10
- package/src/orchestration/fact-dedup-window.ts +5 -12
- package/src/orchestration/turn-ingestion.ts +38 -39
- package/src/recall-navigation-operations.ts +9 -2
- package/src/source-agent-qualifier.ts +3 -0
- package/src/storage/buffer-drain-claims.test.ts +330 -6
- package/src/storage/buffer-drain-claims.ts +226 -80
- package/src/storage/buffer-session-files.ts +2 -2
- package/src/storage/content-hash-index.ts +9 -0
- package/src/storage.ts +15 -0
- package/src/transfer/capsule-gunzip.ts +39 -0
- package/src/transfer/capsule-import.test.ts +73 -0
- package/src/transfer/capsule-import.ts +2 -2
- package/src/transfer/capsule-merge.test.ts +34 -0
- package/src/transfer/capsule-merge.ts +2 -10
- package/dist/capsule-merge-XVTQJJ6R.js.map +0 -1
- package/dist/chunk-2XJZLSXE.js.map +0 -1
- package/dist/chunk-3JPTUCD7.js.map +0 -1
- package/dist/chunk-4KLQI3L2.js.map +0 -1
- package/dist/chunk-6LCWKS62.js.map +0 -1
- package/dist/chunk-77R7BQZ2.js.map +0 -1
- package/dist/chunk-7PMOCQOL.js.map +0 -1
- package/dist/chunk-B74NPUHT.js.map +0 -1
- package/dist/chunk-D5SSBCYY.js.map +0 -1
- package/dist/chunk-HLKUZW42.js.map +0 -1
- package/dist/chunk-HWHNQVRV.js.map +0 -1
- package/dist/chunk-KASJJGRG.js.map +0 -1
- package/dist/chunk-KQUSP6LB.js.map +0 -1
- package/dist/chunk-LGEH473S.js.map +0 -1
- package/dist/chunk-LU66I56Q.js.map +0 -1
- package/dist/chunk-MPDLLLOG.js.map +0 -1
- package/dist/chunk-MPGLM2VU.js.map +0 -1
- package/dist/chunk-QZBTIYKD.js.map +0 -1
- package/dist/chunk-VLMBSGQF.js.map +0 -1
- package/dist/chunk-WAD32CZG.js.map +0 -1
- package/dist/chunk-WC475JOG.js.map +0 -1
- package/dist/chunk-X2KO4FK5.js.map +0 -1
- package/dist/chunk-XYP5WBDO.js.map +0 -1
- package/dist/chunk-YK7GOPIE.js.map +0 -1
- package/dist/chunk-Z3DDQXM4.js.map +0 -1
- /package/dist/{capsule-crypto-YO5QJ6L3.js.map → access-mcp-frames.js.map} +0 -0
- /package/dist/{auto-sync-C7E6G7Y2.js.map → auto-sync-3AZW7MXI.js.map} +0 -0
- /package/dist/{graph-edge-decay-CXTNJ7IQ.js.map → buffer-admission.js.map} +0 -0
- /package/dist/{resolution-BNWE5Y25.js.map → capsule-crypto-7FJQINUR.js.map} +0 -0
- /package/dist/{chunk-MSIRVXQ3.js.map → chunk-2G4TV2ML.js.map} +0 -0
- /package/dist/{chunk-IR4C3DP2.js.map → chunk-2K3AUDH7.js.map} +0 -0
- /package/dist/{chunk-2IW5PT7U.js.map → chunk-2N4OUSIA.js.map} +0 -0
- /package/dist/{chunk-BXLOS5AJ.js.map → chunk-2NLLXCJG.js.map} +0 -0
- /package/dist/{chunk-QZSIDSB2.js.map → chunk-2NUDHVYM.js.map} +0 -0
- /package/dist/{chunk-HPFVZPRH.js.map → chunk-2U4LMSEX.js.map} +0 -0
- /package/dist/{chunk-WHQXWFH7.js.map → chunk-2XOFVTTT.js.map} +0 -0
- /package/dist/{chunk-I6ORDT54.js.map → chunk-32CA7B6L.js.map} +0 -0
- /package/dist/{chunk-T77AX6DG.js.map → chunk-32YX7EJ3.js.map} +0 -0
- /package/dist/{chunk-HLWXCDUQ.js.map → chunk-3DAWHP5K.js.map} +0 -0
- /package/dist/{chunk-ZJJFUEPO.js.map → chunk-3PJEDHLD.js.map} +0 -0
- /package/dist/{chunk-PJYK7HH2.js.map → chunk-3UZ2VMKD.js.map} +0 -0
- /package/dist/{chunk-IN4OFAHX.js.map → chunk-3Y5X6YFH.js.map} +0 -0
- /package/dist/{chunk-YUTT4ZTI.js.map → chunk-45VUHDV2.js.map} +0 -0
- /package/dist/{chunk-T6T2RMWW.js.map → chunk-4GMI5HFH.js.map} +0 -0
- /package/dist/{chunk-YOEYL6CH.js.map → chunk-4LCVA2LW.js.map} +0 -0
- /package/dist/{chunk-66JOLMWS.js.map → chunk-4X7HQKAG.js.map} +0 -0
- /package/dist/{chunk-65SKM4BF.js.map → chunk-4XYAWK5H.js.map} +0 -0
- /package/dist/{chunk-H7BZBSP6.js.map → chunk-52II7PB6.js.map} +0 -0
- /package/dist/{chunk-TPX7XXY4.js.map → chunk-5SOSQTVE.js.map} +0 -0
- /package/dist/{chunk-G3T6YMBO.js.map → chunk-64S6X4IU.js.map} +0 -0
- /package/dist/{chunk-BK7AJUWB.js.map → chunk-6BCWFCDG.js.map} +0 -0
- /package/dist/{chunk-V27FK6D6.js.map → chunk-6XTUZKCZ.js.map} +0 -0
- /package/dist/{chunk-LECSS7EE.js.map → chunk-73UZZFJC.js.map} +0 -0
- /package/dist/{chunk-4EACCIPO.js.map → chunk-77PDJ4OE.js.map} +0 -0
- /package/dist/{chunk-GQZSGXR6.js.map → chunk-7GSL4LBG.js.map} +0 -0
- /package/dist/{chunk-B6SPPYGJ.js.map → chunk-7IWRLYFJ.js.map} +0 -0
- /package/dist/{chunk-R45L4TV6.js.map → chunk-7LCGFUMB.js.map} +0 -0
- /package/dist/{chunk-A7BM2JTH.js.map → chunk-AJHNXIQU.js.map} +0 -0
- /package/dist/{chunk-2D7BTSDW.js.map → chunk-ANZZLRUX.js.map} +0 -0
- /package/dist/{chunk-ZXF3O7P4.js.map → chunk-ARRTLPRC.js.map} +0 -0
- /package/dist/{chunk-S5CQI2KF.js.map → chunk-B3GKQ6DU.js.map} +0 -0
- /package/dist/{chunk-XRBHIR7Q.js.map → chunk-B56LORLY.js.map} +0 -0
- /package/dist/{chunk-KO3YBHOV.js.map → chunk-BIVKPQ6Q.js.map} +0 -0
- /package/dist/{chunk-54FDG7K7.js.map → chunk-C2HORX76.js.map} +0 -0
- /package/dist/{chunk-E33UJHY3.js.map → chunk-CN7Q3T2J.js.map} +0 -0
- /package/dist/{chunk-YUTG35M4.js.map → chunk-CYCEROPR.js.map} +0 -0
- /package/dist/{chunk-TFLPDNQV.js.map → chunk-D5EV6Y2L.js.map} +0 -0
- /package/dist/{chunk-BFBS7OFQ.js.map → chunk-DC55RIEZ.js.map} +0 -0
- /package/dist/{chunk-B4ZU34JQ.js.map → chunk-DT7SNJH6.js.map} +0 -0
- /package/dist/{chunk-FVRTCYZ3.js.map → chunk-EA2LA5RI.js.map} +0 -0
- /package/dist/{chunk-WBN66HPI.js.map → chunk-ELHJK7LM.js.map} +0 -0
- /package/dist/{chunk-YNDLCWXS.js.map → chunk-EZ25VE3G.js.map} +0 -0
- /package/dist/{chunk-YAUHSNPB.js.map → chunk-F74G4KIH.js.map} +0 -0
- /package/dist/{chunk-BV2BRHD4.js.map → chunk-FHGWKODN.js.map} +0 -0
- /package/dist/{chunk-KESJ5XX3.js.map → chunk-G54BOKZ6.js.map} +0 -0
- /package/dist/{chunk-K36RMINQ.js.map → chunk-GOZXQNIM.js.map} +0 -0
- /package/dist/{chunk-OQSSQOKQ.js.map → chunk-GULUWOA5.js.map} +0 -0
- /package/dist/{chunk-K6RTQZA4.js.map → chunk-HFUKXOUW.js.map} +0 -0
- /package/dist/{chunk-WV254W4V.js.map → chunk-HLN2HOXX.js.map} +0 -0
- /package/dist/{chunk-FUOAIJKQ.js.map → chunk-IBDWYRDR.js.map} +0 -0
- /package/dist/{chunk-AJG2TAMR.js.map → chunk-IEEV27BC.js.map} +0 -0
- /package/dist/{chunk-LTDLJCMQ.js.map → chunk-IJ3OEECW.js.map} +0 -0
- /package/dist/{chunk-BK4FBHZ3.js.map → chunk-IPD5GC7C.js.map} +0 -0
- /package/dist/{chunk-KFLD7ZZG.js.map → chunk-IUKYFTGW.js.map} +0 -0
- /package/dist/{chunk-GCAQ3VUJ.js.map → chunk-JM2YZKCQ.js.map} +0 -0
- /package/dist/{chunk-BNQJKWWZ.js.map → chunk-K3FH3LAQ.js.map} +0 -0
- /package/dist/{chunk-RZH5RVJC.js.map → chunk-MTTYIXSU.js.map} +0 -0
- /package/dist/{chunk-XHGYZRVW.js.map → chunk-NIVKG3DS.js.map} +0 -0
- /package/dist/{chunk-VZELUMKK.js.map → chunk-NQP4ZYGG.js.map} +0 -0
- /package/dist/{chunk-YO2JEX2Z.js.map → chunk-OGBQMY46.js.map} +0 -0
- /package/dist/{chunk-TLHF75OR.js.map → chunk-OL553AWT.js.map} +0 -0
- /package/dist/{chunk-CLVILSBR.js.map → chunk-OZNBZJ3S.js.map} +0 -0
- /package/dist/{chunk-VUROWXFL.js.map → chunk-P452SEKO.js.map} +0 -0
- /package/dist/{chunk-JX3E4XCW.js.map → chunk-PDOOUXCS.js.map} +0 -0
- /package/dist/{chunk-6QYPL6NI.js.map → chunk-PKZ274PI.js.map} +0 -0
- /package/dist/{chunk-KJCL2FZO.js.map → chunk-QD5R6U5J.js.map} +0 -0
- /package/dist/{chunk-JRVMCZE3.js.map → chunk-QEYTRFR3.js.map} +0 -0
- /package/dist/{chunk-VKDAJJQP.js.map → chunk-QEZ3DW5O.js.map} +0 -0
- /package/dist/{chunk-WYPCJK6K.js.map → chunk-QKERFEJS.js.map} +0 -0
- /package/dist/{chunk-BDN3TDGV.js.map → chunk-QKES7GU6.js.map} +0 -0
- /package/dist/{chunk-PCQWKMOL.js.map → chunk-QNSZYTSG.js.map} +0 -0
- /package/dist/{chunk-IZJQNDGI.js.map → chunk-R6HMAIKM.js.map} +0 -0
- /package/dist/{chunk-NUSAAN75.js.map → chunk-ROKDHO74.js.map} +0 -0
- /package/dist/{chunk-FF6N7BXC.js.map → chunk-S45INSV3.js.map} +0 -0
- /package/dist/{chunk-2RUTN7PR.js.map → chunk-S7GJNA3K.js.map} +0 -0
- /package/dist/{chunk-XT45WCKX.js.map → chunk-SYKJBS7S.js.map} +0 -0
- /package/dist/{chunk-5BE3FLKL.js.map → chunk-TAUHAP5J.js.map} +0 -0
- /package/dist/{chunk-RJWL3RHB.js.map → chunk-TFEHSPGQ.js.map} +0 -0
- /package/dist/{chunk-K3B72DKJ.js.map → chunk-TRMZHGIX.js.map} +0 -0
- /package/dist/{chunk-WBDIZWJQ.js.map → chunk-TSS3D7ZY.js.map} +0 -0
- /package/dist/{chunk-HQPFACXO.js.map → chunk-UH3FPX3L.js.map} +0 -0
- /package/dist/{chunk-GGJFRVRD.js.map → chunk-US7KPQA5.js.map} +0 -0
- /package/dist/{chunk-FJ2VJTGA.js.map → chunk-UWRHHRDK.js.map} +0 -0
- /package/dist/{chunk-SDESKFKT.js.map → chunk-UYHDMCY2.js.map} +0 -0
- /package/dist/{chunk-3T3VHXUH.js.map → chunk-VKILERSL.js.map} +0 -0
- /package/dist/{chunk-2TGIKMMZ.js.map → chunk-WXDTOE6F.js.map} +0 -0
- /package/dist/{chunk-KQLBXUUQ.js.map → chunk-WYG5UNDY.js.map} +0 -0
- /package/dist/{chunk-DQEMWVMT.js.map → chunk-X7Y7WX73.js.map} +0 -0
- /package/dist/{chunk-FZVROZKC.js.map → chunk-XVZA6VXC.js.map} +0 -0
- /package/dist/{chunk-QA3Y2O6H.js.map → chunk-YAVIBVCU.js.map} +0 -0
- /package/dist/{chunk-VPEIWMUT.js.map → chunk-YLTU2DC4.js.map} +0 -0
- /package/dist/{chunk-EBOHFZI4.js.map → chunk-YRZPBN46.js.map} +0 -0
- /package/dist/{chunk-FMFCQRDM.js.map → chunk-ZANNIXXE.js.map} +0 -0
- /package/dist/{chunk-HQGATKG2.js.map → chunk-ZBFLV657.js.map} +0 -0
- /package/dist/{chunk-6L63IN3M.js.map → chunk-ZOJUWVAU.js.map} +0 -0
- /package/dist/{first-start-migration-QVD22WWS.js.map → first-start-migration-A6PHIBUQ.js.map} +0 -0
package/src/buffer.ts
CHANGED
|
@@ -23,39 +23,32 @@ import {
|
|
|
23
23
|
bufferTurnsEqual,
|
|
24
24
|
copyBufferTurn,
|
|
25
25
|
describeError,
|
|
26
|
+
entryActivityAt,
|
|
27
|
+
entryHoldsAcceptedCapture,
|
|
26
28
|
hasPinnedCaptureScope,
|
|
27
29
|
liveTurnsFromExtractionSnapshot,
|
|
28
30
|
matchingQueuedExtractionPrefixLength,
|
|
31
|
+
normalizeBufferState,
|
|
29
32
|
probeWithTimeout,
|
|
30
33
|
selectRetainedDeferredTurns,
|
|
31
34
|
type BufferEntryCounts,
|
|
32
35
|
} from "./buffer-turn-helpers.js";
|
|
36
|
+
import { BufferAdmissionRefusedError, canAdmitNewEntryUnlocked } from "./buffer-admission.js";
|
|
37
|
+
export { BufferAdmissionRefusedError } from "./buffer-admission.js";
|
|
38
|
+
import type { AddTurnMutationResult, AddTurnOutcome, RetainedTurnCleanupOptions, TriggerDecision } from "./buffer-types.js";
|
|
33
39
|
|
|
34
|
-
export type TriggerDecision
|
|
40
|
+
export type { TriggerDecision, AddTurnOutcome, RetainedTurnCleanupOptions } from "./buffer-types.js";
|
|
41
|
+
|
|
42
|
+
// Eviction hooks are pure functions of an entry; one shared instance serves
|
|
43
|
+
// pruneEntries, the admission probe and the batch preflight.
|
|
44
|
+
const EVICTION_HOOKS = { activityAt: entryActivityAt, holdsAcceptedCapture: entryHoldsAcceptedCapture };
|
|
35
45
|
|
|
36
46
|
export type { BufferSurpriseProbe } from "./buffer-types.js";
|
|
37
47
|
import type { BufferSurpriseProbe, SurpriseTelemetryQueueEntry } from "./buffer-types.js";
|
|
38
48
|
|
|
39
|
-
export interface AddTurnOutcome {
|
|
40
|
-
decision: TriggerDecision;
|
|
41
|
-
extractionTurns?: BufferTurn[];
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export interface RetainedTurnCleanupOptions {
|
|
45
|
-
abortSignal?: AbortSignal;
|
|
46
|
-
deadlineMs?: number;
|
|
47
|
-
/** Keep cleanup within the accepted namespace. */
|
|
48
|
-
writeNamespaceOverride?: string;
|
|
49
|
-
/** Match the original profile and project binding, not just its write namespace. */
|
|
50
|
-
scopeProfileWritePlan?: import("./namespaces/scope-profiles.js").ResolvedScopeProfilePlan | null;
|
|
51
|
-
codingContext?: import("./types.js").CodingContext;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
49
|
// Raised from 200 in #3303: live captures were being dropped at busy hours
|
|
55
50
|
// while the single extraction worker drained a backlog.
|
|
56
51
|
const FALLBACK_MAX_BUFFER_SESSIONS = 1000;
|
|
57
|
-
const isAcceptedTurn = (t: { acceptedCapture?: boolean; writeNamespaceOverride?: string }): boolean =>
|
|
58
|
-
t.acceptedCapture === true || t.writeNamespaceOverride !== undefined;
|
|
59
52
|
|
|
60
53
|
/**
|
|
61
54
|
* Upper bound on how long a debounced buffer save may be deferred under
|
|
@@ -76,15 +69,6 @@ const BUFFER_SAVE_MAX_DEFER_MULTIPLIER = 5;
|
|
|
76
69
|
*/
|
|
77
70
|
const MAX_SET_TIMEOUT_MS = 2_147_483_647;
|
|
78
71
|
|
|
79
|
-
interface AddTurnMutationResult {
|
|
80
|
-
decision: TriggerDecision;
|
|
81
|
-
signalLevel: SignalLevel;
|
|
82
|
-
priorTurns: BufferTurn[];
|
|
83
|
-
activeTurnsSnapshot: BufferTurn[];
|
|
84
|
-
retainedTurnsSnapshot: BufferTurn[];
|
|
85
|
-
turnCountInWindow: number;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
72
|
export class SmartBuffer {
|
|
89
73
|
private state: BufferState;
|
|
90
74
|
private loaded = false;
|
|
@@ -182,61 +166,13 @@ export class SmartBuffer {
|
|
|
182
166
|
};
|
|
183
167
|
}
|
|
184
168
|
|
|
185
|
-
private normalizeState(state: BufferState): BufferState {
|
|
186
|
-
const entries = Object.assign(
|
|
187
|
-
Object.create(null),
|
|
188
|
-
state.entries ?? {},
|
|
189
|
-
) as NonNullable<BufferState["entries"]>;
|
|
190
|
-
if (!entries.default) {
|
|
191
|
-
entries.default = {
|
|
192
|
-
turns: Array.isArray(state.turns) ? [...state.turns] : [],
|
|
193
|
-
lastExtractionAt: state.lastExtractionAt ?? null,
|
|
194
|
-
extractionCount:
|
|
195
|
-
typeof state.extractionCount === "number" ? state.extractionCount : 0,
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
return {
|
|
199
|
-
turns: entries.default.turns,
|
|
200
|
-
lastExtractionAt: entries.default.lastExtractionAt,
|
|
201
|
-
extractionCount: entries.default.extractionCount,
|
|
202
|
-
entries,
|
|
203
|
-
};
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
private entryActivityAt(entry: BufferEntryState): number {
|
|
207
|
-
const lastTurnAt = entry.turns.reduce((latest, turn) => {
|
|
208
|
-
const parsed = Date.parse(turn.timestamp);
|
|
209
|
-
return Number.isFinite(parsed) ? Math.max(latest, parsed) : latest;
|
|
210
|
-
}, -1);
|
|
211
|
-
const lastExtractionAt =
|
|
212
|
-
typeof entry.lastExtractionAt === "string"
|
|
213
|
-
? Date.parse(entry.lastExtractionAt)
|
|
214
|
-
: Number.NaN;
|
|
215
|
-
return Math.max(
|
|
216
|
-
lastTurnAt,
|
|
217
|
-
Number.isFinite(lastExtractionAt) ? lastExtractionAt : -1,
|
|
218
|
-
);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
169
|
/** Evict oldest entries past this.maxSessionEntries and queue their session files for deletion. */
|
|
222
170
|
private pruneEntries(retainKeys: string[], maxCount = this.maxSessionEntries): void {
|
|
223
171
|
const entries = this.state.entries;
|
|
224
172
|
if (!entries) return;
|
|
225
|
-
const evicted = selectEvictedBufferKeys(entries, retainKeys, maxCount,
|
|
226
|
-
activityAt: (entry) => this.entryActivityAt(entry),
|
|
227
|
-
holdsAcceptedCapture: (entry) => this.entryHoldsAcceptedCapture(entry),
|
|
228
|
-
});
|
|
173
|
+
const evicted = selectEvictedBufferKeys(entries, retainKeys, maxCount, EVICTION_HOOKS);
|
|
229
174
|
for (const key of evicted) delete entries[key];
|
|
230
175
|
this.persistence.markEvicted(evicted);
|
|
231
|
-
if (evicted.length > 0) {
|
|
232
|
-
// Loud degradation (extraction hot-loop hardening, Step 7): buffer
|
|
233
|
-
// pressure during a provider outage is bounded and expected, but must
|
|
234
|
-
// be observable, not silent.
|
|
235
|
-
log.warn(
|
|
236
|
-
`buffer: pruned ${evicted.length} oldest session entr${evicted.length === 1 ? "y" : "ies"} ` +
|
|
237
|
-
`past the session-entry cap (${this.maxSessionEntries}); buffered turn data for those sessions was dropped`,
|
|
238
|
-
);
|
|
239
|
-
}
|
|
240
176
|
}
|
|
241
177
|
|
|
242
178
|
private async loadUnlocked(): Promise<void> {
|
|
@@ -244,7 +180,7 @@ export class SmartBuffer {
|
|
|
244
180
|
if (!this.loadPromise) {
|
|
245
181
|
this.loadPromise = this.storage.loadBuffer()
|
|
246
182
|
.then((state) => {
|
|
247
|
-
this.state =
|
|
183
|
+
this.state = normalizeBufferState(state);
|
|
248
184
|
this.loaded = true;
|
|
249
185
|
})
|
|
250
186
|
.finally(() => {
|
|
@@ -300,16 +236,16 @@ export class SmartBuffer {
|
|
|
300
236
|
this.loaded = true;
|
|
301
237
|
}
|
|
302
238
|
|
|
303
|
-
private async saveUnlocked(): Promise<void> {
|
|
304
|
-
const { handedOver, drainedTurns } = await this.persistence.persist(this.storage, this.state, (key) => this.peekEntry(key) ?? undefined);
|
|
239
|
+
private async saveUnlocked(reconcile?: { key: string; drained: import("./buffer-turn-helpers.js").DrainedTurnSets }): Promise<void> {
|
|
240
|
+
const { handedOver, drainedTurns } = await this.persistence.persist(this.storage, this.state, (key) => this.peekEntry(key) ?? undefined, reconcile);
|
|
305
241
|
// A drain tombstone: the turns the drain extracted leave this copy too,
|
|
306
242
|
// so a stale owner never extracts (or persists) them a second time.
|
|
307
243
|
for (const [key, drained] of drainedTurns) {
|
|
308
244
|
const entry = this.peekEntry(key);
|
|
309
245
|
if (!entry) continue;
|
|
310
|
-
entry.turns = subtractBufferTurns(entry.turns, drained);
|
|
246
|
+
entry.turns = subtractBufferTurns(entry.turns, drained.turns);
|
|
311
247
|
if (entry.retainedTurns && entry.retainedTurns.length > 0) {
|
|
312
|
-
entry.retainedTurns = subtractBufferTurns(entry.retainedTurns, drained);
|
|
248
|
+
entry.retainedTurns = subtractBufferTurns(entry.retainedTurns, drained.retainedTurns);
|
|
313
249
|
if (entry.retainedTurns.length === 0) delete entry.retainedTurns;
|
|
314
250
|
}
|
|
315
251
|
if (key === "default") this.state.turns = entry.turns;
|
|
@@ -340,8 +276,8 @@ export class SmartBuffer {
|
|
|
340
276
|
return bufferEntryCounts(this.state);
|
|
341
277
|
}
|
|
342
278
|
|
|
343
|
-
async save(): Promise<void> {
|
|
344
|
-
await this.enqueueMutation(async () => this.saveUnlocked());
|
|
279
|
+
async save(reconcile?: { key: string; drained: import("./buffer-turn-helpers.js").DrainedTurnSets }): Promise<void> {
|
|
280
|
+
await this.enqueueMutation(async () => this.saveUnlocked(reconcile));
|
|
345
281
|
}
|
|
346
282
|
|
|
347
283
|
/**
|
|
@@ -517,24 +453,80 @@ export class SmartBuffer {
|
|
|
517
453
|
if (mutation === null) return null;
|
|
518
454
|
return this.completeAddTurnOutcome(bufferKey, turn, mutation);
|
|
519
455
|
}
|
|
456
|
+
/**
|
|
457
|
+
* Admit a multi-session durable capture as one capacity transaction.
|
|
458
|
+
* Preflight every new key under the mutation lock before persisting any
|
|
459
|
+
* turn; refusal records nothing and drops nothing.
|
|
460
|
+
*/
|
|
461
|
+
async addTurnsBounded(
|
|
462
|
+
batches: readonly { bufferKey: string; turns: readonly BufferTurn[] }[],
|
|
463
|
+
): Promise<Array<{ bufferKey: string; turn: BufferTurn; outcome: AddTurnOutcome }> | null> {
|
|
464
|
+
const pending = await this.enqueueMutation(async () => {
|
|
465
|
+
await this.loadUnlocked();
|
|
466
|
+
const additions: Array<{ bufferKey: string; turn: BufferTurn }> = [];
|
|
467
|
+
for (const batch of batches) {
|
|
468
|
+
for (const turn of batch.turns) {
|
|
469
|
+
additions.push({ bufferKey: batch.bufferKey, turn });
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
const entries = this.state.entries ?? {};
|
|
474
|
+
const newKeys = [...new Set(
|
|
475
|
+
additions
|
|
476
|
+
.map(({ bufferKey }) => bufferKey)
|
|
477
|
+
.filter((bufferKey) => this.peekEntry(bufferKey) === null),
|
|
478
|
+
)];
|
|
479
|
+
const count = Object.keys(entries).length;
|
|
480
|
+
const requiredEvictions = Math.max(0, count + newKeys.length - this.maxSessionEntries);
|
|
481
|
+
if (requiredEvictions > 0) {
|
|
482
|
+
const target = Math.max(0, this.maxSessionEntries - newKeys.length);
|
|
483
|
+
const evicted = selectEvictedBufferKeys(entries, newKeys, target, EVICTION_HOOKS);
|
|
484
|
+
if (newKeys.length > 0 && evicted.length < requiredEvictions) return null;
|
|
485
|
+
for (const key of evicted) delete entries[key];
|
|
486
|
+
this.persistence.markEvicted(evicted);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
const recorded: Array<{ bufferKey: string; turn: BufferTurn; mutation: AddTurnMutationResult }> = [];
|
|
490
|
+
for (const { bufferKey, turn } of additions) {
|
|
491
|
+
recorded.push({ bufferKey, turn, mutation: await this.recordTurnUnlocked(bufferKey, turn) });
|
|
492
|
+
}
|
|
493
|
+
return recorded;
|
|
494
|
+
});
|
|
495
|
+
if (pending === null) return null;
|
|
496
|
+
|
|
497
|
+
const outcomes: Array<{ bufferKey: string; turn: BufferTurn; outcome: AddTurnOutcome }> = [];
|
|
498
|
+
for (const item of pending) {
|
|
499
|
+
outcomes.push({
|
|
500
|
+
bufferKey: item.bufferKey,
|
|
501
|
+
turn: item.turn,
|
|
502
|
+
outcome: await this.completeAddTurnOutcome(item.bufferKey, item.turn, item.mutation),
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
return outcomes;
|
|
506
|
+
}
|
|
520
507
|
|
|
521
|
-
/** Free one slot
|
|
508
|
+
/** Free one slot only when an empty entry can be reclaimed. */
|
|
522
509
|
private makeRoomForEntryUnlocked(): void {
|
|
523
510
|
const entries = this.state.entries ?? {};
|
|
524
511
|
const target = Math.max(0, this.maxSessionEntries - 1);
|
|
525
|
-
const pinned = Object.keys(entries).filter((k) => k === "default" ||
|
|
526
|
-
if (pinned.length <= target) this.pruneEntries([], target);
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
private entryHoldsAcceptedCapture(entry: BufferEntryState | undefined): boolean {
|
|
530
|
-
return (entry?.turns ?? []).some(isAcceptedTurn) || (entry?.retainedTurns ?? []).some(isAcceptedTurn);
|
|
512
|
+
const pinned = Object.keys(entries).filter((k) => k === "default" || entryHoldsAcceptedCapture(entries[k]));
|
|
513
|
+
if (pinned.length <= target) this.pruneEntries([], target);
|
|
531
514
|
}
|
|
532
515
|
|
|
533
516
|
async addTurnWithOutcome(
|
|
534
517
|
bufferKey: string,
|
|
535
518
|
turn: BufferTurn,
|
|
536
519
|
): Promise<AddTurnOutcome> {
|
|
537
|
-
const mutation = await this.enqueueMutation(() =>
|
|
520
|
+
const mutation = await this.enqueueMutation(async () => {
|
|
521
|
+
await this.loadUnlocked();
|
|
522
|
+
if (
|
|
523
|
+
this.peekEntry(bufferKey) === null &&
|
|
524
|
+
!canAdmitNewEntryUnlocked(this.state.entries ?? {}, bufferKey, this.maxSessionEntries, EVICTION_HOOKS)
|
|
525
|
+
) {
|
|
526
|
+
throw new BufferAdmissionRefusedError(bufferKey, this.maxSessionEntries);
|
|
527
|
+
}
|
|
528
|
+
return this.recordTurnUnlocked(bufferKey, turn);
|
|
529
|
+
});
|
|
538
530
|
return this.completeAddTurnOutcome(bufferKey, turn, mutation);
|
|
539
531
|
}
|
|
540
532
|
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { constants as fsConstants } from "node:fs";
|
|
2
|
+
import { access, realpath, stat } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { ZodError } from "zod";
|
|
5
|
+
import { EngramAccessInputError } from "./access-errors.js";
|
|
6
|
+
import { defaultCapsulesDir } from "./capsule-cli.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Import-path gate for remote capsule imports (issue #3225 C1).
|
|
10
|
+
*
|
|
11
|
+
* `EngramAccessService.capsuleImport` serves the HTTP route and the
|
|
12
|
+
* `capsule_import` MCP operation, where the caller supplies `archivePath`.
|
|
13
|
+
* The destination namespace is authorized, but the source archive previously
|
|
14
|
+
* was not: any path the server process could read was accepted. This module
|
|
15
|
+
* confines the source to the namespace capsule store, `defaultCapsulesDir`
|
|
16
|
+
* of the destination storage dir, which is the same store `capsule export`
|
|
17
|
+
* writes and `capsule_list` lists.
|
|
18
|
+
*
|
|
19
|
+
* The CLI import path does not go through this gate; it is the explicit
|
|
20
|
+
* operator authority and keeps unrestricted local-path imports.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/** True when the caught error carries the given errno-style code. */
|
|
24
|
+
function hasFsErrorCode(cause: unknown, code: string): boolean {
|
|
25
|
+
return cause instanceof Object && "code" in cause && cause.code === code;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** True when `cause` is a path error the gate reports as an input error instead of a server fault. */
|
|
29
|
+
function isInputFsError(cause: unknown): boolean {
|
|
30
|
+
return (
|
|
31
|
+
hasFsErrorCode(cause, "ENOENT") ||
|
|
32
|
+
hasFsErrorCode(cause, "ENOTDIR") ||
|
|
33
|
+
hasFsErrorCode(cause, "EACCES") ||
|
|
34
|
+
hasFsErrorCode(cause, "EPERM") ||
|
|
35
|
+
hasFsErrorCode(cause, "ELOOP") ||
|
|
36
|
+
hasFsErrorCode(cause, "ENAMETOOLONG") ||
|
|
37
|
+
hasFsErrorCode(cause, "ERR_INVALID_ARG_VALUE")
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Matches zod-style `Z_` error codes carried on error objects. */
|
|
42
|
+
const ZOD_STYLE_CODE = /^Z_/;
|
|
43
|
+
|
|
44
|
+
/** True when the caught error carries a zod-style `Z_` code. */
|
|
45
|
+
function hasZodStyleErrorCode(cause: unknown): boolean {
|
|
46
|
+
return cause instanceof Object && "code" in cause && ZOD_STYLE_CODE.test(String(cause.code));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** True when the importer failed on archive input (shape, gzip, checksum) rather than backend errors. */
|
|
50
|
+
export function isCapsuleImportArchiveInputError(cause: unknown, message: string): boolean {
|
|
51
|
+
if (cause instanceof ZodError) return true;
|
|
52
|
+
if (hasZodStyleErrorCode(cause)) return true;
|
|
53
|
+
return (
|
|
54
|
+
message.startsWith("importCapsule: archive") ||
|
|
55
|
+
message.startsWith("importCapsule: bundle") ||
|
|
56
|
+
message.startsWith("importCapsule: manifest") ||
|
|
57
|
+
message.startsWith("importCapsule: record") ||
|
|
58
|
+
/incorrect header check|invalid stored block lengths|not in gzip format|unexpected end of file/i.test(message)
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* One message for every refusal before confinement is proven. A caller that
|
|
64
|
+
* can name any server path must not learn from the error whether that path
|
|
65
|
+
* exists, is a directory, or is unreadable.
|
|
66
|
+
*/
|
|
67
|
+
const IMPORT_SOURCE_REFUSED =
|
|
68
|
+
"capsule import failed: archivePath must be an existing file inside the namespace capsule store";
|
|
69
|
+
|
|
70
|
+
/** Resolve a path to its real path; a missing, looping, or unreadable path resolves to null. */
|
|
71
|
+
async function realpathOrNull(target: string): Promise<string | null> {
|
|
72
|
+
try {
|
|
73
|
+
return await realpath(target);
|
|
74
|
+
} catch (cause) {
|
|
75
|
+
if (!isInputFsError(cause)) throw cause;
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** True when `target` is a strict descendant of `directory` (both already resolved). */
|
|
81
|
+
function isInsideDirectory(directory: string, target: string): boolean {
|
|
82
|
+
const rel = path.relative(directory, target);
|
|
83
|
+
return rel !== "" && rel !== ".." && !rel.startsWith(`..${path.sep}`) && !path.isAbsolute(rel);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Validate a remote import source and confine it to the namespace capsule
|
|
88
|
+
* store. Both real paths are resolved first, so `..` segments and store
|
|
89
|
+
* symlinks that point outside are refused. Confinement is checked before the
|
|
90
|
+
* file is inspected in any other way, and every failure before it proves
|
|
91
|
+
* confinement raises the same message.
|
|
92
|
+
*/
|
|
93
|
+
export async function validateCapsuleImportArchive(archivePath: string, storageDir: string): Promise<void> {
|
|
94
|
+
const storeReal = await realpathOrNull(defaultCapsulesDir(storageDir));
|
|
95
|
+
const archiveReal = await realpathOrNull(archivePath);
|
|
96
|
+
if (storeReal === null || archiveReal === null || !isInsideDirectory(storeReal, archiveReal)) {
|
|
97
|
+
throw new EngramAccessInputError(IMPORT_SOURCE_REFUSED);
|
|
98
|
+
}
|
|
99
|
+
// The path now names a store entry, so the checks below only describe the store.
|
|
100
|
+
if (!(await stat(archiveReal)).isFile()) {
|
|
101
|
+
throw new EngramAccessInputError("capsule import failed: archivePath must point to a file");
|
|
102
|
+
}
|
|
103
|
+
try {
|
|
104
|
+
await access(archiveReal, fsConstants.R_OK);
|
|
105
|
+
} catch (cause) {
|
|
106
|
+
if (!isInputFsError(cause)) throw cause;
|
|
107
|
+
throw new EngramAccessInputError("capsule import failed: archive is not readable");
|
|
108
|
+
}
|
|
109
|
+
}
|
package/src/cli.ts
CHANGED
|
@@ -4895,7 +4895,7 @@ export function registerCli(
|
|
|
4895
4895
|
// No sidecar — attempt in-memory decryption if the secure-store is
|
|
4896
4896
|
// unlocked. decryptCapsuleFileInMemory returns the plaintext gzip
|
|
4897
4897
|
// bytes; we then gunzip and parse exactly like the plaintext path.
|
|
4898
|
-
const {
|
|
4898
|
+
const { gunzipCapsuleArchive } = await import("./transfer/capsule-gunzip.js");
|
|
4899
4899
|
const { parseExportBundle } = await import("./transfer/types.js");
|
|
4900
4900
|
let decryptedBuf: Buffer;
|
|
4901
4901
|
try {
|
|
@@ -4917,7 +4917,7 @@ export function registerCli(
|
|
|
4917
4917
|
process.exitCode = 1;
|
|
4918
4918
|
return;
|
|
4919
4919
|
}
|
|
4920
|
-
const json =
|
|
4920
|
+
const json = gunzipCapsuleArchive(decryptedBuf, "capsule inspect", archivePath);
|
|
4921
4921
|
const parsed2 = parseExportBundle(JSON.parse(json));
|
|
4922
4922
|
if (parsed2.capsuleVersion !== 2) {
|
|
4923
4923
|
process.stderr.write(
|
|
@@ -4929,10 +4929,10 @@ export function registerCli(
|
|
|
4929
4929
|
manifest = (parsed2.bundle as { manifest: Record<string, unknown> }).manifest;
|
|
4930
4930
|
} else {
|
|
4931
4931
|
const { readFile } = await import("node:fs/promises");
|
|
4932
|
-
const {
|
|
4932
|
+
const { gunzipCapsuleArchive } = await import("./transfer/capsule-gunzip.js");
|
|
4933
4933
|
const { parseExportBundle } = await import("./transfer/types.js");
|
|
4934
4934
|
const buf = await readFile(archivePath);
|
|
4935
|
-
const json =
|
|
4935
|
+
const json = gunzipCapsuleArchive(buf, "capsule inspect", archivePath);
|
|
4936
4936
|
const parsed2 = parseExportBundle(JSON.parse(json));
|
|
4937
4937
|
if (parsed2.capsuleVersion !== 2) {
|
|
4938
4938
|
process.stderr.write(
|
|
@@ -410,6 +410,55 @@ test("a claim that inverts a negated quote is rejected, a restated exclusion is
|
|
|
410
410
|
assert.deepEqual(keptContents(grounded), ["Alice would avoid approving the budget."]);
|
|
411
411
|
});
|
|
412
412
|
|
|
413
|
+
test("a claim that keeps one quote negation and flips another is rejected", () => {
|
|
414
|
+
const source = "Notes: Alice did not approve the budget. Bob did not review the ledger.";
|
|
415
|
+
const quote = "Alice did not approve the budget. Bob did not review the ledger.";
|
|
416
|
+
const grounded = filterExtractionResultBySource(
|
|
417
|
+
resultOf([
|
|
418
|
+
{ content: "Alice did not approve the budget, and Bob reviewed the ledger.", quote },
|
|
419
|
+
{
|
|
420
|
+
content: "Alice did not approve the budget, and Bob did not review the ledger.",
|
|
421
|
+
quote,
|
|
422
|
+
},
|
|
423
|
+
]),
|
|
424
|
+
source,
|
|
425
|
+
source,
|
|
426
|
+
);
|
|
427
|
+
assert.deepEqual(keptContents(grounded), [
|
|
428
|
+
"Alice did not approve the budget, and Bob did not review the ledger.",
|
|
429
|
+
]);
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
test("a claim that keeps the denial in a pronoun clause is kept", () => {
|
|
433
|
+
const source = "Notes: Alice did not approve the budget.";
|
|
434
|
+
const quote = "Alice did not approve the budget.";
|
|
435
|
+
const claims = [
|
|
436
|
+
"Alice discussed the budget; she did not approve it.",
|
|
437
|
+
"Alice reviewed the budget, but she did not approve it.",
|
|
438
|
+
];
|
|
439
|
+
const grounded = filterExtractionResultBySource(
|
|
440
|
+
resultOf(claims.map((content) => ({ content, quote }))),
|
|
441
|
+
source,
|
|
442
|
+
source,
|
|
443
|
+
);
|
|
444
|
+
assert.deepEqual(keptContents(grounded), claims);
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
test("a negator in a claim clause that shares only the subject does not keep the denial", () => {
|
|
448
|
+
const source = "Notes: Alice did not approve the budget. Alice did not review the contract.";
|
|
449
|
+
const grounded = filterExtractionResultBySource(
|
|
450
|
+
resultOf([
|
|
451
|
+
{
|
|
452
|
+
content: "Alice did not review the contract. She approved the budget.",
|
|
453
|
+
quote: "Alice did not approve the budget.",
|
|
454
|
+
},
|
|
455
|
+
]),
|
|
456
|
+
source,
|
|
457
|
+
source,
|
|
458
|
+
);
|
|
459
|
+
assert.equal(grounded.facts.length, 0);
|
|
460
|
+
});
|
|
461
|
+
|
|
413
462
|
test("a claim that inverts a denial verb in the quote is rejected", () => {
|
|
414
463
|
const source = "Notes: Alice denied approving the budget. Bob reviewed it.";
|
|
415
464
|
const grounded = filterExtractionResultBySource(
|
|
@@ -544,3 +593,79 @@ test("a quote naming rewritten text is located after temporal anchoring", () =>
|
|
|
544
593
|
);
|
|
545
594
|
assert.equal(grounded.facts.length, 1);
|
|
546
595
|
});
|
|
596
|
+
|
|
597
|
+
const TURN_ONE =
|
|
598
|
+
"The river gauges read high all week near the mill.\n\nAlso the culvert repair is scheduled for next Tuesday at the plant.";
|
|
599
|
+
const TURN_TWO = "A different conversation about the warehouse roof leaks and the insurance claim.";
|
|
600
|
+
const TURNED_SOURCE = `${TURN_ONE}\n\n${TURN_TWO}`;
|
|
601
|
+
|
|
602
|
+
test("a quote crossing a blank line inside one turn is anchored when turn boundaries are given", () => {
|
|
603
|
+
const quote = "near the mill. Also the culvert repair is scheduled for next Tuesday at the plant";
|
|
604
|
+
const anchors = quoteAnchors(quote, TURNED_SOURCE, undefined, [TURN_ONE, TURN_TWO]);
|
|
605
|
+
assert.equal(anchors.length, 1);
|
|
606
|
+
assert.equal(anchors[0]!.quote, quote);
|
|
607
|
+
});
|
|
608
|
+
|
|
609
|
+
test("a quote spanning two turns still yields no anchor even with turn boundaries given", () => {
|
|
610
|
+
const stitched = "scheduled for next Tuesday at the plant.\n\nA different conversation about the warehouse";
|
|
611
|
+
assert.deepEqual(quoteAnchors(stitched, TURNED_SOURCE, undefined, [TURN_ONE, TURN_TWO]), []);
|
|
612
|
+
});
|
|
613
|
+
|
|
614
|
+
test("the anchor window reaches past a blank line to its turn's end, never into the next turn", () => {
|
|
615
|
+
const [anchor] = quoteAnchors(
|
|
616
|
+
"The river gauges read high all week near the mill.",
|
|
617
|
+
TURNED_SOURCE,
|
|
618
|
+
undefined,
|
|
619
|
+
[TURN_ONE, TURN_TWO],
|
|
620
|
+
);
|
|
621
|
+
assert.ok(anchor !== undefined);
|
|
622
|
+
assert.ok(anchor.window.includes("culvert repair is scheduled for next Tuesday at the plant"));
|
|
623
|
+
assert.ok(!anchor.window.includes("warehouse"));
|
|
624
|
+
});
|
|
625
|
+
|
|
626
|
+
test("without turn boundaries a blank line still rejects the quote and cuts the window", () => {
|
|
627
|
+
const quote = "near the mill. Also the culvert repair is scheduled for next Tuesday at the plant";
|
|
628
|
+
assert.deepEqual(quoteAnchors(quote, TURNED_SOURCE), []);
|
|
629
|
+
const [anchor] = quoteAnchors("The river gauges read high all week near the mill.", TURNED_SOURCE);
|
|
630
|
+
assert.ok(anchor !== undefined);
|
|
631
|
+
assert.ok(!anchor.window.includes("culvert repair"));
|
|
632
|
+
});
|
|
633
|
+
|
|
634
|
+
test("turn texts that do not tile the source fall back to blank-line behavior", () => {
|
|
635
|
+
const quote = "near the mill. Also the culvert repair is scheduled for next Tuesday at the plant";
|
|
636
|
+
assert.deepEqual(quoteAnchors(quote, TURNED_SOURCE, undefined, ["a turn that is not in the source"]), []);
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
const LONG_TAIL = Array.from({ length: 60 }, (_, index) => `word${index} filler`).join(" ");
|
|
640
|
+
const LONG_TURN = `The river gauges read high all week near the mill. ${LONG_TAIL}`;
|
|
641
|
+
const LONG_SOURCE = `${LONG_TURN}\n\n${TURN_TWO}`;
|
|
642
|
+
|
|
643
|
+
test("the window cut by the turn length ends on a whole word, matching the no-turns window", () => {
|
|
644
|
+
const quote = "The river gauges read high all week near the mill.";
|
|
645
|
+
const [bounded] = quoteAnchors(quote, LONG_SOURCE, undefined, [LONG_TURN, TURN_TWO]);
|
|
646
|
+
const [plain] = quoteAnchors(quote, LONG_TURN);
|
|
647
|
+
assert.ok(bounded !== undefined && plain !== undefined);
|
|
648
|
+
assert.equal(bounded.window, plain.window);
|
|
649
|
+
});
|
|
650
|
+
|
|
651
|
+
test("the window of a quote in a non-last turn does not end with a separator newline", () => {
|
|
652
|
+
const [anchor] = quoteAnchors(
|
|
653
|
+
"The river gauges read high all week near the mill.",
|
|
654
|
+
TURNED_SOURCE,
|
|
655
|
+
undefined,
|
|
656
|
+
[TURN_ONE, TURN_TWO],
|
|
657
|
+
);
|
|
658
|
+
assert.ok(anchor !== undefined);
|
|
659
|
+
assert.ok(!anchor.window.endsWith("\n"));
|
|
660
|
+
});
|
|
661
|
+
|
|
662
|
+
test("a quote ending exactly at the last character of a non-last turn still anchors", () => {
|
|
663
|
+
const anchors = quoteAnchors(
|
|
664
|
+
"Also the culvert repair is scheduled for next Tuesday at the plant.",
|
|
665
|
+
TURNED_SOURCE,
|
|
666
|
+
undefined,
|
|
667
|
+
[TURN_ONE, TURN_TWO],
|
|
668
|
+
);
|
|
669
|
+
assert.equal(anchors.length, 1);
|
|
670
|
+
assert.ok(anchors[0]!.window.endsWith("at the plant."));
|
|
671
|
+
});
|