@remnic/core 10.0.30 → 10.0.31
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 +47 -46
- package/dist/access-authorization-probe.js +48 -47
- package/dist/access-boundary.js +47 -46
- package/dist/access-cli.js +107 -107
- package/dist/access-extraction-force-flush.d.ts.map +1 -1
- package/dist/access-extraction-force-flush.js +47 -46
- package/dist/access-http-briefing.js +48 -47
- package/dist/access-http-query.js +49 -48
- package/dist/access-http.js +65 -64
- package/dist/access-identity-continuity-surface.js +47 -46
- package/dist/access-lcm-surface.js +47 -46
- package/dist/access-mcp.js +57 -56
- package/dist/access-namespace-preflight.js +47 -46
- package/dist/access-observe-write-surface.d.ts.map +1 -1
- package/dist/access-observe-write-surface.js +47 -46
- package/dist/access-offline-manifest.js +4 -4
- package/dist/access-operations-batch.js +48 -47
- package/dist/access-operations.js +55 -54
- package/dist/access-recall-concurrency.js +47 -46
- package/dist/access-recall-diagnostics.js +2 -2
- package/dist/access-recall-response.js +47 -46
- package/dist/access-recall-surface.js +47 -46
- package/dist/access-schema.d.ts +47 -47
- package/dist/access-service.js +47 -46
- package/dist/access-surface-catalog.js +49 -48
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/active-recall.js +20 -20
- package/dist/briefing.js +21 -21
- package/dist/buffer-turn-helpers.d.ts +20 -0
- package/dist/buffer-turn-helpers.d.ts.map +1 -1
- package/dist/buffer-turn-helpers.js +11 -3
- package/dist/buffer-turn.d.ts +50 -0
- package/dist/buffer-turn.d.ts.map +1 -0
- package/dist/buffer-turn.js +1 -0
- package/dist/buffer-turn.js.map +1 -0
- package/dist/buffer.d.ts +13 -1
- package/dist/buffer.d.ts.map +1 -1
- package/dist/buffer.js +4 -4
- package/dist/causal-consolidation.js +26 -26
- package/dist/{chunk-BIE3ZH3N.js → chunk-2IXEKMBJ.js} +143 -112
- package/dist/chunk-2IXEKMBJ.js.map +1 -0
- package/dist/{chunk-YGVZ4QOZ.js → chunk-3CRE3UZI.js} +2 -2
- package/dist/{chunk-YZTFQBYY.js → chunk-3GOPAWA7.js} +3 -3
- package/dist/{chunk-NAPHQ2MG.js → chunk-3IDNKOCE.js} +2 -2
- package/dist/{chunk-PYCTZ2HX.js → chunk-3VYNGM5A.js} +2 -2
- package/dist/{chunk-2XVLY424.js → chunk-42MM5DKK.js} +2 -2
- package/dist/{chunk-CKR7LXEK.js → chunk-464QR7WO.js} +255 -63
- package/dist/chunk-464QR7WO.js.map +1 -0
- package/dist/{chunk-3IXNL6SK.js → chunk-4ZTVOECF.js} +4 -4
- package/dist/{chunk-ETZUIRCI.js → chunk-53GYS3GG.js} +2 -2
- package/dist/{chunk-ZXTAHSQU.js → chunk-5GPHJ333.js} +2 -2
- package/dist/{chunk-AUYFUBBE.js → chunk-5HJCZ7SB.js} +4 -4
- package/dist/{chunk-52II7PB6.js → chunk-645WOU5I.js} +4 -4
- package/dist/{chunk-2WDMUQOH.js → chunk-64IO6ZEE.js} +2 -2
- package/dist/{chunk-OIIAIY7J.js → chunk-7SXUGYPE.js} +3 -3
- package/dist/{chunk-74IN6PV5.js → chunk-7WWITD3H.js} +4 -4
- package/dist/{chunk-7FZ4YVOH.js → chunk-A5ZY537U.js} +2 -2
- package/dist/{chunk-LDXNKEYB.js → chunk-A6PKEU7T.js} +1 -1
- package/dist/chunk-A6PKEU7T.js.map +1 -0
- package/dist/{chunk-VLBFSD7B.js → chunk-APRGEZQN.js} +2 -2
- package/dist/{chunk-XNROYP5E.js → chunk-AQ5XLA36.js} +2 -2
- package/dist/{chunk-K2REHR42.js → chunk-BDHYRMJC.js} +2 -2
- package/dist/{chunk-GQ7VWY6N.js → chunk-BQ6DGL6A.js} +2 -2
- package/dist/{chunk-4OE4UE2Y.js → chunk-D3EXT5KG.js} +2 -2
- package/dist/{chunk-MROA6OFU.js → chunk-DGBWPSM6.js} +2 -2
- package/dist/{chunk-NOMHXZD7.js → chunk-DNZ2CWPG.js} +2 -2
- package/dist/{chunk-HG2VVIKI.js → chunk-DZBMASSI.js} +12 -12
- package/dist/{chunk-NB2YX6X2.js → chunk-EXYDKAR6.js} +5 -5
- package/dist/{chunk-V4FI2TG6.js → chunk-F5FZ7DB4.js} +2 -2
- package/dist/{chunk-IY7DGT2Z.js → chunk-GDPTMK5V.js} +2 -2
- package/dist/{chunk-27OJ5G3D.js → chunk-GJBSEMC5.js} +7 -7
- package/dist/{chunk-MMBLOJJB.js → chunk-HMON55NJ.js} +85 -44
- package/dist/chunk-HMON55NJ.js.map +1 -0
- package/dist/{chunk-C2QVDLQV.js → chunk-HNTB7NIE.js} +2 -2
- package/dist/{chunk-4HNINU7Q.js → chunk-HSPEVXT5.js} +42 -42
- package/dist/{chunk-4QPW6JVI.js → chunk-ID2PLENW.js} +2 -2
- package/dist/{chunk-FN6OFDBZ.js → chunk-ID62FNER.js} +2 -2
- package/dist/{chunk-GSKW64NB.js → chunk-J6SZXAQ2.js} +2 -2
- package/dist/{chunk-3CHHQXAR.js → chunk-JTACUJP3.js} +2 -2
- package/dist/{chunk-3SN2D43X.js → chunk-K6RQ2KOX.js} +2 -2
- package/dist/{chunk-GWB7ZD2A.js → chunk-K6YJGWJP.js} +2 -2
- package/dist/{chunk-OANSZGAG.js → chunk-KFR343VH.js} +2 -2
- package/dist/{chunk-WC3V7HHP.js → chunk-KJZKO2M6.js} +2 -1
- package/dist/chunk-KJZKO2M6.js.map +1 -0
- package/dist/{chunk-T5IF2ZCE.js → chunk-KZMRMKC7.js} +81 -2
- package/dist/chunk-KZMRMKC7.js.map +1 -0
- package/dist/{chunk-NPO4ZQFY.js → chunk-LDXS746V.js} +3 -3
- package/dist/{chunk-UTXYOWDR.js → chunk-LGR54NYT.js} +3 -3
- package/dist/{chunk-UTXYOWDR.js.map → chunk-LGR54NYT.js.map} +1 -1
- package/dist/{chunk-DDLRKPR2.js → chunk-NKW27NU3.js} +2 -2
- package/dist/{chunk-4HYP4OKH.js → chunk-NU247WVX.js} +2 -2
- package/dist/{chunk-RRJ462HP.js → chunk-O6YJI5VX.js} +2 -2
- package/dist/{chunk-WYLBEJQI.js → chunk-OCWNT322.js} +4 -4
- package/dist/{chunk-UUYAW3JH.js → chunk-OIKLZCJD.js} +2 -2
- package/dist/{chunk-IO2UQVR2.js → chunk-OTWZXOJI.js} +2 -2
- package/dist/{chunk-OXYXMGRH.js → chunk-PGHYQMKZ.js} +11 -11
- package/dist/{chunk-LDEKVBVO.js → chunk-PZWW6MDE.js} +2 -2
- package/dist/{chunk-TFA6HPOA.js → chunk-QCP75JGO.js} +5 -5
- package/dist/{chunk-M236YHUH.js → chunk-RILIWZA6.js} +3 -3
- package/dist/{chunk-7VB3Y5OL.js → chunk-RRYN5FFC.js} +4 -4
- package/dist/{chunk-PZEADMX4.js → chunk-RU6WB55E.js} +9 -9
- package/dist/{chunk-VARNSLUW.js → chunk-SGII36L6.js} +2 -2
- package/dist/{chunk-KFKFK6G6.js → chunk-TB2J4PBY.js} +3 -3
- package/dist/{chunk-WQIYGYY6.js → chunk-TEUPXKC5.js} +2 -2
- package/dist/{chunk-VEB7NEON.js → chunk-U4BNX4R2.js} +3 -3
- package/dist/{chunk-7HFTCBCZ.js → chunk-UBBZFODO.js} +2 -2
- package/dist/{chunk-654GT5UP.js → chunk-UZDOPJ2P.js} +2 -2
- package/dist/{chunk-D4RV54HH.js → chunk-VAPVRDC4.js} +2 -2
- package/dist/{chunk-OXX4ORRL.js → chunk-W7X7XT7Z.js} +15 -15
- package/dist/{chunk-5NPZFXQH.js → chunk-WK7GFAQ2.js} +2 -2
- package/dist/{chunk-G6DAE2LT.js → chunk-WPCK6EJ2.js} +2 -2
- package/dist/{chunk-VKQI47DJ.js → chunk-Y7427SL7.js} +4 -4
- package/dist/{chunk-ZCRDYQL6.js → chunk-YGBWSKBD.js} +2 -2
- package/dist/{chunk-NCPR2FOJ.js → chunk-YXWLQHAW.js} +2 -2
- package/dist/{chunk-UM73Q46J.js → chunk-ZEMBRSKK.js} +2 -2
- package/dist/{chunk-TTIEXXL3.js → chunk-ZGP2XB4S.js} +16 -16
- package/dist/{chunk-UVUBLLM3.js → chunk-ZY4S5WMQ.js} +2 -2
- package/dist/cli.js +83 -82
- package/dist/coding/export-okf-codegraph.js +20 -20
- package/dist/compounding/engine.js +22 -22
- package/dist/config.js +20 -20
- package/dist/connectors/codex-materialize-runner.js +21 -21
- package/dist/connectors/index.js +21 -21
- package/dist/convergence-refresh.js +23 -23
- package/dist/conversation-index/backend.js +2 -2
- package/dist/corpus-watermark.js +23 -23
- package/dist/entity-retrieval.js +22 -22
- package/dist/event-order-recall.js +3 -3
- package/dist/external-wiki-access.js +48 -47
- package/dist/extraction.js +31 -31
- package/dist/harmonic-retrieval.js +21 -21
- package/dist/index.js +126 -126
- package/dist/lcm/engine.js +2 -2
- package/dist/lcm/index.js +2 -2
- package/dist/location/index.js +23 -23
- package/dist/maintenance/memory-governance.js +21 -21
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +21 -21
- package/dist/maintenance/rebuild-memory-projection-runner.js +23 -23
- package/dist/maintenance/rebuild-memory-projection.js +22 -22
- package/dist/memory-browse-operations.js +48 -47
- package/dist/namespaces/migrate.js +22 -22
- package/dist/namespaces/scope-profiles.d.ts +1 -0
- package/dist/namespaces/scope-profiles.d.ts.map +1 -1
- package/dist/namespaces/search.js +9 -9
- package/dist/namespaces/storage.js +21 -21
- package/dist/offline-sync-impression-drain.js +3 -3
- package/dist/operator-doctor-corpus.js +24 -24
- package/dist/operator-toolkit.js +32 -32
- package/dist/orchestration/maintenance.js +33 -33
- package/dist/orchestration/session-context.d.ts +6 -0
- package/dist/orchestration/session-context.d.ts.map +1 -1
- package/dist/orchestration/turn-ingestion.d.ts +35 -1
- package/dist/orchestration/turn-ingestion.d.ts.map +1 -1
- package/dist/orchestrator.d.ts +2 -32
- package/dist/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator.js +107 -107
- package/dist/recall-explain-renderer.js +3 -3
- package/dist/recall-navigate-access.js +2 -2
- package/dist/recall-navigate-disclosure.js +2 -2
- package/dist/recall-navigate.js +2 -2
- package/dist/recall-navigation-operations.js +48 -47
- package/dist/recall-navigation.js +47 -46
- package/dist/recall-xray-cli.js +4 -4
- package/dist/recall-xray-renderer.js +3 -3
- package/dist/recall-xray.js +2 -2
- package/dist/relay/mission.d.ts +2 -2
- package/dist/resume-bundles.js +20 -20
- package/dist/schemas.d.ts +4 -4
- package/dist/search/factory.js +8 -8
- package/dist/search/index.js +13 -13
- 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 +22 -22
- package/dist/semantic-rule-promotion.js +21 -21
- package/dist/semantic-rule-verifier.js +21 -21
- package/dist/source-agent-qualifier.js +24 -24
- package/dist/standup/build.js +21 -21
- package/dist/storage.js +20 -20
- package/dist/support-passport/contracts.d.ts +6 -6
- package/dist/support-passport/grant-contracts.d.ts +4 -4
- package/dist/support-passport/index.js +50 -49
- package/dist/transfer/export-okf.js +21 -21
- package/dist/types.d.ts +3 -17
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -1
- package/dist/verified-recall.js +21 -21
- package/dist/who-knows-cli.js +22 -22
- package/dist/who-knows.js +21 -21
- package/package.json +2 -2
- package/src/access-extraction-force-flush.ts +37 -25
- package/src/access-observe-acceptance-boundary.test.ts +172 -0
- package/src/access-observe-replay-durability.test.ts +2212 -0
- package/src/access-observe-write-surface.ts +36 -41
- package/src/access-service-observe-lcm-parity.test.ts +63 -39
- package/src/access-service-observe-scope.test.ts +3 -2
- package/src/buffer-turn-helpers.ts +120 -1
- package/src/buffer-turn.ts +50 -0
- package/src/buffer.ts +115 -49
- package/src/namespaces/scope-profiles.ts +1 -1
- package/src/orchestration/extraction-run.ts +1 -1
- package/src/orchestration/session-context.ts +117 -49
- package/src/orchestration/turn-ingestion.ts +313 -9
- package/src/orchestrator-flush.test.ts +16 -3
- package/src/orchestrator.ts +2 -32
- package/src/types.ts +3 -17
- package/dist/chunk-BIE3ZH3N.js.map +0 -1
- package/dist/chunk-CKR7LXEK.js.map +0 -1
- package/dist/chunk-LDXNKEYB.js.map +0 -1
- package/dist/chunk-MMBLOJJB.js.map +0 -1
- package/dist/chunk-T5IF2ZCE.js.map +0 -1
- package/dist/chunk-WC3V7HHP.js.map +0 -1
- /package/dist/{chunk-YGVZ4QOZ.js.map → chunk-3CRE3UZI.js.map} +0 -0
- /package/dist/{chunk-YZTFQBYY.js.map → chunk-3GOPAWA7.js.map} +0 -0
- /package/dist/{chunk-NAPHQ2MG.js.map → chunk-3IDNKOCE.js.map} +0 -0
- /package/dist/{chunk-PYCTZ2HX.js.map → chunk-3VYNGM5A.js.map} +0 -0
- /package/dist/{chunk-2XVLY424.js.map → chunk-42MM5DKK.js.map} +0 -0
- /package/dist/{chunk-3IXNL6SK.js.map → chunk-4ZTVOECF.js.map} +0 -0
- /package/dist/{chunk-ETZUIRCI.js.map → chunk-53GYS3GG.js.map} +0 -0
- /package/dist/{chunk-ZXTAHSQU.js.map → chunk-5GPHJ333.js.map} +0 -0
- /package/dist/{chunk-AUYFUBBE.js.map → chunk-5HJCZ7SB.js.map} +0 -0
- /package/dist/{chunk-52II7PB6.js.map → chunk-645WOU5I.js.map} +0 -0
- /package/dist/{chunk-2WDMUQOH.js.map → chunk-64IO6ZEE.js.map} +0 -0
- /package/dist/{chunk-OIIAIY7J.js.map → chunk-7SXUGYPE.js.map} +0 -0
- /package/dist/{chunk-74IN6PV5.js.map → chunk-7WWITD3H.js.map} +0 -0
- /package/dist/{chunk-7FZ4YVOH.js.map → chunk-A5ZY537U.js.map} +0 -0
- /package/dist/{chunk-VLBFSD7B.js.map → chunk-APRGEZQN.js.map} +0 -0
- /package/dist/{chunk-XNROYP5E.js.map → chunk-AQ5XLA36.js.map} +0 -0
- /package/dist/{chunk-K2REHR42.js.map → chunk-BDHYRMJC.js.map} +0 -0
- /package/dist/{chunk-GQ7VWY6N.js.map → chunk-BQ6DGL6A.js.map} +0 -0
- /package/dist/{chunk-4OE4UE2Y.js.map → chunk-D3EXT5KG.js.map} +0 -0
- /package/dist/{chunk-MROA6OFU.js.map → chunk-DGBWPSM6.js.map} +0 -0
- /package/dist/{chunk-NOMHXZD7.js.map → chunk-DNZ2CWPG.js.map} +0 -0
- /package/dist/{chunk-HG2VVIKI.js.map → chunk-DZBMASSI.js.map} +0 -0
- /package/dist/{chunk-NB2YX6X2.js.map → chunk-EXYDKAR6.js.map} +0 -0
- /package/dist/{chunk-V4FI2TG6.js.map → chunk-F5FZ7DB4.js.map} +0 -0
- /package/dist/{chunk-IY7DGT2Z.js.map → chunk-GDPTMK5V.js.map} +0 -0
- /package/dist/{chunk-27OJ5G3D.js.map → chunk-GJBSEMC5.js.map} +0 -0
- /package/dist/{chunk-C2QVDLQV.js.map → chunk-HNTB7NIE.js.map} +0 -0
- /package/dist/{chunk-4HNINU7Q.js.map → chunk-HSPEVXT5.js.map} +0 -0
- /package/dist/{chunk-4QPW6JVI.js.map → chunk-ID2PLENW.js.map} +0 -0
- /package/dist/{chunk-FN6OFDBZ.js.map → chunk-ID62FNER.js.map} +0 -0
- /package/dist/{chunk-GSKW64NB.js.map → chunk-J6SZXAQ2.js.map} +0 -0
- /package/dist/{chunk-3CHHQXAR.js.map → chunk-JTACUJP3.js.map} +0 -0
- /package/dist/{chunk-3SN2D43X.js.map → chunk-K6RQ2KOX.js.map} +0 -0
- /package/dist/{chunk-GWB7ZD2A.js.map → chunk-K6YJGWJP.js.map} +0 -0
- /package/dist/{chunk-OANSZGAG.js.map → chunk-KFR343VH.js.map} +0 -0
- /package/dist/{chunk-NPO4ZQFY.js.map → chunk-LDXS746V.js.map} +0 -0
- /package/dist/{chunk-DDLRKPR2.js.map → chunk-NKW27NU3.js.map} +0 -0
- /package/dist/{chunk-4HYP4OKH.js.map → chunk-NU247WVX.js.map} +0 -0
- /package/dist/{chunk-RRJ462HP.js.map → chunk-O6YJI5VX.js.map} +0 -0
- /package/dist/{chunk-WYLBEJQI.js.map → chunk-OCWNT322.js.map} +0 -0
- /package/dist/{chunk-UUYAW3JH.js.map → chunk-OIKLZCJD.js.map} +0 -0
- /package/dist/{chunk-IO2UQVR2.js.map → chunk-OTWZXOJI.js.map} +0 -0
- /package/dist/{chunk-OXYXMGRH.js.map → chunk-PGHYQMKZ.js.map} +0 -0
- /package/dist/{chunk-LDEKVBVO.js.map → chunk-PZWW6MDE.js.map} +0 -0
- /package/dist/{chunk-TFA6HPOA.js.map → chunk-QCP75JGO.js.map} +0 -0
- /package/dist/{chunk-M236YHUH.js.map → chunk-RILIWZA6.js.map} +0 -0
- /package/dist/{chunk-7VB3Y5OL.js.map → chunk-RRYN5FFC.js.map} +0 -0
- /package/dist/{chunk-PZEADMX4.js.map → chunk-RU6WB55E.js.map} +0 -0
- /package/dist/{chunk-VARNSLUW.js.map → chunk-SGII36L6.js.map} +0 -0
- /package/dist/{chunk-KFKFK6G6.js.map → chunk-TB2J4PBY.js.map} +0 -0
- /package/dist/{chunk-WQIYGYY6.js.map → chunk-TEUPXKC5.js.map} +0 -0
- /package/dist/{chunk-VEB7NEON.js.map → chunk-U4BNX4R2.js.map} +0 -0
- /package/dist/{chunk-7HFTCBCZ.js.map → chunk-UBBZFODO.js.map} +0 -0
- /package/dist/{chunk-654GT5UP.js.map → chunk-UZDOPJ2P.js.map} +0 -0
- /package/dist/{chunk-D4RV54HH.js.map → chunk-VAPVRDC4.js.map} +0 -0
- /package/dist/{chunk-OXX4ORRL.js.map → chunk-W7X7XT7Z.js.map} +0 -0
- /package/dist/{chunk-5NPZFXQH.js.map → chunk-WK7GFAQ2.js.map} +0 -0
- /package/dist/{chunk-G6DAE2LT.js.map → chunk-WPCK6EJ2.js.map} +0 -0
- /package/dist/{chunk-VKQI47DJ.js.map → chunk-Y7427SL7.js.map} +0 -0
- /package/dist/{chunk-ZCRDYQL6.js.map → chunk-YGBWSKBD.js.map} +0 -0
- /package/dist/{chunk-NCPR2FOJ.js.map → chunk-YXWLQHAW.js.map} +0 -0
- /package/dist/{chunk-UM73Q46J.js.map → chunk-ZEMBRSKK.js.map} +0 -0
- /package/dist/{chunk-TTIEXXL3.js.map → chunk-ZGP2XB4S.js.map} +0 -0
- /package/dist/{chunk-UVUBLLM3.js.map → chunk-ZY4S5WMQ.js.map} +0 -0
|
@@ -20,7 +20,7 @@ import { createHash, randomBytes } from "node:crypto";
|
|
|
20
20
|
import { abortError } from "../abort-error.js";
|
|
21
21
|
import { SmartBuffer } from "../buffer.js";
|
|
22
22
|
import type { ImportTurn } from "../bulk-import/types.js";
|
|
23
|
-
import { resolvePipelineProcessingCapabilities, resolveRecallAuxiliaryCapabilities } from "../capabilities.js";
|
|
23
|
+
import { resolveNamespaceCapabilities, resolvePipelineProcessingCapabilities, resolveRecallAuxiliaryCapabilities } from "../capabilities.js";
|
|
24
24
|
import type { CorrectionService } from "../correction/correction-service.js";
|
|
25
25
|
import { type PassiveCaptureConfig, capturePassiveCorrections } from "../correction/passive-capture.js";
|
|
26
26
|
import { detectPassiveCorrections } from "../correction/passive-correction-detector.js";
|
|
@@ -40,7 +40,12 @@ import { SessionObserverState } from "../session-observer-state.js";
|
|
|
40
40
|
import { CODEX_THREAD_KEY_PREFIX } from "../thread-key.js";
|
|
41
41
|
import { TranscriptManager } from "../transcript.js";
|
|
42
42
|
import type { BufferTurn, PluginConfig, SourceConnectorProvenance } from "../types.js";
|
|
43
|
-
|
|
43
|
+
|
|
44
|
+
import { groupTurnsByExtractionScope, bufferTurnsEqual } from "../buffer-turn-helpers.js";
|
|
45
|
+
import { resolveScopeProfilePlan, type ResolvedScopeProfilePlan, hasExplicitNamespacePolicy } from "../namespaces/scope-profiles.js";
|
|
46
|
+
import { resolveCodingNamespaceOverlay, combineNamespaces } from "../coding/coding-namespace.js";
|
|
47
|
+
import { canWriteNamespace, defaultNamespaceForPrincipal } from "../namespaces/principal.js";
|
|
48
|
+
import { resolvePrincipal } from "../namespaces/principal.js";
|
|
44
49
|
import {
|
|
45
50
|
BulkImportBatchPartialFailureError,
|
|
46
51
|
splitTurnsBySourceValidAt,
|
|
@@ -48,6 +53,19 @@ import {
|
|
|
48
53
|
type BulkImportBatchIngestResult,
|
|
49
54
|
} from "../orchestrator.js";
|
|
50
55
|
|
|
56
|
+
/**
|
|
57
|
+
* #3251: raised by the buffered observe capture path when bounded admission
|
|
58
|
+
* refuses a NEW session entry because the extraction buffer is at its entry
|
|
59
|
+
* cap. The request was never accepted — no durable capture exists and no
|
|
60
|
+
* previously accepted capture was evicted to make room.
|
|
61
|
+
*/
|
|
62
|
+
export class ReplayAdmissionRefusedError extends Error {
|
|
63
|
+
constructor(message: string) {
|
|
64
|
+
super(message);
|
|
65
|
+
this.name = "ReplayAdmissionRefusedError";
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
51
69
|
export interface TurnIngestionDeps {
|
|
52
70
|
readonly buffer: SmartBuffer;
|
|
53
71
|
bulkImportWriteNamespace(): string;
|
|
@@ -202,6 +220,13 @@ export class TurnIngestionCoordinator {
|
|
|
202
220
|
|
|
203
221
|
if (outcome.decision === "keep_buffering") return;
|
|
204
222
|
if (!outcome.extractionTurns) return;
|
|
223
|
+
if (outcome.extractionTurns.some((turn) => turn.acceptedCapture === true)) {
|
|
224
|
+
// #3251: native triggers must not run mixed accepted scopes under one
|
|
225
|
+
// policy — each scope group drains through the shared execution
|
|
226
|
+
// boundary with its own pins.
|
|
227
|
+
this.queueBufferedCaptureScopeGroups(outcome.extractionTurns, bufferKey, {});
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
205
230
|
await this.deps.queueBufferedExtraction(
|
|
206
231
|
outcome.extractionTurns,
|
|
207
232
|
"trigger_mode",
|
|
@@ -249,14 +274,25 @@ export class TurnIngestionCoordinator {
|
|
|
249
274
|
* and import callers leave it unset.
|
|
250
275
|
*/
|
|
251
276
|
sessionOwnerPrincipal?: string;
|
|
277
|
+
/**
|
|
278
|
+
* #3251: "immediate" (default) keeps the pre-#3251 forced-queue
|
|
279
|
+
* semantics. "buffered" is the access `observe` capture mode — turns
|
|
280
|
+
* are capacity-admitted, scope-pinned, and made durable before this
|
|
281
|
+
* promise resolves; extraction only queues on the buffer's native
|
|
282
|
+
* trigger, and abort/deadline/restart leave the capture recoverable.
|
|
283
|
+
*/
|
|
284
|
+
extractionMode?: "immediate" | "buffered";
|
|
285
|
+
/** #3251: invoked per trigger-queued extraction promise (buffered mode). */
|
|
286
|
+
onExtractionQueued?: (extraction: Promise<void>) => void;
|
|
287
|
+
/**
|
|
288
|
+
* #3251: the ALREADY-resolved native coding context for this capture
|
|
289
|
+
* (buffered mode). Pinned on the durable turns so drains re-resolve
|
|
290
|
+
* current policy for the SAME project binding.
|
|
291
|
+
*/
|
|
292
|
+
codingContext?: import("../types.js").CodingContext;
|
|
252
293
|
} = {},
|
|
253
294
|
): Promise<void> {
|
|
254
295
|
if (!Array.isArray(turns) || turns.length === 0) return;
|
|
255
|
-
if (options.abortSignal?.aborted) {
|
|
256
|
-
throw options.abortSignal.reason instanceof Error
|
|
257
|
-
? options.abortSignal.reason
|
|
258
|
-
: new Error("ingestReplayBatch aborted");
|
|
259
|
-
}
|
|
260
296
|
if (shouldSkipImplicitExtraction(this.deps.config)) {
|
|
261
297
|
log.debug(
|
|
262
298
|
"ingestReplayBatch: skipping implicit extraction because captureMode=explicit",
|
|
@@ -285,6 +321,19 @@ export class TurnIngestionCoordinator {
|
|
|
285
321
|
bySession.set(key, list);
|
|
286
322
|
}
|
|
287
323
|
|
|
324
|
+
// #3251: the buffered capture ignores pre-aborted signals — cancellation
|
|
325
|
+
// applies to extraction, never to durable admission. The abort pre-check
|
|
326
|
+
// below guards only the immediate (forced-queue) path.
|
|
327
|
+
if (options.extractionMode === "buffered") {
|
|
328
|
+
return this.ingestReplayBatchBuffered(bySession, options);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
if (options.abortSignal?.aborted) {
|
|
332
|
+
throw options.abortSignal.reason instanceof Error
|
|
333
|
+
? options.abortSignal.reason
|
|
334
|
+
: new Error("ingestReplayBatch aborted");
|
|
335
|
+
}
|
|
336
|
+
|
|
288
337
|
const replaySlices: Array<{
|
|
289
338
|
bufferKey: string;
|
|
290
339
|
order: number;
|
|
@@ -358,6 +407,123 @@ export class TurnIngestionCoordinator {
|
|
|
358
407
|
}
|
|
359
408
|
}
|
|
360
409
|
|
|
410
|
+
/** #3251 buffered capture: durable scope-pinned admission; await settles at durability. */
|
|
411
|
+
private async ingestReplayBatchBuffered(
|
|
412
|
+
bySession: Map<string, BufferTurn[]>,
|
|
413
|
+
options: {
|
|
414
|
+
deadlineMs?: number;
|
|
415
|
+
archiveLcm?: boolean;
|
|
416
|
+
abortSignal?: AbortSignal;
|
|
417
|
+
writeNamespaceOverride?: string;
|
|
418
|
+
principalOverride?: string;
|
|
419
|
+
scopeProfileWritePlan?: ResolvedScopeProfilePlan | null;
|
|
420
|
+
codingContext?: import("../types.js").CodingContext;
|
|
421
|
+
onExtractionQueued?: (extraction: Promise<void>) => void;
|
|
422
|
+
},
|
|
423
|
+
): Promise<void> {
|
|
424
|
+
// #3251: resolve the original actual storage target ONCE at method entry,
|
|
425
|
+
// BEFORE any LCM archival or buffer admission. Explicit override is
|
|
426
|
+
// authoritative; otherwise namespaces OFF → the collapsed default store;
|
|
427
|
+
// namespaces ON → the plan's writeNamespace. Reject before any side
|
|
428
|
+
// effect if neither is available.
|
|
429
|
+
const resolvedWriteTarget =
|
|
430
|
+
options.writeNamespaceOverride ??
|
|
431
|
+
(resolveNamespaceCapabilities(this.deps.config).namespaces === true
|
|
432
|
+
? options.scopeProfileWritePlan?.writeNamespace
|
|
433
|
+
: this.deps.config.defaultNamespace);
|
|
434
|
+
if (!resolvedWriteTarget) {
|
|
435
|
+
throw new ReplayAdmissionRefusedError(
|
|
436
|
+
"accepted capture requires an explicit storage target (writeNamespaceOverride or scopeProfileWritePlan.writeNamespace)",
|
|
437
|
+
);
|
|
438
|
+
}
|
|
439
|
+
for (const [bufferKey, sessionTurns] of bySession) {
|
|
440
|
+
// No top-level abort check: cancellation applies to the background
|
|
441
|
+
// extraction, never to the durable capture or save barrier (#3251).
|
|
442
|
+
if (options.archiveLcm !== false && this.deps.lcmEngine?.enabled) {
|
|
443
|
+
await this.deps.lcmEngine.observeMessages(
|
|
444
|
+
bufferKey,
|
|
445
|
+
sessionTurns.map((turn) => ({
|
|
446
|
+
role: turn.role,
|
|
447
|
+
content: turn.content,
|
|
448
|
+
parts: turn.parts,
|
|
449
|
+
rawContent: turn.rawContent,
|
|
450
|
+
sourceFormat: turn.sourceFormat,
|
|
451
|
+
})),
|
|
452
|
+
);
|
|
453
|
+
}
|
|
454
|
+
for (const turn of sessionTurns) {
|
|
455
|
+
const pinned: BufferTurn = { ...turn, acceptedCapture: true, writeNamespaceOverride: resolvedWriteTarget };
|
|
456
|
+
if (options.codingContext) pinned.codingContext = options.codingContext;
|
|
457
|
+
if (options.principalOverride) pinned.principalOverride = options.principalOverride;
|
|
458
|
+
if (options.scopeProfileWritePlan) pinned.scopeProfileWritePlan = options.scopeProfileWritePlan;
|
|
459
|
+
const outcome = await this.deps.buffer.addTurnBounded(bufferKey, pinned);
|
|
460
|
+
if (outcome === null) {
|
|
461
|
+
throw new ReplayAdmissionRefusedError(
|
|
462
|
+
`durable observe capture refused: extraction buffer at entry capacity for ${bufferKey}`,
|
|
463
|
+
);
|
|
464
|
+
}
|
|
465
|
+
if (outcome.decision !== "keep_buffering" && outcome.extractionTurns) {
|
|
466
|
+
this.queueBufferedCaptureScopeGroups(outcome.extractionTurns, bufferKey, options);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
// Acceptance durability barrier (#1909 seam): surfaces storage failures
|
|
470
|
+
// BEFORE the caller can report acceptance. Not abort-gated.
|
|
471
|
+
await this.deps.buffer.flushPendingSave({ throwOnFailure: true });
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* Buffer-approved captures skip threshold/dedupe rechecks, not provider retry cooldowns.
|
|
477
|
+
* Scope and staleness are enforced at the shared queueBufferedExtraction boundary.
|
|
478
|
+
*/
|
|
479
|
+
private queueBufferedCaptureScopeGroups(
|
|
480
|
+
extractionTurns: BufferTurn[],
|
|
481
|
+
bufferKey: string,
|
|
482
|
+
options: {
|
|
483
|
+
deadlineMs?: number;
|
|
484
|
+
abortSignal?: AbortSignal;
|
|
485
|
+
writeNamespaceOverride?: string;
|
|
486
|
+
principalOverride?: string;
|
|
487
|
+
scopeProfileWritePlan?: ResolvedScopeProfilePlan | null;
|
|
488
|
+
codingContext?: import("../types.js").CodingContext;
|
|
489
|
+
onExtractionQueued?: (extraction: Promise<void>) => void;
|
|
490
|
+
},
|
|
491
|
+
): void {
|
|
492
|
+
for (const group of groupTurnsByExtractionScope(extractionTurns)) {
|
|
493
|
+
const groupIsAccepted = group.turns.some((turn) => turn.acceptedCapture === true);
|
|
494
|
+
if (!groupIsAccepted) {
|
|
495
|
+
// Native groups keep their own routing; skipped accepted prefixes require identity clearing.
|
|
496
|
+
void this.deps.queueBufferedExtraction(group.turns, "trigger_mode", {
|
|
497
|
+
bufferKey,
|
|
498
|
+
clearMatchingTurns: true,
|
|
499
|
+
}).catch((err) => log.error(`native trigger extraction failed: ${err}`));
|
|
500
|
+
continue;
|
|
501
|
+
}
|
|
502
|
+
// Accepted groups use ONLY their own pins — no fallback to the
|
|
503
|
+
// triggering observe's scope.
|
|
504
|
+
const extraction = new Promise<void>((resolve, reject) => {
|
|
505
|
+
void this.deps.queueBufferedExtraction(group.turns, "trigger_mode", {
|
|
506
|
+
bufferKey,
|
|
507
|
+
clearBufferAfterExtraction: true,
|
|
508
|
+
clearMatchingTurns: true,
|
|
509
|
+
skipDedupeCheck: true,
|
|
510
|
+
skipCharThreshold: true,
|
|
511
|
+
skipUserTurnThreshold: true,
|
|
512
|
+
abortSignal: options.abortSignal,
|
|
513
|
+
extractionDeadlineMs: options.deadlineMs,
|
|
514
|
+
writeNamespaceOverride: group.writeNamespaceOverride,
|
|
515
|
+
principalOverride: group.principalOverride,
|
|
516
|
+
// #3251: accepted groups with no plan pin dispatch null (explicit
|
|
517
|
+
// none) — not undefined which would re-resolve the CURRENT profile.
|
|
518
|
+
scopeProfileWritePlan: group.scopeProfileWritePlan ?? null,
|
|
519
|
+
onTaskSettled: (err) => (err ? reject(err) : resolve()),
|
|
520
|
+
}).catch(reject);
|
|
521
|
+
});
|
|
522
|
+
if (options.onExtractionQueued) options.onExtractionQueued(extraction);
|
|
523
|
+
else extraction.catch((err) => log.error(`buffered capture extraction failed: ${err}`));
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
361
527
|
/**
|
|
362
528
|
* Ingest a batch of bulk-import turns (#460). Like ingestReplayBatch, this
|
|
363
529
|
* normalizes user/assistant turns into the extraction buffer and awaits
|
|
@@ -633,6 +799,12 @@ export class TurnIngestionCoordinator {
|
|
|
633
799
|
log.debug(
|
|
634
800
|
`heartbeat observer trigger: session=${sessionKey} deltaBytes=${decision.deltaBytes} deltaTokens=${decision.deltaTokens}`,
|
|
635
801
|
);
|
|
802
|
+
if (turns.some((turn) => turn.acceptedCapture === true)) {
|
|
803
|
+
// #3251: heartbeat triggers must not run mixed accepted scopes
|
|
804
|
+
// under one policy — per-scope groups via the shared boundary.
|
|
805
|
+
this.queueBufferedCaptureScopeGroups(turns, bufferKey, {});
|
|
806
|
+
return;
|
|
807
|
+
}
|
|
636
808
|
await this.deps.queueBufferedExtraction(turns, "heartbeat_observer", {
|
|
637
809
|
bufferKey,
|
|
638
810
|
});
|
|
@@ -771,7 +943,136 @@ export class TurnIngestionCoordinator {
|
|
|
771
943
|
}
|
|
772
944
|
clearQueueWaitTimer();
|
|
773
945
|
try {
|
|
774
|
-
|
|
946
|
+
// #3251 shared execution boundary for accepted captures (trigger and
|
|
947
|
+
// flush drains both converge here): re-read the live buffer so a
|
|
948
|
+
// concurrent drain that already took these turns skips the LLM work,
|
|
949
|
+
// and re-resolve a pinned plan against CURRENT config — revoke skips
|
|
950
|
+
// WITHOUT clearing, and the plan is never retargeted.
|
|
951
|
+
let effectiveTurns = turnsToExtract;
|
|
952
|
+
let effectiveScopePlan = options.scopeProfileWritePlan;
|
|
953
|
+
if (effectiveTurns.some((turn) => turn.acceptedCapture === true)) {
|
|
954
|
+
const liveTurns = this.deps.buffer
|
|
955
|
+
.getTurns(bufferKey)
|
|
956
|
+
.filter((live) => effectiveTurns.some((snapshotted) => bufferTurnsEqual(live, snapshotted)));
|
|
957
|
+
if (liveTurns.length === 0) {
|
|
958
|
+
settleTask(undefined, {
|
|
959
|
+
status: "skipped",
|
|
960
|
+
reason: "already_drained",
|
|
961
|
+
persistedCount: 0,
|
|
962
|
+
durableOutputCount: 0,
|
|
963
|
+
});
|
|
964
|
+
return;
|
|
965
|
+
}
|
|
966
|
+
effectiveTurns = liveTurns;
|
|
967
|
+
// Pinned-namespace guard (#3251): if namespaces are now DISABLED, a
|
|
968
|
+
// non-default pinned namespace can no longer be honored as a
|
|
969
|
+
// separate store — skip + preserve rather than silently flattening
|
|
970
|
+
// the capture into the default store.
|
|
971
|
+
const namespacesOn = resolveNamespaceCapabilities(this.deps.config).namespaces === true;
|
|
972
|
+
const acceptedTurn = effectiveTurns.find((turn) => turn.acceptedCapture === true);
|
|
973
|
+
const pinnedNamespace = acceptedTurn?.writeNamespaceOverride;
|
|
974
|
+
// #3251: policy-preserving skips reject when the caller demands
|
|
975
|
+
// failure (forceflush) so retained cleanup never deletes preserved
|
|
976
|
+
// captures; background triggers soft-skip and keep the data.
|
|
977
|
+
const policySkipError = (reason: string): Error | undefined =>
|
|
978
|
+
options.failOnExtractionFailure === true
|
|
979
|
+
? new Error(`accepted capture preserved: ${reason} (${bufferKey})`)
|
|
980
|
+
: undefined;
|
|
981
|
+
if (
|
|
982
|
+
!namespacesOn &&
|
|
983
|
+
pinnedNamespace !== undefined &&
|
|
984
|
+
pinnedNamespace !== this.deps.config.defaultNamespace
|
|
985
|
+
) {
|
|
986
|
+
const err = policySkipError("pinned_namespace_unavailable");
|
|
987
|
+
if (err) { settleTask(err); return; }
|
|
988
|
+
settleTask(undefined, {
|
|
989
|
+
status: "skipped",
|
|
990
|
+
reason: "pinned_namespace_unavailable",
|
|
991
|
+
persistedCount: 0,
|
|
992
|
+
durableOutputCount: 0,
|
|
993
|
+
});
|
|
994
|
+
return;
|
|
995
|
+
}
|
|
996
|
+
// Current-policy write re-auth for pinned namespaces (#3251): the
|
|
997
|
+
// grant at capture time may have been revoked. Project-derived
|
|
998
|
+
// namespaces honor native base-inheritance (never blanket
|
|
999
|
+
// canWriteNamespace on the combined name); explicit-policy and
|
|
1000
|
+
// default pins re-check directly — default may be revoked too.
|
|
1001
|
+
const firstSessionKey = effectiveTurns[0]?.sessionKey ?? "";
|
|
1002
|
+
const principal =
|
|
1003
|
+
options.principalOverride !== undefined && options.principalOverride.length > 0
|
|
1004
|
+
? options.principalOverride
|
|
1005
|
+
: resolvePrincipal(firstSessionKey, this.deps.config);
|
|
1006
|
+
if (namespacesOn && pinnedNamespace !== undefined && !effectiveScopePlan) {
|
|
1007
|
+
const originalContext = acceptedTurn?.codingContext ?? null;
|
|
1008
|
+
const overlay = originalContext
|
|
1009
|
+
? resolveCodingNamespaceOverlay(
|
|
1010
|
+
originalContext,
|
|
1011
|
+
this.deps.config.codingMode,
|
|
1012
|
+
this.deps.config.defaultNamespace,
|
|
1013
|
+
)
|
|
1014
|
+
: null;
|
|
1015
|
+
const baseNamespace = defaultNamespaceForPrincipal(principal, this.deps.config);
|
|
1016
|
+
const projectNamespace =
|
|
1017
|
+
overlay && this.deps.config.codingMode
|
|
1018
|
+
? combineNamespaces(baseNamespace, overlay.namespace)
|
|
1019
|
+
: undefined;
|
|
1020
|
+
const writeAuthorized =
|
|
1021
|
+
projectNamespace === pinnedNamespace
|
|
1022
|
+
? hasExplicitNamespacePolicy(pinnedNamespace, this.deps.config)
|
|
1023
|
+
? canWriteNamespace(principal, pinnedNamespace, this.deps.config)
|
|
1024
|
+
: canWriteNamespace(principal, baseNamespace, this.deps.config)
|
|
1025
|
+
: canWriteNamespace(principal, pinnedNamespace, this.deps.config);
|
|
1026
|
+
if (!writeAuthorized) {
|
|
1027
|
+
const err = policySkipError("namespace_write_revoked");
|
|
1028
|
+
if (err) { settleTask(err); return; }
|
|
1029
|
+
settleTask(undefined, {
|
|
1030
|
+
status: "skipped",
|
|
1031
|
+
reason: "namespace_write_revoked",
|
|
1032
|
+
persistedCount: 0,
|
|
1033
|
+
durableOutputCount: 0,
|
|
1034
|
+
});
|
|
1035
|
+
return;
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
if (effectiveScopePlan) {
|
|
1039
|
+
// #3251: re-resolve with the ORIGINAL coding binding (stored
|
|
1040
|
+
// natively on the turn) so project-scoped captures re-authorize
|
|
1041
|
+
// against CURRENT policy without losing their project identity.
|
|
1042
|
+
const originalContext = acceptedTurn?.codingContext ?? null;
|
|
1043
|
+
const codingOverlay = originalContext
|
|
1044
|
+
? resolveCodingNamespaceOverlay(
|
|
1045
|
+
originalContext,
|
|
1046
|
+
this.deps.config.codingMode,
|
|
1047
|
+
this.deps.config.defaultNamespace,
|
|
1048
|
+
)
|
|
1049
|
+
: null;
|
|
1050
|
+
const fresh = resolveScopeProfilePlan({
|
|
1051
|
+
config: this.deps.config,
|
|
1052
|
+
principal,
|
|
1053
|
+
codingContext: originalContext,
|
|
1054
|
+
codingOverlay,
|
|
1055
|
+
});
|
|
1056
|
+
const identityHolds =
|
|
1057
|
+
fresh !== null &&
|
|
1058
|
+
fresh.profileId === effectiveScopePlan.profileId &&
|
|
1059
|
+
fresh.writeLayer === effectiveScopePlan.writeLayer &&
|
|
1060
|
+
fresh.writeNamespace === effectiveScopePlan.writeNamespace;
|
|
1061
|
+
if (!identityHolds) {
|
|
1062
|
+
const err = policySkipError("scope_profile_revoked");
|
|
1063
|
+
if (err) { settleTask(err); return; }
|
|
1064
|
+
settleTask(undefined, {
|
|
1065
|
+
status: "skipped",
|
|
1066
|
+
reason: "scope_profile_revoked",
|
|
1067
|
+
persistedCount: 0,
|
|
1068
|
+
durableOutputCount: 0,
|
|
1069
|
+
});
|
|
1070
|
+
return;
|
|
1071
|
+
}
|
|
1072
|
+
effectiveScopePlan = fresh;
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
const result = await this.deps.runExtraction(effectiveTurns, {
|
|
775
1076
|
clearBufferAfterExtraction:
|
|
776
1077
|
options.clearBufferAfterExtraction ?? true,
|
|
777
1078
|
clearMatchingTurns: options.clearMatchingTurns === true,
|
|
@@ -784,7 +1085,7 @@ export class TurnIngestionCoordinator {
|
|
|
784
1085
|
failOnExtractionFailure: options.failOnExtractionFailure === true,
|
|
785
1086
|
writeNamespaceOverride: options.writeNamespaceOverride,
|
|
786
1087
|
principalOverride: options.principalOverride,
|
|
787
|
-
scopeProfileWritePlan:
|
|
1088
|
+
scopeProfileWritePlan: effectiveScopePlan,
|
|
788
1089
|
forceExtractionAttempt: options.forceExtractionAttempt === true,
|
|
789
1090
|
});
|
|
790
1091
|
settleTask(undefined, result);
|
|
@@ -889,3 +1190,6 @@ export class TurnIngestionCoordinator {
|
|
|
889
1190
|
}
|
|
890
1191
|
}
|
|
891
1192
|
}
|
|
1193
|
+
|
|
1194
|
+
/** Named option contract for `TurnIngestionCoordinator.ingestReplayBatch` (#3251). */
|
|
1195
|
+
export type IngestReplayBatchOptions = Parameters<TurnIngestionCoordinator["ingestReplayBatch"]>[1];
|
|
@@ -225,7 +225,12 @@ test("flushSession preserves retained context for other scoped sessions", async
|
|
|
225
225
|
_reason: string,
|
|
226
226
|
options?: Record<string, unknown>,
|
|
227
227
|
) => {
|
|
228
|
-
|
|
228
|
+
// #3251: scoped retainDeferredTurns at the extraction boundary preserves
|
|
229
|
+
// other-scope retained turns — simulate that here.
|
|
230
|
+
retainedTurns = [
|
|
231
|
+
...retainedTurns.filter((turn) => turn.sessionKey !== "session-z"),
|
|
232
|
+
makeTurn("session-z", "new session A context", "alice"),
|
|
233
|
+
];
|
|
229
234
|
(options?.onTaskSettled as ((error?: unknown) => void) | undefined)?.();
|
|
230
235
|
};
|
|
231
236
|
|
|
@@ -262,7 +267,11 @@ test("flushSession keeps all other-session retained turns ahead of the scoped ca
|
|
|
262
267
|
_reason: string,
|
|
263
268
|
options?: Record<string, unknown>,
|
|
264
269
|
) => {
|
|
265
|
-
|
|
270
|
+
// #3251: scoped retainDeferredTurns preserves other-scope retained turns.
|
|
271
|
+
retainedTurns = [
|
|
272
|
+
...retainedTurns.filter((turn) => turn.sessionKey !== "session-z"),
|
|
273
|
+
makeTurn("session-z", "new session A context", "alice"),
|
|
274
|
+
];
|
|
266
275
|
(options?.onTaskSettled as ((error?: unknown) => void) | undefined)?.();
|
|
267
276
|
};
|
|
268
277
|
|
|
@@ -273,9 +282,13 @@ test("flushSession keeps all other-session retained turns ahead of the scoped ca
|
|
|
273
282
|
});
|
|
274
283
|
|
|
275
284
|
assert.deepEqual(
|
|
276
|
-
retainedTurns.map((turn) => turn.content),
|
|
285
|
+
retainedTurns.filter((turn) => turn.sessionKey === "session-y").map((turn) => turn.content),
|
|
277
286
|
otherSessionTurns.map((turn) => turn.content),
|
|
278
287
|
);
|
|
288
|
+
assert.ok(
|
|
289
|
+
retainedTurns.some((turn) => turn.content === "new session A context"),
|
|
290
|
+
"own-scope new retained context added alongside preserved others",
|
|
291
|
+
);
|
|
279
292
|
});
|
|
280
293
|
|
|
281
294
|
|
package/src/orchestrator.ts
CHANGED
|
@@ -135,7 +135,7 @@ import { RecallSearchPipelineCoordinator } from "./orchestration/recall-search-p
|
|
|
135
135
|
import type { GraphRecallExpansionOptions, GraphRecallExpansionResult } from "./orchestration/graph-recall-coordinator.js";
|
|
136
136
|
import type { ArtifactRecallOptions } from "./orchestration/recall-search-prefilter.js";
|
|
137
137
|
import type { CorpusReadOptions } from "./corpus-read-cancellation.js";
|
|
138
|
-
import { TurnIngestionCoordinator, type TurnIngestionOptions } from "./orchestration/turn-ingestion.js";
|
|
138
|
+
import { TurnIngestionCoordinator, type IngestReplayBatchOptions, type TurnIngestionOptions } from "./orchestration/turn-ingestion.js";
|
|
139
139
|
import { RecallIntrospectionCoordinator } from "./orchestration/recall-introspection.js";
|
|
140
140
|
import { OrchestratorInitCoordinator } from "./orchestration/orchestrator-init.js";
|
|
141
141
|
import { PersistenceIndexCoordinator } from "./orchestration/persistence-index.js";
|
|
@@ -2971,37 +2971,7 @@ export class Orchestrator {
|
|
|
2971
2971
|
|
|
2972
2972
|
async ingestReplayBatch(
|
|
2973
2973
|
turns: ReplayTurn[],
|
|
2974
|
-
options: {
|
|
2975
|
-
deadlineMs?: number;
|
|
2976
|
-
archiveLcm?: boolean;
|
|
2977
|
-
abortSignal?: AbortSignal;
|
|
2978
|
-
/**
|
|
2979
|
-
* Pin extraction writes to this namespace instead of deriving one from
|
|
2980
|
-
* `defaultNamespaceForPrincipal(resolvePrincipal(sessionKey))` + the
|
|
2981
|
-
* coding overlay (#1495). The access `observe` surface resolves a single
|
|
2982
|
-
* effective scope plan and passes its `writeNamespace` here so the
|
|
2983
|
-
* extracted memories land in the SAME namespace as LCM archival,
|
|
2984
|
-
* objective-state snapshots, and project-scoped recall — without relying
|
|
2985
|
-
* on re-deriving the namespace from a namespace-prefixed session key.
|
|
2986
|
-
* Same hook bulk-import uses (#460).
|
|
2987
|
-
*/
|
|
2988
|
-
writeNamespaceOverride?: string;
|
|
2989
|
-
/**
|
|
2990
|
-
* Pin the provenance PRINCIPAL instead of deriving it from
|
|
2991
|
-
* `resolvePrincipal(turn.sessionKey)` (#1495 thread 1). The access
|
|
2992
|
-
* `observe` surface authenticates the caller at the transport layer and
|
|
2993
|
-
* passes its resolved principal here so extracted-memory provenance uses
|
|
2994
|
-
* the SAME identity the surface authorized — independent of storage
|
|
2995
|
-
* routing (`writeNamespaceOverride`) and of whatever `resolvePrincipal`
|
|
2996
|
-
* would parse from the raw session key. Mirrors the recall path's
|
|
2997
|
-
* `principalOverride` (issue #570 PR 4).
|
|
2998
|
-
*/
|
|
2999
|
-
principalOverride?: string;
|
|
3000
|
-
/** Forward the observe surface's resolved scope-profile write plan (#3051). */
|
|
3001
|
-
scopeProfileWritePlan?: ResolvedScopeProfilePlan | null;
|
|
3002
|
-
/** Persist the authenticated session owner on buffered turns. */
|
|
3003
|
-
sessionOwnerPrincipal?: string;
|
|
3004
|
-
} = {},
|
|
2974
|
+
options: IngestReplayBatchOptions = {},
|
|
3005
2975
|
): Promise<void> {
|
|
3006
2976
|
return this.turnIngestionCoordinator.ingestReplayBatch(
|
|
3007
2977
|
turns,
|
package/src/types.ts
CHANGED
|
@@ -31,7 +31,7 @@ import type { SessionExperienceConfig } from "./experience/session-experience-co
|
|
|
31
31
|
import type { ActionGateConfig } from "./coding/action-gate.js";
|
|
32
32
|
import type { ActiveContextConfigFields } from "./active-context-config.js";
|
|
33
33
|
import type { LocalLlmConfig } from "./local-llm-config.js";
|
|
34
|
-
import type {
|
|
34
|
+
import type { SecurityConfig, OriginMetadata } from "./security/types.js";
|
|
35
35
|
export type MemorySubject = "user" | "agent";
|
|
36
36
|
export type SubjectGuardMode = "off" | "warn" | "enforce";
|
|
37
37
|
export type ReasoningEffort = "none" | "low" | "medium" | "high";
|
|
@@ -2656,22 +2656,8 @@ export interface SourceConnectorProvenance {
|
|
|
2656
2656
|
sourceConnector?: string;
|
|
2657
2657
|
originRole?: "user" | "assistant" | "tool";
|
|
2658
2658
|
}
|
|
2659
|
-
export
|
|
2660
|
-
|
|
2661
|
-
content: string;
|
|
2662
|
-
timestamp: string;
|
|
2663
|
-
sourceValidAt?: string;
|
|
2664
|
-
sessionKey?: string;
|
|
2665
|
-
logicalSessionKey?: string;
|
|
2666
|
-
providerThreadId?: string | null;
|
|
2667
|
-
turnFingerprint?: string;
|
|
2668
|
-
persistProcessedFingerprint?: boolean;
|
|
2669
|
-
extractionContextOnly?: boolean;
|
|
2670
|
-
parts?: import("./message-parts/index.js").LcmMessagePartInput[];
|
|
2671
|
-
rawContent?: unknown;
|
|
2672
|
-
sourceFormat?: import("./message-parts/index.js").MessagePartSourceFormat;
|
|
2673
|
-
importProvenance?: import("./bulk-import/types.js").ImportTurnProvenance;
|
|
2674
|
-
}
|
|
2659
|
+
export type { BufferTurn } from "./buffer-turn.js";
|
|
2660
|
+
import type { BufferTurn } from "./buffer-turn.js";
|
|
2675
2661
|
|
|
2676
2662
|
export interface BufferEntryState {
|
|
2677
2663
|
turns: BufferTurn[];
|