@remnic/core 9.3.654 → 9.3.656
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-cli.js +29 -29
- package/dist/access-http.d.ts +4 -4
- package/dist/access-http.js +17 -17
- package/dist/access-mcp.d.ts +4 -4
- package/dist/access-mcp.js +16 -16
- package/dist/access-schema.d.ts +10 -10
- package/dist/{access-service-C8A5hoXJ.d.ts → access-service-D_nbpexW.d.ts} +33 -2
- package/dist/access-service.d.ts +4 -4
- package/dist/access-service.js +15 -15
- 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/behavior-learner.d.ts +1 -1
- package/dist/behavior-signals.d.ts +1 -1
- package/dist/bootstrap.d.ts +3 -3
- package/dist/briefing.d.ts +1 -1
- package/dist/briefing.js +3 -3
- package/dist/buffer-surprise-report.d.ts +1 -1
- package/dist/buffer.d.ts +1 -1
- package/dist/calibration.d.ts +1 -1
- package/dist/causal-behavior.d.ts +1 -1
- package/dist/causal-consolidation.d.ts +1 -1
- package/dist/causal-consolidation.js +4 -4
- package/dist/{chunk-JMQSYGXS.js → chunk-2BD7DG37.js} +2 -2
- package/dist/{chunk-FVRBLJP6.js → chunk-2MXEVL75.js} +2 -2
- package/dist/{chunk-LJCEWTG3.js → chunk-4UL7VPTD.js} +277 -58
- package/dist/chunk-4UL7VPTD.js.map +1 -0
- package/dist/{chunk-JYN7QNTA.js → chunk-54XF2FY7.js} +17 -17
- package/dist/{chunk-7WEB3FLJ.js → chunk-5PLUC5OB.js} +2 -2
- package/dist/{chunk-JX2RINDR.js → chunk-6G5JEN55.js} +2 -2
- package/dist/{chunk-ZCORQM74.js → chunk-AGJKWOKV.js} +2 -2
- package/dist/{chunk-NE2JBMLN.js → chunk-AZBV4RRY.js} +1 -1
- package/dist/chunk-AZBV4RRY.js.map +1 -0
- package/dist/{chunk-YLZLPVKK.js → chunk-CTAV55JM.js} +344 -1
- package/dist/chunk-CTAV55JM.js.map +1 -0
- package/dist/{chunk-2DSTAWNZ.js → chunk-DIBWFCLA.js} +3 -3
- package/dist/{chunk-NAZWHTYV.js → chunk-DR67OK4E.js} +5 -5
- package/dist/{chunk-XBIACVCO.js → chunk-EC2AYKRX.js} +2 -2
- package/dist/{chunk-JVRPJ7D4.js → chunk-EKQMQQ3U.js} +48 -12
- package/dist/chunk-EKQMQQ3U.js.map +1 -0
- package/dist/{chunk-RGPUQ66K.js → chunk-GCYFUTUC.js} +2 -2
- package/dist/{chunk-JBHXMCYN.js → chunk-GRYAECRV.js} +2 -2
- package/dist/{chunk-BJA6DQOC.js → chunk-GSHW5VVD.js} +5 -5
- package/dist/chunk-GYSYLGNE.js +650 -0
- package/dist/chunk-GYSYLGNE.js.map +1 -0
- package/dist/{chunk-NCGWXCSW.js → chunk-IOZ5WBWD.js} +2 -2
- package/dist/{chunk-QKK64Z6M.js → chunk-JSVFEHLL.js} +7 -5
- package/dist/chunk-JSVFEHLL.js.map +1 -0
- package/dist/{chunk-7LWRCOP7.js → chunk-LZTFCAKE.js} +2 -2
- package/dist/{chunk-2DGQLOOM.js → chunk-M3VYPE2H.js} +1 -1
- package/dist/{chunk-2DGQLOOM.js.map → chunk-M3VYPE2H.js.map} +1 -1
- package/dist/{chunk-6CVI6BP6.js → chunk-NXCK7DO7.js} +2 -2
- package/dist/{chunk-Z5MQI7K2.js → chunk-PEPHBH2W.js} +2 -2
- package/dist/{chunk-PYWNNF2I.js → chunk-QRSKPI62.js} +99 -66
- package/dist/chunk-QRSKPI62.js.map +1 -0
- package/dist/{chunk-XWQ6ERUG.js → chunk-QZRKNA5F.js} +2 -2
- package/dist/{chunk-PS3SYNHP.js → chunk-R5DB26G6.js} +2 -2
- package/dist/{chunk-OL2364SB.js → chunk-RDW5G6DO.js} +1502 -335
- package/dist/chunk-RDW5G6DO.js.map +1 -0
- package/dist/{chunk-YM3LR4LS.js → chunk-SSSXWIBP.js} +5 -5
- package/dist/{chunk-T2C6QJG2.js → chunk-SWDHVH2P.js} +2 -2
- package/dist/{chunk-DBM2BD22.js → chunk-SXYCVRLK.js} +3 -3
- package/dist/{chunk-K6X553JB.js → chunk-TFFZUFEP.js} +7 -5
- package/dist/chunk-TFFZUFEP.js.map +1 -0
- package/dist/{chunk-ENV6RDTD.js → chunk-TIJYQXDI.js} +2 -2
- package/dist/{chunk-BP2EV6W5.js → chunk-VAEAGTEQ.js} +4 -4
- package/dist/{chunk-3RACUBII.js → chunk-WIKMCJUR.js} +2 -2
- package/dist/{chunk-QW6JZO5P.js → chunk-WWMHAMAY.js} +2 -2
- package/dist/{chunk-GPW2E4LN.js → chunk-YEZHZCUO.js} +4 -4
- package/dist/{chunk-5FOCXX5E.js → chunk-YVVQUAOO.js} +3 -3
- package/dist/{chunk-5FOCXX5E.js.map → chunk-YVVQUAOO.js.map} +1 -1
- package/dist/{chunk-3XGWCZ63.js → chunk-YXLT4EMM.js} +2 -2
- package/dist/{chunk-Y2RIIF6H.js → chunk-Z6UDTNY6.js} +2 -2
- package/dist/{cli-uQgvDFNE.d.ts → cli-aYxSuPvP.d.ts} +3 -3
- package/dist/cli.d.ts +5 -5
- package/dist/cli.js +29 -29
- package/dist/compounding/engine.d.ts +1 -1
- package/dist/compounding/engine.js +3 -3
- 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 +3 -3
- package/dist/connectors/codex-materialize.d.ts +1 -1
- package/dist/connectors/index.d.ts +1 -1
- package/dist/connectors/index.js +3 -3
- package/dist/consolidation-provenance-check.d.ts +1 -1
- package/dist/consolidation-undo.d.ts +1 -1
- package/dist/contradiction/index.d.ts +1 -1
- package/dist/conversation-index/backend.d.ts +1 -1
- 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/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 +1 -1
- package/dist/entity-retrieval.js +3 -3
- package/dist/entity-schema.d.ts +1 -1
- package/dist/explicit-capture.d.ts +3 -3
- package/dist/explicit-cue-recall.js +2 -2
- 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.d.ts +1 -1
- package/dist/fallback-llm.d.ts +1 -1
- package/dist/focused-list-recall.js +2 -2
- package/dist/identity-continuity.d.ts +1 -1
- package/dist/importance.d.ts +1 -1
- package/dist/index.d.ts +121 -121
- package/dist/index.js +39 -39
- package/dist/intent.d.ts +1 -1
- package/dist/lcm/engine.d.ts +1 -1
- package/dist/lcm/index.d.ts +1 -1
- package/dist/lcm/tools.d.ts +1 -1
- package/dist/lcm-fallback-read.js +1 -1
- package/dist/lifecycle.d.ts +1 -1
- package/dist/live-connectors-runner.d.ts +1 -1
- package/dist/local-llm.d.ts +1 -1
- package/dist/maintenance/memory-governance.d.ts +1 -1
- 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 +4 -4
- package/dist/memory-action-policy.d.ts +1 -1
- package/dist/memory-cache.d.ts +1 -1
- 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 +1 -1
- package/dist/models-json.d.ts +1 -1
- package/dist/namespaces/migrate.d.ts +1 -1
- package/dist/namespaces/migrate.js +11 -11
- package/dist/namespaces/principal.d.ts +1 -1
- package/dist/namespaces/search.d.ts +15 -4
- package/dist/namespaces/search.js +7 -7
- package/dist/namespaces/storage.d.ts +1 -1
- package/dist/namespaces/storage.js +3 -3
- package/dist/native-knowledge.d.ts +1 -1
- package/dist/operator-toolkit.d.ts +1 -1
- package/dist/operator-toolkit.js +14 -14
- package/dist/{orchestrator-B4Y4sWQH.d.ts → orchestrator-D1wcmPNj.d.ts} +17 -14
- package/dist/orchestrator.d.ts +3 -3
- package/dist/orchestrator.js +25 -25
- package/dist/patterns-cli.d.ts +1 -1
- package/dist/policy-runtime.d.ts +1 -1
- package/dist/qmd-recall-cache.d.ts +1 -1
- package/dist/qmd.d.ts +5 -1
- package/dist/qmd.js +2 -2
- 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-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-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/resolve-auth-token.d.ts +1 -1
- package/dist/response-guidance-recall.js +2 -2
- package/dist/resume-bundles.js +2 -2
- package/dist/retrieval-agents.d.ts +1 -1
- 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/schemas.d.ts +22 -22
- package/dist/search/embed-helper.d.ts +1 -1
- package/dist/search/factory.d.ts +1 -1
- package/dist/search/factory.js +6 -6
- package/dist/search/index.d.ts +1 -1
- package/dist/search/index.js +6 -6
- package/dist/search/lancedb-backend.d.ts +1 -1
- package/dist/search/lancedb-backend.js +2 -2
- package/dist/search/meilisearch-backend.d.ts +1 -1
- package/dist/search/meilisearch-backend.js +2 -2
- package/dist/search/noop-backend.d.ts +1 -1
- package/dist/search/orama-backend.d.ts +1 -1
- package/dist/search/orama-backend.js +2 -2
- package/dist/search/port.d.ts +17 -1
- package/dist/search/port.js +1 -1
- package/dist/search/remote-backend.d.ts +1 -1
- package/dist/{semantic-consolidation-BKd0Pype.d.ts → semantic-consolidation-MWOdNtSE.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +2 -2
- package/dist/semantic-consolidation.js +4 -4
- package/dist/semantic-rule-promotion.js +3 -3
- package/dist/semantic-rule-verifier.d.ts +3 -2
- package/dist/semantic-rule-verifier.js +5 -3
- 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.d.ts +1 -1
- package/dist/storage.js +2 -2
- package/dist/summarizer.d.ts +1 -1
- package/dist/summary-snapshot.d.ts +1 -1
- package/dist/targeted-fact-recall.js +2 -2
- package/dist/temporal-supersession.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 +1 -1
- package/dist/tier-routing.d.ts +1 -1
- package/dist/topics.d.ts +1 -1
- package/dist/transcript.d.ts +1 -1
- package/dist/transfer/types.d.ts +12 -12
- package/dist/{types-BgChEr0M.d.ts → types-CgcCpUrf.d.ts} +51 -1
- 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.d.ts +2 -1
- package/dist/verified-recall.js +5 -3
- package/package.json +1 -1
- package/src/access-service-observe-lcm-parity.test.ts +86 -1
- package/src/access-service-observe-scope.test.ts +283 -1
- package/src/access-service-raw-excerpt-read-gate.test.ts +53 -0
- package/src/access-service.ts +391 -93
- package/src/coding/coding-namespace.ts +0 -3
- package/src/config.test.ts +69 -0
- package/src/config.ts +417 -0
- package/src/lcm-fallback-read.ts +2 -6
- package/src/maintenance/namespace-planner.test.ts +1120 -0
- package/src/maintenance/namespace-planner.ts +893 -0
- package/src/namespaces/scope-profiles.test.ts +1074 -0
- package/src/namespaces/scope-profiles.ts +456 -0
- package/src/namespaces/search.test.ts +130 -2
- package/src/namespaces/search.ts +71 -10
- package/src/orchestrator-flush.test.ts +606 -44
- package/src/orchestrator-source-attribution.test.ts +73 -0
- package/src/orchestrator.ts +932 -229
- package/src/qmd-client.test.ts +59 -0
- package/src/qmd.ts +124 -84
- package/src/search/port.ts +16 -0
- package/src/semantic-rule-verifier.ts +13 -6
- package/src/types.ts +64 -0
- package/src/verified-recall.ts +10 -6
- package/dist/chunk-JVRPJ7D4.js.map +0 -1
- package/dist/chunk-K6X553JB.js.map +0 -1
- package/dist/chunk-LJCEWTG3.js.map +0 -1
- package/dist/chunk-MMJANTJX.js +0 -339
- package/dist/chunk-MMJANTJX.js.map +0 -1
- package/dist/chunk-NE2JBMLN.js.map +0 -1
- package/dist/chunk-OL2364SB.js.map +0 -1
- package/dist/chunk-PYWNNF2I.js.map +0 -1
- package/dist/chunk-QKK64Z6M.js.map +0 -1
- package/dist/chunk-YLZLPVKK.js.map +0 -1
- /package/dist/{chunk-JMQSYGXS.js.map → chunk-2BD7DG37.js.map} +0 -0
- /package/dist/{chunk-FVRBLJP6.js.map → chunk-2MXEVL75.js.map} +0 -0
- /package/dist/{chunk-JYN7QNTA.js.map → chunk-54XF2FY7.js.map} +0 -0
- /package/dist/{chunk-7WEB3FLJ.js.map → chunk-5PLUC5OB.js.map} +0 -0
- /package/dist/{chunk-JX2RINDR.js.map → chunk-6G5JEN55.js.map} +0 -0
- /package/dist/{chunk-ZCORQM74.js.map → chunk-AGJKWOKV.js.map} +0 -0
- /package/dist/{chunk-2DSTAWNZ.js.map → chunk-DIBWFCLA.js.map} +0 -0
- /package/dist/{chunk-NAZWHTYV.js.map → chunk-DR67OK4E.js.map} +0 -0
- /package/dist/{chunk-XBIACVCO.js.map → chunk-EC2AYKRX.js.map} +0 -0
- /package/dist/{chunk-RGPUQ66K.js.map → chunk-GCYFUTUC.js.map} +0 -0
- /package/dist/{chunk-JBHXMCYN.js.map → chunk-GRYAECRV.js.map} +0 -0
- /package/dist/{chunk-BJA6DQOC.js.map → chunk-GSHW5VVD.js.map} +0 -0
- /package/dist/{chunk-NCGWXCSW.js.map → chunk-IOZ5WBWD.js.map} +0 -0
- /package/dist/{chunk-7LWRCOP7.js.map → chunk-LZTFCAKE.js.map} +0 -0
- /package/dist/{chunk-6CVI6BP6.js.map → chunk-NXCK7DO7.js.map} +0 -0
- /package/dist/{chunk-Z5MQI7K2.js.map → chunk-PEPHBH2W.js.map} +0 -0
- /package/dist/{chunk-XWQ6ERUG.js.map → chunk-QZRKNA5F.js.map} +0 -0
- /package/dist/{chunk-PS3SYNHP.js.map → chunk-R5DB26G6.js.map} +0 -0
- /package/dist/{chunk-YM3LR4LS.js.map → chunk-SSSXWIBP.js.map} +0 -0
- /package/dist/{chunk-T2C6QJG2.js.map → chunk-SWDHVH2P.js.map} +0 -0
- /package/dist/{chunk-DBM2BD22.js.map → chunk-SXYCVRLK.js.map} +0 -0
- /package/dist/{chunk-ENV6RDTD.js.map → chunk-TIJYQXDI.js.map} +0 -0
- /package/dist/{chunk-BP2EV6W5.js.map → chunk-VAEAGTEQ.js.map} +0 -0
- /package/dist/{chunk-3RACUBII.js.map → chunk-WIKMCJUR.js.map} +0 -0
- /package/dist/{chunk-QW6JZO5P.js.map → chunk-WWMHAMAY.js.map} +0 -0
- /package/dist/{chunk-GPW2E4LN.js.map → chunk-YEZHZCUO.js.map} +0 -0
- /package/dist/{chunk-3XGWCZ63.js.map → chunk-YXLT4EMM.js.map} +0 -0
- /package/dist/{chunk-Y2RIIF6H.js.map → chunk-Z6UDTNY6.js.map} +0 -0
package/src/access-service.ts
CHANGED
|
@@ -56,6 +56,12 @@ import {
|
|
|
56
56
|
} from "./memory-lifecycle-ledger-utils.js";
|
|
57
57
|
import { getMemoryProjectionPath } from "./memory-projection-store.js";
|
|
58
58
|
import { canReadNamespace, canWriteNamespace, defaultNamespaceForPrincipal, recallNamespacesForPrincipal, resolvePrincipal } from "./namespaces/principal.js";
|
|
59
|
+
import {
|
|
60
|
+
expandScopeProfileReadNamespaces,
|
|
61
|
+
resolveScopeProfilePlan,
|
|
62
|
+
type ScopeProfileLayerResolution,
|
|
63
|
+
type ScopeProfilePromotionResolution,
|
|
64
|
+
} from "./namespaces/scope-profiles.js";
|
|
59
65
|
import { namespaceIdentityFromToken } from "./namespaces/identity.js";
|
|
60
66
|
import { namespaceCollectionName } from "./namespaces/search.js";
|
|
61
67
|
import { SecureStoreLockedError } from "./secure-store/index.js";
|
|
@@ -888,6 +894,14 @@ export interface MemoryScopePlan {
|
|
|
888
894
|
objectiveStateNamespace: string;
|
|
889
895
|
/** Namespaces a same-session recall would read (cheap subset). */
|
|
890
896
|
readNamespaces: string[];
|
|
897
|
+
/** Active scope profile id, when `defaultScopeProfile` is configured. */
|
|
898
|
+
scopeProfile?: string;
|
|
899
|
+
/** Resolved profile layer that supplied `writeNamespace`. */
|
|
900
|
+
writeLayer?: string;
|
|
901
|
+
/** Resolved profile layers in the active profile contract. */
|
|
902
|
+
layers?: ScopeProfileLayerResolution[];
|
|
903
|
+
/** Authorized promotion targets from the active profile contract. */
|
|
904
|
+
promotionTargets?: ScopeProfilePromotionResolution[];
|
|
891
905
|
/** Whether the coding overlay changed the base namespace. */
|
|
892
906
|
codingOverlayApplied: boolean;
|
|
893
907
|
/** Non-fatal diagnostics surfaced during resolution. */
|
|
@@ -966,6 +980,10 @@ export interface EngramAccessScopeDebug {
|
|
|
966
980
|
codingOverlayApplied: boolean;
|
|
967
981
|
/** Namespaces a same-session recall would read, when cheap to compute. */
|
|
968
982
|
readNamespaces?: string[];
|
|
983
|
+
scopeProfile?: string;
|
|
984
|
+
writeLayer?: string;
|
|
985
|
+
layers?: ScopeProfileLayerResolution[];
|
|
986
|
+
promotionTargets?: ScopeProfilePromotionResolution[];
|
|
969
987
|
}
|
|
970
988
|
|
|
971
989
|
export interface EngramAccessObserveResponse {
|
|
@@ -1398,17 +1416,45 @@ export class EngramAccessService {
|
|
|
1398
1416
|
// `default-project-*` that its own recall never searches (Codex review).
|
|
1399
1417
|
const hasSession =
|
|
1400
1418
|
typeof request.sessionKey === "string" && request.sessionKey.length > 0;
|
|
1419
|
+
const codingContext =
|
|
1420
|
+
hasSession &&
|
|
1421
|
+
this.orchestrator.config.namespacesEnabled &&
|
|
1422
|
+
this.orchestrator.config.codingMode?.projectScope
|
|
1423
|
+
? this.orchestrator.getCodingContextForSession(request.sessionKey) ??
|
|
1424
|
+
(await this.resolveCodingContextFromOptions(request))
|
|
1425
|
+
: null;
|
|
1401
1426
|
const overlay =
|
|
1402
1427
|
hasSession &&
|
|
1403
1428
|
this.orchestrator.config.namespacesEnabled &&
|
|
1404
1429
|
this.orchestrator.config.codingMode?.projectScope
|
|
1405
1430
|
? resolveCodingNamespaceOverlay(
|
|
1406
|
-
|
|
1407
|
-
(await this.resolveCodingContextFromOptions(request)),
|
|
1431
|
+
codingContext,
|
|
1408
1432
|
this.orchestrator.config.codingMode,
|
|
1409
1433
|
this.orchestrator.config.defaultNamespace,
|
|
1410
1434
|
)
|
|
1411
1435
|
: null;
|
|
1436
|
+
const principal = this.resolveRequestPrincipal(
|
|
1437
|
+
request.sessionKey,
|
|
1438
|
+
request.authenticatedPrincipal,
|
|
1439
|
+
);
|
|
1440
|
+
const profilePlan = resolveScopeProfilePlan({
|
|
1441
|
+
config: this.orchestrator.config,
|
|
1442
|
+
principal,
|
|
1443
|
+
codingContext,
|
|
1444
|
+
codingOverlay: overlay,
|
|
1445
|
+
});
|
|
1446
|
+
if (profilePlan) {
|
|
1447
|
+
const selectedLayer = profilePlan.layers.find((layer) => layer.id === profilePlan.writeLayer);
|
|
1448
|
+
const writeNamespaceReadable =
|
|
1449
|
+
profilePlan.writeNamespace.length > 0 &&
|
|
1450
|
+
profilePlan.readNamespaces.includes(profilePlan.writeNamespace);
|
|
1451
|
+
if (!selectedLayer?.writable || !writeNamespaceReadable) {
|
|
1452
|
+
throw new EngramAccessInputError(
|
|
1453
|
+
`scope profile ${profilePlan.profileId} has no writable layer inside the profile read stack for principal ${principal ?? "anonymous"}`,
|
|
1454
|
+
);
|
|
1455
|
+
}
|
|
1456
|
+
return profilePlan.writeNamespace;
|
|
1457
|
+
}
|
|
1412
1458
|
if (!overlay) {
|
|
1413
1459
|
// No coding overlay → unqualified write stays on config.defaultNamespace,
|
|
1414
1460
|
// exactly the pre-#1434 behavior (auth-checked, like the legacy path).
|
|
@@ -1422,10 +1468,6 @@ export class EngramAccessService {
|
|
|
1422
1468
|
// recall/observe/buffer-flush use. The result is a principal-owned
|
|
1423
1469
|
// `project-*` sub-namespace derived from this authorized base, so it needs
|
|
1424
1470
|
// no separate write policy.
|
|
1425
|
-
const principal = this.resolveRequestPrincipal(
|
|
1426
|
-
request.sessionKey,
|
|
1427
|
-
request.authenticatedPrincipal,
|
|
1428
|
-
);
|
|
1429
1471
|
const base = defaultNamespaceForPrincipal(principal, this.orchestrator.config);
|
|
1430
1472
|
if (!canWriteNamespace(principal, base, this.orchestrator.config)) {
|
|
1431
1473
|
throw new EngramAccessInputError(`namespace is not writable: ${base}`);
|
|
@@ -1565,6 +1607,66 @@ export class EngramAccessService {
|
|
|
1565
1607
|
baseNamespace,
|
|
1566
1608
|
);
|
|
1567
1609
|
const codingOverlayApplied = overlaidBase !== baseNamespace;
|
|
1610
|
+
const codingOverlay = overlayEligible
|
|
1611
|
+
? resolveCodingNamespaceOverlay(
|
|
1612
|
+
attachedContext,
|
|
1613
|
+
this.orchestrator.config.codingMode,
|
|
1614
|
+
this.orchestrator.config.defaultNamespace,
|
|
1615
|
+
)
|
|
1616
|
+
: null;
|
|
1617
|
+
const profilePlan = resolveScopeProfilePlan({
|
|
1618
|
+
config: this.orchestrator.config,
|
|
1619
|
+
principal,
|
|
1620
|
+
codingContext: attachedContext,
|
|
1621
|
+
codingOverlay,
|
|
1622
|
+
});
|
|
1623
|
+
if (profilePlan) {
|
|
1624
|
+
const selectedLayer = profilePlan.layers.find((layer) => layer.id === profilePlan.writeLayer);
|
|
1625
|
+
const writeNamespaceReadable =
|
|
1626
|
+
profilePlan.writeNamespace.length > 0 &&
|
|
1627
|
+
profilePlan.readNamespaces.includes(profilePlan.writeNamespace);
|
|
1628
|
+
if (!selectedLayer?.writable || !writeNamespaceReadable) {
|
|
1629
|
+
clearSeededContext();
|
|
1630
|
+
throw new EngramAccessInputError(
|
|
1631
|
+
`scope profile ${profilePlan.profileId} has no writable layer inside the profile read stack for principal ${principal ?? "anonymous"}`,
|
|
1632
|
+
);
|
|
1633
|
+
}
|
|
1634
|
+
const legacyRecallNamespaces = Array.isArray(this.orchestrator.config.defaultRecallNamespaces)
|
|
1635
|
+
? recallNamespacesForPrincipal(principal, this.orchestrator.config)
|
|
1636
|
+
: [];
|
|
1637
|
+
const expandedReadNamespaces = expandScopeProfileReadNamespaces({
|
|
1638
|
+
profilePlan,
|
|
1639
|
+
principalSelfNamespace: profilePlan.baseNamespace,
|
|
1640
|
+
config: this.orchestrator.config,
|
|
1641
|
+
principal,
|
|
1642
|
+
codingOverlay,
|
|
1643
|
+
legacyRecallNamespaces,
|
|
1644
|
+
});
|
|
1645
|
+
const readNamespaces = expandedReadNamespaces;
|
|
1646
|
+
const profileCodingOverlayApplied = Boolean(
|
|
1647
|
+
codingOverlay &&
|
|
1648
|
+
profilePlan.layers.some(
|
|
1649
|
+
(layer) =>
|
|
1650
|
+
(layer.id === "userProject" || layer.id === "teamProject") &&
|
|
1651
|
+
layer.readable &&
|
|
1652
|
+
layer.namespace &&
|
|
1653
|
+
readNamespaces.includes(layer.namespace),
|
|
1654
|
+
),
|
|
1655
|
+
);
|
|
1656
|
+
return {
|
|
1657
|
+
principal,
|
|
1658
|
+
baseNamespace: profilePlan.baseNamespace,
|
|
1659
|
+
writeNamespace: profilePlan.writeNamespace,
|
|
1660
|
+
objectiveStateNamespace: profilePlan.writeNamespace,
|
|
1661
|
+
readNamespaces,
|
|
1662
|
+
scopeProfile: profilePlan.profileId,
|
|
1663
|
+
writeLayer: profilePlan.writeLayer,
|
|
1664
|
+
layers: profilePlan.layers,
|
|
1665
|
+
promotionTargets: profilePlan.promotionTargets,
|
|
1666
|
+
codingOverlayApplied: profileCodingOverlayApplied,
|
|
1667
|
+
warnings: [...warnings, ...profilePlan.warnings],
|
|
1668
|
+
};
|
|
1669
|
+
}
|
|
1568
1670
|
|
|
1569
1671
|
if (!codingOverlayApplied) {
|
|
1570
1672
|
// No overlay → the LCM/extraction/response write namespace mirrors the
|
|
@@ -1640,12 +1742,7 @@ export class EngramAccessService {
|
|
|
1640
1742
|
// matches what a same-session recall searches. Resolved through the pure
|
|
1641
1743
|
// overlay helper to enumerate fallbacks; the write namespace itself already
|
|
1642
1744
|
// came from `applyCodingNamespaceOverlay` so the two agree.
|
|
1643
|
-
const
|
|
1644
|
-
attachedContext,
|
|
1645
|
-
this.orchestrator.config.codingMode,
|
|
1646
|
-
this.orchestrator.config.defaultNamespace,
|
|
1647
|
-
);
|
|
1648
|
-
for (const fallback of overlay?.readFallbacks ?? []) {
|
|
1745
|
+
for (const fallback of codingOverlay?.readFallbacks ?? []) {
|
|
1649
1746
|
const ns = combineNamespaces(baseNamespace, fallback);
|
|
1650
1747
|
if (!readNamespaces.includes(ns)) readNamespaces.push(ns);
|
|
1651
1748
|
}
|
|
@@ -1660,6 +1757,19 @@ export class EngramAccessService {
|
|
|
1660
1757
|
};
|
|
1661
1758
|
}
|
|
1662
1759
|
|
|
1760
|
+
private legacyResponseNamespaceForScope(scope: MemoryScopePlan): string {
|
|
1761
|
+
if (scope.explicitNamespace) return scope.writeNamespace;
|
|
1762
|
+
// Legacy overlay compatibility only applies to the principal-owned
|
|
1763
|
+
// user-project layer. Hosted profile layers such as teamProject are not the
|
|
1764
|
+
// old overlay response shape; reporting default there hides the real write.
|
|
1765
|
+
if (scope.scopeProfile && scope.writeLayer !== "userProject") {
|
|
1766
|
+
return scope.writeNamespace;
|
|
1767
|
+
}
|
|
1768
|
+
return scope.codingOverlayApplied
|
|
1769
|
+
? this.orchestrator.config.defaultNamespace
|
|
1770
|
+
: scope.writeNamespace;
|
|
1771
|
+
}
|
|
1772
|
+
|
|
1663
1773
|
private async objectiveStateStoreLocationForNamespace(namespace: string): Promise<{
|
|
1664
1774
|
memoryDir: string;
|
|
1665
1775
|
objectiveStateStoreDir?: string;
|
|
@@ -1723,8 +1833,30 @@ export class EngramAccessService {
|
|
|
1723
1833
|
);
|
|
1724
1834
|
}
|
|
1725
1835
|
|
|
1726
|
-
|
|
1727
|
-
|
|
1836
|
+
const legacyRecallNamespaces = recallNamespacesForPrincipal(
|
|
1837
|
+
principal,
|
|
1838
|
+
this.orchestrator.config,
|
|
1839
|
+
);
|
|
1840
|
+
const profilePlan = resolveScopeProfilePlan({
|
|
1841
|
+
config: this.orchestrator.config,
|
|
1842
|
+
principal,
|
|
1843
|
+
codingContext: null,
|
|
1844
|
+
codingOverlay: null,
|
|
1845
|
+
});
|
|
1846
|
+
const namespaces = profilePlan
|
|
1847
|
+
? expandScopeProfileReadNamespaces({
|
|
1848
|
+
profilePlan,
|
|
1849
|
+
principalSelfNamespace: profilePlan.baseNamespace,
|
|
1850
|
+
config: this.orchestrator.config,
|
|
1851
|
+
principal,
|
|
1852
|
+
codingOverlay: null,
|
|
1853
|
+
legacyRecallNamespaces,
|
|
1854
|
+
})
|
|
1855
|
+
: legacyRecallNamespaces;
|
|
1856
|
+
if (profilePlan) return namespaces;
|
|
1857
|
+
return namespaces.filter((ns) =>
|
|
1858
|
+
canReadNamespace(principal, ns, this.orchestrator.config),
|
|
1859
|
+
);
|
|
1728
1860
|
}
|
|
1729
1861
|
|
|
1730
1862
|
private resolveAllReadableConfiguredNamespaces(principal: string): string[] {
|
|
@@ -1752,8 +1884,18 @@ export class EngramAccessService {
|
|
|
1752
1884
|
return namespaces;
|
|
1753
1885
|
}
|
|
1754
1886
|
|
|
1887
|
+
const activeScopeProfilePlan = collectionPrincipal
|
|
1888
|
+
? resolveScopeProfilePlan({
|
|
1889
|
+
config: this.orchestrator.config,
|
|
1890
|
+
principal: collectionPrincipal,
|
|
1891
|
+
codingContext: null,
|
|
1892
|
+
codingOverlay: null,
|
|
1893
|
+
})
|
|
1894
|
+
: null;
|
|
1755
1895
|
const candidates = collectionPrincipal
|
|
1756
|
-
?
|
|
1896
|
+
? activeScopeProfilePlan
|
|
1897
|
+
? namespaces
|
|
1898
|
+
: this.resolveAllReadableConfiguredNamespaces(collectionPrincipal)
|
|
1757
1899
|
: namespaces;
|
|
1758
1900
|
const matchedNamespaces = candidates.filter((namespace) => {
|
|
1759
1901
|
const canonical = namespaceCollectionName(baseCollection, namespace, {
|
|
@@ -1867,7 +2009,7 @@ export class EngramAccessService {
|
|
|
1867
2009
|
...(options.rawExcerptNamespace
|
|
1868
2010
|
? { rawExcerptNamespace: options.rawExcerptNamespace }
|
|
1869
2011
|
: {}),
|
|
1870
|
-
...(options.rawExcerptSessionIds
|
|
2012
|
+
...(options.rawExcerptSessionIds !== undefined
|
|
1871
2013
|
? { rawExcerptSessionIds: options.rawExcerptSessionIds }
|
|
1872
2014
|
: {}),
|
|
1873
2015
|
...(options.rawExcerptsSuppressed
|
|
@@ -2093,7 +2235,7 @@ export class EngramAccessService {
|
|
|
2093
2235
|
? { sessionKey: rawContext.sessionKey }
|
|
2094
2236
|
: {}),
|
|
2095
2237
|
namespace: rawContext.rawExcerptNamespace ?? namespace,
|
|
2096
|
-
...(rawContext.rawExcerptSessionIds
|
|
2238
|
+
...(rawContext.rawExcerptSessionIds !== undefined
|
|
2097
2239
|
? { lcmSessionIds: rawContext.rawExcerptSessionIds }
|
|
2098
2240
|
: {}),
|
|
2099
2241
|
}
|
|
@@ -2241,7 +2383,7 @@ export class EngramAccessService {
|
|
|
2241
2383
|
? `${context.namespace}:${context.sessionKey}`
|
|
2242
2384
|
: context.sessionKey;
|
|
2243
2385
|
const lcmSessionIds =
|
|
2244
|
-
context.lcmSessionIds
|
|
2386
|
+
context.lcmSessionIds !== undefined
|
|
2245
2387
|
? context.lcmSessionIds
|
|
2246
2388
|
: [legacyKey];
|
|
2247
2389
|
// Cap the excerpt fanout so recall responses stay bounded. Five matches
|
|
@@ -2252,14 +2394,15 @@ export class EngramAccessService {
|
|
|
2252
2394
|
const limit = 5;
|
|
2253
2395
|
const seenRows = new Set<string>();
|
|
2254
2396
|
const excerpts: NonNullable<EngramAccessMemorySummary["rawExcerpts"]> = [];
|
|
2255
|
-
|
|
2397
|
+
const settledRows = await Promise.allSettled(
|
|
2398
|
+
lcmSessionIds.map(async (lcmSessionKey) =>
|
|
2399
|
+
lcm.searchContextFull(context.query, limit, lcmSessionKey),
|
|
2400
|
+
),
|
|
2401
|
+
);
|
|
2402
|
+
for (const result of settledRows) {
|
|
2256
2403
|
if (excerpts.length >= limit) break;
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
limit,
|
|
2260
|
-
lcmSessionKey,
|
|
2261
|
-
);
|
|
2262
|
-
for (const r of rows) {
|
|
2404
|
+
if (result.status !== "fulfilled") continue;
|
|
2405
|
+
for (const r of result.value) {
|
|
2263
2406
|
const dedupeKey = `${r.session_id} ${r.turn_index}`;
|
|
2264
2407
|
if (seenRows.has(dedupeKey)) continue;
|
|
2265
2408
|
seenRows.add(dedupeKey);
|
|
@@ -3048,6 +3191,29 @@ export class EngramAccessService {
|
|
|
3048
3191
|
}
|
|
3049
3192
|
const principal = maybePrincipal ?? "default";
|
|
3050
3193
|
const principalNamespace = defaultNamespaceForPrincipal(principal, this.orchestrator.config);
|
|
3194
|
+
const profileCodingContext =
|
|
3195
|
+
request.sessionKey && typeof this.orchestrator.getCodingContextForSession === "function"
|
|
3196
|
+
? this.orchestrator.getCodingContextForSession(request.sessionKey)
|
|
3197
|
+
: null;
|
|
3198
|
+
const profileCodingOverlay =
|
|
3199
|
+
!namespaceOverride &&
|
|
3200
|
+
profileCodingContext &&
|
|
3201
|
+
this.orchestrator.config.namespacesEnabled &&
|
|
3202
|
+
this.orchestrator.config.codingMode?.projectScope
|
|
3203
|
+
? resolveCodingNamespaceOverlay(
|
|
3204
|
+
profileCodingContext,
|
|
3205
|
+
this.orchestrator.config.codingMode,
|
|
3206
|
+
this.orchestrator.config.defaultNamespace,
|
|
3207
|
+
)
|
|
3208
|
+
: null;
|
|
3209
|
+
const profilePlan = namespaceOverride
|
|
3210
|
+
? null
|
|
3211
|
+
: resolveScopeProfilePlan({
|
|
3212
|
+
config: this.orchestrator.config,
|
|
3213
|
+
principal,
|
|
3214
|
+
codingContext: profileCodingContext,
|
|
3215
|
+
codingOverlay: profileCodingOverlay,
|
|
3216
|
+
});
|
|
3051
3217
|
// Skip budget checks for modes that never perform a cross-namespace read.
|
|
3052
3218
|
const modeSkipsBudget = mode === "no_recall";
|
|
3053
3219
|
// Derive the full set of namespaces the orchestrator will actually search.
|
|
@@ -3056,14 +3222,22 @@ export class EngramAccessService {
|
|
|
3056
3222
|
// against every cross-namespace entry in the effective set so that omitting
|
|
3057
3223
|
// `namespace` cannot bypass the limiter (Cursor/Codex review feedback).
|
|
3058
3224
|
//
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
// namespaces are a second-layer defense covered by the anomaly detector
|
|
3063
|
-
// (PR 5/5 of issue #565).
|
|
3225
|
+
const legacyRecallNamespaces = Array.isArray(this.orchestrator.config.defaultRecallNamespaces)
|
|
3226
|
+
? recallNamespacesForPrincipal(principal, this.orchestrator.config)
|
|
3227
|
+
: [];
|
|
3064
3228
|
const effectiveNamespaces = namespaceOverride
|
|
3065
3229
|
? [namespaceOverride]
|
|
3066
|
-
:
|
|
3230
|
+
: profilePlan
|
|
3231
|
+
? expandScopeProfileReadNamespaces({
|
|
3232
|
+
profilePlan,
|
|
3233
|
+
principalSelfNamespace: profilePlan.baseNamespace,
|
|
3234
|
+
config: this.orchestrator.config,
|
|
3235
|
+
principal,
|
|
3236
|
+
codingOverlay: profileCodingOverlay,
|
|
3237
|
+
legacyRecallNamespaces,
|
|
3238
|
+
})
|
|
3239
|
+
: legacyRecallNamespaces;
|
|
3240
|
+
const budgetPrincipalNamespace = profilePlan?.baseNamespace ?? principalNamespace;
|
|
3067
3241
|
let budgetDecision: BudgetDecision;
|
|
3068
3242
|
let recordBudgetAfterSuccess = false;
|
|
3069
3243
|
if (modeSkipsBudget) {
|
|
@@ -3091,7 +3265,7 @@ export class EngramAccessService {
|
|
|
3091
3265
|
for (const ns of effectiveNamespaces) {
|
|
3092
3266
|
const peek = this.budget.peek({
|
|
3093
3267
|
principal,
|
|
3094
|
-
principalNamespace,
|
|
3268
|
+
principalNamespace: budgetPrincipalNamespace,
|
|
3095
3269
|
queryNamespace: ns,
|
|
3096
3270
|
});
|
|
3097
3271
|
if (peek.reason !== "allowed-same-namespace") {
|
|
@@ -3286,7 +3460,7 @@ export class EngramAccessService {
|
|
|
3286
3460
|
query,
|
|
3287
3461
|
sessionKey: trimmedSessionKey,
|
|
3288
3462
|
...(rawExcerptNamespace ? { rawExcerptNamespace } : {}),
|
|
3289
|
-
...(rawExcerptSessionIds ? { rawExcerptSessionIds } : {}),
|
|
3463
|
+
...(rawExcerptSessionIds !== undefined ? { rawExcerptSessionIds } : {}),
|
|
3290
3464
|
...(rawExcerptsSuppressed ? { rawExcerptsSuppressed } : {}),
|
|
3291
3465
|
});
|
|
3292
3466
|
|
|
@@ -3829,7 +4003,7 @@ export class EngramAccessService {
|
|
|
3829
4003
|
...(rawExcerptNamespace
|
|
3830
4004
|
? { namespace: rawExcerptNamespace }
|
|
3831
4005
|
: {}),
|
|
3832
|
-
...(rawExcerptSessionIds
|
|
4006
|
+
...(rawExcerptSessionIds !== undefined
|
|
3833
4007
|
? { lcmSessionIds: rawExcerptSessionIds }
|
|
3834
4008
|
: {}),
|
|
3835
4009
|
})
|
|
@@ -3981,7 +4155,7 @@ export class EngramAccessService {
|
|
|
3981
4155
|
...(xrayRawExcerptNamespace
|
|
3982
4156
|
? { rawExcerptNamespace: xrayRawExcerptNamespace }
|
|
3983
4157
|
: {}),
|
|
3984
|
-
...(xrayRawExcerptSessionIds
|
|
4158
|
+
...(xrayRawExcerptSessionIds !== undefined
|
|
3985
4159
|
? { rawExcerptSessionIds: xrayRawExcerptSessionIds }
|
|
3986
4160
|
: {}),
|
|
3987
4161
|
...(xrayRawExcerptsSuppressed
|
|
@@ -5165,15 +5339,11 @@ export class EngramAccessService {
|
|
|
5165
5339
|
// the single authorization point (rule 22 / 39); the legacy field must reuse it
|
|
5166
5340
|
// and never re-authorize. Pre-#1495 semantics were exactly
|
|
5167
5341
|
// `resolveWritableNamespace(request.namespace)` (overlay-agnostic): the explicit
|
|
5168
|
-
// namespace when supplied, else `config.defaultNamespace
|
|
5169
|
-
//
|
|
5170
|
-
//
|
|
5171
|
-
//
|
|
5172
|
-
const namespace = scope
|
|
5173
|
-
? scope.writeNamespace
|
|
5174
|
-
: scope.codingOverlayApplied
|
|
5175
|
-
? this.orchestrator.config.defaultNamespace
|
|
5176
|
-
: scope.writeNamespace;
|
|
5342
|
+
// namespace when supplied, else `config.defaultNamespace` for user-project
|
|
5343
|
+
// coding overlays. Hosted scope-profile layers such as `teamProject` report
|
|
5344
|
+
// their effective profile write namespace because there is no legacy
|
|
5345
|
+
// overlay-compatible base namespace for those writes.
|
|
5346
|
+
const namespace = this.legacyResponseNamespaceForScope(scope);
|
|
5177
5347
|
const shouldWriteObjectiveState =
|
|
5178
5348
|
this.orchestrator.config.objectiveStateMemoryEnabled === true &&
|
|
5179
5349
|
this.orchestrator.config.objectiveStateSnapshotWritesEnabled === true;
|
|
@@ -5339,6 +5509,10 @@ export class EngramAccessService {
|
|
|
5339
5509
|
writeNamespace: scope.writeNamespace,
|
|
5340
5510
|
codingOverlayApplied: scope.codingOverlayApplied,
|
|
5341
5511
|
readNamespaces: scope.readNamespaces,
|
|
5512
|
+
scopeProfile: scope.scopeProfile,
|
|
5513
|
+
writeLayer: scope.writeLayer,
|
|
5514
|
+
layers: scope.layers,
|
|
5515
|
+
promotionTargets: scope.promotionTargets,
|
|
5342
5516
|
},
|
|
5343
5517
|
lcmArchived,
|
|
5344
5518
|
extractionQueued,
|
|
@@ -5364,9 +5538,17 @@ export class EngramAccessService {
|
|
|
5364
5538
|
// still succeeds via `recallNamespacesForPrincipal`, so `lcmSearch` must too
|
|
5365
5539
|
// (the same defect class the raw-excerpt path fixes). `undefined` ⇒ no
|
|
5366
5540
|
// readable LCM namespace exists, so return NO rows rather than throwing.
|
|
5541
|
+
const profileLcmReadNamespaces = hasExplicitNamespace
|
|
5542
|
+
? null
|
|
5543
|
+
: this.resolveScopeProfileLcmReadNamespaces(
|
|
5544
|
+
request.sessionKey,
|
|
5545
|
+
request.authenticatedPrincipal,
|
|
5546
|
+
);
|
|
5367
5547
|
const namespace = hasExplicitNamespace
|
|
5368
5548
|
? this.resolveReadableNamespace(request.namespace, principal)
|
|
5369
|
-
:
|
|
5549
|
+
: profileLcmReadNamespaces !== null
|
|
5550
|
+
? profileLcmReadNamespaces[0]
|
|
5551
|
+
: this.resolveImplicitLcmReadFallbackNamespace(principal);
|
|
5370
5552
|
|
|
5371
5553
|
if (!this.orchestrator.lcmEngine || !this.orchestrator.lcmEngine.enabled) {
|
|
5372
5554
|
return {
|
|
@@ -5378,6 +5560,18 @@ export class EngramAccessService {
|
|
|
5378
5560
|
};
|
|
5379
5561
|
}
|
|
5380
5562
|
|
|
5563
|
+
// An active scope profile with no readable layers is authoritative: search
|
|
5564
|
+
// no legacy/default LCM keys instead of falling back around the profile.
|
|
5565
|
+
if (profileLcmReadNamespaces !== null && profileLcmReadNamespaces.length === 0) {
|
|
5566
|
+
return {
|
|
5567
|
+
query: request.query,
|
|
5568
|
+
namespace: this.orchestrator.config.defaultNamespace,
|
|
5569
|
+
results: [],
|
|
5570
|
+
count: 0,
|
|
5571
|
+
lcmEnabled: true,
|
|
5572
|
+
};
|
|
5573
|
+
}
|
|
5574
|
+
|
|
5381
5575
|
// No readable LCM namespace for an IMPLICIT read (restrictive `default` READ
|
|
5382
5576
|
// policy, no readable overlay/self) ⇒ return NO rows instead of pre-
|
|
5383
5577
|
// authorizing the denied default (#1505 thread NBHWz). Normal recall still
|
|
@@ -5402,34 +5596,47 @@ export class EngramAccessService {
|
|
|
5402
5596
|
// (`request.sessionKey`) — the prefix is a search fragment with no bound
|
|
5403
5597
|
// coding context, so it inherits the same namespace. Collapses to the raw key
|
|
5404
5598
|
// for single-store / no-overlay / explicit-default flows (existing behavior).
|
|
5405
|
-
const lcmReadNamespace =
|
|
5406
|
-
|
|
5407
|
-
|
|
5408
|
-
request.sessionKey,
|
|
5409
|
-
request.authenticatedPrincipal,
|
|
5410
|
-
);
|
|
5411
|
-
// Ordered, read-authorized LCM read key SET for a concrete `sessionKey`
|
|
5412
|
-
// (#1505 fallback unification). A branch-scoped session whose rows were
|
|
5413
|
-
// archived at project/root scope is found by querying the primary overlay key
|
|
5414
|
-
// first, then each coding read fallback — exactly as the orchestrator recall
|
|
5415
|
-
// path does. Collapses to a single key for explicit-namespace / no-overlay /
|
|
5416
|
-
// unreadable-self flows. The `sessionPrefix` search fragment stays on the
|
|
5417
|
-
// primary overlay namespace (its own coding context can't be looked up).
|
|
5418
|
-
const lcmSessionKeyIds = request.sessionKey
|
|
5419
|
-
? this.resolveLcmReadSessionIds(
|
|
5599
|
+
const lcmReadNamespace = profileLcmReadNamespaces !== null
|
|
5600
|
+
? profileLcmReadNamespaces[0] ?? this.orchestrator.config.defaultNamespace
|
|
5601
|
+
: this.resolveLcmReadNamespace(
|
|
5420
5602
|
request.namespace,
|
|
5421
5603
|
namespace,
|
|
5422
5604
|
request.sessionKey,
|
|
5423
5605
|
request.authenticatedPrincipal,
|
|
5424
|
-
)
|
|
5606
|
+
);
|
|
5607
|
+
// Ordered, read-authorized LCM read key SET for a concrete `sessionKey`
|
|
5608
|
+
// (#1505 fallback unification + #1501 scope profiles). A branch-scoped
|
|
5609
|
+
// session whose rows were archived at project/root scope is found by querying
|
|
5610
|
+
// the primary overlay key first, then each fallback. When a scope profile is
|
|
5611
|
+
// active, the profile's expanded read namespace set is authoritative,
|
|
5612
|
+
// including the empty set.
|
|
5613
|
+
const lcmSessionKeyIds = request.sessionKey
|
|
5614
|
+
? profileLcmReadNamespaces !== null
|
|
5615
|
+
? this.lcmSessionIdsForNamespaces(
|
|
5616
|
+
profileLcmReadNamespaces,
|
|
5617
|
+
request.sessionKey,
|
|
5618
|
+
)
|
|
5619
|
+
: this.resolveLcmReadSessionIds(
|
|
5620
|
+
request.namespace,
|
|
5621
|
+
namespace,
|
|
5622
|
+
request.sessionKey,
|
|
5623
|
+
request.authenticatedPrincipal,
|
|
5624
|
+
)
|
|
5625
|
+
: [undefined];
|
|
5626
|
+
const lcmSessionPrefixes = request.sessionPrefix
|
|
5627
|
+
? profileLcmReadNamespaces !== null && !request.sessionKey
|
|
5628
|
+
? this.lcmSessionIdsForNamespaces(
|
|
5629
|
+
profileLcmReadNamespaces,
|
|
5630
|
+
request.sessionPrefix,
|
|
5631
|
+
)
|
|
5632
|
+
: [
|
|
5633
|
+
lcmSessionKeyForNamespace(
|
|
5634
|
+
lcmReadNamespace,
|
|
5635
|
+
request.sessionPrefix,
|
|
5636
|
+
this.orchestrator.config.defaultNamespace,
|
|
5637
|
+
) ?? request.sessionPrefix,
|
|
5638
|
+
]
|
|
5425
5639
|
: [undefined];
|
|
5426
|
-
const lcmSessionPrefix = request.sessionPrefix
|
|
5427
|
-
? lcmSessionKeyForNamespace(
|
|
5428
|
-
lcmReadNamespace,
|
|
5429
|
-
request.sessionPrefix,
|
|
5430
|
-
this.orchestrator.config.defaultNamespace,
|
|
5431
|
-
) ?? request.sessionPrefix
|
|
5432
|
-
: request.sessionPrefix;
|
|
5433
5640
|
// SECURITY (#1495 P1 + codex P1 r2 "Require a scoped LCM filter before
|
|
5434
5641
|
// archive searches"): a sessionless, prefixless `lcmSearch` issues
|
|
5435
5642
|
// `searchContextFull(query, limit, undefined, undefined)`, an archive-wide
|
|
@@ -5451,7 +5658,7 @@ export class EngramAccessService {
|
|
|
5451
5658
|
const hasScopedSession =
|
|
5452
5659
|
(typeof request.sessionKey === "string" &&
|
|
5453
5660
|
request.sessionKey.length > 0) ||
|
|
5454
|
-
(typeof
|
|
5661
|
+
lcmSessionPrefixes.some((prefix) => typeof prefix === "string" && prefix.length > 0);
|
|
5455
5662
|
if (!hasScopedSession && this.orchestrator.config.namespacesEnabled === true) {
|
|
5456
5663
|
return {
|
|
5457
5664
|
query: request.query,
|
|
@@ -5463,18 +5670,44 @@ export class EngramAccessService {
|
|
|
5463
5670
|
}
|
|
5464
5671
|
// Query each LCM read key in order, merging + deduping rows (by
|
|
5465
5672
|
// sessionId+turnIndex) and preserving first-seen order, capped at `limit`.
|
|
5673
|
+
// Use allSettled so one corrupt/failed namespace key cannot discard sibling
|
|
5674
|
+
// results from other authorized profile namespaces.
|
|
5466
5675
|
const seenRows = new Set<string>();
|
|
5467
5676
|
const results: Array<{ sessionId: string; content: string; turnIndex: number }> = [];
|
|
5677
|
+
const lcmSearches: Array<{
|
|
5678
|
+
key: string | undefined;
|
|
5679
|
+
prefix: string | undefined;
|
|
5680
|
+
promise: Promise<Array<{ session_id: string; content: string; turn_index: number }>>;
|
|
5681
|
+
}> = [];
|
|
5468
5682
|
for (const lcmSessionKey of lcmSessionKeyIds) {
|
|
5683
|
+
for (const lcmSessionPrefix of lcmSessionPrefixes) {
|
|
5684
|
+
lcmSearches.push({
|
|
5685
|
+
key: lcmSessionKey,
|
|
5686
|
+
prefix: lcmSessionPrefix,
|
|
5687
|
+
promise: this.orchestrator.lcmEngine.searchContextFull(
|
|
5688
|
+
request.query,
|
|
5689
|
+
limit,
|
|
5690
|
+
lcmSessionKey,
|
|
5691
|
+
lcmSessionPrefix,
|
|
5692
|
+
) as Promise<Array<{ session_id: string; content: string; turn_index: number }>>,
|
|
5693
|
+
});
|
|
5694
|
+
}
|
|
5695
|
+
}
|
|
5696
|
+
const settledSearches = await Promise.allSettled(
|
|
5697
|
+
lcmSearches.map((search) => search.promise),
|
|
5698
|
+
);
|
|
5699
|
+
for (let i = 0; i < settledSearches.length; i += 1) {
|
|
5469
5700
|
if (results.length >= limit) break;
|
|
5470
|
-
const
|
|
5471
|
-
|
|
5472
|
-
|
|
5473
|
-
|
|
5474
|
-
|
|
5475
|
-
|
|
5476
|
-
|
|
5477
|
-
|
|
5701
|
+
const settled = settledSearches[i];
|
|
5702
|
+
if (!settled || settled.status === "rejected") {
|
|
5703
|
+
const failed = lcmSearches[i];
|
|
5704
|
+
log.warn(
|
|
5705
|
+
`lcmSearch: failed for key=${failed?.key ?? "<none>"} prefix=${failed?.prefix ?? "<none>"}: ${settled?.status === "rejected" ? settled.reason : "missing result"}`,
|
|
5706
|
+
);
|
|
5707
|
+
continue;
|
|
5708
|
+
}
|
|
5709
|
+
for (const r of settled.value) {
|
|
5710
|
+
const dedupeKey = `${r.session_id}\0${r.turn_index}`;
|
|
5478
5711
|
if (seenRows.has(dedupeKey)) continue;
|
|
5479
5712
|
seenRows.add(dedupeKey);
|
|
5480
5713
|
results.push({
|
|
@@ -5659,10 +5892,21 @@ export class EngramAccessService {
|
|
|
5659
5892
|
"read",
|
|
5660
5893
|
);
|
|
5661
5894
|
}
|
|
5662
|
-
// IMPLICIT raw recall:
|
|
5663
|
-
//
|
|
5664
|
-
//
|
|
5665
|
-
//
|
|
5895
|
+
// IMPLICIT raw recall: an active scope profile owns the same LCM read
|
|
5896
|
+
// namespace set used by recall and lcmSearch. Return the first profile
|
|
5897
|
+
// namespace as the legacy raw-excerpt namespace hint; the concrete ordered
|
|
5898
|
+
// key set is still produced by resolveLcmReadSessionIds(), which also treats
|
|
5899
|
+
// an empty profile read set as authoritative.
|
|
5900
|
+
const profileReadNamespaces = this.resolveScopeProfileLcmReadNamespaces(
|
|
5901
|
+
sessionKey,
|
|
5902
|
+
authenticatedPrincipal,
|
|
5903
|
+
);
|
|
5904
|
+
if (profileReadNamespaces !== null) return profileReadNamespaces[0];
|
|
5905
|
+
|
|
5906
|
+
// Otherwise derive the read fallback from the ALREADY read-authorized recall
|
|
5907
|
+
// namespace set — NEVER pre-authorize `default` (#1505 thread NBHWz). When
|
|
5908
|
+
// namespaces are disabled the default store is the only namespace and is
|
|
5909
|
+
// always readable (byte-for-byte single-user path).
|
|
5666
5910
|
const fallbackNamespace =
|
|
5667
5911
|
this.resolveImplicitLcmReadFallbackNamespace(principal);
|
|
5668
5912
|
// No readable LCM namespace at all ⇒ no excerpts (caller short-circuits).
|
|
@@ -5789,6 +6033,59 @@ export class EngramAccessService {
|
|
|
5789
6033
|
* `<principal>-project-*` key is ever searched for an unauthorized reader (no
|
|
5790
6034
|
* cross-tenant read leak).
|
|
5791
6035
|
*/
|
|
6036
|
+
private resolveScopeProfileLcmReadNamespaces(
|
|
6037
|
+
sessionKey: string | undefined,
|
|
6038
|
+
authenticatedPrincipal: string | undefined,
|
|
6039
|
+
): string[] | null {
|
|
6040
|
+
const config = this.orchestrator.config;
|
|
6041
|
+
const principal = this.resolveRequestPrincipal(sessionKey, authenticatedPrincipal);
|
|
6042
|
+
const codingContext = sessionKey
|
|
6043
|
+
? this.orchestrator.getCodingContextForSession(sessionKey)
|
|
6044
|
+
: null;
|
|
6045
|
+
const codingOverlay = resolveCodingNamespaceOverlay(
|
|
6046
|
+
codingContext,
|
|
6047
|
+
config.codingMode,
|
|
6048
|
+
config.defaultNamespace,
|
|
6049
|
+
);
|
|
6050
|
+
const profilePlan = resolveScopeProfilePlan({
|
|
6051
|
+
config,
|
|
6052
|
+
principal,
|
|
6053
|
+
codingContext,
|
|
6054
|
+
codingOverlay,
|
|
6055
|
+
});
|
|
6056
|
+
if (!profilePlan) return null;
|
|
6057
|
+
const principalSelfNamespace = defaultNamespaceForPrincipal(principal, config);
|
|
6058
|
+
const legacyRecallNamespaces = Array.isArray(config.defaultRecallNamespaces)
|
|
6059
|
+
? recallNamespacesForPrincipal(principal, config)
|
|
6060
|
+
: [];
|
|
6061
|
+
return expandScopeProfileReadNamespaces({
|
|
6062
|
+
profilePlan,
|
|
6063
|
+
principalSelfNamespace: profilePlan.baseNamespace,
|
|
6064
|
+
config,
|
|
6065
|
+
principal,
|
|
6066
|
+
codingOverlay,
|
|
6067
|
+
legacyRecallNamespaces,
|
|
6068
|
+
});
|
|
6069
|
+
}
|
|
6070
|
+
|
|
6071
|
+
private lcmSessionIdsForNamespaces(namespaces: string[], sessionKey: string): string[] {
|
|
6072
|
+
const out: string[] = [];
|
|
6073
|
+
const seen = new Set<string>();
|
|
6074
|
+
for (const namespace of namespaces) {
|
|
6075
|
+
const key =
|
|
6076
|
+
lcmSessionKeyForNamespace(
|
|
6077
|
+
namespace,
|
|
6078
|
+
sessionKey,
|
|
6079
|
+
this.orchestrator.config.defaultNamespace,
|
|
6080
|
+
) ?? sessionKey;
|
|
6081
|
+
if (!seen.has(key)) {
|
|
6082
|
+
seen.add(key);
|
|
6083
|
+
out.push(key);
|
|
6084
|
+
}
|
|
6085
|
+
}
|
|
6086
|
+
return out;
|
|
6087
|
+
}
|
|
6088
|
+
|
|
5792
6089
|
private resolveLcmReadSessionIds(
|
|
5793
6090
|
explicitNamespace: string | undefined,
|
|
5794
6091
|
resolvedNamespace: string,
|
|
@@ -5809,6 +6106,14 @@ export class EngramAccessService {
|
|
|
5809
6106
|
// explicit read). Single key, unchanged.
|
|
5810
6107
|
if (hasExplicitNamespace) return [primary];
|
|
5811
6108
|
|
|
6109
|
+
const profileReadNamespaces = this.resolveScopeProfileLcmReadNamespaces(
|
|
6110
|
+
sessionKey,
|
|
6111
|
+
authenticatedPrincipal,
|
|
6112
|
+
);
|
|
6113
|
+
if (profileReadNamespaces !== null) {
|
|
6114
|
+
return this.lcmSessionIdsForNamespaces(profileReadNamespaces, sessionKey);
|
|
6115
|
+
}
|
|
6116
|
+
|
|
5812
6117
|
const principal = this.resolveRequestPrincipal(
|
|
5813
6118
|
sessionKey,
|
|
5814
6119
|
authenticatedPrincipal,
|
|
@@ -5883,13 +6188,10 @@ export class EngramAccessService {
|
|
|
5883
6188
|
// `resolveWritableNamespace(request.namespace)` (overlay-agnostic) — the
|
|
5884
6189
|
// authorized explicit namespace when supplied, else `config.defaultNamespace`.
|
|
5885
6190
|
// DERIVED from the scope plan (NOT a second auth pass, #1505 thread jvO):
|
|
5886
|
-
// explicit ⇒ writeNamespace; coding overlay ⇒ defaultNamespace;
|
|
5887
|
-
//
|
|
5888
|
-
|
|
5889
|
-
|
|
5890
|
-
: scope.codingOverlayApplied
|
|
5891
|
-
? this.orchestrator.config.defaultNamespace
|
|
5892
|
-
: scope.writeNamespace;
|
|
6191
|
+
// explicit ⇒ writeNamespace; user-project coding overlay ⇒ defaultNamespace;
|
|
6192
|
+
// non-user scope-profile layer/no overlay ⇒ writeNamespace. Identical to
|
|
6193
|
+
// observe's legacy field.
|
|
6194
|
+
const namespace = this.legacyResponseNamespaceForScope(scope);
|
|
5893
6195
|
if (!this.orchestrator.lcmEngine || !this.orchestrator.lcmEngine.enabled) {
|
|
5894
6196
|
return {
|
|
5895
6197
|
enabled: false,
|
|
@@ -5948,11 +6250,7 @@ export class EngramAccessService {
|
|
|
5948
6250
|
// overlay write and never throws `not writable: default` for a validly scoped
|
|
5949
6251
|
// observe's queue.
|
|
5950
6252
|
const scope = await this.resolveMemoryScopePlan(request);
|
|
5951
|
-
const namespace = scope
|
|
5952
|
-
? scope.writeNamespace
|
|
5953
|
-
: scope.codingOverlayApplied
|
|
5954
|
-
? this.orchestrator.config.defaultNamespace
|
|
5955
|
-
: scope.writeNamespace;
|
|
6253
|
+
const namespace = this.legacyResponseNamespaceForScope(scope);
|
|
5956
6254
|
if (!this.orchestrator.lcmEngine || !this.orchestrator.lcmEngine.enabled) {
|
|
5957
6255
|
return {
|
|
5958
6256
|
enabled: false,
|