@remnic/core 10.0.76 → 10.0.78
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 +27 -27
- package/dist/access-authorization-probe.js +28 -28
- package/dist/access-boundary.js +27 -27
- package/dist/access-cli.js +78 -77
- package/dist/access-cli.js.map +1 -1
- package/dist/access-extraction-force-flush.js +27 -27
- package/dist/access-http-briefing.js +28 -28
- package/dist/access-http-query.js +29 -29
- package/dist/access-http.js +45 -45
- package/dist/access-identity-continuity-surface.js +27 -27
- package/dist/access-lcm-surface.js +27 -27
- package/dist/access-mcp.js +37 -37
- package/dist/access-namespace-preflight.js +27 -27
- package/dist/access-observe-helpers.d.ts.map +1 -1
- package/dist/access-observe-helpers.js +1 -1
- package/dist/access-observe-write-category.js +5 -5
- package/dist/access-observe-write-surface.js +27 -27
- package/dist/access-operations-batch.js +29 -29
- package/dist/access-operations.js +36 -36
- package/dist/access-recall-concurrency.js +27 -27
- package/dist/access-recall-response.js +27 -27
- package/dist/access-recall-surface.js +27 -27
- package/dist/access-schema.js +4 -4
- package/dist/access-service.js +27 -27
- package/dist/access-surface-catalog.js +29 -29
- package/dist/active-recall.js +7 -7
- package/dist/briefing.js +8 -8
- package/dist/calibration.js +1 -1
- package/dist/{capsule-crypto-7FJQINUR.js → capsule-crypto-YO5QJ6L3.js} +2 -2
- package/dist/causal-consolidation.js +9 -9
- package/dist/{chunk-Z3CKK5RR.js → chunk-2XG7QECM.js} +3 -3
- package/dist/{chunk-BZTA7DR4.js → chunk-35RSL5B4.js} +3 -3
- package/dist/{chunk-3GGCMRO7.js → chunk-3RYP4OTZ.js} +2 -2
- package/dist/{chunk-VEQVXNWR.js → chunk-446H5UUO.js} +4 -4
- package/dist/{chunk-XC7OYOQC.js → chunk-4BCX6YLW.js} +2 -2
- package/dist/{chunk-RXGFITWS.js → chunk-4HLPFYF2.js} +7 -7
- package/dist/{chunk-WIAXVBQH.js → chunk-65SKM4BF.js} +2 -2
- package/dist/{chunk-VEWTHVX2.js → chunk-6HERQLF4.js} +2 -2
- package/dist/{chunk-4DLZ2ITE.js → chunk-6OGFQ5GH.js} +2 -2
- package/dist/{chunk-C44DRDZM.js → chunk-6WULHFNJ.js} +2 -2
- package/dist/{chunk-IVXOYE43.js → chunk-7IQ5HYBJ.js} +2 -2
- package/dist/{chunk-SZBZOUHR.js → chunk-A45ZOJV4.js} +2 -2
- package/dist/chunk-ADJXJKU6.js +74 -0
- package/dist/chunk-ADJXJKU6.js.map +1 -0
- package/dist/{chunk-DANFOVQG.js → chunk-B7PLF3HW.js} +2 -2
- package/dist/{chunk-PBE7NFB5.js → chunk-BNQJKWWZ.js} +4 -4
- package/dist/{chunk-AY2UK5XK.js → chunk-BSBGI4BD.js} +2 -2
- package/dist/{chunk-AY2UK5XK.js.map → chunk-BSBGI4BD.js.map} +1 -1
- package/dist/{chunk-2NLLXCJG.js → chunk-BXLOS5AJ.js} +2 -2
- package/dist/{chunk-IPHIIRDN.js → chunk-CYTTY4M2.js} +5 -7
- package/dist/chunk-CYTTY4M2.js.map +1 -0
- package/dist/{chunk-R24RYSQX.js → chunk-CZD654DQ.js} +22 -22
- package/dist/{chunk-MBENRPMY.js → chunk-D3WNJF7D.js} +12 -12
- package/dist/{chunk-5IQL4N37.js → chunk-D4WBMLPD.js} +2 -2
- package/dist/{chunk-FYQUUIPI.js → chunk-DLZGSZVC.js} +4 -4
- package/dist/{chunk-YK6SFDP2.js → chunk-DOJBV6WR.js} +4 -4
- package/dist/{chunk-X7Y7WX73.js → chunk-DQEMWVMT.js} +1 -1
- package/dist/{chunk-FETPTCQZ.js → chunk-E33UJHY3.js} +2 -2
- package/dist/{chunk-LJUQPT5G.js → chunk-EFRMEOZQ.js} +3 -3
- package/dist/{chunk-HTDXNIO6.js → chunk-HK3CUTAG.js} +2 -2
- package/dist/{chunk-FGUWCE5I.js → chunk-HUF4S4MY.js} +2 -2
- package/dist/{chunk-6Q6AQ36B.js → chunk-HWHNQVRV.js} +2 -2
- package/dist/{chunk-SYDPJUFR.js → chunk-IDGCL5OP.js} +2 -2
- package/dist/{chunk-F3FNXE7C.js → chunk-JHJP2IAU.js} +3 -3
- package/dist/{chunk-IBQ7LGUJ.js → chunk-JIGHVQF6.js} +6 -6
- package/dist/{chunk-P7HNMNN2.js → chunk-K4SVTZWP.js} +7 -7
- package/dist/{chunk-KAED7IBB.js → chunk-KDWO22ZK.js} +2 -2
- package/dist/{chunk-N6GEGRCT.js → chunk-KYVBGDGA.js} +2 -2
- package/dist/{chunk-HB5TNQMM.js → chunk-L7BOS7KV.js} +2 -2
- package/dist/{chunk-3MBSD53O.js → chunk-LE4MQ2WF.js} +2 -2
- package/dist/{chunk-I4LJJ44E.js → chunk-LNHBYT3F.js} +2 -2
- package/dist/{chunk-SHVLNI4L.js → chunk-LU66I56Q.js} +2 -2
- package/dist/{chunk-TD5VTVPT.js → chunk-N2H6VC65.js} +3 -3
- package/dist/{chunk-L4QYW2HO.js → chunk-NBFHOQIO.js} +2 -2
- package/dist/{chunk-KNZDGZSY.js → chunk-NVYY2TJG.js} +2 -2
- package/dist/{chunk-7FFGWIBN.js → chunk-PCSQRQPJ.js} +2 -2
- package/dist/{chunk-P3AQ2YSX.js → chunk-PFUXPTBT.js} +4 -4
- package/dist/{chunk-KQAFEZQX.js → chunk-R45L4TV6.js} +6 -6
- package/dist/{chunk-E22CQZ3H.js → chunk-R63X5BQA.js} +12 -12
- package/dist/{chunk-PLGBPFEO.js → chunk-RF7QJ736.js} +2 -2
- package/dist/{chunk-ZZSFRWKD.js → chunk-RIBCP4DJ.js} +2 -2
- package/dist/{chunk-HDN7IVIO.js → chunk-RIZ5NUNN.js} +16 -62
- package/dist/chunk-RIZ5NUNN.js.map +1 -0
- package/dist/{chunk-HR6NTVYZ.js → chunk-S34XZUTY.js} +172 -39
- package/dist/chunk-S34XZUTY.js.map +1 -0
- package/dist/{chunk-DEGE32C3.js → chunk-SLORPQZT.js} +2 -2
- package/dist/{chunk-6RPPZL7W.js → chunk-SMSJOWVE.js} +2 -2
- package/dist/{chunk-X53HJENJ.js → chunk-SPYFXSFZ.js} +2 -2
- package/dist/{chunk-IRFQKR4Y.js → chunk-SW6OAWK7.js} +2 -2
- package/dist/{chunk-VPEMGBTI.js → chunk-SZEPOUW2.js} +2 -2
- package/dist/{chunk-COIQ5N4J.js → chunk-TSITK6QK.js} +2 -2
- package/dist/{chunk-HCFNZWFB.js → chunk-VBNXDC7P.js} +2 -2
- package/dist/{chunk-FP2AT4WL.js → chunk-VJ3HFCG2.js} +2 -2
- package/dist/{chunk-OBQ2NZAR.js → chunk-VKDAJJQP.js} +4 -4
- package/dist/{chunk-HZNURRDS.js → chunk-VUROWXFL.js} +2 -2
- package/dist/{chunk-G5NH3SSX.js → chunk-X3KFSJLQ.js} +2 -2
- package/dist/{chunk-GCJA5KKT.js → chunk-XBNO56HC.js} +2 -2
- package/dist/{chunk-GWOFCHPN.js → chunk-YGECOOTF.js} +2 -2
- package/dist/{chunk-2R7OCBRR.js → chunk-YK7GOPIE.js} +2 -2
- package/dist/{chunk-ELUG6NKQ.js → chunk-YSA4CYTK.js} +2 -2
- package/dist/{chunk-233S3MXC.js → chunk-YXUNSOHD.js} +3 -3
- package/dist/{chunk-SY4AFWUZ.js → chunk-Z3O7ZOCC.js} +30 -30
- package/dist/{chunk-ZG57BEUS.js → chunk-ZAU2OPDW.js} +2 -2
- package/dist/cli.js +63 -62
- package/dist/coding/export-okf-codegraph.js +7 -7
- package/dist/compounding/engine.js +9 -9
- package/dist/config.js +7 -7
- package/dist/connectors/codex-materialize-runner.js +8 -8
- package/dist/connectors/index.js +8 -8
- package/dist/convergence-refresh.js +10 -10
- package/dist/corpus-watermark.js +10 -10
- package/dist/deep-recall-http-glue.js +5 -5
- package/dist/entity-retrieval.js +8 -8
- package/dist/external-wiki-access.js +28 -28
- package/dist/extraction.js +10 -10
- package/dist/harmonic-retrieval.js +8 -8
- package/dist/index.js +86 -85
- package/dist/lcm/engine.js +2 -2
- package/dist/lcm/index.js +5 -5
- package/dist/local-llm.js +1 -1
- package/dist/location/index.js +10 -10
- package/dist/maintenance/memory-governance.js +8 -8
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +8 -8
- package/dist/maintenance/rebuild-memory-projection-runner.js +10 -10
- package/dist/maintenance/rebuild-memory-projection.js +9 -9
- package/dist/memory-browse-operations.js +28 -28
- package/dist/namespaces/migrate.js +9 -9
- package/dist/namespaces/search.js +6 -6
- package/dist/namespaces/storage.js +8 -8
- package/dist/operator-doctor-corpus.js +11 -11
- package/dist/operator-toolkit.js +16 -16
- package/dist/orchestration/backlog-scheduler.js +79 -78
- package/dist/orchestration/backlog-scheduler.js.map +1 -1
- package/dist/orchestration/buffer-drain-runner.js +79 -78
- package/dist/orchestration/extraction-queue-snapshot-sharing.d.ts +113 -0
- package/dist/orchestration/extraction-queue-snapshot-sharing.d.ts.map +1 -0
- package/dist/orchestration/maintenance.js +19 -19
- package/dist/orchestration/turn-ingestion.d.ts +3 -0
- package/dist/orchestration/turn-ingestion.d.ts.map +1 -1
- package/dist/orchestrator.js +78 -77
- package/dist/recall-navigation-operations.js +28 -28
- package/dist/recall-navigation.js +27 -27
- package/dist/resume-bundles.js +10 -9
- package/dist/search/factory.js +5 -5
- package/dist/search/index.js +5 -5
- package/dist/search/lancedb-backend.js +2 -2
- package/dist/search/meilisearch-backend.js +2 -2
- package/dist/search/orama-backend.js +2 -2
- package/dist/semantic-consolidation.js +9 -9
- package/dist/semantic-rule-promotion.js +8 -8
- package/dist/semantic-rule-verifier.js +8 -8
- package/dist/source-agent-qualifier.js +8 -8
- package/dist/standup/build.js +8 -8
- package/dist/storage.js +7 -7
- package/dist/summarizer.js +2 -2
- package/dist/support-passport/index.js +30 -30
- package/dist/transcript-ownership-digest.d.ts +31 -0
- package/dist/transcript-ownership-digest.d.ts.map +1 -0
- package/dist/transcript-ownership-digest.js +10 -0
- package/dist/transcript-ownership-digest.js.map +1 -0
- package/dist/transcript.d.ts +2 -5
- package/dist/transcript.d.ts.map +1 -1
- package/dist/transcript.js +2 -1
- 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-import.js +2 -2
- package/dist/transfer/export-okf.js +8 -8
- package/dist/verified-recall.js +8 -8
- package/dist/who-knows-cli.js +9 -9
- package/dist/who-knows.js +8 -8
- package/package.json +2 -2
- package/src/access-observe-helpers.test.ts +156 -0
- package/src/access-observe-helpers.ts +6 -6
- package/src/local-llm-qos.test.ts +59 -0
- package/src/local-llm.ts +1 -1
- package/src/orchestration/extraction-queue-bounded-retention.test.ts +548 -0
- package/src/orchestration/extraction-queue-snapshot-sharing.ts +257 -0
- package/src/orchestration/turn-ingestion.ts +19 -6
- package/src/transcript-ownership-digest.test.ts +403 -0
- package/src/transcript-ownership-digest.ts +99 -0
- package/src/transcript.ts +14 -76
- package/dist/chunk-HDN7IVIO.js.map +0 -1
- package/dist/chunk-HR6NTVYZ.js.map +0 -1
- package/dist/chunk-IPHIIRDN.js.map +0 -1
- /package/dist/{capsule-crypto-7FJQINUR.js.map → capsule-crypto-YO5QJ6L3.js.map} +0 -0
- /package/dist/{chunk-Z3CKK5RR.js.map → chunk-2XG7QECM.js.map} +0 -0
- /package/dist/{chunk-BZTA7DR4.js.map → chunk-35RSL5B4.js.map} +0 -0
- /package/dist/{chunk-3GGCMRO7.js.map → chunk-3RYP4OTZ.js.map} +0 -0
- /package/dist/{chunk-VEQVXNWR.js.map → chunk-446H5UUO.js.map} +0 -0
- /package/dist/{chunk-XC7OYOQC.js.map → chunk-4BCX6YLW.js.map} +0 -0
- /package/dist/{chunk-RXGFITWS.js.map → chunk-4HLPFYF2.js.map} +0 -0
- /package/dist/{chunk-WIAXVBQH.js.map → chunk-65SKM4BF.js.map} +0 -0
- /package/dist/{chunk-VEWTHVX2.js.map → chunk-6HERQLF4.js.map} +0 -0
- /package/dist/{chunk-4DLZ2ITE.js.map → chunk-6OGFQ5GH.js.map} +0 -0
- /package/dist/{chunk-C44DRDZM.js.map → chunk-6WULHFNJ.js.map} +0 -0
- /package/dist/{chunk-IVXOYE43.js.map → chunk-7IQ5HYBJ.js.map} +0 -0
- /package/dist/{chunk-SZBZOUHR.js.map → chunk-A45ZOJV4.js.map} +0 -0
- /package/dist/{chunk-DANFOVQG.js.map → chunk-B7PLF3HW.js.map} +0 -0
- /package/dist/{chunk-PBE7NFB5.js.map → chunk-BNQJKWWZ.js.map} +0 -0
- /package/dist/{chunk-2NLLXCJG.js.map → chunk-BXLOS5AJ.js.map} +0 -0
- /package/dist/{chunk-R24RYSQX.js.map → chunk-CZD654DQ.js.map} +0 -0
- /package/dist/{chunk-MBENRPMY.js.map → chunk-D3WNJF7D.js.map} +0 -0
- /package/dist/{chunk-5IQL4N37.js.map → chunk-D4WBMLPD.js.map} +0 -0
- /package/dist/{chunk-FYQUUIPI.js.map → chunk-DLZGSZVC.js.map} +0 -0
- /package/dist/{chunk-YK6SFDP2.js.map → chunk-DOJBV6WR.js.map} +0 -0
- /package/dist/{chunk-X7Y7WX73.js.map → chunk-DQEMWVMT.js.map} +0 -0
- /package/dist/{chunk-FETPTCQZ.js.map → chunk-E33UJHY3.js.map} +0 -0
- /package/dist/{chunk-LJUQPT5G.js.map → chunk-EFRMEOZQ.js.map} +0 -0
- /package/dist/{chunk-HTDXNIO6.js.map → chunk-HK3CUTAG.js.map} +0 -0
- /package/dist/{chunk-FGUWCE5I.js.map → chunk-HUF4S4MY.js.map} +0 -0
- /package/dist/{chunk-6Q6AQ36B.js.map → chunk-HWHNQVRV.js.map} +0 -0
- /package/dist/{chunk-SYDPJUFR.js.map → chunk-IDGCL5OP.js.map} +0 -0
- /package/dist/{chunk-F3FNXE7C.js.map → chunk-JHJP2IAU.js.map} +0 -0
- /package/dist/{chunk-IBQ7LGUJ.js.map → chunk-JIGHVQF6.js.map} +0 -0
- /package/dist/{chunk-P7HNMNN2.js.map → chunk-K4SVTZWP.js.map} +0 -0
- /package/dist/{chunk-KAED7IBB.js.map → chunk-KDWO22ZK.js.map} +0 -0
- /package/dist/{chunk-N6GEGRCT.js.map → chunk-KYVBGDGA.js.map} +0 -0
- /package/dist/{chunk-HB5TNQMM.js.map → chunk-L7BOS7KV.js.map} +0 -0
- /package/dist/{chunk-3MBSD53O.js.map → chunk-LE4MQ2WF.js.map} +0 -0
- /package/dist/{chunk-I4LJJ44E.js.map → chunk-LNHBYT3F.js.map} +0 -0
- /package/dist/{chunk-SHVLNI4L.js.map → chunk-LU66I56Q.js.map} +0 -0
- /package/dist/{chunk-TD5VTVPT.js.map → chunk-N2H6VC65.js.map} +0 -0
- /package/dist/{chunk-L4QYW2HO.js.map → chunk-NBFHOQIO.js.map} +0 -0
- /package/dist/{chunk-KNZDGZSY.js.map → chunk-NVYY2TJG.js.map} +0 -0
- /package/dist/{chunk-7FFGWIBN.js.map → chunk-PCSQRQPJ.js.map} +0 -0
- /package/dist/{chunk-P3AQ2YSX.js.map → chunk-PFUXPTBT.js.map} +0 -0
- /package/dist/{chunk-KQAFEZQX.js.map → chunk-R45L4TV6.js.map} +0 -0
- /package/dist/{chunk-E22CQZ3H.js.map → chunk-R63X5BQA.js.map} +0 -0
- /package/dist/{chunk-PLGBPFEO.js.map → chunk-RF7QJ736.js.map} +0 -0
- /package/dist/{chunk-ZZSFRWKD.js.map → chunk-RIBCP4DJ.js.map} +0 -0
- /package/dist/{chunk-DEGE32C3.js.map → chunk-SLORPQZT.js.map} +0 -0
- /package/dist/{chunk-6RPPZL7W.js.map → chunk-SMSJOWVE.js.map} +0 -0
- /package/dist/{chunk-X53HJENJ.js.map → chunk-SPYFXSFZ.js.map} +0 -0
- /package/dist/{chunk-IRFQKR4Y.js.map → chunk-SW6OAWK7.js.map} +0 -0
- /package/dist/{chunk-VPEMGBTI.js.map → chunk-SZEPOUW2.js.map} +0 -0
- /package/dist/{chunk-COIQ5N4J.js.map → chunk-TSITK6QK.js.map} +0 -0
- /package/dist/{chunk-HCFNZWFB.js.map → chunk-VBNXDC7P.js.map} +0 -0
- /package/dist/{chunk-FP2AT4WL.js.map → chunk-VJ3HFCG2.js.map} +0 -0
- /package/dist/{chunk-OBQ2NZAR.js.map → chunk-VKDAJJQP.js.map} +0 -0
- /package/dist/{chunk-HZNURRDS.js.map → chunk-VUROWXFL.js.map} +0 -0
- /package/dist/{chunk-G5NH3SSX.js.map → chunk-X3KFSJLQ.js.map} +0 -0
- /package/dist/{chunk-GCJA5KKT.js.map → chunk-XBNO56HC.js.map} +0 -0
- /package/dist/{chunk-GWOFCHPN.js.map → chunk-YGECOOTF.js.map} +0 -0
- /package/dist/{chunk-2R7OCBRR.js.map → chunk-YK7GOPIE.js.map} +0 -0
- /package/dist/{chunk-ELUG6NKQ.js.map → chunk-YSA4CYTK.js.map} +0 -0
- /package/dist/{chunk-233S3MXC.js.map → chunk-YXUNSOHD.js.map} +0 -0
- /package/dist/{chunk-SY4AFWUZ.js.map → chunk-Z3O7ZOCC.js.map} +0 -0
- /package/dist/{chunk-ZG57BEUS.js.map → chunk-ZAU2OPDW.js.map} +0 -0
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded-queue retention for automatic extraction snapshots (#3324
|
|
3
|
+
* follow-up).
|
|
4
|
+
*
|
|
5
|
+
* The coordinator's queue keeps every accepted task's own snapshot (that is
|
|
6
|
+
* the #3324 contract: per-entry captured scope and settlement), but nothing
|
|
7
|
+
* requires each queued snapshot to RETAIN its own turn objects. Automatic
|
|
8
|
+
* triggers hand out prefix-extended snapshots of the same buffer (the buffer
|
|
9
|
+
* clears only when extraction runs), so consecutive queued snapshots overlap
|
|
10
|
+
* almost entirely while their drain is slow. Retaining one deep copy per
|
|
11
|
+
* snapshot grows quadratic overhead (demonstrated: scaling exponent 1.89 on
|
|
12
|
+
* main, 36× the unique content at 1000 turns for one session).
|
|
13
|
+
*
|
|
14
|
+
* This registry makes the OVERLAP shared without changing ANY task's
|
|
15
|
+
* semantics: a queued snapshot is stored as a chain node
|
|
16
|
+
* `{ base, tail }` whose turns are verified element-wise equivalent to the
|
|
17
|
+
* base chain at admit time. Each task materializes its own fresh array at
|
|
18
|
+
* run time — identical values, same windows, same chunking, same clear
|
|
19
|
+
* matching, same settlements. Sharing is data-structure only.
|
|
20
|
+
*
|
|
21
|
+
* Safety properties:
|
|
22
|
+
* - Equivalence is CONSUMER-equivalence, not `bufferTurnsEqual` alone: the
|
|
23
|
+
* five fields `bufferTurnsEqual` ignores (extractionContextOnly, parts,
|
|
24
|
+
* rawContent, sourceFormat, importProvenance) are compared strictly
|
|
25
|
+
* (objects by reference identity), so an aliased segment is
|
|
26
|
+
* indistinguishable from a private copy to every downstream reader.
|
|
27
|
+
* - Turn objects are immutable by audit: no code path writes a BufferTurn
|
|
28
|
+
* field or a parts array in place (all writes go to freshly constructed
|
|
29
|
+
* objects: `copyBufferTurn`, the replay `pinned` spread). Audited across
|
|
30
|
+
* the extraction call graph.
|
|
31
|
+
* - Distinct scope pins can never share: pins are turn fields covered by
|
|
32
|
+
* `bufferTurnsEqual`, and the scope-class bucket is a lookup heuristic
|
|
33
|
+
* only — a wrong pairing fails the element-wise check and simply does not
|
|
34
|
+
* share.
|
|
35
|
+
* - Replay, bulk import, force flush, fail-closed callers, and claim-backed
|
|
36
|
+
* execution contexts are excluded (they are not automatic snapshots of the
|
|
37
|
+
* live buffer).
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
import type { BufferTurn } from "../types.js";
|
|
41
|
+
import { bufferTurnsEqual, scopeProfilePlanIdentity } from "../buffer-turn-helpers.js";
|
|
42
|
+
|
|
43
|
+
/** Option surface of `queueBufferedExtraction` relevant to eligibility. */
|
|
44
|
+
export interface AutomaticSharingOptions {
|
|
45
|
+
/** Claim-backed backlog tasks own a different buffer view: never share. */
|
|
46
|
+
execution?: unknown;
|
|
47
|
+
/** Automatic trigger paths set this; forced replay/import do not. */
|
|
48
|
+
preemptable?: boolean;
|
|
49
|
+
failOnExtractionFailure?: boolean;
|
|
50
|
+
forceExtractionAttempt?: boolean;
|
|
51
|
+
/** Fail-closed front flush: never share. */
|
|
52
|
+
preemptRunning?: boolean;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function automaticSnapshotSharingEligible(options: AutomaticSharingOptions): boolean {
|
|
56
|
+
return (
|
|
57
|
+
options.execution === undefined &&
|
|
58
|
+
options.preemptable === true &&
|
|
59
|
+
options.failOnExtractionFailure !== true &&
|
|
60
|
+
options.forceExtractionAttempt !== true &&
|
|
61
|
+
options.preemptRunning !== true
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Consumer-visible equivalence: `bufferTurnsEqual` PLUS the fields it ignores. */
|
|
66
|
+
export function turnRepresentationEquivalent(left: BufferTurn, right: BufferTurn): boolean {
|
|
67
|
+
return (
|
|
68
|
+
bufferTurnsEqual(left, right) &&
|
|
69
|
+
left.extractionContextOnly === right.extractionContextOnly &&
|
|
70
|
+
left.importProvenance === right.importProvenance &&
|
|
71
|
+
left.parts === right.parts &&
|
|
72
|
+
left.rawContent === right.rawContent &&
|
|
73
|
+
left.sourceFormat === right.sourceFormat
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Scope-class bucket key, the same composite `groupTurnsByExtractionScope` uses. */
|
|
78
|
+
function scopeClassKey(turn: BufferTurn): string {
|
|
79
|
+
return [
|
|
80
|
+
turn.writeNamespaceOverride ?? "",
|
|
81
|
+
turn.principalOverride ?? "",
|
|
82
|
+
scopeProfilePlanIdentity(turn.scopeProfileWritePlan),
|
|
83
|
+
turn.acceptedCapture === true ? "accepted" : "",
|
|
84
|
+
turn.codingContext?.projectId ?? "",
|
|
85
|
+
turn.codingContext?.rootPath ?? "",
|
|
86
|
+
turn.codingContext?.branch ?? "",
|
|
87
|
+
turn.codingContext?.defaultBranch ?? "",
|
|
88
|
+
].join("\u0000");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** One queued automatic snapshot: `base` chain plus this trigger's own new turns. */
|
|
92
|
+
export interface SnapshotChain {
|
|
93
|
+
readonly key: string;
|
|
94
|
+
readonly scopeClass: string;
|
|
95
|
+
readonly base: SnapshotChain | undefined;
|
|
96
|
+
/** Total turns retained by the base chain. */
|
|
97
|
+
readonly baseLength: number;
|
|
98
|
+
/** This trigger's non-shared suffix (fresh reference slots, disjoint across the chain). */
|
|
99
|
+
readonly tail: readonly BufferTurn[];
|
|
100
|
+
/** Total turns this snapshot represents. */
|
|
101
|
+
readonly total: number;
|
|
102
|
+
/** Outstanding tasks holding this node; the node leaves the registry when it reaches 0. */
|
|
103
|
+
holders: number;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export interface SnapshotSharingStats {
|
|
107
|
+
/** Distinct content chains registered (not task count — see queuedHolders). */
|
|
108
|
+
queuedNodes: number;
|
|
109
|
+
/** Σ per-node window lengths over registered nodes. Sibling nodes sharing
|
|
110
|
+
* a base chain count that base once per node (per-task window basis). */
|
|
111
|
+
queuedTotalRefs: number;
|
|
112
|
+
/** Distinct turn references REACHABLE from queued nodes, counting
|
|
113
|
+
* released ancestors reached through `base` exactly once (visited-set). */
|
|
114
|
+
queuedTailRefs: number;
|
|
115
|
+
/** Longest base chain reachable from a queued node (must stay bounded). */
|
|
116
|
+
queuedReachableDepth: number;
|
|
117
|
+
/** Outstanding tasks holding nodes (per-task, not per-node). */
|
|
118
|
+
queuedHolders: number;
|
|
119
|
+
/** What retention would be WITHOUT sharing: Σ per-node window length ×
|
|
120
|
+
* holders (each outstanding task would carry its own full window). */
|
|
121
|
+
unsharedEquivalentRefs: number;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** Iterative root-first walk: recursive `yield*` delegation costs O(depth)
|
|
125
|
+
* per item and hangs production-scale chains (3,000+ turn sessions,
|
|
126
|
+
* hours-long backlogs). Same order, bounded stack, no casts. */
|
|
127
|
+
function chainNodes(chain: SnapshotChain): SnapshotChain[] {
|
|
128
|
+
const nodes: SnapshotChain[] = [];
|
|
129
|
+
for (let node: SnapshotChain | undefined = chain; node; node = node.base) nodes.push(node);
|
|
130
|
+
return [...nodes].reverse();
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Element-wise consumer-equivalence of the chain's turns against a snapshot
|
|
135
|
+
* prefix. Cost is O(chain.total) compares per admit — required to prove the
|
|
136
|
+
* shared prefix is consumer-equivalent to the incoming snapshot — so a chain
|
|
137
|
+
* build is O(depth^2) compares in total (measured, acknowledged in the PR).
|
|
138
|
+
*/
|
|
139
|
+
export function chainPrefixEquivalent(chain: SnapshotChain, turns: readonly BufferTurn[]): boolean {
|
|
140
|
+
let offset = 0;
|
|
141
|
+
for (const node of chainNodes(chain)) {
|
|
142
|
+
for (const chained of node.tail) {
|
|
143
|
+
const incoming = turns[offset];
|
|
144
|
+
if (incoming === undefined) return false;
|
|
145
|
+
if (!turnRepresentationEquivalent(chained, incoming)) return false;
|
|
146
|
+
offset += 1;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return offset === chain.total;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** Fresh array with exactly this snapshot's turns, in order. Run-time only. */
|
|
153
|
+
export function materializeChain(chain: SnapshotChain): BufferTurn[] {
|
|
154
|
+
const out: BufferTurn[] = [];
|
|
155
|
+
for (const node of chainNodes(chain)) {
|
|
156
|
+
for (const turn of node.tail) out.push(turn);
|
|
157
|
+
}
|
|
158
|
+
return out;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export class ExtractionSnapshotSharingRegistry {
|
|
162
|
+
private readonly buckets = new Map<string, SnapshotChain[]>();
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Admit one automatic snapshot for `bufferKey`: chain it onto the newest
|
|
166
|
+
* queued same-scope snapshot when that is a verified prefix-extension,
|
|
167
|
+
* otherwise start a fresh chain. The caller's array is never mutated.
|
|
168
|
+
*/
|
|
169
|
+
admit(bufferKey: string, turns: readonly BufferTurn[]): SnapshotChain {
|
|
170
|
+
const scopeClass = turns.length > 0 ? scopeClassKey(turns[0]) : "";
|
|
171
|
+
const bucketKey = `${bufferKey}\u0000${scopeClass}`;
|
|
172
|
+
const list = this.buckets.get(bucketKey);
|
|
173
|
+
const base = list !== undefined && list.length > 0 ? list[list.length - 1] : undefined;
|
|
174
|
+
if (base && base.total === turns.length && chainPrefixEquivalent(base, turns)) {
|
|
175
|
+
// Identical window: reuse the existing node. Creating a tail=[] node
|
|
176
|
+
// here would chain onto the base and grow reachable depth (and admit
|
|
177
|
+
// cost) by one per admission under continuous unchanged ingress, while
|
|
178
|
+
// stats showed only the newest node. Sharing is exact: the element-wise
|
|
179
|
+
// equivalence above proved this window equals the base's. The holder
|
|
180
|
+
// count keeps the node registered until the LAST sharer releases.
|
|
181
|
+
base.holders += 1;
|
|
182
|
+
return base;
|
|
183
|
+
}
|
|
184
|
+
const node: SnapshotChain =
|
|
185
|
+
base && base.total <= turns.length && chainPrefixEquivalent(base, turns)
|
|
186
|
+
? {
|
|
187
|
+
key: bufferKey,
|
|
188
|
+
scopeClass,
|
|
189
|
+
base,
|
|
190
|
+
baseLength: base.total,
|
|
191
|
+
tail: turns.slice(base.total),
|
|
192
|
+
total: turns.length,
|
|
193
|
+
holders: 1,
|
|
194
|
+
}
|
|
195
|
+
: {
|
|
196
|
+
key: bufferKey,
|
|
197
|
+
scopeClass,
|
|
198
|
+
base: undefined,
|
|
199
|
+
baseLength: 0,
|
|
200
|
+
tail: [...turns],
|
|
201
|
+
total: turns.length,
|
|
202
|
+
holders: 1,
|
|
203
|
+
};
|
|
204
|
+
if (list) list.push(node);
|
|
205
|
+
else this.buckets.set(bucketKey, [node]);
|
|
206
|
+
return node;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/** Release one holder of a node when its task exits (or on enqueue
|
|
210
|
+
* refusal). CONTRACT: called EXACTLY ONCE per admit, by the task that
|
|
211
|
+
* admitted it — the registry has no task identity, so a second call by the
|
|
212
|
+
* same task would steal another holder's count. The only production caller
|
|
213
|
+
* (queueBufferedExtraction) enforces this structurally: the closure-finally
|
|
214
|
+
* and the enqueue-refusal branch are mutually exclusive. Defensively, a
|
|
215
|
+
* release past zero is a no-op. */
|
|
216
|
+
release(node: SnapshotChain): void {
|
|
217
|
+
if (node.holders <= 0) return;
|
|
218
|
+
node.holders -= 1;
|
|
219
|
+
if (node.holders > 0) return;
|
|
220
|
+
const list = this.buckets.get(`${node.key}\u0000${node.scopeClass}`);
|
|
221
|
+
if (!list) return;
|
|
222
|
+
const index = list.indexOf(node);
|
|
223
|
+
if (index >= 0) list.splice(index, 1);
|
|
224
|
+
if (list.length === 0) this.buckets.delete(`${node.key}\u0000${node.scopeClass}`);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/** Proof seam: what the queue retains right now. */
|
|
228
|
+
stats(): SnapshotSharingStats {
|
|
229
|
+
// Reachability-accurate accounting: a released ancestor can remain
|
|
230
|
+
// reachable through a queued descendant's `base`, so bucket-node sums
|
|
231
|
+
// under-report. Walk each chain once with a visited set of nodes.
|
|
232
|
+
const visited = new Set<SnapshotChain>();
|
|
233
|
+
let queuedNodes = 0;
|
|
234
|
+
let queuedTailRefs = 0;
|
|
235
|
+
let queuedReachableDepth = 0;
|
|
236
|
+
let queuedHolders = 0;
|
|
237
|
+
let unsharedEquivalentRefs = 0;
|
|
238
|
+
let queuedTotalRefs = 0;
|
|
239
|
+
for (const list of this.buckets.values()) {
|
|
240
|
+
for (const node of list) {
|
|
241
|
+
queuedNodes += 1;
|
|
242
|
+
unsharedEquivalentRefs += node.total * node.holders;
|
|
243
|
+
queuedTotalRefs += node.total;
|
|
244
|
+
let depth = 0;
|
|
245
|
+
for (let walk: SnapshotChain | undefined = node; walk; walk = walk.base) {
|
|
246
|
+
depth += 1;
|
|
247
|
+
if (visited.has(walk)) continue;
|
|
248
|
+
visited.add(walk);
|
|
249
|
+
queuedTailRefs += walk.tail.length;
|
|
250
|
+
queuedHolders += walk.holders;
|
|
251
|
+
}
|
|
252
|
+
if (depth > queuedReachableDepth) queuedReachableDepth = depth;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return { queuedNodes, queuedTotalRefs, queuedTailRefs, queuedReachableDepth, queuedHolders, unsharedEquivalentRefs };
|
|
256
|
+
}
|
|
257
|
+
}
|
|
@@ -44,11 +44,8 @@ import type { BufferTurn, PluginConfig, SourceConnectorProvenance } from "../typ
|
|
|
44
44
|
import { groupTurnsByExtractionScope, bufferTurnsEqual } from "../buffer-turn-helpers.js";
|
|
45
45
|
import { ExtractionDrain } from "./extraction-drain.js";
|
|
46
46
|
import { skipClaimedSession } from "./buffer-drain-gate.js";
|
|
47
|
-
import {
|
|
48
|
-
|
|
49
|
-
type CaptureScopeGroupQueueOptions,
|
|
50
|
-
type ExtractionTaskExecutionContext,
|
|
51
|
-
} from "./extraction-task-queueing.js";
|
|
47
|
+
import { queueBufferedCaptureScopeGroups, type CaptureScopeGroupQueueOptions, type ExtractionTaskExecutionContext } from "./extraction-task-queueing.js";
|
|
48
|
+
import { automaticSnapshotSharingEligible, ExtractionSnapshotSharingRegistry, materializeChain, type SnapshotChain } from "./extraction-queue-snapshot-sharing.js";
|
|
52
49
|
import { resolveScopeProfilePlan, type ResolvedScopeProfilePlan, hasExplicitNamespacePolicy } from "../namespaces/scope-profiles.js";
|
|
53
50
|
import { resolveCodingNamespaceOverlay, combineNamespaces } from "../coding/coding-namespace.js";
|
|
54
51
|
import { canWriteNamespace, defaultNamespaceForPrincipal } from "../namespaces/principal.js";
|
|
@@ -166,6 +163,8 @@ function isFlushPlanRecoveryTurn(
|
|
|
166
163
|
|
|
167
164
|
export class TurnIngestionCoordinator {
|
|
168
165
|
private readonly drain: ExtractionDrain; // chunked trigger-drain (extraction-drain.ts)
|
|
166
|
+
/** Queued automatic-snapshot chains: bounded-queue retention via structural sharing. */
|
|
167
|
+
readonly snapshotSharing = new ExtractionSnapshotSharingRegistry();
|
|
169
168
|
constructor(private readonly deps: TurnIngestionDeps) {
|
|
170
169
|
this.drain = new ExtractionDrain(deps);
|
|
171
170
|
}
|
|
@@ -902,6 +901,15 @@ export class TurnIngestionCoordinator {
|
|
|
902
901
|
}
|
|
903
902
|
if (settled) return;
|
|
904
903
|
const preemptable = options.preemptable === true && options.preemptRunning !== true;
|
|
904
|
+
const sharingNode =
|
|
905
|
+
automaticSnapshotSharingEligible(options) && turnsToExtract.length > 0
|
|
906
|
+
? this.snapshotSharing.admit(bufferKey, turnsToExtract)
|
|
907
|
+
: undefined;
|
|
908
|
+
// Discriminated source so the task closure never captures the caller's
|
|
909
|
+
// snapshot array when sharing: a textual reference would retain every
|
|
910
|
+
// overlapping copy and defeat the bound.
|
|
911
|
+
const queuedTurnsSource: { chain: SnapshotChain } | { direct: BufferTurn[] } =
|
|
912
|
+
sharingNode ? { chain: sharingNode } : { direct: turnsToExtract };
|
|
905
913
|
const accepted = this.deps.extractionQueueCoordinator.enqueue(async (preemptHandle) => {
|
|
906
914
|
try {
|
|
907
915
|
await this.deps.extractionQueueCoordinator.runPreemptable(preemptHandle, preemptable, options.abortSignal, async (abortSignal) => {
|
|
@@ -931,7 +939,10 @@ export class TurnIngestionCoordinator {
|
|
|
931
939
|
// concurrent drain that already took these turns skips the LLM work,
|
|
932
940
|
// and re-resolve a pinned plan against CURRENT config — revoke skips
|
|
933
941
|
// WITHOUT clearing, and the plan is never retargeted.
|
|
934
|
-
let effectiveTurns =
|
|
942
|
+
let effectiveTurns =
|
|
943
|
+
"chain" in queuedTurnsSource
|
|
944
|
+
? materializeChain(queuedTurnsSource.chain)
|
|
945
|
+
: queuedTurnsSource.direct;
|
|
935
946
|
let effectiveScopePlan = options.scopeProfileWritePlan;
|
|
936
947
|
const executionBuffer = options.execution?.buffer;
|
|
937
948
|
if (effectiveTurns.some((turn) => turn.acceptedCapture === true)) {
|
|
@@ -1083,10 +1094,12 @@ export class TurnIngestionCoordinator {
|
|
|
1083
1094
|
}
|
|
1084
1095
|
});
|
|
1085
1096
|
} finally {
|
|
1097
|
+
if (sharingNode) this.snapshotSharing.release(sharingNode);
|
|
1086
1098
|
options.onTaskExit?.();
|
|
1087
1099
|
}
|
|
1088
1100
|
}, { front: options.preemptRunning === true, key: bufferKey });
|
|
1089
1101
|
if (!accepted) {
|
|
1102
|
+
if (sharingNode) this.snapshotSharing.release(sharingNode);
|
|
1090
1103
|
settleTask(new Error("extraction queue is stopped"));
|
|
1091
1104
|
options.onTaskExit?.();
|
|
1092
1105
|
return;
|