@remnic/core 9.30.1 → 9.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/access-admin-ops-surface.d.ts +10 -10
- package/dist/access-admin-ops-surface.js +50 -44
- package/dist/access-authorization-probe.d.ts +10 -10
- package/dist/access-authorization-probe.js +51 -45
- package/dist/access-boundary.d.ts +13 -11
- package/dist/access-boundary.js +50 -44
- package/dist/access-cli.js +168 -123
- package/dist/access-cli.js.map +1 -1
- package/dist/access-extraction-force-flush.d.ts +119 -0
- package/dist/access-extraction-force-flush.js +166 -0
- package/dist/access-health-types.d.ts +1 -1
- package/dist/access-http-lcm-compaction.d.ts +47 -13
- package/dist/access-http-lcm-compaction.js +7 -3
- package/dist/access-http-lifecycle-flush.d.ts +132 -0
- package/dist/access-http-lifecycle-flush.js +9 -0
- package/dist/access-http-lifecycle-flush.js.map +1 -0
- package/dist/access-http.d.ts +11 -10
- package/dist/access-http.js +66 -59
- package/dist/access-identity-continuity-surface.d.ts +8 -8
- package/dist/access-identity-continuity-surface.js +50 -44
- package/dist/access-lcm-surface.d.ts +10 -10
- package/dist/access-lcm-surface.js +50 -44
- package/dist/access-mcp-output-schemas.js +1 -1
- package/dist/access-mcp.d.ts +16 -10
- package/dist/access-mcp.js +58 -52
- package/dist/access-memory-search-fanout.d.ts +2 -2
- package/dist/{access-namespace-preflight-VfXssvoI.d.ts → access-namespace-preflight-D4vW97H1.d.ts} +1 -1
- package/dist/access-namespace-preflight.d.ts +3 -3
- package/dist/access-namespace-preflight.js +50 -44
- package/dist/access-observe-helpers.d.ts +22 -0
- package/dist/access-observe-helpers.js +10 -0
- package/dist/access-observe-helpers.js.map +1 -0
- package/dist/access-observe-write-surface.d.ts +51 -47
- package/dist/access-observe-write-surface.js +50 -44
- package/dist/access-operations-batch.js +53 -47
- package/dist/access-operations.d.ts +11 -11
- package/dist/access-operations.js +55 -49
- package/dist/access-recall-concurrency.d.ts +10 -10
- package/dist/access-recall-concurrency.js +50 -44
- package/dist/access-recall-response.d.ts +10 -10
- package/dist/access-recall-response.js +50 -44
- package/dist/access-recall-surface.d.ts +10 -10
- package/dist/access-recall-surface.js +50 -44
- package/dist/access-schema.d.ts +37 -7
- package/dist/access-schema.js +5 -3
- package/dist/{access-service-B5RwVsTV.d.ts → access-service-B6PZ_xUL.d.ts} +44 -20
- package/dist/access-service-helpers.d.ts +113 -0
- package/dist/access-service-helpers.js +8 -0
- package/dist/access-service-helpers.js.map +1 -0
- package/dist/access-service.d.ts +10 -10
- package/dist/access-service.js +50 -44
- package/dist/access-surface-catalog.d.ts +10 -10
- package/dist/access-surface-catalog.js +2 -0
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/access-wearables-meetings-surface.d.ts +3 -3
- package/dist/action-confidence.d.ts +1 -1
- package/dist/active-memory-bridge.d.ts +1 -1
- package/dist/active-recall.d.ts +1 -1
- package/dist/active-recall.js +1 -1
- package/dist/adapters/index.js +7 -7
- package/dist/adapters/registry.js +3 -3
- package/dist/behavior-learner.d.ts +1 -1
- package/dist/behavior-signals.d.ts +1 -1
- package/dist/bootstrap.d.ts +8 -8
- package/dist/briefing.d.ts +2 -2
- package/dist/briefing.js +14 -14
- package/dist/buffer-surprise-report.d.ts +1 -1
- package/dist/buffer-turn-helpers.d.ts +5 -0
- package/dist/buffer-turn-helpers.js +24 -0
- package/dist/buffer-turn-helpers.js.map +1 -0
- package/dist/buffer.d.ts +17 -4
- package/dist/buffer.js +21 -1
- package/dist/bulk-import/index.d.ts +3 -3
- package/dist/calibration.d.ts +1 -1
- package/dist/capabilities.d.ts +1 -1
- package/dist/{capsule-crypto-GWVG7LGC.js → capsule-crypto-7FJQINUR.js} +2 -2
- package/dist/capsule-crypto-7FJQINUR.js.map +1 -0
- package/dist/{capsule-merge-5KKJQBWQ.js → capsule-merge-2H2IUTBT.js} +4 -4
- package/dist/{catalog-V7inUQdp.d.ts → catalog-CGFYmTT8.d.ts} +1 -1
- package/dist/causal-behavior.d.ts +1 -1
- package/dist/causal-behavior.js +2 -2
- package/dist/causal-chain.js +2 -2
- package/dist/causal-consolidation.d.ts +1 -1
- package/dist/causal-consolidation.js +19 -19
- package/dist/causal-retrieval.js +2 -2
- package/dist/causal-trajectory-graph.d.ts +1 -1
- package/dist/causal-trajectory.js +1 -1
- package/dist/{chunk-LEPOP46W.js → chunk-227UFSEQ.js} +4 -4
- package/dist/{chunk-GIBMDSJ2.js → chunk-27P5YVDU.js} +2 -2
- package/dist/{chunk-2SA56WMI.js → chunk-2LTDWSR6.js} +4 -4
- package/dist/{chunk-OWHERGF2.js → chunk-2NLLXCJG.js} +2 -2
- package/dist/{chunk-YTSNAUXN.js → chunk-3F2LKUMU.js} +22 -8
- package/dist/chunk-3F2LKUMU.js.map +1 -0
- package/dist/chunk-3QL24R5Y.js +9 -0
- package/dist/chunk-3QL24R5Y.js.map +1 -0
- package/dist/chunk-4RNZMRAV.js +60 -0
- package/dist/chunk-4RNZMRAV.js.map +1 -0
- package/dist/{chunk-6U7F52DE.js → chunk-4XHR3I67.js} +60 -60
- package/dist/chunk-5IVLTFOV.js +65 -0
- package/dist/chunk-5IVLTFOV.js.map +1 -0
- package/dist/{chunk-2EUVEDF5.js → chunk-5XA7PQ5I.js} +2 -2
- package/dist/{chunk-ALSGMEJR.js → chunk-65ZPVYTA.js} +7 -7
- package/dist/{chunk-5VQJBH2G.js → chunk-6TAUHL33.js} +2 -2
- package/dist/{chunk-HUHX2OCX.js → chunk-7DRETLP5.js} +1 -1
- package/dist/chunk-7DRETLP5.js.map +1 -0
- package/dist/{chunk-RGIWINDN.js → chunk-7G5MH4NT.js} +30 -30
- package/dist/{chunk-WVO4G37W.js → chunk-7TEZUUGM.js} +3 -3
- package/dist/{chunk-MJCGLM25.js → chunk-7VUAG236.js} +5 -5
- package/dist/{chunk-M3C2V3PV.js → chunk-AJEMDQNA.js} +12 -12
- package/dist/{chunk-RKNJBZ55.js → chunk-AU7Q3LSC.js} +7 -7
- package/dist/{chunk-ACXPX4AG.js → chunk-BR2K43MK.js} +2 -2
- package/dist/{chunk-IYZ5K7MU.js → chunk-BUE5E2HL.js} +4 -187
- package/dist/chunk-BUE5E2HL.js.map +1 -0
- package/dist/{chunk-CZRYLSSW.js → chunk-BUGVGH4N.js} +2 -2
- package/dist/{chunk-YTQNQ4KB.js → chunk-C4VQMFVM.js} +3 -3
- package/dist/{chunk-ZPSVBSOF.js → chunk-CIVDJD6P.js} +3 -3
- package/dist/{chunk-K5GB36ME.js → chunk-CZDOT5I2.js} +2 -2
- package/dist/{chunk-VI2JQPNQ.js → chunk-E4PWACUN.js} +2 -2
- package/dist/{chunk-D2ANTDGO.js → chunk-E6BMSH7U.js} +2 -2
- package/dist/{chunk-P5PXWTW7.js → chunk-EJCAV3QZ.js} +3 -3
- package/dist/{chunk-CKMO4RDY.js → chunk-EMDLM3LW.js} +4 -4
- package/dist/chunk-ER7W6H4T.js +112 -0
- package/dist/chunk-ER7W6H4T.js.map +1 -0
- package/dist/{chunk-6FUPCJUL.js → chunk-FI4F5X2V.js} +54 -54
- package/dist/chunk-FI4F5X2V.js.map +1 -0
- package/dist/{chunk-LGHKJABJ.js → chunk-GOUILH55.js} +40 -18
- package/dist/chunk-GOUILH55.js.map +1 -0
- package/dist/{chunk-G5R3D5UP.js → chunk-GTTAHHD3.js} +2 -2
- package/dist/{chunk-H5CPS5JP.js → chunk-H36LJIPD.js} +3 -3
- package/dist/{chunk-AITCS2RC.js → chunk-IJ7HK452.js} +4 -4
- package/dist/{chunk-D3LMYTBV.js → chunk-J7WZUL2K.js} +9 -9
- package/dist/{chunk-5W4ZLBEZ.js → chunk-JCFTIQBR.js} +2 -2
- package/dist/{chunk-XOZ4ALGB.js → chunk-KE353EWI.js} +3 -3
- package/dist/{chunk-W5EG6LE3.js → chunk-KIT6M7EB.js} +3 -3
- package/dist/{chunk-5W7CTZ2E.js → chunk-KQAFEZQX.js} +4 -4
- package/dist/{chunk-Z54EM5YZ.js → chunk-MAXVH44E.js} +7 -7
- package/dist/{chunk-WZFAPHIK.js → chunk-MU7ZHSZE.js} +2 -2
- package/dist/chunk-N5Z4EVOR.js +123 -0
- package/dist/chunk-N5Z4EVOR.js.map +1 -0
- package/dist/{chunk-66772WBP.js → chunk-NFXQJHJD.js} +5 -5
- package/dist/{chunk-AZ5BTEKX.js → chunk-NQUF7XKR.js} +2 -2
- package/dist/{chunk-W4FBGYGK.js → chunk-NRV4Y3PM.js} +1 -1
- package/dist/{chunk-NHWB6HG2.js → chunk-NYCGIQRA.js} +2 -2
- package/dist/{chunk-4WKA6I65.js → chunk-OGCNZPKX.js} +1119 -309
- package/dist/chunk-OGCNZPKX.js.map +1 -0
- package/dist/{chunk-QJAQNXWI.js → chunk-ONHRRJZM.js} +6 -6
- package/dist/{chunk-FDAMS4PK.js → chunk-PNPOWBGC.js} +2 -2
- package/dist/{chunk-IC6CBHCA.js → chunk-QGENAYVS.js} +2 -2
- package/dist/{chunk-GBJ4RDFR.js → chunk-QIHIHZYC.js} +66 -91
- package/dist/chunk-QIHIHZYC.js.map +1 -0
- package/dist/{chunk-YNQBRLC5.js → chunk-RUYJ7TWU.js} +517 -2011
- package/dist/chunk-RUYJ7TWU.js.map +1 -0
- package/dist/{chunk-4A6YGWQN.js → chunk-TL4TO3EA.js} +115 -120
- package/dist/chunk-TL4TO3EA.js.map +1 -0
- package/dist/{chunk-SPJXKAVF.js → chunk-U52AKICI.js} +14 -13
- package/dist/chunk-U52AKICI.js.map +1 -0
- package/dist/chunk-ULARSG5Z.js +203 -0
- package/dist/chunk-ULARSG5Z.js.map +1 -0
- package/dist/{chunk-62U4J2GN.js → chunk-UR77VKF7.js} +2 -2
- package/dist/{chunk-JCBWCYEJ.js → chunk-VANLTS5F.js} +2 -2
- package/dist/{chunk-4Z4XNEWZ.js → chunk-VCD4PSK2.js} +56 -12
- package/dist/chunk-VCD4PSK2.js.map +1 -0
- package/dist/{chunk-RMMVQQA6.js → chunk-WDISJRMG.js} +2 -2
- package/dist/{chunk-B6JDYXL7.js → chunk-WWUVONGW.js} +7 -1
- package/dist/chunk-WWUVONGW.js.map +1 -0
- package/dist/{chunk-UVYI6VIX.js → chunk-X7Y7WX73.js} +1 -1
- package/dist/{chunk-TH2LSRMG.js → chunk-XHDIB4T4.js} +2 -2
- package/dist/{chunk-CVILPI77.js → chunk-XOQSEF7X.js} +6 -6
- package/dist/{chunk-LBOD4U5B.js → chunk-YFOMN2II.js} +6 -6
- package/dist/{chunk-RPW2NOU6.js → chunk-YIAA2X3D.js} +41 -1
- package/dist/chunk-YIAA2X3D.js.map +1 -0
- package/dist/chunk-YPC7W6GA.js +1604 -0
- package/dist/chunk-YPC7W6GA.js.map +1 -0
- package/dist/{chunk-I5NLEENJ.js → chunk-Z4SWV4VW.js} +3 -3
- package/dist/{chunk-PHWUFPCO.js → chunk-ZCPP5OW6.js} +61 -53
- package/dist/chunk-ZCPP5OW6.js.map +1 -0
- package/dist/{cli-C4GbETPC.d.ts → cli-BptUDTtp.d.ts} +5 -5
- package/dist/cli.d.ts +12 -12
- package/dist/cli.js +91 -84
- package/dist/compounding/engine.d.ts +2 -2
- package/dist/compounding/engine.js +14 -14
- package/dist/compounding/preference-consolidator.d.ts +1 -1
- package/dist/compression-optimizer.d.ts +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.js +1 -1
- package/dist/connectors/codex-materialize-runner.d.ts +1 -1
- package/dist/connectors/codex-materialize-runner.js +14 -14
- package/dist/connectors/codex-materialize.d.ts +1 -1
- package/dist/connectors/index.d.ts +1 -1
- package/dist/connectors/index.js +17 -17
- package/dist/consolidation-provenance-check.d.ts +2 -2
- package/dist/consolidation-provenance-check.js +5 -5
- package/dist/consolidation-undo.d.ts +2 -2
- package/dist/consolidation-undo.js +3 -3
- package/dist/contradiction/index.d.ts +2 -2
- package/dist/contradiction/index.js +4 -4
- package/dist/conversation-index/backend.d.ts +1 -1
- package/dist/conversation-index/backend.js +2 -2
- package/dist/conversation-index/chunker.d.ts +1 -1
- package/dist/conversation-index/faiss-adapter.d.ts +1 -1
- package/dist/conversation-index/indexer.d.ts +1 -1
- package/dist/conversation-index/search.d.ts +1 -1
- package/dist/corpus-watermark.d.ts +1 -1
- package/dist/corpus-watermark.js +26 -26
- package/dist/day-summary.d.ts +1 -1
- package/dist/delinearize.d.ts +1 -1
- package/dist/direct-answer-wiring.d.ts +1 -1
- package/dist/direct-answer.d.ts +1 -1
- package/dist/embedding-fallback.d.ts +1 -1
- package/dist/enrichment/index.d.ts +1 -1
- package/dist/entity-retrieval.d.ts +2 -2
- package/dist/entity-retrieval.js +14 -14
- package/dist/entity-schema.d.ts +1 -1
- package/dist/explicit-capture.d.ts +8 -8
- package/dist/extraction-error-classification.d.ts +1 -1
- package/dist/extraction-faithfulness.d.ts +1 -1
- package/dist/extraction-judge-telemetry.d.ts +1 -1
- package/dist/extraction-judge-training.d.ts +1 -1
- package/dist/extraction-judge.d.ts +1 -1
- package/dist/extraction-liveness.d.ts +1 -1
- package/dist/extraction-source-grounding-rules.d.ts +1 -1
- package/dist/extraction-source-grounding.d.ts +15 -2
- package/dist/extraction-source-grounding.js +10 -1
- package/dist/extraction.d.ts +2 -15
- package/dist/extraction.js +5 -4
- package/dist/fallback-llm.d.ts +1 -1
- package/dist/graph-dashboard-diff.d.ts +1 -1
- package/dist/graph-dashboard-key.d.ts +1 -1
- package/dist/graph-dashboard-parser.d.ts +1 -1
- package/dist/graph-edge-reinforcement.d.ts +1 -1
- package/dist/graph-snapshot.d.ts +1 -1
- package/dist/graph.d.ts +1 -1
- package/dist/importance.d.ts +1 -1
- package/dist/importers/index.d.ts +1 -1
- package/dist/in-flight-reads.d.ts +1 -1
- package/dist/index.d.ts +19 -19
- package/dist/index.js +215 -207
- package/dist/intent.d.ts +1 -1
- package/dist/lcm/engine.d.ts +1 -1
- package/dist/lcm/engine.js +3 -3
- package/dist/lcm/index.d.ts +1 -1
- package/dist/lcm/index.js +6 -6
- package/dist/lcm/tools.d.ts +1 -1
- package/dist/lifecycle.d.ts +1 -1
- package/dist/live-connectors-runner.d.ts +1 -1
- package/dist/local-llm-helpers.d.ts +7 -0
- package/dist/local-llm-helpers.js +16 -0
- package/dist/local-llm-helpers.js.map +1 -0
- package/dist/local-llm.d.ts +3 -6
- package/dist/local-llm.js +2 -1
- package/dist/local-model-endpoint.d.ts +1 -1
- package/dist/maintenance/memory-governance.d.ts +1 -1
- package/dist/maintenance/memory-governance.js +14 -14
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +14 -14
- package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
- package/dist/maintenance/rebuild-memory-projection.js +15 -15
- package/dist/{maintenance-CL30NWtc.d.ts → maintenance-b6f92bRz.d.ts} +3 -3
- package/dist/mcp-memory-inspector-app.d.ts +10 -10
- package/dist/memory-action-policy.d.ts +1 -1
- package/dist/memory-cache.d.ts +1 -1
- package/dist/memory-corpus-version.js +2 -2
- package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
- package/dist/memory-projection-store.d.ts +1 -1
- package/dist/memory-provenance.d.ts +1 -1
- package/dist/memory-worth-outcomes.d.ts +2 -2
- package/dist/models-json.d.ts +1 -1
- package/dist/namespaces/migrate.d.ts +3 -3
- package/dist/namespaces/migrate.js +24 -24
- package/dist/namespaces/principal.d.ts +1 -1
- package/dist/namespaces/search.d.ts +1 -1
- package/dist/namespaces/search.js +9 -9
- package/dist/namespaces/storage.d.ts +3 -3
- package/dist/namespaces/storage.js +14 -14
- package/dist/native-knowledge.d.ts +1 -1
- package/dist/offline-sync-impression-drain.d.ts +1 -1
- package/dist/offline-sync-impression-drain.js +6 -5
- package/dist/operator-doctor-corpus.d.ts +1 -1
- package/dist/operator-doctor-corpus.js +29 -29
- package/dist/operator-doctor-replica.d.ts +1 -1
- package/dist/operator-doctor-replica.js +3 -3
- package/dist/operator-toolkit.d.ts +3 -3
- package/dist/operator-toolkit.js +38 -37
- package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
- package/dist/orchestration/maintenance.d.ts +4 -4
- package/dist/orchestration/maintenance.js +22 -21
- package/dist/{orchestrator-CKTCRwWV.d.ts → orchestrator-3uGxC1qO.d.ts} +72 -34
- package/dist/orchestrator.d.ts +8 -8
- package/dist/orchestrator.js +167 -159
- package/dist/page-versioning.js +3 -3
- package/dist/patterns-cli.d.ts +1 -1
- package/dist/{pipeline-B7wj4rRZ.d.ts → pipeline-DepuNr-m.d.ts} +1 -1
- package/dist/policy-runtime.d.ts +1 -1
- package/dist/proactive-contention.d.ts +1 -1
- package/dist/provenance.d.ts +1 -1
- package/dist/{qmd-q9tg4dHp.d.ts → qmd-Dalr3Jby.d.ts} +1 -1
- package/dist/qmd-preflight.d.ts +2 -2
- package/dist/qmd-recall-cache.d.ts +1 -1
- package/dist/qmd.d.ts +2 -2
- package/dist/qmd.js +4 -4
- package/dist/recall-concurrency-config.d.ts +1 -1
- package/dist/recall-disclosure-escalation.d.ts +1 -1
- package/dist/recall-explain-renderer.d.ts +1 -1
- package/dist/recall-explain-renderer.js +3 -3
- package/dist/recall-memory-map.d.ts +1 -1
- package/dist/recall-planner-llm.d.ts +1 -1
- package/dist/recall-state.d.ts +1 -1
- package/dist/recall-tag-filter.d.ts +1 -1
- package/dist/recall-timings.d.ts +1 -1
- package/dist/recall-xray-cli.d.ts +1 -1
- package/dist/recall-xray-cli.js +4 -4
- package/dist/recall-xray-renderer.d.ts +1 -1
- package/dist/recall-xray-renderer.js +3 -3
- package/dist/recall-xray.d.ts +1 -1
- package/dist/recall-xray.js +2 -2
- package/dist/replay/normalizers/chatgpt.d.ts +1 -1
- package/dist/replay/normalizers/claude.d.ts +1 -1
- package/dist/replay/normalizers/openclaw.d.ts +1 -1
- package/dist/replay/normalizers/shared.d.ts +1 -1
- package/dist/replay/runner.d.ts +1 -1
- package/dist/replay/types.d.ts +1 -1
- package/dist/replica-divergence.d.ts +1 -1
- package/dist/replica-divergence.js +2 -2
- package/dist/replica-peers-config.d.ts +1 -1
- package/dist/resolve-auth-token.d.ts +1 -1
- package/dist/resume-bundles.js +1 -1
- package/dist/retrieval-agents.d.ts +2 -2
- package/dist/retrieval-tiers.d.ts +1 -1
- package/dist/routing/engine.d.ts +1 -1
- package/dist/routing/store.d.ts +1 -1
- package/dist/salvage-envelope.d.ts +1 -1
- package/dist/{scope-profiles-CWDyglPM.d.ts → scope-profiles-BpiM5hTU.d.ts} +1 -1
- package/dist/search/embed-helper.d.ts +1 -1
- package/dist/search/factory.d.ts +1 -1
- package/dist/search/factory.js +8 -8
- package/dist/search/index.d.ts +1 -1
- package/dist/search/index.js +12 -12
- package/dist/search/lancedb-backend.d.ts +1 -1
- package/dist/search/meilisearch-backend.d.ts +1 -1
- package/dist/search/noop-backend.d.ts +1 -1
- package/dist/search/orama-backend.d.ts +1 -1
- package/dist/search/port.d.ts +1 -1
- package/dist/search/remote-backend.d.ts +1 -1
- package/dist/{semantic-consolidation-BUE3deLn.d.ts → semantic-consolidation-CMtVrf9f.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +2 -2
- package/dist/semantic-consolidation.js +16 -16
- package/dist/semantic-rule-promotion.js +14 -14
- package/dist/semantic-rule-verifier.d.ts +1 -1
- package/dist/semantic-rule-verifier.js +14 -14
- package/dist/{service-CXgM0bQG.d.ts → service-DuAxwSgg.d.ts} +2 -2
- package/dist/session-observer-bands.d.ts +1 -1
- package/dist/session-observer-state.d.ts +1 -1
- package/dist/shared-context/manager.d.ts +1 -1
- package/dist/signal.d.ts +1 -1
- package/dist/{storage-DysJq-XH.d.ts → storage-CF0Ih8GP.d.ts} +1 -1
- package/dist/storage.d.ts +2 -2
- package/dist/storage.js +13 -13
- package/dist/summarizer.d.ts +1 -1
- package/dist/summarizer.js +3 -2
- package/dist/summary-snapshot.d.ts +1 -1
- package/dist/temporal-supersession.d.ts +2 -2
- package/dist/temporal-timeline-recall.d.ts +1 -1
- package/dist/temporal-validity.d.ts +1 -1
- package/dist/threading.d.ts +1 -1
- package/dist/tier-migration.d.ts +2 -2
- package/dist/tier-routing.d.ts +1 -1
- package/dist/tokens.js +2 -2
- package/dist/topics.d.ts +1 -1
- package/dist/transcript.d.ts +1 -1
- package/dist/transfer/backup.js +2 -2
- package/dist/transfer/capsule-export.js +2 -2
- package/dist/transfer/capsule-import.js +5 -5
- package/dist/trust-score-stage.d.ts +1 -1
- package/dist/trust-score.d.ts +1 -1
- package/dist/{types-aPPzhnjT.d.ts → types-BpaYvJ6v.d.ts} +22 -2
- package/dist/types.d.ts +1 -1
- package/dist/types.js +1 -1
- package/dist/utility-runtime.d.ts +1 -1
- package/dist/verified-recall.js +14 -14
- package/dist/write-envelope.d.ts +1 -1
- package/package.json +2 -2
- package/src/access-boundary.ts +3 -0
- package/src/access-cli.test.ts +93 -0
- package/src/access-cli.ts +56 -2
- package/src/access-extraction-force-flush.ts +177 -0
- package/src/access-http-extraction-force-flush.test.ts +132 -0
- package/src/access-http-lcm-compaction.ts +99 -22
- package/src/access-http-lifecycle-flush.ts +81 -0
- package/src/access-http.test.ts +227 -0
- package/src/access-http.ts +33 -40
- package/src/access-mcp-output-schemas.ts +6 -0
- package/src/access-mcp.test.ts +40 -0
- package/src/access-mcp.ts +32 -1
- package/src/access-observe-helpers.ts +180 -0
- package/src/access-observe-write-surface.ts +78 -19
- package/src/access-operations-batch.ts +2 -1
- package/src/access-schema-pi.test.ts +17 -0
- package/src/access-schema.ts +28 -11
- package/src/access-service-helpers.ts +46 -0
- package/src/access-service-observe-lcm-parity.test.ts +781 -31
- package/src/access-service-observe-scope.test.ts +88 -0
- package/src/access-service.ts +46 -128
- package/src/access-surface-catalog.test.ts +32 -0
- package/src/access-surface-catalog.ts +2 -0
- package/src/buffer-session.test.ts +148 -0
- package/src/buffer-turn-helpers.ts +152 -0
- package/src/buffer.ts +126 -201
- package/src/correction/correction-access-wiring.ts +79 -27
- package/src/correction/correction-executor.test.ts +542 -1
- package/src/correction/correction-executor.ts +309 -89
- package/src/correction/correction-planner.test.ts +35 -1
- package/src/correction/correction-planner.ts +50 -3
- package/src/correction/correction-service.ts +12 -7
- package/src/correction/correction-storage-integration.test.ts +172 -1
- package/src/correction/passive-capture.test.ts +35 -0
- package/src/correction/passive-capture.ts +17 -3
- package/src/extraction-source-grounding.ts +55 -1
- package/src/extraction-timeout.test.ts +51 -0
- package/src/extraction.ts +64 -90
- package/src/local-llm-headers-timeout.test.ts +48 -0
- package/src/local-llm-helpers.ts +58 -0
- package/src/local-llm.ts +62 -58
- package/src/orchestration/extraction-run-helpers.ts +309 -0
- package/src/orchestration/extraction-run.test.ts +350 -7
- package/src/orchestration/extraction-run.ts +327 -250
- package/src/orchestration/session-context.ts +193 -18
- package/src/orchestration/turn-ingestion.ts +61 -11
- package/src/orchestrator-flush.test.ts +511 -5
- package/src/orchestrator.ts +8 -6
- package/src/types.ts +2 -2
- package/dist/chunk-4A6YGWQN.js.map +0 -1
- package/dist/chunk-4WKA6I65.js.map +0 -1
- package/dist/chunk-4Z4XNEWZ.js.map +0 -1
- package/dist/chunk-6FUPCJUL.js.map +0 -1
- package/dist/chunk-B6JDYXL7.js.map +0 -1
- package/dist/chunk-GBJ4RDFR.js.map +0 -1
- package/dist/chunk-HUHX2OCX.js.map +0 -1
- package/dist/chunk-IYZ5K7MU.js.map +0 -1
- package/dist/chunk-LGHKJABJ.js.map +0 -1
- package/dist/chunk-PHWUFPCO.js.map +0 -1
- package/dist/chunk-RPW2NOU6.js.map +0 -1
- package/dist/chunk-SPJXKAVF.js.map +0 -1
- package/dist/chunk-YNQBRLC5.js.map +0 -1
- package/dist/chunk-YTSNAUXN.js.map +0 -1
- /package/dist/{capsule-crypto-GWVG7LGC.js.map → access-extraction-force-flush.js.map} +0 -0
- /package/dist/{capsule-merge-5KKJQBWQ.js.map → capsule-merge-2H2IUTBT.js.map} +0 -0
- /package/dist/{chunk-LEPOP46W.js.map → chunk-227UFSEQ.js.map} +0 -0
- /package/dist/{chunk-GIBMDSJ2.js.map → chunk-27P5YVDU.js.map} +0 -0
- /package/dist/{chunk-2SA56WMI.js.map → chunk-2LTDWSR6.js.map} +0 -0
- /package/dist/{chunk-OWHERGF2.js.map → chunk-2NLLXCJG.js.map} +0 -0
- /package/dist/{chunk-6U7F52DE.js.map → chunk-4XHR3I67.js.map} +0 -0
- /package/dist/{chunk-2EUVEDF5.js.map → chunk-5XA7PQ5I.js.map} +0 -0
- /package/dist/{chunk-ALSGMEJR.js.map → chunk-65ZPVYTA.js.map} +0 -0
- /package/dist/{chunk-5VQJBH2G.js.map → chunk-6TAUHL33.js.map} +0 -0
- /package/dist/{chunk-RGIWINDN.js.map → chunk-7G5MH4NT.js.map} +0 -0
- /package/dist/{chunk-WVO4G37W.js.map → chunk-7TEZUUGM.js.map} +0 -0
- /package/dist/{chunk-MJCGLM25.js.map → chunk-7VUAG236.js.map} +0 -0
- /package/dist/{chunk-M3C2V3PV.js.map → chunk-AJEMDQNA.js.map} +0 -0
- /package/dist/{chunk-RKNJBZ55.js.map → chunk-AU7Q3LSC.js.map} +0 -0
- /package/dist/{chunk-ACXPX4AG.js.map → chunk-BR2K43MK.js.map} +0 -0
- /package/dist/{chunk-CZRYLSSW.js.map → chunk-BUGVGH4N.js.map} +0 -0
- /package/dist/{chunk-YTQNQ4KB.js.map → chunk-C4VQMFVM.js.map} +0 -0
- /package/dist/{chunk-ZPSVBSOF.js.map → chunk-CIVDJD6P.js.map} +0 -0
- /package/dist/{chunk-K5GB36ME.js.map → chunk-CZDOT5I2.js.map} +0 -0
- /package/dist/{chunk-VI2JQPNQ.js.map → chunk-E4PWACUN.js.map} +0 -0
- /package/dist/{chunk-D2ANTDGO.js.map → chunk-E6BMSH7U.js.map} +0 -0
- /package/dist/{chunk-P5PXWTW7.js.map → chunk-EJCAV3QZ.js.map} +0 -0
- /package/dist/{chunk-CKMO4RDY.js.map → chunk-EMDLM3LW.js.map} +0 -0
- /package/dist/{chunk-G5R3D5UP.js.map → chunk-GTTAHHD3.js.map} +0 -0
- /package/dist/{chunk-H5CPS5JP.js.map → chunk-H36LJIPD.js.map} +0 -0
- /package/dist/{chunk-AITCS2RC.js.map → chunk-IJ7HK452.js.map} +0 -0
- /package/dist/{chunk-D3LMYTBV.js.map → chunk-J7WZUL2K.js.map} +0 -0
- /package/dist/{chunk-5W4ZLBEZ.js.map → chunk-JCFTIQBR.js.map} +0 -0
- /package/dist/{chunk-XOZ4ALGB.js.map → chunk-KE353EWI.js.map} +0 -0
- /package/dist/{chunk-W5EG6LE3.js.map → chunk-KIT6M7EB.js.map} +0 -0
- /package/dist/{chunk-5W7CTZ2E.js.map → chunk-KQAFEZQX.js.map} +0 -0
- /package/dist/{chunk-Z54EM5YZ.js.map → chunk-MAXVH44E.js.map} +0 -0
- /package/dist/{chunk-WZFAPHIK.js.map → chunk-MU7ZHSZE.js.map} +0 -0
- /package/dist/{chunk-66772WBP.js.map → chunk-NFXQJHJD.js.map} +0 -0
- /package/dist/{chunk-AZ5BTEKX.js.map → chunk-NQUF7XKR.js.map} +0 -0
- /package/dist/{chunk-W4FBGYGK.js.map → chunk-NRV4Y3PM.js.map} +0 -0
- /package/dist/{chunk-NHWB6HG2.js.map → chunk-NYCGIQRA.js.map} +0 -0
- /package/dist/{chunk-QJAQNXWI.js.map → chunk-ONHRRJZM.js.map} +0 -0
- /package/dist/{chunk-FDAMS4PK.js.map → chunk-PNPOWBGC.js.map} +0 -0
- /package/dist/{chunk-IC6CBHCA.js.map → chunk-QGENAYVS.js.map} +0 -0
- /package/dist/{chunk-62U4J2GN.js.map → chunk-UR77VKF7.js.map} +0 -0
- /package/dist/{chunk-JCBWCYEJ.js.map → chunk-VANLTS5F.js.map} +0 -0
- /package/dist/{chunk-RMMVQQA6.js.map → chunk-WDISJRMG.js.map} +0 -0
- /package/dist/{chunk-UVYI6VIX.js.map → chunk-X7Y7WX73.js.map} +0 -0
- /package/dist/{chunk-TH2LSRMG.js.map → chunk-XHDIB4T4.js.map} +0 -0
- /package/dist/{chunk-CVILPI77.js.map → chunk-XOQSEF7X.js.map} +0 -0
- /package/dist/{chunk-LBOD4U5B.js.map → chunk-YFOMN2II.js.map} +0 -0
- /package/dist/{chunk-I5NLEENJ.js.map → chunk-Z4SWV4VW.js.map} +0 -0
|
@@ -29,8 +29,11 @@ import { tmpdir } from "node:os";
|
|
|
29
29
|
import { join } from "node:path";
|
|
30
30
|
import test from "node:test";
|
|
31
31
|
|
|
32
|
-
import { EngramAccessService } from "./access-service.js";
|
|
32
|
+
import { EngramAccessInputError, EngramAccessService } from "./access-service.js";
|
|
33
|
+
import { EngramAccessForbiddenError } from "./access-errors.js";
|
|
33
34
|
import { Orchestrator } from "./orchestrator.js";
|
|
35
|
+
import { ExtractionDeadlineError } from "./orchestration/extraction-run.js";
|
|
36
|
+
import { SessionOwnershipError } from "./orchestration/session-context.js";
|
|
34
37
|
import type { EngramAccessObserveRequest } from "./access-service.js";
|
|
35
38
|
import {
|
|
36
39
|
combineNamespaces,
|
|
@@ -54,7 +57,25 @@ interface ParityProbe {
|
|
|
54
57
|
sessionKeys: string[];
|
|
55
58
|
writeNamespaceOverride?: string;
|
|
56
59
|
principalOverride?: string;
|
|
60
|
+
sessionOwnerPrincipal?: string;
|
|
57
61
|
}>;
|
|
62
|
+
lcmEngine: {
|
|
63
|
+
enabled: boolean;
|
|
64
|
+
waitForSessionObserveIdle?: (sessionKey: string) => Promise<void>;
|
|
65
|
+
};
|
|
66
|
+
extractionForceFlushCalls: ExtractionForceFlushCall[];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
interface ExtractionForceFlushCall {
|
|
70
|
+
sessionKey: string;
|
|
71
|
+
options: {
|
|
72
|
+
reason: string;
|
|
73
|
+
extractionDeadlineMs?: number;
|
|
74
|
+
failOnExtractionFailure?: boolean;
|
|
75
|
+
abortSignal?: AbortSignal;
|
|
76
|
+
writeNamespaceOverride?: string;
|
|
77
|
+
principalOverride?: string;
|
|
78
|
+
};
|
|
58
79
|
}
|
|
59
80
|
|
|
60
81
|
/**
|
|
@@ -72,6 +93,7 @@ function makeParityProbe(overrides: Partial<PluginConfig> = {}): ParityProbe {
|
|
|
72
93
|
const searchSessionIds: Array<string | undefined> = [];
|
|
73
94
|
const searchSessionPrefixes: Array<string | undefined> = [];
|
|
74
95
|
const extractionCalls: ParityProbe["extractionCalls"] = [];
|
|
96
|
+
const extractionForceFlushCalls: ExtractionForceFlushCall[] = [];
|
|
75
97
|
|
|
76
98
|
const config = {
|
|
77
99
|
namespacesEnabled: true,
|
|
@@ -96,6 +118,35 @@ function makeParityProbe(overrides: Partial<PluginConfig> = {}): ParityProbe {
|
|
|
96
118
|
...overrides,
|
|
97
119
|
} as unknown as PluginConfig;
|
|
98
120
|
|
|
121
|
+
const lcmEngine = {
|
|
122
|
+
enabled: true,
|
|
123
|
+
enqueueObserveMessages: (sessionKey: string) => {
|
|
124
|
+
lcmWriteKeys.push(sessionKey);
|
|
125
|
+
},
|
|
126
|
+
waitForSessionObserveIdle: async (_sessionKey: string) => {},
|
|
127
|
+
preCompactionFlush: async (sessionKey: string) => {
|
|
128
|
+
compactionFlushKeys.push(sessionKey);
|
|
129
|
+
},
|
|
130
|
+
recordCompaction: async (
|
|
131
|
+
sessionKey: string,
|
|
132
|
+
_before: number,
|
|
133
|
+
_after: number,
|
|
134
|
+
) => {
|
|
135
|
+
compactionRecordKeys.push(sessionKey);
|
|
136
|
+
},
|
|
137
|
+
searchContextFull: async (
|
|
138
|
+
_query: string,
|
|
139
|
+
_limit: number,
|
|
140
|
+
sessionId?: string,
|
|
141
|
+
sessionPrefix?: string,
|
|
142
|
+
) => {
|
|
143
|
+
searchSessionIds.push(sessionId);
|
|
144
|
+
searchSessionPrefixes.push(sessionPrefix);
|
|
145
|
+
return [];
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
|
|
99
150
|
const orch = {
|
|
100
151
|
config,
|
|
101
152
|
getCodingContextForSession: (sk: string | undefined) =>
|
|
@@ -110,45 +161,29 @@ function makeParityProbe(overrides: Partial<PluginConfig> = {}): ParityProbe {
|
|
|
110
161
|
Orchestrator.prototype.resolvePrincipal.call(orch, sk),
|
|
111
162
|
resolveSelfNamespace: (sk?: string) =>
|
|
112
163
|
Orchestrator.prototype.resolveSelfNamespace.call(orch, sk),
|
|
113
|
-
lcmEngine
|
|
114
|
-
enabled: true,
|
|
115
|
-
enqueueObserveMessages: (sessionKey: string) => {
|
|
116
|
-
lcmWriteKeys.push(sessionKey);
|
|
117
|
-
},
|
|
118
|
-
waitForSessionObserveIdle: async (_sessionKey: string) => {},
|
|
119
|
-
preCompactionFlush: async (sessionKey: string) => {
|
|
120
|
-
compactionFlushKeys.push(sessionKey);
|
|
121
|
-
},
|
|
122
|
-
recordCompaction: async (
|
|
123
|
-
sessionKey: string,
|
|
124
|
-
_before: number,
|
|
125
|
-
_after: number,
|
|
126
|
-
) => {
|
|
127
|
-
compactionRecordKeys.push(sessionKey);
|
|
128
|
-
},
|
|
129
|
-
searchContextFull: async (
|
|
130
|
-
_query: string,
|
|
131
|
-
_limit: number,
|
|
132
|
-
sessionId?: string,
|
|
133
|
-
sessionPrefix?: string,
|
|
134
|
-
) => {
|
|
135
|
-
searchSessionIds.push(sessionId);
|
|
136
|
-
searchSessionPrefixes.push(sessionPrefix);
|
|
137
|
-
return [];
|
|
138
|
-
},
|
|
139
|
-
},
|
|
140
|
-
// Capture extraction routing/identity so the provenance-principal tests can
|
|
141
|
-
// assert what `observe` threads into `ingestReplayBatch`.
|
|
164
|
+
lcmEngine,
|
|
142
165
|
ingestReplayBatch: async (
|
|
143
166
|
turns: Array<{ sessionKey: string }>,
|
|
144
|
-
options: {
|
|
167
|
+
options: {
|
|
168
|
+
writeNamespaceOverride?: string;
|
|
169
|
+
principalOverride?: string;
|
|
170
|
+
sessionOwnerPrincipal?: string;
|
|
171
|
+
abortSignal?: AbortSignal;
|
|
172
|
+
} = {},
|
|
145
173
|
) => {
|
|
146
174
|
extractionCalls.push({
|
|
147
175
|
sessionKeys: turns.map((t) => t.sessionKey),
|
|
148
176
|
writeNamespaceOverride: options.writeNamespaceOverride,
|
|
149
177
|
principalOverride: options.principalOverride,
|
|
178
|
+
sessionOwnerPrincipal: options.sessionOwnerPrincipal,
|
|
150
179
|
});
|
|
151
180
|
},
|
|
181
|
+
flushSession: async (
|
|
182
|
+
sessionKey: string,
|
|
183
|
+
options: ExtractionForceFlushCall["options"],
|
|
184
|
+
) => {
|
|
185
|
+
extractionForceFlushCalls.push({ sessionKey, options });
|
|
186
|
+
},
|
|
152
187
|
} as unknown as Orchestrator;
|
|
153
188
|
|
|
154
189
|
return {
|
|
@@ -160,6 +195,8 @@ function makeParityProbe(overrides: Partial<PluginConfig> = {}): ParityProbe {
|
|
|
160
195
|
searchSessionIds,
|
|
161
196
|
searchSessionPrefixes,
|
|
162
197
|
extractionCalls,
|
|
198
|
+
lcmEngine,
|
|
199
|
+
extractionForceFlushCalls,
|
|
163
200
|
};
|
|
164
201
|
}
|
|
165
202
|
|
|
@@ -339,6 +376,719 @@ test("#1505 thread 2 (c) projectTag: observe LCM write key == recall reader key
|
|
|
339
376
|
assert.equal(probe.compactionRecordKeys[0], expectedKey, "record key");
|
|
340
377
|
});
|
|
341
378
|
|
|
379
|
+
test("#2128: disabled LCM flush does not bind per-call project context", async () => {
|
|
380
|
+
const probe = makeParityProbe(withSelfPolicyPrefix("pi-geek"));
|
|
381
|
+
const service = new EngramAccessService(probe.orch);
|
|
382
|
+
const sessionKey = "pi-geek:disabled-lcm-flush";
|
|
383
|
+
probe.lcmEngine.enabled = false;
|
|
384
|
+
|
|
385
|
+
const response = await service.lcmCompactionFlush({
|
|
386
|
+
sessionKey,
|
|
387
|
+
projectTag: "Acme/Webshop",
|
|
388
|
+
authenticatedPrincipal: "pi-geek",
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
assert.equal(response.enabled, false);
|
|
392
|
+
assert.equal(probe.orch.getCodingContextForSession(sessionKey), null);
|
|
393
|
+
assert.equal(probe.compactionFlushKeys.length, 0);
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
test("#2128: failed LCM flush rolls back a seeded project context", async () => {
|
|
397
|
+
const probe = makeParityProbe(withSelfPolicyPrefix("pi-geek"));
|
|
398
|
+
const service = new EngramAccessService(probe.orch);
|
|
399
|
+
const sessionKey = "pi-geek:failed-lcm-flush";
|
|
400
|
+
probe.lcmEngine.waitForSessionObserveIdle = async () => {
|
|
401
|
+
throw new Error("idle wait failed");
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
await assert.rejects(
|
|
405
|
+
() =>
|
|
406
|
+
service.lcmCompactionFlush({
|
|
407
|
+
sessionKey,
|
|
408
|
+
projectTag: "Acme/Webshop",
|
|
409
|
+
authenticatedPrincipal: "pi-geek",
|
|
410
|
+
}),
|
|
411
|
+
/idle wait failed/,
|
|
412
|
+
);
|
|
413
|
+
assert.equal(probe.orch.getCodingContextForSession(sessionKey), null);
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
test("#2128: successful LCM flush does not bind per-call project context", async () => {
|
|
417
|
+
const probe = makeParityProbe(withSelfPolicyPrefix("pi-geek"));
|
|
418
|
+
const service = new EngramAccessService(probe.orch);
|
|
419
|
+
const sessionKey = "pi-geek:successful-lcm-flush";
|
|
420
|
+
|
|
421
|
+
const response = await service.lcmCompactionFlush({
|
|
422
|
+
sessionKey,
|
|
423
|
+
projectTag: "Acme/Webshop",
|
|
424
|
+
authenticatedPrincipal: "pi-geek",
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
assert.equal(response.enabled, true);
|
|
428
|
+
assert.equal(response.flushed, true);
|
|
429
|
+
assert.equal(probe.orch.getCodingContextForSession(sessionKey), null);
|
|
430
|
+
assert.equal(probe.compactionFlushKeys.length, 1);
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
test("#2128: extraction force-flush uses observe's scoped target even when LCM is disabled", async () => {
|
|
434
|
+
const probe = makeParityProbe(withSelfPolicyPrefix("pi-geek"));
|
|
435
|
+
const service = new EngramAccessService(probe.orch);
|
|
436
|
+
const deadlineMs = Date.now() + 10_000;
|
|
437
|
+
const abortController = new AbortController();
|
|
438
|
+
probe.lcmEngine.enabled = false;
|
|
439
|
+
|
|
440
|
+
const response = await service.extractionForceFlush({
|
|
441
|
+
sessionKey: "pi-geek:force-flush",
|
|
442
|
+
projectTag: "Acme/Webshop",
|
|
443
|
+
deadlineMs,
|
|
444
|
+
abortSignal: abortController.signal,
|
|
445
|
+
authenticatedPrincipal: "pi-geek",
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
const expectedNamespace = combineNamespaces(
|
|
449
|
+
"pi-geek",
|
|
450
|
+
projectNamespaceName(projectTagProjectId("Acme/Webshop")),
|
|
451
|
+
);
|
|
452
|
+
assert.equal(response.flushed, true);
|
|
453
|
+
assert.equal(response.effectiveNamespace, expectedNamespace);
|
|
454
|
+
assert.equal(probe.extractionForceFlushCalls.length, 1);
|
|
455
|
+
const [call] = probe.extractionForceFlushCalls;
|
|
456
|
+
assert.equal(call.sessionKey, "pi-geek:force-flush");
|
|
457
|
+
assert.equal(call.options.reason, "access_force_flush");
|
|
458
|
+
assert.equal(
|
|
459
|
+
Object.hasOwn(call.options, "bufferKey"),
|
|
460
|
+
false,
|
|
461
|
+
"force-flush must let the orchestrator discover all session buffer keys",
|
|
462
|
+
);
|
|
463
|
+
assert.equal(call.options.extractionDeadlineMs, deadlineMs);
|
|
464
|
+
assert.equal(call.options.failOnExtractionFailure, true);
|
|
465
|
+
assert.equal(call.options.abortSignal, abortController.signal);
|
|
466
|
+
assert.equal(call.options.writeNamespaceOverride, expectedNamespace);
|
|
467
|
+
assert.equal(
|
|
468
|
+
probe.orch.getCodingContextForSession("pi-geek:force-flush"),
|
|
469
|
+
null,
|
|
470
|
+
"successful extraction force-flush must clear per-call coding context",
|
|
471
|
+
);
|
|
472
|
+
assert.equal(call.options.principalOverride, "pi-geek");
|
|
473
|
+
assert.equal(
|
|
474
|
+
Object.hasOwn(call.options, "sessionOwnerPrincipal"),
|
|
475
|
+
false,
|
|
476
|
+
"force-flush must not claim ownership for opaque buffered turns",
|
|
477
|
+
);
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
test("#2128: single-store force-flush clears retained turns without an owner filter", async () => {
|
|
481
|
+
const probe = makeParityProbe({ namespacesEnabled: false } as Partial<PluginConfig>);
|
|
482
|
+
const cleanupOwners: Array<string | undefined> = [];
|
|
483
|
+
(probe.orch as unknown as {
|
|
484
|
+
buffer: {
|
|
485
|
+
clearRetainedTurnsForSession(
|
|
486
|
+
sessionKey: string,
|
|
487
|
+
ownerPrincipal?: string,
|
|
488
|
+
options?: { abortSignal?: AbortSignal; deadlineMs?: number },
|
|
489
|
+
): Promise<void>;
|
|
490
|
+
};
|
|
491
|
+
}).buffer = {
|
|
492
|
+
clearRetainedTurnsForSession: async (_sessionKey, ownerPrincipal) => {
|
|
493
|
+
cleanupOwners.push(ownerPrincipal);
|
|
494
|
+
},
|
|
495
|
+
};
|
|
496
|
+
const service = new EngramAccessService(probe.orch);
|
|
497
|
+
|
|
498
|
+
await service.extractionForceFlush({
|
|
499
|
+
sessionKey: "single-store-session",
|
|
500
|
+
authenticatedPrincipal: "pi-geek",
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
assert.deepEqual(cleanupOwners, [undefined]);
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
test("#2128: force-flush waits for a pending observe extraction", async () => {
|
|
507
|
+
const probe = makeParityProbe({ namespacesEnabled: false } as Partial<PluginConfig>);
|
|
508
|
+
let resolveExtraction!: () => void;
|
|
509
|
+
const pendingExtraction = new Promise<void>((resolve) => {
|
|
510
|
+
resolveExtraction = resolve;
|
|
511
|
+
});
|
|
512
|
+
probe.orch.ingestReplayBatch = async () => pendingExtraction;
|
|
513
|
+
const service = new EngramAccessService(probe.orch);
|
|
514
|
+
const sessionKey = "pending-observe-extraction";
|
|
515
|
+
|
|
516
|
+
await service.observe(
|
|
517
|
+
observeRequest({
|
|
518
|
+
sessionKey,
|
|
519
|
+
skipExtraction: false,
|
|
520
|
+
}),
|
|
521
|
+
);
|
|
522
|
+
|
|
523
|
+
let settled = false;
|
|
524
|
+
const flushPromise = service.extractionForceFlush({ sessionKey });
|
|
525
|
+
void flushPromise.then(
|
|
526
|
+
() => {
|
|
527
|
+
settled = true;
|
|
528
|
+
},
|
|
529
|
+
() => {
|
|
530
|
+
settled = true;
|
|
531
|
+
},
|
|
532
|
+
);
|
|
533
|
+
await new Promise<void>((resolve) => setImmediate(resolve));
|
|
534
|
+
assert.equal(settled, false);
|
|
535
|
+
|
|
536
|
+
resolveExtraction();
|
|
537
|
+
const response = await flushPromise;
|
|
538
|
+
assert.equal(response.flushed, true);
|
|
539
|
+
});
|
|
540
|
+
test("#2128: pending extraction barriers stay isolated by authenticated principal", async () => {
|
|
541
|
+
const probe = makeParityProbe({
|
|
542
|
+
namespacePolicies: [
|
|
543
|
+
{ name: "team", readPrincipals: ["alice", "bob"], writePrincipals: ["alice", "bob"] },
|
|
544
|
+
],
|
|
545
|
+
} as Partial<PluginConfig>);
|
|
546
|
+
const pending = new Map<string, () => void>();
|
|
547
|
+
probe.orch.ingestReplayBatch = async (_turns, options = {}) =>
|
|
548
|
+
new Promise<void>((resolve) => {
|
|
549
|
+
pending.set(options.principalOverride ?? "", resolve);
|
|
550
|
+
});
|
|
551
|
+
const service = new EngramAccessService(probe.orch);
|
|
552
|
+
const sessionKey = "shared-session";
|
|
553
|
+
|
|
554
|
+
await service.observe(
|
|
555
|
+
observeRequest({
|
|
556
|
+
sessionKey,
|
|
557
|
+
namespace: "team",
|
|
558
|
+
authenticatedPrincipal: "alice",
|
|
559
|
+
skipExtraction: false,
|
|
560
|
+
}),
|
|
561
|
+
);
|
|
562
|
+
await service.observe(
|
|
563
|
+
observeRequest({
|
|
564
|
+
sessionKey,
|
|
565
|
+
namespace: "team",
|
|
566
|
+
authenticatedPrincipal: "bob",
|
|
567
|
+
skipExtraction: false,
|
|
568
|
+
}),
|
|
569
|
+
);
|
|
570
|
+
assert.deepEqual([...pending.keys()].sort(), ["alice", "bob"]);
|
|
571
|
+
|
|
572
|
+
const aliceFlush = service.extractionForceFlush({
|
|
573
|
+
sessionKey,
|
|
574
|
+
namespace: "team",
|
|
575
|
+
authenticatedPrincipal: "alice",
|
|
576
|
+
deadlineMs: Date.now() + 500,
|
|
577
|
+
});
|
|
578
|
+
await new Promise<void>((resolve) => setImmediate(resolve));
|
|
579
|
+
pending.get("alice")?.();
|
|
580
|
+
assert.equal((await aliceFlush).flushed, true);
|
|
581
|
+
|
|
582
|
+
const bobFlush = service.extractionForceFlush({
|
|
583
|
+
sessionKey,
|
|
584
|
+
namespace: "team",
|
|
585
|
+
authenticatedPrincipal: "bob",
|
|
586
|
+
deadlineMs: Date.now() + 500,
|
|
587
|
+
});
|
|
588
|
+
pending.get("bob")?.();
|
|
589
|
+
assert.equal((await bobFlush).flushed, true);
|
|
590
|
+
});
|
|
591
|
+
|
|
592
|
+
test("#2128: chained observes remain behind one force-flush barrier", async () => {
|
|
593
|
+
const probe = makeParityProbe({ namespacesEnabled: false } as Partial<PluginConfig>);
|
|
594
|
+
const resolvers: Array<() => void> = [];
|
|
595
|
+
probe.orch.ingestReplayBatch = async () =>
|
|
596
|
+
new Promise<void>((resolve) => {
|
|
597
|
+
resolvers.push(resolve);
|
|
598
|
+
});
|
|
599
|
+
const service = new EngramAccessService(probe.orch);
|
|
600
|
+
const sessionKey = "chained-observes";
|
|
601
|
+
|
|
602
|
+
await service.observe(observeRequest({ sessionKey, skipExtraction: false }));
|
|
603
|
+
const flushPromise = service.extractionForceFlush({ sessionKey, deadlineMs: Date.now() + 500 });
|
|
604
|
+
await new Promise<void>((resolve) => setImmediate(resolve));
|
|
605
|
+
await service.observe(observeRequest({ sessionKey, skipExtraction: false }));
|
|
606
|
+
assert.equal(resolvers.length, 2);
|
|
607
|
+
|
|
608
|
+
let settled = false;
|
|
609
|
+
void flushPromise.then(
|
|
610
|
+
() => {
|
|
611
|
+
settled = true;
|
|
612
|
+
},
|
|
613
|
+
() => {
|
|
614
|
+
settled = true;
|
|
615
|
+
},
|
|
616
|
+
);
|
|
617
|
+
resolvers[0]?.();
|
|
618
|
+
await new Promise<void>((resolve) => setImmediate(resolve));
|
|
619
|
+
assert.equal(settled, false);
|
|
620
|
+
resolvers[1]?.();
|
|
621
|
+
assert.equal((await flushPromise).flushed, true);
|
|
622
|
+
});
|
|
623
|
+
|
|
624
|
+
test("#2128: a failed observe extraction is consumed after force-flush reports it", async () => {
|
|
625
|
+
const probe = makeParityProbe({ namespacesEnabled: false } as Partial<PluginConfig>);
|
|
626
|
+
let rejectExtraction!: (error: Error) => void;
|
|
627
|
+
let extractionAttempt = 0;
|
|
628
|
+
probe.orch.ingestReplayBatch = async () => {
|
|
629
|
+
extractionAttempt += 1;
|
|
630
|
+
if (extractionAttempt > 1) return;
|
|
631
|
+
return new Promise<void>((_resolve, reject) => {
|
|
632
|
+
rejectExtraction = reject;
|
|
633
|
+
});
|
|
634
|
+
};
|
|
635
|
+
const service = new EngramAccessService(probe.orch);
|
|
636
|
+
const sessionKey = "failed-observe-extraction";
|
|
637
|
+
const failure = new Error("provider failed");
|
|
638
|
+
|
|
639
|
+
await service.observe(observeRequest({ sessionKey, skipExtraction: false }));
|
|
640
|
+
rejectExtraction(failure);
|
|
641
|
+
await assert.rejects(
|
|
642
|
+
service.extractionForceFlush({ sessionKey }),
|
|
643
|
+
(error: unknown) => error === failure,
|
|
644
|
+
);
|
|
645
|
+
|
|
646
|
+
await service.observe(observeRequest({ sessionKey, skipExtraction: false }));
|
|
647
|
+
await assert.doesNotReject(() => service.extractionForceFlush({ sessionKey }));
|
|
648
|
+
});
|
|
649
|
+
|
|
650
|
+
test("#2128: force-flush deadline cancels the pending observe extraction", async () => {
|
|
651
|
+
const probe = makeParityProbe({ namespacesEnabled: false } as Partial<PluginConfig>);
|
|
652
|
+
let extractionSignal: AbortSignal | undefined;
|
|
653
|
+
probe.orch.ingestReplayBatch = async (_turns, options = {}) => {
|
|
654
|
+
extractionSignal = options.abortSignal;
|
|
655
|
+
return new Promise<void>((_resolve, reject) => {
|
|
656
|
+
options.abortSignal?.addEventListener(
|
|
657
|
+
"abort",
|
|
658
|
+
() => reject(new Error("extraction cancelled")),
|
|
659
|
+
{ once: true },
|
|
660
|
+
);
|
|
661
|
+
});
|
|
662
|
+
};
|
|
663
|
+
const service = new EngramAccessService(probe.orch);
|
|
664
|
+
const sessionKey = "deadline-cancelled-extraction";
|
|
665
|
+
|
|
666
|
+
await service.observe(observeRequest({ sessionKey, skipExtraction: false }));
|
|
667
|
+
const keepAlive = setInterval(() => {}, 5);
|
|
668
|
+
try {
|
|
669
|
+
await assert.rejects(
|
|
670
|
+
service.extractionForceFlush({
|
|
671
|
+
sessionKey,
|
|
672
|
+
deadlineMs: Date.now() + 25,
|
|
673
|
+
}),
|
|
674
|
+
(error: unknown) =>
|
|
675
|
+
error instanceof EngramAccessInputError &&
|
|
676
|
+
error.message.includes("pending_observe_extraction"),
|
|
677
|
+
);
|
|
678
|
+
} finally {
|
|
679
|
+
clearInterval(keepAlive);
|
|
680
|
+
}
|
|
681
|
+
assert.equal(extractionSignal?.aborted, true);
|
|
682
|
+
});
|
|
683
|
+
|
|
684
|
+
test("#2128: force-flush abort signal cancels the pending observe extraction", async () => {
|
|
685
|
+
const probe = makeParityProbe({ namespacesEnabled: false } as Partial<PluginConfig>);
|
|
686
|
+
let extractionSignal: AbortSignal | undefined;
|
|
687
|
+
probe.orch.ingestReplayBatch = async (_turns, options = {}) => {
|
|
688
|
+
extractionSignal = options.abortSignal;
|
|
689
|
+
return new Promise<void>((_resolve, reject) => {
|
|
690
|
+
options.abortSignal?.addEventListener(
|
|
691
|
+
"abort",
|
|
692
|
+
() => reject(new Error("extraction cancelled")),
|
|
693
|
+
{ once: true },
|
|
694
|
+
);
|
|
695
|
+
});
|
|
696
|
+
};
|
|
697
|
+
const service = new EngramAccessService(probe.orch);
|
|
698
|
+
const sessionKey = "abort-cancelled-extraction";
|
|
699
|
+
const abortController = new AbortController();
|
|
700
|
+
|
|
701
|
+
await service.observe(observeRequest({ sessionKey, skipExtraction: false }));
|
|
702
|
+
const flushPromise = service.extractionForceFlush({
|
|
703
|
+
sessionKey,
|
|
704
|
+
abortSignal: abortController.signal,
|
|
705
|
+
});
|
|
706
|
+
await new Promise<void>((resolve) => setImmediate(resolve));
|
|
707
|
+
abortController.abort();
|
|
708
|
+
await assert.rejects(
|
|
709
|
+
flushPromise,
|
|
710
|
+
(error: unknown) => error instanceof Error && error.message === "extraction force-flush aborted",
|
|
711
|
+
);
|
|
712
|
+
assert.equal(extractionSignal?.aborted, true);
|
|
713
|
+
});
|
|
714
|
+
|
|
715
|
+
test("#2128: force-flush abort only cancels the resolved namespace barrier", async () => {
|
|
716
|
+
const probe = makeParityProbe({
|
|
717
|
+
namespacePolicies: [
|
|
718
|
+
{ name: "project-a", readPrincipals: ["pi-geek"], writePrincipals: ["pi-geek"] },
|
|
719
|
+
{ name: "project-b", readPrincipals: ["pi-geek"], writePrincipals: ["pi-geek"] },
|
|
720
|
+
],
|
|
721
|
+
} as Partial<PluginConfig>);
|
|
722
|
+
const extractionSignals = new Map<string, AbortSignal | undefined>();
|
|
723
|
+
const extractionResolvers = new Map<string, () => void>();
|
|
724
|
+
probe.orch.ingestReplayBatch = async (_turns, options = {}) => {
|
|
725
|
+
const namespace = options.writeNamespaceOverride ?? "";
|
|
726
|
+
extractionSignals.set(namespace, options.abortSignal);
|
|
727
|
+
return new Promise<void>((resolve, reject) => {
|
|
728
|
+
extractionResolvers.set(namespace, resolve);
|
|
729
|
+
options.abortSignal?.addEventListener(
|
|
730
|
+
"abort",
|
|
731
|
+
() => reject(options.abortSignal?.reason ?? new Error("extraction cancelled")),
|
|
732
|
+
{ once: true },
|
|
733
|
+
);
|
|
734
|
+
});
|
|
735
|
+
};
|
|
736
|
+
const service = new EngramAccessService(probe.orch);
|
|
737
|
+
const sessionKey = "opaque-shared-session";
|
|
738
|
+
const namespaceA = "project-a";
|
|
739
|
+
const namespaceB = "project-b";
|
|
740
|
+
|
|
741
|
+
await service.observe(
|
|
742
|
+
observeRequest({
|
|
743
|
+
sessionKey,
|
|
744
|
+
authenticatedPrincipal: "pi-geek",
|
|
745
|
+
namespace: namespaceA,
|
|
746
|
+
skipExtraction: false,
|
|
747
|
+
}),
|
|
748
|
+
);
|
|
749
|
+
await service.observe(
|
|
750
|
+
observeRequest({
|
|
751
|
+
sessionKey,
|
|
752
|
+
authenticatedPrincipal: "pi-geek",
|
|
753
|
+
namespace: namespaceB,
|
|
754
|
+
skipExtraction: false,
|
|
755
|
+
}),
|
|
756
|
+
);
|
|
757
|
+
assert.ok(extractionSignals.has(namespaceA));
|
|
758
|
+
assert.ok(extractionSignals.has(namespaceB));
|
|
759
|
+
|
|
760
|
+
const abortController = new AbortController();
|
|
761
|
+
const flushA = service.extractionForceFlush({
|
|
762
|
+
sessionKey,
|
|
763
|
+
authenticatedPrincipal: "pi-geek",
|
|
764
|
+
namespace: namespaceA,
|
|
765
|
+
abortSignal: abortController.signal,
|
|
766
|
+
});
|
|
767
|
+
await new Promise<void>((resolve) => setImmediate(resolve));
|
|
768
|
+
abortController.abort();
|
|
769
|
+
await assert.rejects(
|
|
770
|
+
flushA,
|
|
771
|
+
(error: unknown) => error instanceof Error && error.message === "extraction force-flush aborted",
|
|
772
|
+
);
|
|
773
|
+
assert.equal(extractionSignals.get(namespaceA)?.aborted, true);
|
|
774
|
+
assert.equal(extractionSignals.get(namespaceB)?.aborted, false);
|
|
775
|
+
|
|
776
|
+
extractionResolvers.get(namespaceB)?.();
|
|
777
|
+
await assert.doesNotReject(() =>
|
|
778
|
+
service.extractionForceFlush({
|
|
779
|
+
sessionKey,
|
|
780
|
+
authenticatedPrincipal: "pi-geek",
|
|
781
|
+
namespace: namespaceB,
|
|
782
|
+
}),
|
|
783
|
+
);
|
|
784
|
+
});
|
|
785
|
+
|
|
786
|
+
test("#2128: authenticated opaque sessions persist their trusted owner for force-flush", async () => {
|
|
787
|
+
const probe = makeParityProbe(withSelfPolicyPrefix("pi-geek"));
|
|
788
|
+
const service = new EngramAccessService(probe.orch);
|
|
789
|
+
const sessionKey = "opaque-session-42";
|
|
790
|
+
|
|
791
|
+
await service.observe(
|
|
792
|
+
observeRequest({
|
|
793
|
+
sessionKey,
|
|
794
|
+
authenticatedPrincipal: "pi-geek",
|
|
795
|
+
skipExtraction: false,
|
|
796
|
+
}),
|
|
797
|
+
);
|
|
798
|
+
|
|
799
|
+
assert.equal(probe.extractionCalls[0]?.sessionOwnerPrincipal, "pi-geek");
|
|
800
|
+
const response = await service.extractionForceFlush({
|
|
801
|
+
sessionKey,
|
|
802
|
+
authenticatedPrincipal: "pi-geek",
|
|
803
|
+
projectTag: "Acme/Webshop",
|
|
804
|
+
});
|
|
805
|
+
assert.equal(response.flushed, true);
|
|
806
|
+
assert.equal(probe.extractionForceFlushCalls[0]?.options.principalOverride, "pi-geek");
|
|
807
|
+
assert.equal(
|
|
808
|
+
probe.orch.getCodingContextForSession(sessionKey),
|
|
809
|
+
null,
|
|
810
|
+
"opaque force-flush must not persist caller project context",
|
|
811
|
+
);
|
|
812
|
+
});
|
|
813
|
+
|
|
814
|
+
|
|
815
|
+
test("#2128: extraction force-flush rejects a session owned by another principal", async () => {
|
|
816
|
+
const probe = makeParityProbe({
|
|
817
|
+
...withSelfPolicyPrefix("pi-geek"),
|
|
818
|
+
namespacePolicies: [
|
|
819
|
+
{ name: "pi-geek", readPrincipals: ["pi-geek"], writePrincipals: ["pi-geek"] },
|
|
820
|
+
{ name: "victim", readPrincipals: ["victim"], writePrincipals: ["victim"] },
|
|
821
|
+
],
|
|
822
|
+
principalFromSessionKeyRules: [
|
|
823
|
+
{ match: "pi-geek:", principal: "pi-geek" },
|
|
824
|
+
{ match: "victim:", principal: "victim" },
|
|
825
|
+
],
|
|
826
|
+
});
|
|
827
|
+
const service = new EngramAccessService(probe.orch);
|
|
828
|
+
|
|
829
|
+
await assert.rejects(
|
|
830
|
+
() =>
|
|
831
|
+
service.extractionForceFlush({
|
|
832
|
+
sessionKey: "victim:private-session",
|
|
833
|
+
authenticatedPrincipal: "pi-geek",
|
|
834
|
+
}),
|
|
835
|
+
/sessionKey is not owned by authenticated principal/,
|
|
836
|
+
);
|
|
837
|
+
assert.equal(probe.extractionForceFlushCalls.length, 0);
|
|
838
|
+
});
|
|
839
|
+
|
|
840
|
+
test("#2128: opaque ownership denial is surfaced as a forbidden access error", async () => {
|
|
841
|
+
const probe = makeParityProbe(withSelfPolicyPrefix("pi-geek"));
|
|
842
|
+
probe.orch.flushSession = async () => {
|
|
843
|
+
throw new SessionOwnershipError("session opaque-session has buffered turns without trusted ownership");
|
|
844
|
+
};
|
|
845
|
+
const service = new EngramAccessService(probe.orch);
|
|
846
|
+
|
|
847
|
+
await assert.rejects(
|
|
848
|
+
() =>
|
|
849
|
+
service.extractionForceFlush({
|
|
850
|
+
sessionKey: "opaque-session",
|
|
851
|
+
authenticatedPrincipal: "pi-geek",
|
|
852
|
+
}),
|
|
853
|
+
(error: unknown) =>
|
|
854
|
+
error instanceof EngramAccessForbiddenError &&
|
|
855
|
+
error.message === "session opaque-session has buffered turns without trusted ownership",
|
|
856
|
+
);
|
|
857
|
+
});
|
|
858
|
+
|
|
859
|
+
test("#2128: explicit namespace force-flush does not bind unrelated project context", async () => {
|
|
860
|
+
const probe = makeParityProbe(withSelfPolicyPrefix("pi-geek"));
|
|
861
|
+
const service = new EngramAccessService(probe.orch);
|
|
862
|
+
const sessionKey = "pi-geek:explicit-scope";
|
|
863
|
+
|
|
864
|
+
await service.extractionForceFlush({
|
|
865
|
+
sessionKey,
|
|
866
|
+
namespace: "pi-geek",
|
|
867
|
+
projectTag: "Acme/Webshop",
|
|
868
|
+
authenticatedPrincipal: "pi-geek",
|
|
869
|
+
});
|
|
870
|
+
|
|
871
|
+
assert.equal(probe.orch.getCodingContextForSession(sessionKey), null);
|
|
872
|
+
});
|
|
873
|
+
test("#2128: post-flush retained cleanup is best effort and receives lifecycle guards", async () => {
|
|
874
|
+
const probe = makeParityProbe(withSelfPolicyPrefix("pi-geek"));
|
|
875
|
+
const abortController = new AbortController();
|
|
876
|
+
const cleanupCalls: Array<{
|
|
877
|
+
sessionKey: string;
|
|
878
|
+
ownerPrincipal?: string;
|
|
879
|
+
options?: { abortSignal?: AbortSignal; deadlineMs?: number };
|
|
880
|
+
}> = [];
|
|
881
|
+
(probe.orch as unknown as {
|
|
882
|
+
buffer: {
|
|
883
|
+
clearRetainedTurnsForSession(
|
|
884
|
+
sessionKey: string,
|
|
885
|
+
ownerPrincipal?: string,
|
|
886
|
+
options?: { abortSignal?: AbortSignal; deadlineMs?: number },
|
|
887
|
+
): Promise<void>;
|
|
888
|
+
};
|
|
889
|
+
}).buffer = {
|
|
890
|
+
clearRetainedTurnsForSession: async (sessionKey, ownerPrincipal, options) => {
|
|
891
|
+
cleanupCalls.push({ sessionKey, ownerPrincipal, options });
|
|
892
|
+
throw new Error("retained cleanup unavailable");
|
|
893
|
+
},
|
|
894
|
+
};
|
|
895
|
+
const service = new EngramAccessService(probe.orch);
|
|
896
|
+
const deadlineMs = Date.now() + 10_000;
|
|
897
|
+
|
|
898
|
+
const response = await service.extractionForceFlush({
|
|
899
|
+
sessionKey: "pi-geek:cleanup-best-effort",
|
|
900
|
+
authenticatedPrincipal: "pi-geek",
|
|
901
|
+
abortSignal: abortController.signal,
|
|
902
|
+
deadlineMs,
|
|
903
|
+
});
|
|
904
|
+
|
|
905
|
+
assert.equal(response.flushed, true);
|
|
906
|
+
assert.deepEqual(cleanupCalls, [{
|
|
907
|
+
sessionKey: "pi-geek:cleanup-best-effort",
|
|
908
|
+
ownerPrincipal: "pi-geek",
|
|
909
|
+
options: { abortSignal: abortController.signal, deadlineMs },
|
|
910
|
+
}]);
|
|
911
|
+
});
|
|
912
|
+
|
|
913
|
+
test("#2128: post-flush retained cleanup stops on abort or deadline", async () => {
|
|
914
|
+
const probe = makeParityProbe(withSelfPolicyPrefix("pi-geek"));
|
|
915
|
+
(probe.orch as unknown as {
|
|
916
|
+
buffer: {
|
|
917
|
+
clearRetainedTurnsForSession(
|
|
918
|
+
sessionKey: string,
|
|
919
|
+
ownerPrincipal?: string,
|
|
920
|
+
options?: { abortSignal?: AbortSignal; deadlineMs?: number },
|
|
921
|
+
): Promise<void>;
|
|
922
|
+
};
|
|
923
|
+
}).buffer = {
|
|
924
|
+
clearRetainedTurnsForSession: async () => new Promise<void>(() => {}),
|
|
925
|
+
};
|
|
926
|
+
const service = new EngramAccessService(probe.orch);
|
|
927
|
+
const abortController = new AbortController();
|
|
928
|
+
setTimeout(() => abortController.abort(), 5).unref();
|
|
929
|
+
|
|
930
|
+
await assert.rejects(
|
|
931
|
+
() =>
|
|
932
|
+
Promise.race([
|
|
933
|
+
service.extractionForceFlush({
|
|
934
|
+
sessionKey: "pi-geek:cleanup-abort",
|
|
935
|
+
authenticatedPrincipal: "pi-geek",
|
|
936
|
+
abortSignal: abortController.signal,
|
|
937
|
+
}),
|
|
938
|
+
new Promise<never>((_resolve, reject) =>
|
|
939
|
+
setTimeout(() => reject(new Error("abort cleanup test timed out")), 100),
|
|
940
|
+
),
|
|
941
|
+
]),
|
|
942
|
+
/extraction force-flush aborted/,
|
|
943
|
+
);
|
|
944
|
+
|
|
945
|
+
await assert.rejects(
|
|
946
|
+
() =>
|
|
947
|
+
Promise.race([
|
|
948
|
+
service.extractionForceFlush({
|
|
949
|
+
sessionKey: "pi-geek:cleanup-deadline",
|
|
950
|
+
authenticatedPrincipal: "pi-geek",
|
|
951
|
+
deadlineMs: Date.now() + 5,
|
|
952
|
+
}),
|
|
953
|
+
new Promise<never>((_resolve, reject) =>
|
|
954
|
+
setTimeout(() => reject(new Error("deadline cleanup test timed out")), 100),
|
|
955
|
+
),
|
|
956
|
+
]),
|
|
957
|
+
/replay extraction deadline exceeded \(retained_turn_cleanup\)/,
|
|
958
|
+
);
|
|
959
|
+
});
|
|
960
|
+
test("#2128: aborted or expired extraction force-flush never touches a buffer", async () => {
|
|
961
|
+
const probe = makeParityProbe(withSelfPolicyPrefix("pi-geek"));
|
|
962
|
+
const service = new EngramAccessService(probe.orch);
|
|
963
|
+
const abortController = new AbortController();
|
|
964
|
+
abortController.abort();
|
|
965
|
+
|
|
966
|
+
await assert.rejects(
|
|
967
|
+
() =>
|
|
968
|
+
service.extractionForceFlush({
|
|
969
|
+
sessionKey: "pi-geek:aborted-flush",
|
|
970
|
+
authenticatedPrincipal: "pi-geek",
|
|
971
|
+
abortSignal: abortController.signal,
|
|
972
|
+
}),
|
|
973
|
+
/extraction force-flush aborted/,
|
|
974
|
+
);
|
|
975
|
+
await assert.rejects(
|
|
976
|
+
() =>
|
|
977
|
+
service.extractionForceFlush({
|
|
978
|
+
sessionKey: "pi-geek:expired-flush",
|
|
979
|
+
authenticatedPrincipal: "pi-geek",
|
|
980
|
+
deadlineMs: Date.now() - 1,
|
|
981
|
+
}),
|
|
982
|
+
(error: unknown) =>
|
|
983
|
+
error instanceof EngramAccessInputError &&
|
|
984
|
+
error.message === "extraction force-flush deadline exceeded before buffer drain",
|
|
985
|
+
);
|
|
986
|
+
assert.equal(probe.extractionForceFlushCalls.length, 0);
|
|
987
|
+
});
|
|
988
|
+
|
|
989
|
+
test("#2128: self-deps wires force-flush cancellation into the observe tracker", async () => {
|
|
990
|
+
const probe = makeParityProbe(withSelfPolicyPrefix("pi-geek"));
|
|
991
|
+
const service = new EngramAccessService(probe.orch);
|
|
992
|
+
const cancellations: Array<{
|
|
993
|
+
sessionKey: string;
|
|
994
|
+
principal?: string;
|
|
995
|
+
namespace?: string;
|
|
996
|
+
}> = [];
|
|
997
|
+
const surface = (service as unknown as {
|
|
998
|
+
accessObserveWriteSurface: {
|
|
999
|
+
cancelPendingObserveExtractions(
|
|
1000
|
+
sessionKey: string,
|
|
1001
|
+
principal?: string,
|
|
1002
|
+
namespace?: string,
|
|
1003
|
+
): void;
|
|
1004
|
+
};
|
|
1005
|
+
}).accessObserveWriteSurface;
|
|
1006
|
+
surface.cancelPendingObserveExtractions = (sessionKey, principal, namespace) => {
|
|
1007
|
+
cancellations.push({ sessionKey, principal, namespace });
|
|
1008
|
+
};
|
|
1009
|
+
|
|
1010
|
+
await assert.rejects(
|
|
1011
|
+
() =>
|
|
1012
|
+
service.extractionForceFlush({
|
|
1013
|
+
sessionKey: "pi-geek:cancel-hook",
|
|
1014
|
+
namespace: "pi-geek",
|
|
1015
|
+
authenticatedPrincipal: "pi-geek",
|
|
1016
|
+
deadlineMs: Date.now() - 1,
|
|
1017
|
+
}),
|
|
1018
|
+
(error: unknown) =>
|
|
1019
|
+
error instanceof EngramAccessInputError &&
|
|
1020
|
+
error.message === "extraction force-flush deadline exceeded before buffer drain",
|
|
1021
|
+
);
|
|
1022
|
+
assert.deepEqual(cancellations, [{
|
|
1023
|
+
sessionKey: "pi-geek:cancel-hook",
|
|
1024
|
+
principal: "pi-geek",
|
|
1025
|
+
namespace: "pi-geek",
|
|
1026
|
+
}]);
|
|
1027
|
+
});
|
|
1028
|
+
|
|
1029
|
+
test("#2128: late extraction deadline is surfaced as an access input error", async () => {
|
|
1030
|
+
const probe = makeParityProbe(withSelfPolicyPrefix("pi-geek"));
|
|
1031
|
+
probe.orch.flushSession = async () => {
|
|
1032
|
+
throw new ExtractionDeadlineError("during_extract");
|
|
1033
|
+
};
|
|
1034
|
+
const service = new EngramAccessService(probe.orch);
|
|
1035
|
+
|
|
1036
|
+
await assert.rejects(
|
|
1037
|
+
() =>
|
|
1038
|
+
service.extractionForceFlush({
|
|
1039
|
+
sessionKey: "pi-geek:late-deadline",
|
|
1040
|
+
authenticatedPrincipal: "pi-geek",
|
|
1041
|
+
deadlineMs: Date.now() + 10_000,
|
|
1042
|
+
}),
|
|
1043
|
+
(error: unknown) =>
|
|
1044
|
+
error instanceof EngramAccessInputError &&
|
|
1045
|
+
error.message === "replay extraction deadline exceeded (during_extract)",
|
|
1046
|
+
);
|
|
1047
|
+
});
|
|
1048
|
+
|
|
1049
|
+
test("#2128: force-flush scope resolution does not overwrite a concurrent observe context", async () => {
|
|
1050
|
+
const probe = makeParityProbe(withSelfPolicyPrefix("pi-geek"));
|
|
1051
|
+
const service = new EngramAccessService(probe.orch);
|
|
1052
|
+
const sessionKey = "pi-geek:concurrent-scope";
|
|
1053
|
+
let releaseFlush!: () => void;
|
|
1054
|
+
const flushBlocked = new Promise<void>((resolve) => {
|
|
1055
|
+
releaseFlush = resolve;
|
|
1056
|
+
});
|
|
1057
|
+
probe.orch.flushSession = async () => flushBlocked;
|
|
1058
|
+
|
|
1059
|
+
const flushPromise = service.extractionForceFlush({
|
|
1060
|
+
sessionKey,
|
|
1061
|
+
projectTag: "Acme/FlushProject",
|
|
1062
|
+
authenticatedPrincipal: "pi-geek",
|
|
1063
|
+
});
|
|
1064
|
+
await new Promise<void>((resolve) => setImmediate(resolve));
|
|
1065
|
+
assert.equal(
|
|
1066
|
+
probe.orch.getCodingContextForSession(sessionKey),
|
|
1067
|
+
null,
|
|
1068
|
+
"force-flush scope resolution must stay local while its drain is pending",
|
|
1069
|
+
);
|
|
1070
|
+
|
|
1071
|
+
await service.observe(
|
|
1072
|
+
observeRequest({
|
|
1073
|
+
sessionKey,
|
|
1074
|
+
projectTag: "Acme/ObserveProject",
|
|
1075
|
+
authenticatedPrincipal: "pi-geek",
|
|
1076
|
+
skipExtraction: true,
|
|
1077
|
+
}),
|
|
1078
|
+
);
|
|
1079
|
+
const observedContext = probe.orch.getCodingContextForSession(sessionKey);
|
|
1080
|
+
assert.ok(observedContext);
|
|
1081
|
+
assert.equal(observedContext.projectId, projectTagProjectId("Acme/ObserveProject"));
|
|
1082
|
+
|
|
1083
|
+
releaseFlush();
|
|
1084
|
+
await flushPromise;
|
|
1085
|
+
assert.equal(
|
|
1086
|
+
probe.orch.getCodingContextForSession(sessionKey)?.projectId,
|
|
1087
|
+
projectTagProjectId("Acme/ObserveProject"),
|
|
1088
|
+
"force-flush cleanup must not clear a context attached by the concurrent observe",
|
|
1089
|
+
);
|
|
1090
|
+
});
|
|
1091
|
+
|
|
342
1092
|
test("#1505 thread 2 (b) cwd git repo: observe LCM write key == recall reader key == compaction keys", async () => {
|
|
343
1093
|
const repoDir = mkdtempSync(join(tmpdir(), "remnic-lcm-parity-git-"));
|
|
344
1094
|
const git = (...args: string[]) =>
|