@remnic/core 10.0.84 → 10.0.85
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 +67 -66
- package/dist/access-authorization-probe.js +68 -67
- package/dist/access-boundary.js +67 -66
- package/dist/access-cli.js +146 -144
- package/dist/access-cli.js.map +1 -1
- package/dist/access-extraction-force-flush.js +67 -66
- package/dist/access-http-briefing.js +68 -67
- package/dist/access-http-query.js +69 -68
- package/dist/access-http.js +91 -89
- package/dist/access-identity-continuity-surface.js +67 -66
- package/dist/access-lcm-surface.js +67 -66
- 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 +82 -80
- package/dist/access-namespace-preflight.js +67 -66
- package/dist/access-observe-write-category.js +9 -9
- package/dist/access-observe-write-surface.d.ts.map +1 -1
- package/dist/access-observe-write-surface.js +67 -66
- package/dist/access-offline-manifest.js +3 -3
- package/dist/access-operations-batch.js +71 -70
- package/dist/access-operations.js +78 -77
- package/dist/access-recall-concurrency.js +67 -66
- package/dist/access-recall-response.js +67 -66
- package/dist/access-recall-surface.js +67 -66
- package/dist/access-schema.js +4 -4
- package/dist/access-service.js +67 -66
- package/dist/access-surface-catalog.js +69 -68
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/active-recall.js +31 -31
- package/dist/{auto-sync-C7E6G7Y2.js → auto-sync-3AZW7MXI.js} +6 -6
- package/dist/briefing.js +25 -25
- 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 +5 -0
- package/dist/buffer-turn-helpers.d.ts.map +1 -1
- package/dist/buffer-turn-helpers.js +1 -1
- package/dist/buffer.d.ts +4 -1
- package/dist/buffer.d.ts.map +1 -1
- package/dist/buffer.js +9 -9
- package/dist/calibration.js +2 -2
- package/dist/{capsule-crypto-YO5QJ6L3.js → capsule-crypto-GWVG7LGC.js} +2 -2
- package/dist/capsule-gunzip-KGBDGF7P.js +11 -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 +32 -32
- 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-T6T2RMWW.js → chunk-23B4HLWG.js} +5 -5
- package/dist/{chunk-LECSS7EE.js → chunk-2ASEDFOA.js} +2 -2
- package/dist/{chunk-TPX7XXY4.js → chunk-2JAT4S7N.js} +2 -2
- package/dist/{chunk-XRBHIR7Q.js → chunk-2URKYLMK.js} +2 -2
- package/dist/{chunk-IN4OFAHX.js → chunk-2XYDL2FG.js} +2 -2
- package/dist/{chunk-HQGATKG2.js → chunk-3KGCHTTK.js} +2 -2
- package/dist/{chunk-YAUHSNPB.js → chunk-3LHPTBWG.js} +2 -2
- package/dist/{chunk-7PMOCQOL.js → chunk-3ODZLCHC.js} +192 -63
- package/dist/chunk-3ODZLCHC.js.map +1 -0
- package/dist/{chunk-XT45WCKX.js → chunk-3VU2FDTU.js} +8 -8
- package/dist/{chunk-CIIHIAJ2.js → chunk-433EXTC4.js} +3 -3
- package/dist/{chunk-QZSIDSB2.js → chunk-44FQCC5D.js} +2 -2
- package/dist/{chunk-YUTT4ZTI.js → chunk-45VUHDV2.js} +2 -2
- package/dist/{chunk-54FDG7K7.js → chunk-4DPLCYEK.js} +2 -2
- package/dist/{chunk-KO3YBHOV.js → chunk-4IWEPQEV.js} +2 -2
- package/dist/{chunk-H7BZBSP6.js → chunk-52II7PB6.js} +4 -4
- package/dist/{chunk-K6RTQZA4.js → chunk-6DANGCMO.js} +2 -2
- package/dist/{chunk-2IW5PT7U.js → chunk-6KFFRMPQ.js} +2 -2
- package/dist/{chunk-MSIRVXQ3.js → chunk-73YVMZ7D.js} +4 -4
- package/dist/{chunk-A7BM2JTH.js → chunk-AJHNXIQU.js} +2 -2
- package/dist/{chunk-2D7BTSDW.js → chunk-ANZZLRUX.js} +2 -2
- package/dist/{chunk-YOEYL6CH.js → chunk-AP3TSV6S.js} +2 -2
- package/dist/{chunk-GQZSGXR6.js → chunk-BATPQNRG.js} +2 -2
- package/dist/{chunk-D5SSBCYY.js → chunk-BLGQUZFB.js} +2 -2
- package/dist/{chunk-BDN3TDGV.js → chunk-BLMTOIBK.js} +2 -2
- package/dist/{chunk-B74NPUHT.js → chunk-BMIM6ESC.js} +43 -43
- package/dist/chunk-BMIM6ESC.js.map +1 -0
- package/dist/{chunk-R45L4TV6.js → chunk-BUKK5SWA.js} +6 -6
- package/dist/{chunk-TFLPDNQV.js → chunk-CCU7URRP.js} +2 -2
- package/dist/{chunk-2XJZLSXE.js → chunk-CMRHXPLQ.js} +20 -20
- package/dist/{chunk-BK4FBHZ3.js → chunk-D6THW7PA.js} +3 -3
- package/dist/{chunk-BFBS7OFQ.js → chunk-DC55RIEZ.js} +4 -4
- package/dist/{chunk-VKDAJJQP.js → chunk-DI5ET2IE.js} +5 -5
- package/dist/{chunk-QZBTIYKD.js → chunk-DM4RRTN7.js} +3 -3
- package/dist/{chunk-EBOHFZI4.js → chunk-E5QEF3JO.js} +2 -2
- package/dist/{chunk-K3B72DKJ.js → chunk-E7V5AK7I.js} +2 -2
- package/dist/{chunk-WAD32CZG.js → chunk-ELWI2R6H.js} +26 -13
- package/dist/chunk-ELWI2R6H.js.map +1 -0
- package/dist/{chunk-BV2BRHD4.js → chunk-FHGWKODN.js} +2 -2
- package/dist/{chunk-HPFVZPRH.js → chunk-FK4WC6VK.js} +3 -3
- package/dist/{chunk-VLMBSGQF.js → chunk-FRM4UTDR.js} +6 -6
- package/dist/{chunk-LTDLJCMQ.js → chunk-FZPDRCOB.js} +2 -2
- package/dist/{chunk-ZJJFUEPO.js → chunk-GBOYOL5L.js} +2 -2
- package/dist/{chunk-YUTG35M4.js → chunk-GJVGFKOU.js} +2 -2
- package/dist/{chunk-77R7BQZ2.js → chunk-GKYIRTNX.js} +33 -11
- package/dist/{chunk-77R7BQZ2.js.map → chunk-GKYIRTNX.js.map} +1 -1
- package/dist/{chunk-K36RMINQ.js → chunk-GOZXQNIM.js} +3 -3
- package/dist/{chunk-HWHNQVRV.js → chunk-GYNRNKMW.js} +2 -2
- package/dist/{chunk-LU66I56Q.js → chunk-H34INI3P.js} +29 -3
- package/dist/chunk-H34INI3P.js.map +1 -0
- package/dist/{chunk-HLKUZW42.js → chunk-H4D5YURJ.js} +80 -94
- package/dist/chunk-H4D5YURJ.js.map +1 -0
- package/dist/{chunk-6LCWKS62.js → chunk-HVFX2N2G.js} +60 -59
- package/dist/chunk-HVFX2N2G.js.map +1 -0
- package/dist/chunk-IGLJNHOX.js +62 -0
- package/dist/chunk-IGLJNHOX.js.map +1 -0
- package/dist/{chunk-KFLD7ZZG.js → chunk-IUKYFTGW.js} +3 -3
- package/dist/{chunk-YK7GOPIE.js → chunk-JFH6JAGY.js} +6 -4
- package/dist/chunk-JFH6JAGY.js.map +1 -0
- package/dist/{chunk-BNQJKWWZ.js → chunk-K3FH3LAQ.js} +4 -4
- package/dist/{chunk-FJ2VJTGA.js → chunk-KHZVAISH.js} +2 -2
- package/dist/{chunk-WHQXWFH7.js → chunk-LT3CMO65.js} +2 -2
- package/dist/{chunk-NUSAAN75.js → chunk-MHSBOEH7.js} +2 -2
- package/dist/{chunk-KJCL2FZO.js → chunk-MNYQVYJ4.js} +2 -2
- package/dist/{chunk-RZH5RVJC.js → chunk-MTTYIXSU.js} +2 -2
- package/dist/{chunk-FVRTCYZ3.js → chunk-MVOJDLXS.js} +2 -2
- package/dist/{chunk-KESJ5XX3.js → chunk-MYCCO6AA.js} +2 -2
- package/dist/{chunk-66JOLMWS.js → chunk-MZCGHPIJ.js} +2 -2
- package/dist/{chunk-B4ZU34JQ.js → chunk-N6II66E5.js} +3 -3
- package/dist/{chunk-BK7AJUWB.js → chunk-NIV7RPWQ.js} +6 -6
- package/dist/{chunk-TLHF75OR.js → chunk-O55AGDTI.js} +10 -10
- package/dist/{chunk-GGJFRVRD.js → chunk-OMYRPMQC.js} +2 -2
- package/dist/{chunk-3JPTUCD7.js → chunk-ONN2E5QD.js} +32 -23
- package/dist/chunk-ONN2E5QD.js.map +1 -0
- package/dist/{chunk-XHGYZRVW.js → chunk-OSTFDWZJ.js} +4 -4
- package/dist/{chunk-BXLOS5AJ.js → chunk-OWHERGF2.js} +2 -2
- package/dist/{chunk-WC475JOG.js → chunk-P225W4RQ.js} +6 -6
- package/dist/{chunk-TFA6HPOA.js → chunk-QCP75JGO.js} +5 -5
- package/dist/{chunk-JRVMCZE3.js → chunk-QEYTRFR3.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-VUROWXFL.js → chunk-RNGDKFY2.js} +2 -2
- package/dist/{chunk-FF6N7BXC.js → chunk-S45INSV3.js} +4 -4
- package/dist/{chunk-2RUTN7PR.js → chunk-S7GJNA3K.js} +2 -2
- package/dist/{chunk-XYP5WBDO.js → chunk-SGHV6LZ7.js} +13 -13
- package/dist/chunk-SGHV6LZ7.js.map +1 -0
- package/dist/{chunk-RJWL3RHB.js → chunk-TFEHSPGQ.js} +2 -2
- package/dist/{chunk-T77AX6DG.js → chunk-TQVECGUQ.js} +4 -4
- package/dist/{chunk-OQSSQOKQ.js → chunk-TV65NR7L.js} +2 -2
- 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-4EACCIPO.js → chunk-UHPHH74F.js} +2 -2
- package/dist/{chunk-DQEMWVMT.js → chunk-UVYI6VIX.js} +1 -1
- package/dist/{chunk-6QYPL6NI.js → chunk-V45TEVDA.js} +3 -3
- package/dist/{chunk-GCAQ3VUJ.js → chunk-VCVEMQJK.js} +2 -2
- package/dist/{chunk-6L63IN3M.js → chunk-VEFGHRKV.js} +1 -1
- package/dist/{chunk-E33UJHY3.js → chunk-WFDWLWDK.js} +2 -2
- package/dist/{chunk-4KLQI3L2.js → chunk-WLNWFHX3.js} +1 -1
- package/dist/chunk-WLNWFHX3.js.map +1 -0
- package/dist/{chunk-KQLBXUUQ.js → chunk-WYG5UNDY.js} +2 -2
- package/dist/{chunk-MPGLM2VU.js → chunk-X7REO4CH.js} +2 -2
- package/dist/{chunk-MPDLLLOG.js → chunk-XO23OKMK.js} +9 -5
- package/dist/chunk-XO23OKMK.js.map +1 -0
- package/dist/{chunk-Z3DDQXM4.js → chunk-XSFQN7TP.js} +35 -36
- package/dist/chunk-XSFQN7TP.js.map +1 -0
- package/dist/{chunk-FZVROZKC.js → chunk-XVZA6VXC.js} +4 -4
- package/dist/{chunk-WV254W4V.js → chunk-Y3IYKNBY.js} +2 -2
- package/dist/{chunk-FUOAIJKQ.js → chunk-Y43X3E24.js} +2 -2
- package/dist/{chunk-3T3VHXUH.js → chunk-YAAKVTZA.js} +2 -2
- package/dist/{chunk-VPEIWMUT.js → chunk-YLTU2DC4.js} +2 -2
- package/dist/{chunk-65SKM4BF.js → chunk-YNBMBL4C.js} +2 -2
- package/dist/{chunk-PJYK7HH2.js → chunk-ZWTHVUT5.js} +2 -2
- package/dist/cli.js +110 -108
- package/dist/coding/export-okf-codegraph.js +25 -25
- package/dist/coding/pre-action-gate.js +2 -2
- package/dist/compounding/engine.js +27 -27
- package/dist/config.js +28 -28
- package/dist/connectors/codex-materialize-runner.js +25 -25
- package/dist/connectors/index.js +25 -25
- package/dist/contradiction/index.js +4 -4
- package/dist/convergence-refresh.js +27 -27
- package/dist/conversation-index/backend.js +2 -2
- package/dist/corpus-watermark.js +27 -27
- package/dist/deep-recall-http-glue.js +5 -5
- package/dist/entity-retrieval.js +25 -25
- package/dist/event-order-recall.js +2 -2
- package/dist/explicit-capture.js +5 -5
- package/dist/external-wiki-access.js +68 -67
- package/dist/extraction-evidence-class.js +2 -2
- package/dist/extraction-quote-grounding.d.ts.map +1 -1
- package/dist/extraction-quote-grounding.js +1 -1
- package/dist/extraction-source-grounding-rules.js +2 -2
- package/dist/extraction-source-grounding.js +5 -5
- package/dist/extraction-span-materialize.js +2 -2
- package/dist/extraction.js +40 -40
- 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 +25 -25
- package/dist/index.js +195 -193
- package/dist/lcm/engine.js +2 -2
- package/dist/lcm/index.js +2 -2
- package/dist/local-llm.js +2 -2
- package/dist/location/index.js +28 -28
- package/dist/maintenance/memory-governance.js +25 -25
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +25 -25
- package/dist/maintenance/rebuild-memory-projection-runner.js +27 -27
- package/dist/maintenance/rebuild-memory-projection.js +26 -26
- package/dist/memory-browse-operations.js +68 -67
- package/dist/memory-subject.js +2 -2
- package/dist/namespaces/migrate.js +26 -26
- package/dist/namespaces/search.d.ts +8 -0
- package/dist/namespaces/search.d.ts.map +1 -1
- package/dist/namespaces/search.js +10 -6
- package/dist/namespaces/storage.js +25 -25
- package/dist/operator-doctor-corpus.js +28 -28
- package/dist/operator-toolkit.js +39 -39
- 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 +157 -155
- 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 +147 -145
- 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 +39 -39
- package/dist/orchestrator.js +146 -144
- package/dist/provenance.js +2 -2
- package/dist/recall-navigation-operations.js +68 -67
- package/dist/recall-navigation.js +67 -66
- package/dist/reconcile/manifest.js +2 -2
- package/dist/{resolution-BNWE5Y25.js → resolution-23ZBDM6A.js} +5 -5
- package/dist/resolution-23ZBDM6A.js.map +1 -0
- package/dist/resume-bundles.js +29 -29
- package/dist/salvage-envelope.js +4 -4
- package/dist/search/factory.js +5 -5
- package/dist/search/index.js +9 -9
- package/dist/semantic-consolidation.js +26 -26
- package/dist/semantic-rule-promotion.js +25 -25
- package/dist/semantic-rule-verifier.js +25 -25
- package/dist/source-agent-qualifier.js +31 -31
- 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 +24 -24
- package/dist/subject-config.js +3 -3
- package/dist/summarizer.js +3 -3
- package/dist/support-passport/index.js +70 -69
- 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 +25 -25
- package/dist/verified-recall.js +25 -25
- 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-mcp-frames.test.ts +47 -0
- package/src/access-mcp-frames.ts +74 -0
- package/src/access-mcp.test.ts +146 -0
- package/src/access-mcp.ts +30 -30
- package/src/access-observe-write-surface.ts +4 -4
- package/src/backlog-scheduler.test.ts +443 -3
- package/src/buffer-persistence.ts +15 -6
- package/src/buffer-turn-helpers.ts +6 -0
- package/src/buffer.ts +6 -6
- package/src/cli.ts +4 -4
- package/src/extraction-quote-grounding.test.ts +49 -0
- package/src/extraction-quote-grounding.ts +50 -12
- package/src/fact-dedup-window.test.ts +103 -20
- package/src/namespaces/search.test.ts +339 -0
- package/src/namespaces/search.ts +54 -1
- 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/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-3JPTUCD7.js.map +0 -1
- package/dist/chunk-4KLQI3L2.js.map +0 -1
- package/dist/chunk-6LCWKS62.js.map +0 -1
- package/dist/chunk-7PMOCQOL.js.map +0 -1
- package/dist/chunk-B74NPUHT.js.map +0 -1
- package/dist/chunk-HLKUZW42.js.map +0 -1
- package/dist/chunk-KQUSP6LB.js.map +0 -1
- package/dist/chunk-LU66I56Q.js.map +0 -1
- package/dist/chunk-MPDLLLOG.js.map +0 -1
- package/dist/chunk-WAD32CZG.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 → capsule-crypto-GWVG7LGC.js.map} +0 -0
- /package/dist/{resolution-BNWE5Y25.js.map → capsule-gunzip-KGBDGF7P.js.map} +0 -0
- /package/dist/{chunk-T6T2RMWW.js.map → chunk-23B4HLWG.js.map} +0 -0
- /package/dist/{chunk-LECSS7EE.js.map → chunk-2ASEDFOA.js.map} +0 -0
- /package/dist/{chunk-TPX7XXY4.js.map → chunk-2JAT4S7N.js.map} +0 -0
- /package/dist/{chunk-XRBHIR7Q.js.map → chunk-2URKYLMK.js.map} +0 -0
- /package/dist/{chunk-IN4OFAHX.js.map → chunk-2XYDL2FG.js.map} +0 -0
- /package/dist/{chunk-HQGATKG2.js.map → chunk-3KGCHTTK.js.map} +0 -0
- /package/dist/{chunk-YAUHSNPB.js.map → chunk-3LHPTBWG.js.map} +0 -0
- /package/dist/{chunk-XT45WCKX.js.map → chunk-3VU2FDTU.js.map} +0 -0
- /package/dist/{chunk-CIIHIAJ2.js.map → chunk-433EXTC4.js.map} +0 -0
- /package/dist/{chunk-QZSIDSB2.js.map → chunk-44FQCC5D.js.map} +0 -0
- /package/dist/{chunk-YUTT4ZTI.js.map → chunk-45VUHDV2.js.map} +0 -0
- /package/dist/{chunk-54FDG7K7.js.map → chunk-4DPLCYEK.js.map} +0 -0
- /package/dist/{chunk-KO3YBHOV.js.map → chunk-4IWEPQEV.js.map} +0 -0
- /package/dist/{chunk-H7BZBSP6.js.map → chunk-52II7PB6.js.map} +0 -0
- /package/dist/{chunk-K6RTQZA4.js.map → chunk-6DANGCMO.js.map} +0 -0
- /package/dist/{chunk-2IW5PT7U.js.map → chunk-6KFFRMPQ.js.map} +0 -0
- /package/dist/{chunk-MSIRVXQ3.js.map → chunk-73YVMZ7D.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-YOEYL6CH.js.map → chunk-AP3TSV6S.js.map} +0 -0
- /package/dist/{chunk-GQZSGXR6.js.map → chunk-BATPQNRG.js.map} +0 -0
- /package/dist/{chunk-D5SSBCYY.js.map → chunk-BLGQUZFB.js.map} +0 -0
- /package/dist/{chunk-BDN3TDGV.js.map → chunk-BLMTOIBK.js.map} +0 -0
- /package/dist/{chunk-R45L4TV6.js.map → chunk-BUKK5SWA.js.map} +0 -0
- /package/dist/{chunk-TFLPDNQV.js.map → chunk-CCU7URRP.js.map} +0 -0
- /package/dist/{chunk-2XJZLSXE.js.map → chunk-CMRHXPLQ.js.map} +0 -0
- /package/dist/{chunk-BK4FBHZ3.js.map → chunk-D6THW7PA.js.map} +0 -0
- /package/dist/{chunk-BFBS7OFQ.js.map → chunk-DC55RIEZ.js.map} +0 -0
- /package/dist/{chunk-VKDAJJQP.js.map → chunk-DI5ET2IE.js.map} +0 -0
- /package/dist/{chunk-QZBTIYKD.js.map → chunk-DM4RRTN7.js.map} +0 -0
- /package/dist/{chunk-EBOHFZI4.js.map → chunk-E5QEF3JO.js.map} +0 -0
- /package/dist/{chunk-K3B72DKJ.js.map → chunk-E7V5AK7I.js.map} +0 -0
- /package/dist/{chunk-BV2BRHD4.js.map → chunk-FHGWKODN.js.map} +0 -0
- /package/dist/{chunk-HPFVZPRH.js.map → chunk-FK4WC6VK.js.map} +0 -0
- /package/dist/{chunk-VLMBSGQF.js.map → chunk-FRM4UTDR.js.map} +0 -0
- /package/dist/{chunk-LTDLJCMQ.js.map → chunk-FZPDRCOB.js.map} +0 -0
- /package/dist/{chunk-ZJJFUEPO.js.map → chunk-GBOYOL5L.js.map} +0 -0
- /package/dist/{chunk-YUTG35M4.js.map → chunk-GJVGFKOU.js.map} +0 -0
- /package/dist/{chunk-K36RMINQ.js.map → chunk-GOZXQNIM.js.map} +0 -0
- /package/dist/{chunk-HWHNQVRV.js.map → chunk-GYNRNKMW.js.map} +0 -0
- /package/dist/{chunk-KFLD7ZZG.js.map → chunk-IUKYFTGW.js.map} +0 -0
- /package/dist/{chunk-BNQJKWWZ.js.map → chunk-K3FH3LAQ.js.map} +0 -0
- /package/dist/{chunk-FJ2VJTGA.js.map → chunk-KHZVAISH.js.map} +0 -0
- /package/dist/{chunk-WHQXWFH7.js.map → chunk-LT3CMO65.js.map} +0 -0
- /package/dist/{chunk-NUSAAN75.js.map → chunk-MHSBOEH7.js.map} +0 -0
- /package/dist/{chunk-KJCL2FZO.js.map → chunk-MNYQVYJ4.js.map} +0 -0
- /package/dist/{chunk-RZH5RVJC.js.map → chunk-MTTYIXSU.js.map} +0 -0
- /package/dist/{chunk-FVRTCYZ3.js.map → chunk-MVOJDLXS.js.map} +0 -0
- /package/dist/{chunk-KESJ5XX3.js.map → chunk-MYCCO6AA.js.map} +0 -0
- /package/dist/{chunk-66JOLMWS.js.map → chunk-MZCGHPIJ.js.map} +0 -0
- /package/dist/{chunk-B4ZU34JQ.js.map → chunk-N6II66E5.js.map} +0 -0
- /package/dist/{chunk-BK7AJUWB.js.map → chunk-NIV7RPWQ.js.map} +0 -0
- /package/dist/{chunk-TLHF75OR.js.map → chunk-O55AGDTI.js.map} +0 -0
- /package/dist/{chunk-GGJFRVRD.js.map → chunk-OMYRPMQC.js.map} +0 -0
- /package/dist/{chunk-XHGYZRVW.js.map → chunk-OSTFDWZJ.js.map} +0 -0
- /package/dist/{chunk-BXLOS5AJ.js.map → chunk-OWHERGF2.js.map} +0 -0
- /package/dist/{chunk-WC475JOG.js.map → chunk-P225W4RQ.js.map} +0 -0
- /package/dist/{chunk-TFA6HPOA.js.map → chunk-QCP75JGO.js.map} +0 -0
- /package/dist/{chunk-JRVMCZE3.js.map → chunk-QEYTRFR3.js.map} +0 -0
- /package/dist/{chunk-IZJQNDGI.js.map → chunk-R6HMAIKM.js.map} +0 -0
- /package/dist/{chunk-VUROWXFL.js.map → chunk-RNGDKFY2.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-RJWL3RHB.js.map → chunk-TFEHSPGQ.js.map} +0 -0
- /package/dist/{chunk-T77AX6DG.js.map → chunk-TQVECGUQ.js.map} +0 -0
- /package/dist/{chunk-OQSSQOKQ.js.map → chunk-TV65NR7L.js.map} +0 -0
- /package/dist/{chunk-HQPFACXO.js.map → chunk-UH3FPX3L.js.map} +0 -0
- /package/dist/{chunk-4EACCIPO.js.map → chunk-UHPHH74F.js.map} +0 -0
- /package/dist/{chunk-DQEMWVMT.js.map → chunk-UVYI6VIX.js.map} +0 -0
- /package/dist/{chunk-6QYPL6NI.js.map → chunk-V45TEVDA.js.map} +0 -0
- /package/dist/{chunk-GCAQ3VUJ.js.map → chunk-VCVEMQJK.js.map} +0 -0
- /package/dist/{chunk-6L63IN3M.js.map → chunk-VEFGHRKV.js.map} +0 -0
- /package/dist/{chunk-E33UJHY3.js.map → chunk-WFDWLWDK.js.map} +0 -0
- /package/dist/{chunk-KQLBXUUQ.js.map → chunk-WYG5UNDY.js.map} +0 -0
- /package/dist/{chunk-MPGLM2VU.js.map → chunk-X7REO4CH.js.map} +0 -0
- /package/dist/{chunk-FZVROZKC.js.map → chunk-XVZA6VXC.js.map} +0 -0
- /package/dist/{chunk-WV254W4V.js.map → chunk-Y3IYKNBY.js.map} +0 -0
- /package/dist/{chunk-FUOAIJKQ.js.map → chunk-Y43X3E24.js.map} +0 -0
- /package/dist/{chunk-3T3VHXUH.js.map → chunk-YAAKVTZA.js.map} +0 -0
- /package/dist/{chunk-VPEIWMUT.js.map → chunk-YLTU2DC4.js.map} +0 -0
- /package/dist/{chunk-65SKM4BF.js.map → chunk-YNBMBL4C.js.map} +0 -0
- /package/dist/{chunk-PJYK7HH2.js.map → chunk-ZWTHVUT5.js.map} +0 -0
- /package/dist/{first-start-migration-QVD22WWS.js.map → first-start-migration-A6PHIBUQ.js.map} +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { DrainedTurnSets } from "./buffer-turn-helpers.js";
|
|
2
|
+
import type { BufferEntryState, BufferState, BufferSurpriseEvent } from "./types.js";
|
|
2
3
|
import type { BufferSessionSaveOutcome } from "./storage/buffer-drain-claims.js";
|
|
3
4
|
|
|
4
5
|
/**
|
|
@@ -26,8 +27,8 @@ export interface BufferStorage {
|
|
|
26
27
|
export interface BufferPersistOutcome {
|
|
27
28
|
/** Sessions whose in-memory entry moved into a drain claim: the caller must evict them (a claimed session no longer lives in this process). */
|
|
28
29
|
handedOver: string[];
|
|
29
|
-
/** Per session, the turns a drain
|
|
30
|
-
drainedTurns: Map<string,
|
|
30
|
+
/** Per session, the turns a drain extracted, kept in their original lists. */
|
|
31
|
+
drainedTurns: Map<string, DrainedTurnSets>;
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
/**
|
|
@@ -73,17 +74,20 @@ export class BufferSessionPersistence {
|
|
|
73
74
|
storage: BufferStorage,
|
|
74
75
|
state: BufferState,
|
|
75
76
|
peekEntry: (key: string) => BufferEntryState | undefined,
|
|
77
|
+
reconcile?: { key: string; drained: DrainedTurnSets },
|
|
76
78
|
): Promise<BufferPersistOutcome> {
|
|
79
|
+
const drainedTurns = new Map<string, DrainedTurnSets>(
|
|
80
|
+
reconcile ? [[reconcile.key, reconcile.drained]] : [],
|
|
81
|
+
);
|
|
77
82
|
const saveSession = storage.saveBufferSession?.bind(storage);
|
|
78
83
|
const deleteSession = storage.deleteBufferSession?.bind(storage);
|
|
79
84
|
if (!saveSession || !deleteSession) {
|
|
80
85
|
await storage.saveBuffer(state);
|
|
81
86
|
this.dirty.clear();
|
|
82
87
|
this.deleted.clear();
|
|
83
|
-
return { handedOver: [], drainedTurns
|
|
88
|
+
return { handedOver: [], drainedTurns };
|
|
84
89
|
}
|
|
85
90
|
const handedOver: string[] = [];
|
|
86
|
-
const drainedTurns = new Map<string, BufferTurn[]>();
|
|
87
91
|
for (const key of [...this.deleted]) {
|
|
88
92
|
await deleteSession(key);
|
|
89
93
|
this.deleted.delete(key);
|
|
@@ -104,7 +108,12 @@ export class BufferSessionPersistence {
|
|
|
104
108
|
if (outcome?.status === "handed_over") handedOver.push(key);
|
|
105
109
|
// A drain tombstone: the turns it extracted must leave this process's
|
|
106
110
|
// copy too, or the owner would extract them a second time.
|
|
107
|
-
if (
|
|
111
|
+
if (
|
|
112
|
+
outcome?.drainedTurns &&
|
|
113
|
+
(outcome.drainedTurns.turns.length > 0 || outcome.drainedTurns.retainedTurns.length > 0)
|
|
114
|
+
) {
|
|
115
|
+
drainedTurns.set(key, outcome.drainedTurns);
|
|
116
|
+
}
|
|
108
117
|
}
|
|
109
118
|
return { handedOver, drainedTurns };
|
|
110
119
|
}
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import type { BufferEntryState, BufferState, BufferTurn } from "./types.js";
|
|
2
2
|
|
|
3
|
+
/** Extracted identities retain whether they came from active or retained turns. */
|
|
4
|
+
export interface DrainedTurnSets {
|
|
5
|
+
turns: BufferTurn[];
|
|
6
|
+
retainedTurns: BufferTurn[];
|
|
7
|
+
}
|
|
8
|
+
|
|
3
9
|
export interface BufferTurnOwner {
|
|
4
10
|
/**
|
|
5
11
|
* Server-resolved principal that owns this session at the authenticated
|
package/src/buffer.ts
CHANGED
|
@@ -300,16 +300,16 @@ export class SmartBuffer {
|
|
|
300
300
|
this.loaded = true;
|
|
301
301
|
}
|
|
302
302
|
|
|
303
|
-
private async saveUnlocked(): Promise<void> {
|
|
304
|
-
const { handedOver, drainedTurns } = await this.persistence.persist(this.storage, this.state, (key) => this.peekEntry(key) ?? undefined);
|
|
303
|
+
private async saveUnlocked(reconcile?: { key: string; drained: import("./buffer-turn-helpers.js").DrainedTurnSets }): Promise<void> {
|
|
304
|
+
const { handedOver, drainedTurns } = await this.persistence.persist(this.storage, this.state, (key) => this.peekEntry(key) ?? undefined, reconcile);
|
|
305
305
|
// A drain tombstone: the turns the drain extracted leave this copy too,
|
|
306
306
|
// so a stale owner never extracts (or persists) them a second time.
|
|
307
307
|
for (const [key, drained] of drainedTurns) {
|
|
308
308
|
const entry = this.peekEntry(key);
|
|
309
309
|
if (!entry) continue;
|
|
310
|
-
entry.turns = subtractBufferTurns(entry.turns, drained);
|
|
310
|
+
entry.turns = subtractBufferTurns(entry.turns, drained.turns);
|
|
311
311
|
if (entry.retainedTurns && entry.retainedTurns.length > 0) {
|
|
312
|
-
entry.retainedTurns = subtractBufferTurns(entry.retainedTurns, drained);
|
|
312
|
+
entry.retainedTurns = subtractBufferTurns(entry.retainedTurns, drained.retainedTurns);
|
|
313
313
|
if (entry.retainedTurns.length === 0) delete entry.retainedTurns;
|
|
314
314
|
}
|
|
315
315
|
if (key === "default") this.state.turns = entry.turns;
|
|
@@ -340,8 +340,8 @@ export class SmartBuffer {
|
|
|
340
340
|
return bufferEntryCounts(this.state);
|
|
341
341
|
}
|
|
342
342
|
|
|
343
|
-
async save(): Promise<void> {
|
|
344
|
-
await this.enqueueMutation(async () => this.saveUnlocked());
|
|
343
|
+
async save(reconcile?: { key: string; drained: import("./buffer-turn-helpers.js").DrainedTurnSets }): Promise<void> {
|
|
344
|
+
await this.enqueueMutation(async () => this.saveUnlocked(reconcile));
|
|
345
345
|
}
|
|
346
346
|
|
|
347
347
|
/**
|
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(
|
|
@@ -130,24 +130,62 @@ function hasNegation(text: string): boolean {
|
|
|
130
130
|
return NEGATOR_PATTERN.test(text.replace(/[\u2018\u2019]/gu, "'")) || hasDenialReporting(text);
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
+
const CLAUSE_PATTERN = /[^;.!?\n]+[;.!?]*/gu;
|
|
134
|
+
/** Split "X, and Y" claim coordination without touching list commas. */
|
|
135
|
+
const CLAIM_COORD_SPLIT = /,\s{1,8}(?:and|but|or|nor)\s{1,8}/iu;
|
|
136
|
+
|
|
137
|
+
function splitClaimClauses(content: string): string[] {
|
|
138
|
+
return (content.match(CLAUSE_PATTERN) ?? [content]).flatMap((clause) => {
|
|
139
|
+
const parts = clause
|
|
140
|
+
.split(CLAIM_COORD_SPLIT)
|
|
141
|
+
.map((part) => part.trim())
|
|
142
|
+
.filter((part) => part.length > 0);
|
|
143
|
+
return parts.length > 0 ? parts : [clause];
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function clauseOverlap(clauseTokens: readonly string[], target: string) {
|
|
148
|
+
const has = tokenPool(tokenize(target));
|
|
149
|
+
const shared = clauseTokens.filter(has).length;
|
|
150
|
+
return { shared, ratio: clauseTokens.length === 0 ? 0 : shared / clauseTokens.length };
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** What a quote clause's first negator governs: the words after it. */
|
|
154
|
+
function negatedScope(clause: string): string {
|
|
155
|
+
const match = NEGATOR_PATTERN.exec(clause.replace(/[\u2018\u2019]/gu, "'"));
|
|
156
|
+
return match ? clause.slice(match.index + match[0].length) : clause;
|
|
157
|
+
}
|
|
158
|
+
|
|
133
159
|
/**
|
|
134
160
|
* True when the claim asserts what a quote clause denies or does not assert:
|
|
135
161
|
* "did not approve the budget" or "denied approving it" restated as "approved
|
|
136
162
|
* the budget", "suspects Bob stole funds" or "Is Alice the CEO?" restated as a
|
|
137
|
-
* plain statement.
|
|
138
|
-
*
|
|
163
|
+
* plain statement. The claim must restate the quote clause, and none of its
|
|
164
|
+
* clauses that share a word with what the negator governs may keep the
|
|
165
|
+
* negator, exclusion word, or reporting marker ("do not X" reworded as "X is
|
|
166
|
+
* excluded", or "Alice reviewed it, but she did not approve it"). A negator in
|
|
167
|
+
* a clause about something else does not count, so a claim that keeps one
|
|
168
|
+
* quote negation can still misstate another quote clause, and a claim clause
|
|
169
|
+
* that shares only the subject does not satisfy the check.
|
|
139
170
|
*/
|
|
140
171
|
function misstatesQuote(content: string, quote: string): boolean {
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
const
|
|
150
|
-
|
|
172
|
+
const claimClauses = splitClaimClauses(content);
|
|
173
|
+
return (quote.match(CLAUSE_PATTERN) ?? []).some((quoteClause) => {
|
|
174
|
+
const needsNegation = hasNegation(quoteClause);
|
|
175
|
+
const needsReporting = quoteClause.trim().endsWith("?") || hasNonAssertiveReporting(quoteClause);
|
|
176
|
+
if (!needsNegation && !needsReporting) return false;
|
|
177
|
+
const clauseTokens = [...tokenize(quoteClause)];
|
|
178
|
+
const whole = clauseOverlap(clauseTokens, content);
|
|
179
|
+
if (whole.shared < GROUNDING_MIN_SHARED_TOKENS || whole.ratio < 0.5) return false;
|
|
180
|
+
const clausesSharing = (tokens: readonly string[]) =>
|
|
181
|
+
claimClauses.filter((claimClause) => clauseOverlap(tokens, claimClause).shared > 0);
|
|
182
|
+
if (needsNegation) {
|
|
183
|
+
const scopeTokens = [...tokenize(negatedScope(quoteClause))];
|
|
184
|
+
const related = clausesSharing(scopeTokens.length > 0 ? scopeTokens : clauseTokens);
|
|
185
|
+
if (!related.some((text) => hasNegation(text) || EXCLUSION_PATTERN.test(text))) return true;
|
|
186
|
+
}
|
|
187
|
+
return needsReporting
|
|
188
|
+
&& !clausesSharing(clauseTokens).some((text) => hasNonAssertiveReporting(text) || text.trim().endsWith("?"));
|
|
151
189
|
});
|
|
152
190
|
}
|
|
153
191
|
|
|
@@ -1,14 +1,27 @@
|
|
|
1
|
-
import test from "node:test";
|
|
1
|
+
import test, { mock } from "node:test";
|
|
2
2
|
import assert from "node:assert/strict";
|
|
3
|
-
import { mkdtemp, rm } from "node:fs/promises";
|
|
3
|
+
import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
4
4
|
import os from "node:os";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { StorageManager } from "./storage.js";
|
|
7
7
|
import { withHeldFileLock } from "./utils/serialize-mutations.js";
|
|
8
8
|
import { confirmActiveFactDuplicate, persistUnderFactDedupWindow } from "./orchestration/fact-dedup-window.js";
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
const SKY_OPTS = {
|
|
11
|
+
category: "fact",
|
|
12
|
+
contentHashDedupKey: "the sky is blue",
|
|
13
|
+
connector: undefined,
|
|
14
|
+
citationEnabled: false,
|
|
15
|
+
citationTemplate: "",
|
|
16
|
+
} as const;
|
|
17
|
+
const CONTENDED_LOCK_OPTIONS = { maxWaitMs: 40, pollMs: 10, retryMaxAttempts: 2, retryBaseMs: 10 };
|
|
18
|
+
|
|
19
|
+
/** Hold a fresh fact-hash index lock the way a peer mid-publish does; returns the release. */
|
|
20
|
+
async function holdIndexLock(root: string): Promise<() => Promise<void>> {
|
|
21
|
+
const lockPath = path.join(root, "state", "fact-hashes.txt.lock");
|
|
22
|
+
await mkdir(path.dirname(lockPath), { recursive: true });
|
|
23
|
+
await writeFile(lockPath, `99999 peer-owner ${new Date().toISOString()}\n`);
|
|
24
|
+
return () => rm(lockPath, { force: true });
|
|
12
25
|
}
|
|
13
26
|
|
|
14
27
|
async function makeStorage(): Promise<{ storage: StorageManager; cleanup: () => Promise<void> }> {
|
|
@@ -19,14 +32,7 @@ async function makeStorage(): Promise<{ storage: StorageManager; cleanup: () =>
|
|
|
19
32
|
test("confirmActiveFactDuplicate sees a fact another session committed into the same namespace", async () => {
|
|
20
33
|
const { storage, cleanup } = await makeStorage();
|
|
21
34
|
try {
|
|
22
|
-
const recheck = () =>
|
|
23
|
-
confirmActiveFactDuplicate(probe(storage), storage, {
|
|
24
|
-
category: "fact",
|
|
25
|
-
contentHashDedupKey: "the sky is blue",
|
|
26
|
-
connector: undefined,
|
|
27
|
-
citationEnabled: false,
|
|
28
|
-
citationTemplate: "",
|
|
29
|
-
});
|
|
35
|
+
const recheck = () => confirmActiveFactDuplicate(storage, SKY_OPTS);
|
|
30
36
|
assert.equal(await recheck(), false, "clean namespace must not report a duplicate");
|
|
31
37
|
|
|
32
38
|
// A concurrent session (separate manager, same dir) commits the fact.
|
|
@@ -48,14 +54,7 @@ test("persistUnderFactDedupWindow suppresses on recheck hit and writes on a miss
|
|
|
48
54
|
await storage.writeMemory("fact", "the sky is blue");
|
|
49
55
|
return "written";
|
|
50
56
|
};
|
|
51
|
-
const recheck = () =>
|
|
52
|
-
confirmActiveFactDuplicate(probe(storage), storage, {
|
|
53
|
-
category: "fact",
|
|
54
|
-
contentHashDedupKey: "the sky is blue",
|
|
55
|
-
connector: undefined,
|
|
56
|
-
citationEnabled: false,
|
|
57
|
-
citationTemplate: "",
|
|
58
|
-
});
|
|
57
|
+
const recheck = () => confirmActiveFactDuplicate(storage, SKY_OPTS);
|
|
59
58
|
|
|
60
59
|
// First session: recheck misses, write proceeds.
|
|
61
60
|
const first = await persistUnderFactDedupWindow(storage["baseDir"], recheck, write);
|
|
@@ -114,3 +113,87 @@ test("persistUnderFactDedupWindow fails closed when a peer holds fact-dedup.lock
|
|
|
114
113
|
await cleanup();
|
|
115
114
|
}
|
|
116
115
|
});
|
|
116
|
+
|
|
117
|
+
test("lookupContentHash never pairs a stale MISS with authority while a peer holds the index lock", async () => {
|
|
118
|
+
const { storage, cleanup } = await makeStorage();
|
|
119
|
+
try {
|
|
120
|
+
storage.factHashIndexLockOptions = CONTENDED_LOCK_OPTIONS;
|
|
121
|
+
assert.equal(await storage.isFactContentHashAuthoritative(), true, "starts authoritative");
|
|
122
|
+
const peer = new StorageManager(storage["baseDir"]);
|
|
123
|
+
await peer.writeMemory("fact", "The sky is BLUE!");
|
|
124
|
+
const release = await holdIndexLock(storage["baseDir"]);
|
|
125
|
+
try {
|
|
126
|
+
assert.deepEqual(
|
|
127
|
+
await storage.lookupContentHash(SKY_OPTS.contentHashDedupKey),
|
|
128
|
+
{ present: false, authoritative: false },
|
|
129
|
+
"the rebuild cannot run, so the stale MISS must not claim authority",
|
|
130
|
+
);
|
|
131
|
+
assert.equal(await confirmActiveFactDuplicate(storage, SKY_OPTS), true, "the corpus confirms the peer's fact");
|
|
132
|
+
} finally {
|
|
133
|
+
await release();
|
|
134
|
+
}
|
|
135
|
+
assert.deepEqual(
|
|
136
|
+
await storage.lookupContentHash(SKY_OPTS.contentHashDedupKey),
|
|
137
|
+
{ present: true, authoritative: true },
|
|
138
|
+
"once the lock is free the rebuild publishes and the hit is authoritative",
|
|
139
|
+
);
|
|
140
|
+
} finally {
|
|
141
|
+
await cleanup();
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
test("confirmActiveFactDuplicate stays a duplicate when the peer releases the index lock right after the lookup", async () => {
|
|
146
|
+
const { storage, cleanup } = await makeStorage();
|
|
147
|
+
try {
|
|
148
|
+
storage.factHashIndexLockOptions = CONTENDED_LOCK_OPTIONS;
|
|
149
|
+
assert.equal(await storage.isFactContentHashAuthoritative(), true, "starts authoritative");
|
|
150
|
+
const peer = new StorageManager(storage["baseDir"]);
|
|
151
|
+
await peer.writeMemory("fact", "The sky is BLUE!");
|
|
152
|
+
const release = await holdIndexLock(storage["baseDir"]);
|
|
153
|
+
const lookup = storage.lookupContentHash.bind(storage);
|
|
154
|
+
mock.method(storage, "lookupContentHash", async (content: string) => {
|
|
155
|
+
const answer = await lookup(content);
|
|
156
|
+
await release();
|
|
157
|
+
return answer;
|
|
158
|
+
});
|
|
159
|
+
assert.equal(
|
|
160
|
+
await confirmActiveFactDuplicate(storage, SKY_OPTS),
|
|
161
|
+
true,
|
|
162
|
+
"a lock released after the lookup must not turn the stale MISS into a clean not-duplicate",
|
|
163
|
+
);
|
|
164
|
+
} finally {
|
|
165
|
+
await cleanup();
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
test("two managers on one directory commit the same fact through the window exactly once", async () => {
|
|
170
|
+
const { storage, cleanup } = await makeStorage();
|
|
171
|
+
try {
|
|
172
|
+
const peer = new StorageManager(storage["baseDir"]);
|
|
173
|
+
const commit = (manager: StorageManager) =>
|
|
174
|
+
persistUnderFactDedupWindow(
|
|
175
|
+
manager.dir,
|
|
176
|
+
() => confirmActiveFactDuplicate(manager, SKY_OPTS),
|
|
177
|
+
() => manager.writeMemory("fact", "The sky is blue"),
|
|
178
|
+
);
|
|
179
|
+
const outcomes = await Promise.all([commit(storage), commit(peer)]);
|
|
180
|
+
assert.equal(outcomes.filter((outcome) => !outcome.suppressed).length, 1, "one writer wins, the other is suppressed");
|
|
181
|
+
const stored = await new StorageManager(storage["baseDir"]).readAllMemories();
|
|
182
|
+
assert.equal(stored.filter((memory) => memory.content.includes("sky is blue")).length, 1);
|
|
183
|
+
} finally {
|
|
184
|
+
await cleanup();
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
test("confirmActiveFactDuplicate keeps the authoritative MISS fast path", async () => {
|
|
189
|
+
const { storage, cleanup } = await makeStorage();
|
|
190
|
+
try {
|
|
191
|
+
assert.equal(await storage.isFactContentHashAuthoritative(), true, "warm the index so no rebuild reads the corpus");
|
|
192
|
+
const corpusReads = mock.method(storage, "readAllMemories");
|
|
193
|
+
assert.equal(await confirmActiveFactDuplicate(storage, SKY_OPTS), false);
|
|
194
|
+
assert.equal(corpusReads.mock.callCount(), 0, "authoritative MISS must not scan the corpus");
|
|
195
|
+
} finally {
|
|
196
|
+
await cleanup();
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
|