@remnic/core 9.6.0 → 9.6.2
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 +7 -8
- package/dist/access-admin-ops-surface.js +8 -8
- package/dist/access-boundary.d.ts +9 -8
- package/dist/access-boundary.js +9 -9
- package/dist/access-cli.js +40 -40
- package/dist/access-http.d.ts +47 -16
- package/dist/access-http.js +13 -13
- package/dist/access-identity-continuity-surface.d.ts +6 -7
- package/dist/access-identity-continuity-surface.js +8 -8
- package/dist/access-lcm-surface.d.ts +7 -8
- package/dist/access-lcm-surface.js +8 -8
- package/dist/access-mcp.d.ts +13 -8
- package/dist/access-mcp.js +12 -12
- package/dist/access-observe-write-surface.d.ts +7 -8
- package/dist/access-observe-write-surface.js +8 -8
- package/dist/access-operations-batch.js +10 -10
- package/dist/access-operations.d.ts +8 -9
- package/dist/access-operations.js +11 -11
- package/dist/access-recall-surface.d.ts +7 -8
- package/dist/access-recall-surface.js +8 -8
- package/dist/access-schema.d.ts +6 -6
- package/dist/{access-service-CXJaql3A.d.ts → access-service-B_sc1w_k.d.ts} +9 -9
- package/dist/access-service.d.ts +7 -8
- package/dist/access-service.js +8 -8
- package/dist/access-surface-catalog.d.ts +7 -8
- package/dist/action-confidence.d.ts +1 -2
- package/dist/active-memory-bridge.d.ts +1 -2
- package/dist/active-recall.d.ts +1 -2
- package/dist/behavior-learner.d.ts +1 -2
- package/dist/behavior-signals.d.ts +1 -2
- package/dist/bootstrap.d.ts +6 -7
- package/dist/briefing.d.ts +2 -3
- package/dist/briefing.js +3 -3
- package/dist/buffer-surprise-report.d.ts +1 -2
- package/dist/buffer.d.ts +2 -3
- package/dist/buffer.js +1 -1
- package/dist/bulk-import/index.d.ts +3 -3
- package/dist/bulk-import/index.js +2 -2
- package/dist/calibration.d.ts +1 -2
- package/dist/capabilities.d.ts +1 -2
- package/dist/{catalog-C9cu67Ig.d.ts → catalog-9WanSGtt.d.ts} +1 -1
- package/dist/causal-behavior.d.ts +1 -2
- package/dist/causal-consolidation.d.ts +1 -2
- package/dist/causal-consolidation.js +4 -4
- package/dist/causal-trajectory-graph.d.ts +1 -2
- package/dist/{chunk-PNLFN2PZ.js → chunk-23G3T2Q5.js} +2 -2
- package/dist/{chunk-SIRPLF54.js → chunk-2K3OSLHE.js} +2 -2
- package/dist/{chunk-JS2HKKOK.js → chunk-3AC5UYKI.js} +1 -1
- package/dist/{chunk-JS2HKKOK.js.map → chunk-3AC5UYKI.js.map} +1 -1
- package/dist/{chunk-FKCRGLRD.js → chunk-4WRKKRTD.js} +266 -160
- package/dist/chunk-4WRKKRTD.js.map +1 -0
- package/dist/{chunk-LQHDIS7L.js → chunk-54BGIBCR.js} +2 -2
- package/dist/{chunk-PVUJ6WVV.js → chunk-5MH5NF3U.js} +5 -5
- package/dist/{chunk-PCLIWBGD.js → chunk-7ARV32PI.js} +8 -6
- package/dist/chunk-7ARV32PI.js.map +1 -0
- package/dist/{chunk-Y7UNNAZD.js → chunk-7ZYBDQ7V.js} +2 -2
- package/dist/{chunk-2PRQG7PV.js → chunk-AJVLDJU6.js} +1 -1
- package/dist/chunk-AJVLDJU6.js.map +1 -0
- package/dist/{chunk-LR5DZ56F.js → chunk-AXALUFAH.js} +2 -2
- package/dist/{chunk-AYZJID4S.js → chunk-B5GBWBCZ.js} +2 -2
- package/dist/{chunk-TLUDFPZL.js → chunk-CAZ3Z5M6.js} +2 -2
- package/dist/{chunk-RGK27ELN.js → chunk-DEKIXXIG.js} +2 -2
- package/dist/{chunk-2KK5WNQB.js → chunk-DQ42IQSK.js} +2 -2
- package/dist/{chunk-UFUKHGZD.js → chunk-F4I5NYBI.js} +89 -33
- package/dist/chunk-F4I5NYBI.js.map +1 -0
- package/dist/{chunk-HOJZMQ4J.js → chunk-FGDKJJZS.js} +2 -2
- package/dist/{chunk-ABP6QMVM.js → chunk-FQ7HAWWC.js} +2 -2
- package/dist/{chunk-CYWA2CXR.js → chunk-FVTLSFWU.js} +2 -2
- package/dist/{chunk-JJEJJ7RK.js → chunk-FXZTL7F7.js} +2 -2
- package/dist/{chunk-LADFWYHY.js → chunk-GOEV7CYF.js} +6 -6
- package/dist/chunk-GOEV7CYF.js.map +1 -0
- package/dist/{chunk-DANV2HTH.js → chunk-GQGDRLDM.js} +3 -3
- package/dist/{chunk-7F7Z6MOS.js → chunk-H4CKS5B2.js} +2 -2
- package/dist/{chunk-SVOHGUMI.js → chunk-H4FHR4UM.js} +174 -197
- package/dist/chunk-H4FHR4UM.js.map +1 -0
- package/dist/{chunk-CKITWVWJ.js → chunk-HSSERO3E.js} +2 -2
- package/dist/{chunk-23JFRB73.js → chunk-JODHPNLN.js} +2 -2
- package/dist/{chunk-DS7MM2ES.js → chunk-JZKR6ZAV.js} +2 -2
- package/dist/{chunk-BEM4D2QG.js → chunk-KJIJNLXT.js} +3 -3
- package/dist/{chunk-JSNVWNGX.js → chunk-KVSVVKHA.js} +2 -2
- package/dist/{chunk-4GNEDXDI.js → chunk-M67TLMP6.js} +2 -2
- package/dist/chunk-M67TLMP6.js.map +1 -0
- package/dist/{chunk-MC4FJXPA.js → chunk-MMACM5G2.js} +2 -2
- package/dist/{chunk-OUELRE5E.js → chunk-NOUJNHWG.js} +1 -1
- package/dist/chunk-NOUJNHWG.js.map +1 -0
- package/dist/{chunk-3XIY7MDQ.js → chunk-O6YI4CVI.js} +2 -2
- package/dist/{chunk-F53UF7CI.js → chunk-QLVLW7UD.js} +6 -2
- package/dist/{chunk-F53UF7CI.js.map → chunk-QLVLW7UD.js.map} +1 -1
- package/dist/{chunk-XCL57M6Q.js → chunk-RRKPLLCC.js} +21 -20
- package/dist/chunk-RRKPLLCC.js.map +1 -0
- package/dist/{chunk-72WG5QKN.js → chunk-SDAXPXER.js} +2 -2
- package/dist/{chunk-4LV23CHK.js → chunk-VHJARF5R.js} +2 -2
- package/dist/{chunk-H2DXDQCQ.js → chunk-VRJG3HIZ.js} +46 -42
- package/dist/chunk-VRJG3HIZ.js.map +1 -0
- package/dist/{chunk-6MMONPHM.js → chunk-W2AHSCKY.js} +2 -2
- package/dist/{chunk-P454KXD6.js → chunk-YAWJMR3Y.js} +21 -21
- package/dist/{chunk-K5LLP4CY.js → chunk-ZGPDSEKG.js} +20 -9
- package/dist/chunk-ZGPDSEKG.js.map +1 -0
- package/dist/{cli-CqdPA6z9.d.ts → cli-CnRsWREp.d.ts} +4 -5
- package/dist/cli.d.ts +9 -10
- package/dist/cli.js +32 -32
- package/dist/compounding/engine.d.ts +2 -3
- package/dist/compounding/engine.js +3 -3
- package/dist/compounding/preference-consolidator.d.ts +1 -2
- package/dist/compression-optimizer.d.ts +1 -2
- package/dist/config.d.ts +1 -2
- package/dist/connectors/codex-materialize-runner.d.ts +1 -2
- package/dist/connectors/codex-materialize-runner.js +3 -3
- package/dist/connectors/codex-materialize.d.ts +1 -2
- package/dist/connectors/index.d.ts +1 -2
- package/dist/connectors/index.js +3 -3
- package/dist/consolidation-provenance-check.d.ts +2 -3
- package/dist/consolidation-undo.d.ts +2 -3
- package/dist/contradiction/index.d.ts +3 -4
- package/dist/conversation-index/backend.d.ts +1 -2
- package/dist/conversation-index/chunker.d.ts +1 -2
- package/dist/conversation-index/faiss-adapter.d.ts +1 -2
- package/dist/conversation-index/indexer.d.ts +1 -2
- package/dist/conversation-index/search.d.ts +1 -2
- package/dist/day-summary.d.ts +1 -2
- package/dist/delinearize.d.ts +1 -2
- package/dist/direct-answer-wiring.d.ts +1 -2
- package/dist/direct-answer.d.ts +1 -2
- package/dist/embedding-fallback.d.ts +1 -2
- package/dist/enrichment/index.d.ts +1 -2
- package/dist/entity-retrieval.d.ts +2 -3
- package/dist/entity-retrieval.js +3 -3
- package/dist/entity-schema.d.ts +1 -2
- package/dist/explicit-capture.d.ts +8 -7
- package/dist/explicit-capture.js +1 -1
- package/dist/extraction-faithfulness.d.ts +1 -2
- package/dist/extraction-judge-telemetry.d.ts +1 -2
- package/dist/extraction-judge-training.d.ts +1 -2
- package/dist/extraction-judge.d.ts +1 -2
- package/dist/extraction.d.ts +1 -2
- package/dist/fallback-llm.d.ts +1 -2
- package/dist/graph-dashboard-diff.d.ts +1 -2
- package/dist/graph-dashboard-key.d.ts +1 -2
- package/dist/graph-dashboard-parser.d.ts +1 -2
- package/dist/graph-edge-reinforcement.d.ts +1 -2
- package/dist/graph-snapshot.d.ts +1 -2
- package/dist/graph.d.ts +1 -2
- package/dist/identity-continuity.d.ts +1 -2
- package/dist/importance.d.ts +1 -2
- package/dist/importers/index.d.ts +1 -1
- package/dist/importers/index.js +2 -2
- package/dist/index.d.ts +14 -15
- package/dist/index.js +40 -40
- package/dist/intent.d.ts +1 -2
- package/dist/lcm/engine.d.ts +1 -2
- package/dist/lcm/index.d.ts +1 -2
- package/dist/lcm/tools.d.ts +1 -2
- package/dist/lifecycle.d.ts +1 -2
- package/dist/live-connectors-runner.d.ts +1 -2
- package/dist/local-llm.d.ts +1 -2
- package/dist/local-model-endpoint.d.ts +1 -2
- package/dist/maintenance/memory-governance.d.ts +1 -2
- package/dist/maintenance/memory-governance.js +3 -3
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +3 -3
- package/dist/maintenance/rebuild-memory-projection.js +4 -4
- package/dist/mcp-memory-inspector-app.d.ts +7 -8
- package/dist/memory-action-policy.d.ts +1 -2
- package/dist/memory-cache.d.ts +1 -2
- package/dist/memory-lifecycle-ledger-utils.d.ts +1 -2
- package/dist/memory-projection-store.d.ts +1 -2
- package/dist/memory-provenance.d.ts +1 -2
- package/dist/memory-worth-outcomes.d.ts +2 -3
- package/dist/models-json.d.ts +1 -2
- package/dist/namespaces/migrate.d.ts +3 -4
- package/dist/namespaces/migrate.js +4 -4
- package/dist/namespaces/principal.d.ts +1 -2
- package/dist/namespaces/search.d.ts +1 -2
- package/dist/namespaces/storage.d.ts +3 -4
- package/dist/namespaces/storage.js +3 -3
- package/dist/native-knowledge.d.ts +1 -2
- package/dist/operator-toolkit.d.ts +2 -3
- package/dist/operator-toolkit.js +7 -7
- package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -3
- package/dist/orchestration/maintenance.d.ts +2 -3
- package/dist/orchestration/maintenance.js +5 -5
- package/dist/{orchestrator-CWFrT8AF.d.ts → orchestrator-NRLVXPpH.d.ts} +40 -15
- package/dist/orchestrator.d.ts +6 -7
- package/dist/orchestrator.js +40 -40
- package/dist/patterns-cli.d.ts +1 -2
- package/dist/{pipeline-DmqtvION.d.ts → pipeline-CiD86zIk.d.ts} +1 -1
- package/dist/policy-runtime.d.ts +1 -2
- package/dist/provenance.d.ts +1 -2
- package/dist/{qmd--fnPMK60.d.ts → qmd-Bef7DDuQ.d.ts} +1 -1
- package/dist/qmd-preflight.d.ts +2 -3
- package/dist/qmd-recall-cache.d.ts +1 -2
- package/dist/qmd.d.ts +2 -3
- package/dist/recall-disclosure-escalation.d.ts +1 -2
- package/dist/recall-explain-renderer.d.ts +1 -2
- package/dist/recall-explain-renderer.js +3 -3
- package/dist/recall-planner-llm.d.ts +1 -2
- package/dist/recall-state.d.ts +1 -2
- package/dist/recall-tag-filter.d.ts +1 -2
- package/dist/recall-timings.d.ts +1 -2
- package/dist/recall-xray-cli.d.ts +1 -2
- package/dist/recall-xray-cli.js +4 -4
- package/dist/recall-xray-renderer.d.ts +1 -2
- package/dist/recall-xray-renderer.js +3 -3
- package/dist/recall-xray.d.ts +1 -2
- package/dist/recall-xray.js +2 -2
- package/dist/replay/normalizers/chatgpt.d.ts +1 -0
- package/dist/replay/normalizers/chatgpt.js +3 -3
- package/dist/replay/normalizers/claude.d.ts +1 -0
- package/dist/replay/normalizers/claude.js +3 -3
- package/dist/replay/normalizers/openclaw.d.ts +1 -0
- package/dist/replay/normalizers/openclaw.js +3 -3
- package/dist/replay/normalizers/shared.d.ts +1 -0
- package/dist/replay/normalizers/shared.js +2 -2
- package/dist/replay/runner.d.ts +1 -0
- package/dist/replay/runner.js +2 -2
- package/dist/replay/types.d.ts +2 -1
- package/dist/replay/types.js +1 -1
- package/dist/resolve-auth-token.d.ts +1 -2
- package/dist/retrieval-agents.d.ts +2 -3
- package/dist/retrieval-tiers.d.ts +1 -2
- package/dist/routing/engine.d.ts +1 -2
- package/dist/routing/store.d.ts +1 -2
- package/dist/schemas.d.ts +44 -44
- package/dist/search/embed-helper.d.ts +1 -2
- package/dist/search/factory.d.ts +1 -2
- package/dist/search/index.d.ts +1 -2
- package/dist/search/lancedb-backend.d.ts +1 -2
- package/dist/search/meilisearch-backend.d.ts +1 -2
- package/dist/search/noop-backend.d.ts +1 -2
- package/dist/search/orama-backend.d.ts +1 -2
- package/dist/search/port.d.ts +1 -2
- package/dist/search/remote-backend.d.ts +1 -2
- package/dist/{semantic-DJR8_DMQ.d.ts → semantic-TddhF0y7.d.ts} +17 -1
- package/dist/{semantic-consolidation-O5lMZ4LG.d.ts → semantic-consolidation-BTShF2Fo.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +2 -3
- package/dist/semantic-consolidation.js +4 -4
- package/dist/semantic-rule-promotion.js +3 -3
- package/dist/semantic-rule-verifier.d.ts +1 -2
- package/dist/semantic-rule-verifier.js +3 -3
- package/dist/session-observer-bands.d.ts +1 -2
- package/dist/session-observer-state.d.ts +1 -2
- package/dist/shared-context/manager.d.ts +3 -4
- package/dist/signal.d.ts +1 -2
- package/dist/{storage-C1maCNbc.d.ts → storage-DxPDAiU9.d.ts} +5 -1
- package/dist/storage.d.ts +2 -3
- package/dist/storage.js +2 -2
- package/dist/summarizer.d.ts +1 -2
- package/dist/summary-snapshot.d.ts +1 -2
- package/dist/temporal-supersession.d.ts +2 -3
- package/dist/temporal-validity.d.ts +1 -2
- package/dist/threading.d.ts +1 -2
- package/dist/tier-migration.d.ts +2 -3
- package/dist/tier-routing.d.ts +1 -2
- package/dist/topics.d.ts +1 -2
- package/dist/transcript.d.ts +1 -2
- package/dist/transfer/types.d.ts +12 -12
- package/dist/trust-score-stage.d.ts +1 -2
- package/dist/trust-score.d.ts +1 -2
- package/dist/{types-CGgcNWCG.d.ts → types-DDUDgd7T.d.ts} +93 -4
- package/dist/types.d.ts +1 -2
- package/dist/types.js +1 -1
- package/dist/utility-runtime.d.ts +1 -2
- package/dist/verified-recall.js +3 -3
- package/package.json +2 -2
- package/src/access-admin-ops-surface.ts +1 -0
- package/src/access-boundary.ts +2 -0
- package/src/access-http.test.ts +129 -0
- package/src/access-http.ts +92 -23
- package/src/access-mcp.ts +11 -2
- package/src/access-observe-write-surface.ts +87 -113
- package/src/access-operations-batch.ts +2 -2
- package/src/access-operations.ts +17 -16
- package/src/access-service.ts +11 -3
- package/src/admin/admin-surfaces.ts +2 -0
- package/src/buffer.ts +6 -1
- package/src/bulk-import/types.ts +2 -1
- package/src/coding/architecture-surfaces.test.ts +79 -5
- package/src/coding/architecture-surfaces.ts +7 -1
- package/src/coding/decision-surfaces.test.ts +1 -0
- package/src/coding/decision-surfaces.ts +4 -0
- package/src/connector-provenance-lifecycle.test.ts +618 -0
- package/src/connector-provenance.test.ts +219 -0
- package/src/dedup/semantic.test.ts +105 -0
- package/src/dedup/semantic.ts +69 -1
- package/src/explicit-capture.ts +21 -4
- package/src/orchestration/extraction-persist.ts +154 -6
- package/src/orchestration/extraction-run.ts +138 -228
- package/src/orchestration/persistence-index.ts +40 -5
- package/src/orchestration/turn-ingestion.ts +16 -9
- package/src/orchestrator-connector-dedup.test.ts +1082 -0
- package/src/orchestrator.ts +7 -11
- package/src/replay/types.ts +2 -1
- package/src/storage.ts +426 -553
- package/src/types.ts +11 -2
- package/src/utils/yaml-scalar.ts +20 -0
- package/dist/chunk-2PRQG7PV.js.map +0 -1
- package/dist/chunk-4GNEDXDI.js.map +0 -1
- package/dist/chunk-FKCRGLRD.js.map +0 -1
- package/dist/chunk-H2DXDQCQ.js.map +0 -1
- package/dist/chunk-K5LLP4CY.js.map +0 -1
- package/dist/chunk-LADFWYHY.js.map +0 -1
- package/dist/chunk-OUELRE5E.js.map +0 -1
- package/dist/chunk-PCLIWBGD.js.map +0 -1
- package/dist/chunk-SVOHGUMI.js.map +0 -1
- package/dist/chunk-UFUKHGZD.js.map +0 -1
- package/dist/chunk-XCL57M6Q.js.map +0 -1
- package/dist/types-gb_SNtjR.d.ts +0 -85
- /package/dist/{chunk-PNLFN2PZ.js.map → chunk-23G3T2Q5.js.map} +0 -0
- /package/dist/{chunk-SIRPLF54.js.map → chunk-2K3OSLHE.js.map} +0 -0
- /package/dist/{chunk-LQHDIS7L.js.map → chunk-54BGIBCR.js.map} +0 -0
- /package/dist/{chunk-PVUJ6WVV.js.map → chunk-5MH5NF3U.js.map} +0 -0
- /package/dist/{chunk-Y7UNNAZD.js.map → chunk-7ZYBDQ7V.js.map} +0 -0
- /package/dist/{chunk-LR5DZ56F.js.map → chunk-AXALUFAH.js.map} +0 -0
- /package/dist/{chunk-AYZJID4S.js.map → chunk-B5GBWBCZ.js.map} +0 -0
- /package/dist/{chunk-TLUDFPZL.js.map → chunk-CAZ3Z5M6.js.map} +0 -0
- /package/dist/{chunk-RGK27ELN.js.map → chunk-DEKIXXIG.js.map} +0 -0
- /package/dist/{chunk-2KK5WNQB.js.map → chunk-DQ42IQSK.js.map} +0 -0
- /package/dist/{chunk-HOJZMQ4J.js.map → chunk-FGDKJJZS.js.map} +0 -0
- /package/dist/{chunk-ABP6QMVM.js.map → chunk-FQ7HAWWC.js.map} +0 -0
- /package/dist/{chunk-CYWA2CXR.js.map → chunk-FVTLSFWU.js.map} +0 -0
- /package/dist/{chunk-JJEJJ7RK.js.map → chunk-FXZTL7F7.js.map} +0 -0
- /package/dist/{chunk-DANV2HTH.js.map → chunk-GQGDRLDM.js.map} +0 -0
- /package/dist/{chunk-7F7Z6MOS.js.map → chunk-H4CKS5B2.js.map} +0 -0
- /package/dist/{chunk-CKITWVWJ.js.map → chunk-HSSERO3E.js.map} +0 -0
- /package/dist/{chunk-23JFRB73.js.map → chunk-JODHPNLN.js.map} +0 -0
- /package/dist/{chunk-DS7MM2ES.js.map → chunk-JZKR6ZAV.js.map} +0 -0
- /package/dist/{chunk-BEM4D2QG.js.map → chunk-KJIJNLXT.js.map} +0 -0
- /package/dist/{chunk-JSNVWNGX.js.map → chunk-KVSVVKHA.js.map} +0 -0
- /package/dist/{chunk-MC4FJXPA.js.map → chunk-MMACM5G2.js.map} +0 -0
- /package/dist/{chunk-3XIY7MDQ.js.map → chunk-O6YI4CVI.js.map} +0 -0
- /package/dist/{chunk-72WG5QKN.js.map → chunk-SDAXPXER.js.map} +0 -0
- /package/dist/{chunk-4LV23CHK.js.map → chunk-VHJARF5R.js.map} +0 -0
- /package/dist/{chunk-6MMONPHM.js.map → chunk-W2AHSCKY.js.map} +0 -0
- /package/dist/{chunk-P454KXD6.js.map → chunk-YAWJMR3Y.js.map} +0 -0
package/src/access-http.test.ts
CHANGED
|
@@ -2585,3 +2585,132 @@ test("HTTP chat/message gates the NEW session's namespace — scoped token canno
|
|
|
2585
2585
|
await rm(dir, { recursive: true, force: true });
|
|
2586
2586
|
}
|
|
2587
2587
|
});
|
|
2588
|
+
|
|
2589
|
+
// ---------------------------------------------------------------------------
|
|
2590
|
+
// PR #1852: token-rotation race — authorized entry must be reused for provenance
|
|
2591
|
+
// ---------------------------------------------------------------------------
|
|
2592
|
+
|
|
2593
|
+
test("PR #1852: token rotation between authorization and write does not stamp the wrong connector", async () => {
|
|
2594
|
+
// Race: the dynamic-token authorization resolves an entry (connector A),
|
|
2595
|
+
// then the provenance resolver re-reads the token store. If the store
|
|
2596
|
+
// rotated between the two reads, the OLD code stamped connector B. The
|
|
2597
|
+
// fix caches the matched entry per-request so the provenance comes from
|
|
2598
|
+
// the SAME entry that authorized.
|
|
2599
|
+
let getterCalls = 0;
|
|
2600
|
+
const entriesGetter = () => {
|
|
2601
|
+
getterCalls++;
|
|
2602
|
+
// First call (authorization): token -> "chatgpt".
|
|
2603
|
+
// Subsequent call (provenance in the OLD code): token -> "codex-cli".
|
|
2604
|
+
// With the fix the getter is called only once; the second call never
|
|
2605
|
+
// happens and the cached "chatgpt" entry is reused.
|
|
2606
|
+
if (getterCalls <= 1) {
|
|
2607
|
+
return [{ token: "race_token", connector: "chatgpt" }];
|
|
2608
|
+
}
|
|
2609
|
+
return [{ token: "race_token", connector: "codex-cli" }];
|
|
2610
|
+
};
|
|
2611
|
+
|
|
2612
|
+
let capturedSourceConnector: string | undefined;
|
|
2613
|
+
const service = {
|
|
2614
|
+
memoryStore: (req: { sourceConnector?: string }) => {
|
|
2615
|
+
capturedSourceConnector = req.sourceConnector;
|
|
2616
|
+
return Promise.resolve({
|
|
2617
|
+
schemaVersion: 1,
|
|
2618
|
+
operation: "memory_store",
|
|
2619
|
+
namespace: "default",
|
|
2620
|
+
dryRun: false,
|
|
2621
|
+
accepted: true,
|
|
2622
|
+
queued: false,
|
|
2623
|
+
status: "stored",
|
|
2624
|
+
});
|
|
2625
|
+
},
|
|
2626
|
+
} as unknown as EngramAccessService;
|
|
2627
|
+
|
|
2628
|
+
const server = new EngramAccessHttpServer({
|
|
2629
|
+
service,
|
|
2630
|
+
port: 0,
|
|
2631
|
+
authTokenEntriesGetter: entriesGetter,
|
|
2632
|
+
adminConsoleEnabled: false,
|
|
2633
|
+
});
|
|
2634
|
+
const status = await server.start();
|
|
2635
|
+
try {
|
|
2636
|
+
const res = await fetch(`http://127.0.0.1:${status.port}/engram/v1/memories`, {
|
|
2637
|
+
method: "POST",
|
|
2638
|
+
headers: {
|
|
2639
|
+
authorization: "Bearer race_token",
|
|
2640
|
+
"content-type": "application/json",
|
|
2641
|
+
},
|
|
2642
|
+
body: JSON.stringify({
|
|
2643
|
+
content: "race-test memory",
|
|
2644
|
+
schemaVersion: 1,
|
|
2645
|
+
idempotencyKey: "race-key-1852",
|
|
2646
|
+
}),
|
|
2647
|
+
});
|
|
2648
|
+
assert.equal(res.status, 201, "memory_store must succeed with a valid entry token");
|
|
2649
|
+
|
|
2650
|
+
// The provenance must come from the entry that AUTHORIZED the request
|
|
2651
|
+
// ("chatgpt"), not from the rotated store ("codex-cli").
|
|
2652
|
+
assert.equal(
|
|
2653
|
+
capturedSourceConnector,
|
|
2654
|
+
"chatgpt",
|
|
2655
|
+
"sourceConnector must be from the authorized entry, not the rotated store",
|
|
2656
|
+
);
|
|
2657
|
+
// The getter must have been called only once — the matched entry is
|
|
2658
|
+
// cached per-request.
|
|
2659
|
+
assert.equal(getterCalls, 1, "authTokenEntriesGetter must be called once (cached per-request)");
|
|
2660
|
+
} finally {
|
|
2661
|
+
await server.stop();
|
|
2662
|
+
}
|
|
2663
|
+
});
|
|
2664
|
+
|
|
2665
|
+
test("PR #1852: static operator token has no connector provenance under rotation", async () => {
|
|
2666
|
+
// An operator-supplied static token must never acquire connector provenance,
|
|
2667
|
+
// even when an entries getter is also configured and the static token
|
|
2668
|
+
// appears there under a different connector. This guards the short-circuit
|
|
2669
|
+
// in resolveMatchedEntry: static tokens return { token } (no connector).
|
|
2670
|
+
let capturedSourceConnector: string | undefined;
|
|
2671
|
+
const service = {
|
|
2672
|
+
memoryStore: (req: { sourceConnector?: string }) => {
|
|
2673
|
+
capturedSourceConnector = req.sourceConnector;
|
|
2674
|
+
return Promise.resolve({
|
|
2675
|
+
schemaVersion: 1,
|
|
2676
|
+
operation: "memory_store",
|
|
2677
|
+
namespace: "default",
|
|
2678
|
+
dryRun: false,
|
|
2679
|
+
accepted: true,
|
|
2680
|
+
queued: false,
|
|
2681
|
+
status: "stored",
|
|
2682
|
+
});
|
|
2683
|
+
},
|
|
2684
|
+
} as unknown as EngramAccessService;
|
|
2685
|
+
|
|
2686
|
+
const server = new EngramAccessHttpServer({
|
|
2687
|
+
service,
|
|
2688
|
+
port: 0,
|
|
2689
|
+
authToken: "operator-static",
|
|
2690
|
+
authTokenEntriesGetter: () => [{ token: "operator-static", connector: "chatgpt" }],
|
|
2691
|
+
adminConsoleEnabled: false,
|
|
2692
|
+
});
|
|
2693
|
+
const status = await server.start();
|
|
2694
|
+
try {
|
|
2695
|
+
const res = await fetch(`http://127.0.0.1:${status.port}/engram/v1/memories`, {
|
|
2696
|
+
method: "POST",
|
|
2697
|
+
headers: {
|
|
2698
|
+
authorization: "Bearer operator-static",
|
|
2699
|
+
"content-type": "application/json",
|
|
2700
|
+
},
|
|
2701
|
+
body: JSON.stringify({
|
|
2702
|
+
content: "operator-token memory",
|
|
2703
|
+
schemaVersion: 1,
|
|
2704
|
+
idempotencyKey: "static-key-1852",
|
|
2705
|
+
}),
|
|
2706
|
+
});
|
|
2707
|
+
assert.equal(res.status, 201);
|
|
2708
|
+
assert.equal(
|
|
2709
|
+
capturedSourceConnector,
|
|
2710
|
+
undefined,
|
|
2711
|
+
"static operator token must carry no connector provenance",
|
|
2712
|
+
);
|
|
2713
|
+
} finally {
|
|
2714
|
+
await server.stop();
|
|
2715
|
+
}
|
|
2716
|
+
});
|
package/src/access-http.ts
CHANGED
|
@@ -1566,6 +1566,9 @@ export class EngramAccessHttpServer {
|
|
|
1566
1566
|
// Forward cwd/projectTag for auto git-context resolution (issue #569).
|
|
1567
1567
|
cwd: body.cwd,
|
|
1568
1568
|
projectTag: body.projectTag,
|
|
1569
|
+
// Phase 1 provenance: server-resolved connector identity from the
|
|
1570
|
+
// bearer token (REST path, mirroring the MCP tools/call dispatch).
|
|
1571
|
+
sourceConnector: this.resolveConnector(req),
|
|
1569
1572
|
},
|
|
1570
1573
|
// Enforce the write-quota INSIDE the service's idempotency lock
|
|
1571
1574
|
// (beforeExecute, only on a real miss). A retried observe that hits the
|
|
@@ -1663,6 +1666,9 @@ export class EngramAccessHttpServer {
|
|
|
1663
1666
|
service: this.service,
|
|
1664
1667
|
authenticatedPrincipal: this.resolveRequestPrincipal(req),
|
|
1665
1668
|
hooks: { enforceWriteQuota: () => this.ensureWriteRateLimitAvailable() },
|
|
1669
|
+
// Phase 1 provenance: server-resolved connector identity from the
|
|
1670
|
+
// bearer token (REST path, mirroring the MCP tools/call dispatch).
|
|
1671
|
+
sourceConnector: this.resolveConnector(req),
|
|
1666
1672
|
})) as { result: EngramAccessWriteResponse };
|
|
1667
1673
|
const response = output.result;
|
|
1668
1674
|
if (this.shouldCountWriteRateLimit(response as { dryRun?: boolean; idempotencyReplay?: boolean })) {
|
|
@@ -1693,6 +1699,7 @@ export class EngramAccessHttpServer {
|
|
|
1693
1699
|
const output = (await op.run(this.gatedBodyNamespace(req, body), {
|
|
1694
1700
|
service: this.service,
|
|
1695
1701
|
authenticatedPrincipal: this.resolveRequestPrincipal(req),
|
|
1702
|
+
sourceConnector: this.resolveConnector(req),
|
|
1696
1703
|
})) as { result: unknown };
|
|
1697
1704
|
if (isWriteSubcommand) {
|
|
1698
1705
|
this.recordWriteRateLimitHit();
|
|
@@ -1717,6 +1724,7 @@ export class EngramAccessHttpServer {
|
|
|
1717
1724
|
const output = (await op.run(this.gatedBodyNamespace(req, body), {
|
|
1718
1725
|
service: this.service,
|
|
1719
1726
|
authenticatedPrincipal: this.resolveRequestPrincipal(req),
|
|
1727
|
+
sourceConnector: this.resolveConnector(req),
|
|
1720
1728
|
})) as { result: unknown };
|
|
1721
1729
|
if (isWriteSubcommand) {
|
|
1722
1730
|
this.recordWriteRateLimitHit();
|
|
@@ -1824,6 +1832,9 @@ export class EngramAccessHttpServer {
|
|
|
1824
1832
|
sourceReason: body.sourceReason,
|
|
1825
1833
|
cwd: body.cwd,
|
|
1826
1834
|
projectTag: body.projectTag,
|
|
1835
|
+
// Phase 1 provenance: server-resolved connector identity from the
|
|
1836
|
+
// bearer token (REST path, mirroring the MCP tools/call dispatch).
|
|
1837
|
+
sourceConnector: this.resolveConnector(req),
|
|
1827
1838
|
};
|
|
1828
1839
|
// Quota enforcement is solely authoritative inside suggestionSubmit
|
|
1829
1840
|
// (enforceWriteQuota), atomic with the real miss and never on a replay; no
|
|
@@ -3106,6 +3117,7 @@ export class EngramAccessHttpServer {
|
|
|
3106
3117
|
enforceWriteQuota: observeSelfEnforcesQuota
|
|
3107
3118
|
? () => this.ensureWriteRateLimitAvailable()
|
|
3108
3119
|
: undefined,
|
|
3120
|
+
sourceConnector: this.resolveConnector(req),
|
|
3109
3121
|
});
|
|
3110
3122
|
|
|
3111
3123
|
if (isMcpWrite && response !== null) {
|
|
@@ -3446,13 +3458,44 @@ export class EngramAccessHttpServer {
|
|
|
3446
3458
|
}
|
|
3447
3459
|
|
|
3448
3460
|
/**
|
|
3449
|
-
*
|
|
3450
|
-
*
|
|
3451
|
-
*
|
|
3452
|
-
*
|
|
3453
|
-
* the
|
|
3461
|
+
* Per-request cache of the matched token entry (the entry whose token
|
|
3462
|
+
* matched the bearer credential, BEFORE any path-policy check). Pinning
|
|
3463
|
+
* the entry to the first read means authorization, capability
|
|
3464
|
+
* enforcement, and connector provenance all observe the SAME token-store
|
|
3465
|
+
* snapshot — a rotation between the auth check and the write handler can
|
|
3466
|
+
* no longer stamp the wrong connector (PR #1852 race).
|
|
3454
3467
|
*/
|
|
3455
|
-
private
|
|
3468
|
+
private matchedEntryCache = new WeakMap<
|
|
3469
|
+
IncomingMessage,
|
|
3470
|
+
{ token: string; connector?: string; capabilities?: TokenCapabilities } | null
|
|
3471
|
+
>();
|
|
3472
|
+
|
|
3473
|
+
/**
|
|
3474
|
+
* Resolve the matched token entry for this request, caching the result so
|
|
3475
|
+
* every downstream consumer (authorization, capability enforcement,
|
|
3476
|
+
* connector provenance) sees the same snapshot entry (PR #1852).
|
|
3477
|
+
*/
|
|
3478
|
+
private resolveMatchedEntry(
|
|
3479
|
+
req: IncomingMessage,
|
|
3480
|
+
pathname?: string,
|
|
3481
|
+
): { token: string; connector?: string; capabilities?: TokenCapabilities } | null {
|
|
3482
|
+
if (this.matchedEntryCache.has(req)) {
|
|
3483
|
+
return this.matchedEntryCache.get(req) ?? null;
|
|
3484
|
+
}
|
|
3485
|
+
const entry = this.computeMatchedEntry(req, pathname);
|
|
3486
|
+
this.matchedEntryCache.set(req, entry);
|
|
3487
|
+
return entry;
|
|
3488
|
+
}
|
|
3489
|
+
|
|
3490
|
+
/**
|
|
3491
|
+
* Find the entry whose token matches the request's bearer credential.
|
|
3492
|
+
* Static operator tokens (`authToken`/`authTokens`) and the string-token
|
|
3493
|
+
* getter carry no capabilities ⇒ unrestricted. Dynamic entry-based tokens
|
|
3494
|
+
* capture connector identity and capabilities. A corrupt or unreadable
|
|
3495
|
+
* token store returns null rather than propagating an error — provenance
|
|
3496
|
+
* must never block an already-authenticated request.
|
|
3497
|
+
*/
|
|
3498
|
+
private computeMatchedEntry(
|
|
3456
3499
|
req: IncomingMessage,
|
|
3457
3500
|
pathname?: string,
|
|
3458
3501
|
): { token: string; connector?: string; capabilities?: TokenCapabilities } | null {
|
|
@@ -3513,13 +3556,13 @@ export class EngramAccessHttpServer {
|
|
|
3513
3556
|
// identity it scopes (mint/revoke coherence). Capabilities ride on the
|
|
3514
3557
|
// same entry so enforcement can never lag the token that validated.
|
|
3515
3558
|
if (this.authTokenEntriesGetter) {
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3559
|
+
try {
|
|
3560
|
+
for (const entry of this.authTokenEntriesGetter()) {
|
|
3561
|
+
if (!this.timingSafeStringEqual(token, entry.token)) continue;
|
|
3562
|
+
return { token: entry.token, connector: entry.connector, capabilities: entry.capabilities };
|
|
3563
|
+
}
|
|
3564
|
+
} catch {
|
|
3565
|
+
// Corrupt or unreadable tokens.json — no match.
|
|
3523
3566
|
}
|
|
3524
3567
|
return null;
|
|
3525
3568
|
}
|
|
@@ -3533,25 +3576,40 @@ export class EngramAccessHttpServer {
|
|
|
3533
3576
|
return null;
|
|
3534
3577
|
}
|
|
3535
3578
|
|
|
3536
|
-
/**
|
|
3537
|
-
|
|
3579
|
+
/**
|
|
3580
|
+
* Resolve the presenting token's entry for an authorized request, or null.
|
|
3581
|
+
* Applies the path-policy gate (if configured) on top of the per-request
|
|
3582
|
+
* cached matched entry so the identity that is authorized is the same one
|
|
3583
|
+
* whose connector later stamps frontmatter. Static operator tokens and the
|
|
3584
|
+
* string-token getter carry no capabilities ⇒ unrestricted.
|
|
3585
|
+
*/
|
|
3586
|
+
private resolveAuthorizedEntry(
|
|
3587
|
+
req: IncomingMessage,
|
|
3588
|
+
pathname?: string,
|
|
3589
|
+
): { token: string; connector?: string; capabilities?: TokenCapabilities } | null {
|
|
3590
|
+
const matched = this.resolveMatchedEntry(req, pathname);
|
|
3591
|
+
if (!matched) return null;
|
|
3592
|
+
// Apply the path-policy gate for dynamic entry-based tokens.
|
|
3593
|
+
if ("connector" in matched && this.tokenPathPolicy) {
|
|
3594
|
+
// Fail closed: a policy without a connector identity denies.
|
|
3595
|
+
if (typeof matched.connector !== "string" || matched.connector.length === 0) return null;
|
|
3596
|
+
return this.tokenPathPolicy(matched.connector, pathname) ? matched : null;
|
|
3597
|
+
}
|
|
3598
|
+
return matched;
|
|
3599
|
+
}
|
|
3538
3600
|
|
|
3539
3601
|
/**
|
|
3540
3602
|
* Resolve the presenting token's capabilities for this request, or
|
|
3541
3603
|
* undefined when the token is unrestricted (legacy / static operator /
|
|
3542
|
-
* explicit-unrestricted record).
|
|
3543
|
-
*
|
|
3604
|
+
* explicit-unrestricted record). Reads from the per-request cached matched
|
|
3605
|
+
* entry so capabilities come from the same snapshot as authorization and
|
|
3606
|
+
* connector provenance (PR #1852).
|
|
3544
3607
|
*/
|
|
3545
3608
|
private resolveTokenCapabilities(
|
|
3546
3609
|
req: IncomingMessage,
|
|
3547
3610
|
pathname?: string,
|
|
3548
3611
|
): TokenCapabilities | undefined {
|
|
3549
|
-
|
|
3550
|
-
return this.capabilityCache.get(req) ?? undefined;
|
|
3551
|
-
}
|
|
3552
|
-
const caps = this.resolveAuthorizedEntry(req, pathname)?.capabilities;
|
|
3553
|
-
this.capabilityCache.set(req, caps ?? null);
|
|
3554
|
-
return caps;
|
|
3612
|
+
return this.resolveMatchedEntry(req, pathname)?.capabilities;
|
|
3555
3613
|
}
|
|
3556
3614
|
|
|
3557
3615
|
/**
|
|
@@ -3578,6 +3636,17 @@ export class EngramAccessHttpServer {
|
|
|
3578
3636
|
);
|
|
3579
3637
|
}
|
|
3580
3638
|
}
|
|
3639
|
+
/**
|
|
3640
|
+
* Resolve the connector identity for the request's bearer token (Phase 1
|
|
3641
|
+
* provenance). Reuses the per-request cached matched entry so a token
|
|
3642
|
+
* rotation between the auth check and the write handler cannot stamp the
|
|
3643
|
+
* wrong connector (PR #1852 race). Returns `undefined` for operator-
|
|
3644
|
+
* supplied static tokens or when no entry getter is configured — those
|
|
3645
|
+
* writes are operator-initiated.
|
|
3646
|
+
*/
|
|
3647
|
+
private resolveConnector(req: IncomingMessage): string | undefined {
|
|
3648
|
+
return this.resolveMatchedEntry(req)?.connector;
|
|
3649
|
+
}
|
|
3581
3650
|
|
|
3582
3651
|
private timingSafeStringEqual(a: string, b: string): boolean {
|
|
3583
3652
|
const left = this.encodeSecret(a);
|
package/src/access-mcp.ts
CHANGED
|
@@ -61,6 +61,12 @@ type McpRequestOptions = {
|
|
|
61
61
|
* the write-rate-limit window); the standalone MCP server has no quota.
|
|
62
62
|
*/
|
|
63
63
|
enforceWriteQuota?: () => void | Promise<void>;
|
|
64
|
+
/**
|
|
65
|
+
* Server-resolved connector identity (Phase 1 provenance). Set by the HTTP
|
|
66
|
+
* auth boundary from the matched token entry's connector; threaded into
|
|
67
|
+
* the operation context so write handlers stamp it onto frontmatter.
|
|
68
|
+
*/
|
|
69
|
+
sourceConnector?: string;
|
|
64
70
|
};
|
|
65
71
|
|
|
66
72
|
type McpTool = {
|
|
@@ -2645,7 +2651,8 @@ export class EngramMcpServer {
|
|
|
2645
2651
|
effectivePrincipal,
|
|
2646
2652
|
options?.sessionId,
|
|
2647
2653
|
mcpScope,
|
|
2648
|
-
options?.enforceWriteQuota
|
|
2654
|
+
options?.enforceWriteQuota,
|
|
2655
|
+
options?.sourceConnector
|
|
2649
2656
|
);
|
|
2650
2657
|
return {
|
|
2651
2658
|
jsonrpc: "2.0",
|
|
@@ -2853,7 +2860,8 @@ export class EngramMcpServer {
|
|
|
2853
2860
|
effectivePrincipal?: string,
|
|
2854
2861
|
mcpSessionId?: string,
|
|
2855
2862
|
scope?: { namespace?: string; sessionKey?: string },
|
|
2856
|
-
enforceWriteQuota?: () => void | Promise<void
|
|
2863
|
+
enforceWriteQuota?: () => void | Promise<void>,
|
|
2864
|
+
sourceConnector?: string,
|
|
2857
2865
|
): Promise<unknown> {
|
|
2858
2866
|
const migrated = MCP_MIGRATED_OPERATIONS[toLegacyToolName(name)];
|
|
2859
2867
|
if (!migrated) {
|
|
@@ -2952,6 +2960,7 @@ export class EngramMcpServer {
|
|
|
2952
2960
|
service: this.service,
|
|
2953
2961
|
authenticatedPrincipal: effectivePrincipal,
|
|
2954
2962
|
...(enforceWriteQuota ? { hooks: { enforceWriteQuota } } : {}),
|
|
2963
|
+
...(sourceConnector ? { sourceConnector } : {}),
|
|
2955
2964
|
})) as { result: unknown };
|
|
2956
2965
|
return output.result;
|
|
2957
2966
|
}
|