@remnic/core 9.3.752 → 9.3.754
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 +194 -0
- package/dist/access-admin-ops-surface.js +128 -0
- package/dist/access-boundary.d.ts +5 -5
- package/dist/access-boundary.js +37 -37
- package/dist/access-cli.js +109 -109
- package/dist/access-http.d.ts +5 -5
- package/dist/access-http.js +46 -46
- package/dist/access-lcm-surface.d.ts +188 -0
- package/dist/access-lcm-surface.js +128 -0
- package/dist/access-lcm-surface.js.map +1 -0
- package/dist/access-mcp.d.ts +5 -5
- package/dist/access-mcp.js +42 -42
- package/dist/access-operations-batch.js +39 -39
- package/dist/access-operations.d.ts +8 -8
- package/dist/access-operations.js +41 -41
- package/dist/access-recall-surface.d.ts +5 -5
- package/dist/access-recall-surface.js +36 -36
- package/dist/access-schema.d.ts +54 -54
- package/dist/access-schema.js +5 -5
- package/dist/{access-service-C2cOHQvg.d.ts → access-service-DKRV1zxh.d.ts} +75 -159
- package/dist/access-service.d.ts +5 -5
- package/dist/access-service.js +40 -36
- package/dist/access-surface-catalog.d.ts +5 -5
- 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 +5 -5
- package/dist/adapters/index.js +7 -7
- package/dist/adapters/registry.js +3 -3
- package/dist/{auto-sync-IEBKPGAM.js → auto-sync-G4YKBPOU.js} +5 -5
- package/dist/behavior-learner.d.ts +1 -1
- package/dist/behavior-signals.d.ts +1 -1
- package/dist/bootstrap.d.ts +4 -4
- package/dist/briefing.d.ts +3 -3
- package/dist/briefing.js +13 -13
- package/dist/buffer-surprise-report.d.ts +1 -1
- package/dist/buffer.d.ts +3 -3
- package/dist/buffer.js +2 -2
- package/dist/calibration.d.ts +1 -1
- package/dist/calibration.js +2 -2
- package/dist/capabilities.d.ts +1 -1
- package/dist/{catalog-D_FvzTM0.d.ts → catalog-BEmNVRN0.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 +16 -16
- package/dist/causal-trajectory-graph.d.ts +1 -1
- package/dist/{chunk-5DXUE7GB.js → chunk-24463PIV.js} +2 -2
- package/dist/{chunk-2DPCAW2T.js → chunk-2MHCWXX6.js} +8 -8
- package/dist/{chunk-KFNG72W7.js → chunk-2MR3MFQB.js} +6 -6
- package/dist/{chunk-YTU7WKYN.js → chunk-2OZ2JEUP.js} +2 -2
- package/dist/{chunk-JBPKEARU.js → chunk-2QSZNTDO.js} +7 -7
- package/dist/{chunk-EHYB325U.js → chunk-3DOD6ICJ.js} +2 -2
- package/dist/{chunk-5JAT4ZJD.js → chunk-4DLFJJOQ.js} +4 -4
- package/dist/{chunk-JNKSFIAY.js → chunk-4DVYRPLL.js} +76 -76
- package/dist/{chunk-VUA4S7P6.js → chunk-5J4OL7TJ.js} +4 -4
- package/dist/{chunk-BIAMJUUJ.js → chunk-5QANTTY2.js} +4 -4
- package/dist/{chunk-K5CWCJKJ.js → chunk-7AL5WNPW.js} +10 -10
- package/dist/{chunk-V4ZPLQLC.js → chunk-7CAJLUNW.js} +2 -2
- package/dist/{chunk-MEPWWSTD.js → chunk-BERWPOXU.js} +4 -4
- package/dist/{chunk-UFNQKZV7.js → chunk-BQ6J6P3K.js} +23 -23
- package/dist/{chunk-KT2VQLP7.js → chunk-CJ276MDI.js} +8 -8
- package/dist/{chunk-DC5OBZS3.js → chunk-COZEVVXZ.js} +2 -2
- package/dist/{chunk-67JRXV6Z.js → chunk-CXCZ4LAI.js} +5 -5
- package/dist/{chunk-MW7UUXTA.js → chunk-DBSMLRTO.js} +5 -5
- package/dist/{chunk-RBYV3WSB.js → chunk-DS4QM6I7.js} +4 -4
- package/dist/{chunk-MLDAD27I.js → chunk-G7LCG56O.js} +8 -8
- package/dist/{chunk-IBPEVGP5.js → chunk-GAH5755F.js} +2 -2
- package/dist/{chunk-SC5AEZLU.js → chunk-GPFXPC2V.js} +10 -10
- package/dist/{chunk-R7TGDLV3.js → chunk-HM6UJPPO.js} +4 -4
- package/dist/{chunk-2U4E34Y3.js → chunk-JBO6UBIE.js} +4 -4
- package/dist/{chunk-33NX5BLR.js → chunk-JRZV3767.js} +4 -4
- package/dist/{chunk-IQWFWSCP.js → chunk-JZ7P26GF.js} +4 -4
- package/dist/{chunk-XKAOT4ZB.js → chunk-K5LLP4CY.js} +4 -4
- package/dist/{chunk-JHZ3LEM7.js → chunk-KURUULFF.js} +2 -2
- package/dist/{chunk-VX2RYM2K.js → chunk-L4AS7TIG.js} +5644 -5529
- package/dist/chunk-L4AS7TIG.js.map +1 -0
- package/dist/{chunk-LQ6JI4VH.js → chunk-LD53WPMU.js} +4 -4
- package/dist/{chunk-RRRZ3CLN.js → chunk-LOPZ2DWR.js} +4 -4
- package/dist/{chunk-GFGYHLON.js → chunk-OH66EBCS.js} +2 -2
- package/dist/{chunk-OKOF7ITI.js → chunk-OSMBC3JU.js} +6 -6
- package/dist/{chunk-QMMCMV2L.js → chunk-PJQMISPD.js} +7 -7
- package/dist/{chunk-VQL22SHO.js → chunk-PYVZKEZZ.js} +130 -130
- package/dist/{chunk-DCWIQFNA.js → chunk-T422SYM6.js} +5 -5
- package/dist/{chunk-5CEJH5ZN.js → chunk-TAPSNIMA.js} +4 -4
- package/dist/{chunk-3NN73CM7.js → chunk-TH7WMHVK.js} +2 -2
- package/dist/{chunk-YGNQG4Q6.js → chunk-THZ4WR5L.js} +19 -19
- package/dist/{chunk-MTN2G4DT.js → chunk-TIFF32QK.js} +2 -2
- package/dist/{chunk-QRM3K3XT.js → chunk-TJATYB3F.js} +14 -14
- package/dist/{chunk-6ROCH5JV.js → chunk-TXALJRYO.js} +8 -8
- package/dist/{chunk-OVMLS7TN.js → chunk-U2SMR57B.js} +10 -10
- package/dist/{chunk-S5UYWK3O.js → chunk-V4C4SFZB.js} +6 -6
- package/dist/{chunk-L3VSTJ2V.js → chunk-VSU2NZGC.js} +2 -2
- package/dist/{chunk-GECEETQ3.js → chunk-W3M34XT4.js} +4 -4
- package/dist/{chunk-FXRFFYWD.js → chunk-WIWPSQYU.js} +4 -4
- package/dist/{chunk-FEELYTRT.js → chunk-WS6GLJ7P.js} +5 -5
- package/dist/{chunk-C4LNKQ3M.js → chunk-WUVUTOUV.js} +5 -5
- package/dist/{chunk-WRFKZEO6.js → chunk-YQGHW5ML.js} +4 -4
- package/dist/{chunk-J2JB6BHT.js → chunk-YRBXBHU7.js} +8 -8
- package/dist/{chunk-ZGGI3COG.js → chunk-ZJMSTFOR.js} +9 -9
- package/dist/{cli-DFUU9WYu.d.ts → cli-D-xw8Sp1.d.ts} +3 -3
- package/dist/cli.d.ts +6 -6
- package/dist/cli.js +73 -73
- package/dist/compounding/engine.d.ts +3 -3
- package/dist/compounding/engine.js +15 -15
- 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 +2 -2
- 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 +16 -16
- 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/contradiction/index.js +2 -2
- package/dist/{contradiction-scan-KO4WWCS4.js → contradiction-scan-2SODRNUF.js} +3 -3
- package/dist/contradiction-scan-2SODRNUF.js.map +1 -0
- 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/day-summary.d.ts +1 -1
- package/dist/day-summary.js +2 -2
- 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/embedding-fallback.js +2 -2
- package/dist/enrichment/index.d.ts +1 -1
- package/dist/entity-retrieval.d.ts +1 -1
- package/dist/entity-retrieval.js +14 -14
- package/dist/entity-schema.d.ts +1 -1
- package/dist/explicit-capture.d.ts +6 -6
- package/dist/explicit-capture.js +2 -2
- package/dist/extraction-faithfulness.d.ts +1 -1
- package/dist/extraction-faithfulness.js +3 -3
- 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-judge.js +3 -3
- package/dist/extraction.d.ts +1 -1
- package/dist/extraction.js +7 -7
- package/dist/fallback-llm.d.ts +1 -1
- package/dist/fallback-llm.js +2 -2
- package/dist/{first-start-migration-4I3VDSYS.js → first-start-migration-DY6YCRC2.js} +2 -2
- package/dist/{forget-WYLR4ZFV.js → forget-OEE5OELK.js} +2 -2
- 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/identity-continuity.d.ts +1 -1
- package/dist/importance.d.ts +1 -1
- package/dist/index.d.ts +1284 -1284
- package/dist/index.js +204 -204
- 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 +8 -8
- 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.d.ts +1 -1
- package/dist/local-llm.js +2 -2
- package/dist/local-model-endpoint.d.ts +1 -1
- package/dist/maintenance/memory-governance.d.ts +1 -1
- package/dist/maintenance/memory-governance.js +13 -13
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +13 -13
- package/dist/maintenance/rebuild-memory-projection.js +14 -14
- package/dist/mcp-memory-inspector-app.d.ts +5 -5
- 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 +2 -2
- package/dist/namespaces/migrate.js +26 -26
- package/dist/namespaces/principal.d.ts +1 -1
- package/dist/namespaces/search.d.ts +1 -1
- package/dist/namespaces/search.js +11 -11
- package/dist/namespaces/storage.d.ts +2 -2
- package/dist/namespaces/storage.js +15 -15
- package/dist/native-knowledge.d.ts +1 -1
- package/dist/operator-toolkit.d.ts +1 -1
- package/dist/operator-toolkit.js +33 -33
- package/dist/orchestration/compression-guideline-coordinator.d.ts +1 -1
- package/dist/orchestration/compression-guideline-coordinator.js +2 -2
- package/dist/orchestration/maintenance.d.ts +2 -2
- package/dist/orchestration/maintenance.js +19 -19
- package/dist/{orchestrator-BhxMxtQJ.d.ts → orchestrator-D7ZGOQLX.d.ts} +77 -77
- package/dist/orchestrator.d.ts +4 -4
- package/dist/orchestrator.js +109 -109
- package/dist/patterns-cli.d.ts +1 -1
- package/dist/policy-runtime.d.ts +1 -1
- package/dist/provenance.d.ts +1 -1
- package/dist/qmd-recall-cache.d.ts +1 -1
- package/dist/qmd.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-planner-llm.d.ts +1 -1
- package/dist/recall-planner-llm.js +2 -2
- 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-renderer.d.ts +1 -1
- package/dist/recall-xray.d.ts +1 -1
- package/dist/resolve-auth-token.d.ts +1 -1
- 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/routing/store.js +2 -2
- package/dist/schemas.d.ts +42 -42
- package/dist/search/embed-helper.d.ts +1 -1
- package/dist/search/embed-helper.js +2 -2
- package/dist/search/factory.d.ts +1 -1
- package/dist/search/factory.js +10 -10
- package/dist/search/index.d.ts +1 -1
- package/dist/search/index.js +14 -14
- 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 +1 -1
- package/dist/search/remote-backend.d.ts +1 -1
- package/dist/{semantic-consolidation-BrsoFeMP.d.ts → semantic-consolidation-7Sndms2M.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 +13 -13
- package/dist/semantic-rule-verifier.d.ts +1 -1
- package/dist/semantic-rule-verifier.js +13 -13
- 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/shared-context/manager.js +2 -2
- package/dist/signal.d.ts +1 -1
- package/dist/storage.d.ts +1 -1
- package/dist/storage.js +12 -12
- package/dist/summarizer.d.ts +1 -1
- package/dist/summarizer.js +5 -5
- package/dist/summary-snapshot.d.ts +1 -1
- 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/{tier-stats-5XF4UBRQ.js → tier-stats-TG6GUZ6N.js} +4 -4
- package/dist/topics.d.ts +1 -1
- package/dist/transcript.d.ts +1 -1
- package/dist/transfer/backup.js +1 -1
- package/dist/transfer/capsule-export.js +1 -1
- package/dist/transfer/types.d.ts +44 -44
- package/dist/trust-score-stage.d.ts +1 -1
- package/dist/trust-score.d.ts +1 -1
- package/dist/{types-BfI4uJeb.d.ts → types-DTEFxFuL.d.ts} +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/utility-runtime.d.ts +1 -1
- package/dist/verified-recall.js +13 -13
- package/package.json +2 -2
- package/src/access-admin-ops-surface.ts +828 -0
- package/src/access-lcm-surface.ts +517 -0
- package/src/access-service.ts +62 -1115
- package/dist/chunk-VX2RYM2K.js.map +0 -1
- /package/dist/{contradiction-scan-KO4WWCS4.js.map → access-admin-ops-surface.js.map} +0 -0
- /package/dist/{auto-sync-IEBKPGAM.js.map → auto-sync-G4YKBPOU.js.map} +0 -0
- /package/dist/{chunk-5DXUE7GB.js.map → chunk-24463PIV.js.map} +0 -0
- /package/dist/{chunk-2DPCAW2T.js.map → chunk-2MHCWXX6.js.map} +0 -0
- /package/dist/{chunk-KFNG72W7.js.map → chunk-2MR3MFQB.js.map} +0 -0
- /package/dist/{chunk-YTU7WKYN.js.map → chunk-2OZ2JEUP.js.map} +0 -0
- /package/dist/{chunk-JBPKEARU.js.map → chunk-2QSZNTDO.js.map} +0 -0
- /package/dist/{chunk-EHYB325U.js.map → chunk-3DOD6ICJ.js.map} +0 -0
- /package/dist/{chunk-5JAT4ZJD.js.map → chunk-4DLFJJOQ.js.map} +0 -0
- /package/dist/{chunk-JNKSFIAY.js.map → chunk-4DVYRPLL.js.map} +0 -0
- /package/dist/{chunk-VUA4S7P6.js.map → chunk-5J4OL7TJ.js.map} +0 -0
- /package/dist/{chunk-BIAMJUUJ.js.map → chunk-5QANTTY2.js.map} +0 -0
- /package/dist/{chunk-K5CWCJKJ.js.map → chunk-7AL5WNPW.js.map} +0 -0
- /package/dist/{chunk-V4ZPLQLC.js.map → chunk-7CAJLUNW.js.map} +0 -0
- /package/dist/{chunk-MEPWWSTD.js.map → chunk-BERWPOXU.js.map} +0 -0
- /package/dist/{chunk-UFNQKZV7.js.map → chunk-BQ6J6P3K.js.map} +0 -0
- /package/dist/{chunk-KT2VQLP7.js.map → chunk-CJ276MDI.js.map} +0 -0
- /package/dist/{chunk-DC5OBZS3.js.map → chunk-COZEVVXZ.js.map} +0 -0
- /package/dist/{chunk-67JRXV6Z.js.map → chunk-CXCZ4LAI.js.map} +0 -0
- /package/dist/{chunk-MW7UUXTA.js.map → chunk-DBSMLRTO.js.map} +0 -0
- /package/dist/{chunk-RBYV3WSB.js.map → chunk-DS4QM6I7.js.map} +0 -0
- /package/dist/{chunk-MLDAD27I.js.map → chunk-G7LCG56O.js.map} +0 -0
- /package/dist/{chunk-IBPEVGP5.js.map → chunk-GAH5755F.js.map} +0 -0
- /package/dist/{chunk-SC5AEZLU.js.map → chunk-GPFXPC2V.js.map} +0 -0
- /package/dist/{chunk-R7TGDLV3.js.map → chunk-HM6UJPPO.js.map} +0 -0
- /package/dist/{chunk-2U4E34Y3.js.map → chunk-JBO6UBIE.js.map} +0 -0
- /package/dist/{chunk-33NX5BLR.js.map → chunk-JRZV3767.js.map} +0 -0
- /package/dist/{chunk-IQWFWSCP.js.map → chunk-JZ7P26GF.js.map} +0 -0
- /package/dist/{chunk-XKAOT4ZB.js.map → chunk-K5LLP4CY.js.map} +0 -0
- /package/dist/{chunk-JHZ3LEM7.js.map → chunk-KURUULFF.js.map} +0 -0
- /package/dist/{chunk-LQ6JI4VH.js.map → chunk-LD53WPMU.js.map} +0 -0
- /package/dist/{chunk-RRRZ3CLN.js.map → chunk-LOPZ2DWR.js.map} +0 -0
- /package/dist/{chunk-GFGYHLON.js.map → chunk-OH66EBCS.js.map} +0 -0
- /package/dist/{chunk-OKOF7ITI.js.map → chunk-OSMBC3JU.js.map} +0 -0
- /package/dist/{chunk-QMMCMV2L.js.map → chunk-PJQMISPD.js.map} +0 -0
- /package/dist/{chunk-VQL22SHO.js.map → chunk-PYVZKEZZ.js.map} +0 -0
- /package/dist/{chunk-DCWIQFNA.js.map → chunk-T422SYM6.js.map} +0 -0
- /package/dist/{chunk-5CEJH5ZN.js.map → chunk-TAPSNIMA.js.map} +0 -0
- /package/dist/{chunk-3NN73CM7.js.map → chunk-TH7WMHVK.js.map} +0 -0
- /package/dist/{chunk-YGNQG4Q6.js.map → chunk-THZ4WR5L.js.map} +0 -0
- /package/dist/{chunk-MTN2G4DT.js.map → chunk-TIFF32QK.js.map} +0 -0
- /package/dist/{chunk-QRM3K3XT.js.map → chunk-TJATYB3F.js.map} +0 -0
- /package/dist/{chunk-6ROCH5JV.js.map → chunk-TXALJRYO.js.map} +0 -0
- /package/dist/{chunk-OVMLS7TN.js.map → chunk-U2SMR57B.js.map} +0 -0
- /package/dist/{chunk-S5UYWK3O.js.map → chunk-V4C4SFZB.js.map} +0 -0
- /package/dist/{chunk-L3VSTJ2V.js.map → chunk-VSU2NZGC.js.map} +0 -0
- /package/dist/{chunk-GECEETQ3.js.map → chunk-W3M34XT4.js.map} +0 -0
- /package/dist/{chunk-FXRFFYWD.js.map → chunk-WIWPSQYU.js.map} +0 -0
- /package/dist/{chunk-FEELYTRT.js.map → chunk-WS6GLJ7P.js.map} +0 -0
- /package/dist/{chunk-C4LNKQ3M.js.map → chunk-WUVUTOUV.js.map} +0 -0
- /package/dist/{chunk-WRFKZEO6.js.map → chunk-YQGHW5ML.js.map} +0 -0
- /package/dist/{chunk-J2JB6BHT.js.map → chunk-YRBXBHU7.js.map} +0 -0
- /package/dist/{chunk-ZGGI3COG.js.map → chunk-ZJMSTFOR.js.map} +0 -0
- /package/dist/{first-start-migration-4I3VDSYS.js.map → first-start-migration-DY6YCRC2.js.map} +0 -0
- /package/dist/{forget-WYLR4ZFV.js.map → forget-OEE5OELK.js.map} +0 -0
- /package/dist/{tier-stats-5XF4UBRQ.js.map → tier-stats-TG6GUZ6N.js.map} +0 -0
package/src/access-service.ts
CHANGED
|
@@ -251,6 +251,8 @@ import {
|
|
|
251
251
|
import { formatProfileTraceAscii } from "./profiling.js";
|
|
252
252
|
import { resolveAccessSetupCapabilities, resolveGraphConstructionCapabilities, resolveIndexingCapabilities } from "./capabilities.js";
|
|
253
253
|
import { resolveRecallEnhancementCapabilities } from "./capabilities.js";
|
|
254
|
+
import { AccessLcmSurface } from "./access-lcm-surface.js";
|
|
255
|
+
import { AccessAdminOpsSurface } from "./access-admin-ops-surface.js";
|
|
254
256
|
import { AccessRecallSurface } from "./access-recall-surface.js";
|
|
255
257
|
import { selfDeps } from "./orchestration/self-deps.js";
|
|
256
258
|
|
|
@@ -302,12 +304,12 @@ function qmdResultPathCandidates(
|
|
|
302
304
|
return [...candidates];
|
|
303
305
|
}
|
|
304
306
|
|
|
305
|
-
type AccessProfilingReportRequest = {
|
|
307
|
+
export type AccessProfilingReportRequest = {
|
|
306
308
|
format?: string;
|
|
307
309
|
limit?: number;
|
|
308
310
|
};
|
|
309
311
|
|
|
310
|
-
type AccessProfilingReportResponse = {
|
|
312
|
+
export type AccessProfilingReportResponse = {
|
|
311
313
|
enabled: boolean;
|
|
312
314
|
format?: "ascii" | "json";
|
|
313
315
|
report?: string;
|
|
@@ -860,7 +862,7 @@ export interface EngramAccessOfflineSyncApplyResponse extends OfflineSyncApplyCh
|
|
|
860
862
|
export type EngramAccessActionConfidenceRequest = ActionConfidenceInput;
|
|
861
863
|
export type EngramAccessActionConfidenceResponse = ActionConfidenceResult;
|
|
862
864
|
|
|
863
|
-
async function buildProjectedGovernanceProposedActions(
|
|
865
|
+
export async function buildProjectedGovernanceProposedActions(
|
|
864
866
|
storage: Awaited<ReturnType<Orchestrator["getStorage"]>>,
|
|
865
867
|
projected: NonNullable<Awaited<ReturnType<Awaited<ReturnType<Orchestrator["getStorage"]>>["getProjectedGovernanceRecord"]>>>,
|
|
866
868
|
): Promise<Awaited<ReturnType<typeof readMemoryGovernanceRunArtifact>>["appliedActions"]> {
|
|
@@ -879,7 +881,7 @@ async function buildProjectedGovernanceProposedActions(
|
|
|
879
881
|
return buildProposedActions(reviewQueue, memories);
|
|
880
882
|
}
|
|
881
883
|
|
|
882
|
-
function hasGroupedGovernanceActions(
|
|
884
|
+
export function hasGroupedGovernanceActions(
|
|
883
885
|
grouped?: Awaited<ReturnType<typeof readMemoryGovernanceRunArtifact>>["transitionReport"]["proposed"],
|
|
884
886
|
): boolean {
|
|
885
887
|
if (!grouped) return false;
|
|
@@ -1307,6 +1309,30 @@ export class EngramAccessService {
|
|
|
1307
1309
|
private readonly budget: CrossNamespaceBudget;
|
|
1308
1310
|
private readonly auditAdapter: AccessAuditAdapter | null;
|
|
1309
1311
|
|
|
1312
|
+
/** AccessLcmSurface (access-service decomposition). Lazy; selfDeps live wiring. */
|
|
1313
|
+
private _accessLcmSurface: AccessLcmSurface | undefined;
|
|
1314
|
+
|
|
1315
|
+
private get accessLcmSurface(): AccessLcmSurface {
|
|
1316
|
+
if (!this._accessLcmSurface) {
|
|
1317
|
+
this._accessLcmSurface = new AccessLcmSurface(
|
|
1318
|
+
selfDeps<ConstructorParameters<typeof AccessLcmSurface>[0]>(this),
|
|
1319
|
+
);
|
|
1320
|
+
}
|
|
1321
|
+
return this._accessLcmSurface;
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
/** AccessAdminOpsSurface (access-service decomposition). Lazy; selfDeps live wiring. */
|
|
1325
|
+
private _accessAdminOpsSurface: AccessAdminOpsSurface | undefined;
|
|
1326
|
+
|
|
1327
|
+
private get accessAdminOpsSurface(): AccessAdminOpsSurface {
|
|
1328
|
+
if (!this._accessAdminOpsSurface) {
|
|
1329
|
+
this._accessAdminOpsSurface = new AccessAdminOpsSurface(
|
|
1330
|
+
selfDeps<ConstructorParameters<typeof AccessAdminOpsSurface>[0]>(this),
|
|
1331
|
+
);
|
|
1332
|
+
}
|
|
1333
|
+
return this._accessAdminOpsSurface;
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1310
1336
|
/** AccessRecallSurface (access-service decomposition). Lazy; selfDeps live wiring. */
|
|
1311
1337
|
private _accessRecallSurface: AccessRecallSurface | undefined;
|
|
1312
1338
|
|
|
@@ -3835,97 +3861,11 @@ export class EngramAccessService {
|
|
|
3835
3861
|
}
|
|
3836
3862
|
|
|
3837
3863
|
async reviewQueue(runId?: string, namespace?: string, principal?: string): Promise<EngramAccessReviewQueueResponse> {
|
|
3838
|
-
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
|
|
3842
|
-
|
|
3843
|
-
action: row.action,
|
|
3844
|
-
memoryId: row.memoryId,
|
|
3845
|
-
reasonCode: row.reasonCode,
|
|
3846
|
-
beforeStatus: row.beforeStatus,
|
|
3847
|
-
afterStatus: row.afterStatus,
|
|
3848
|
-
originalPath: row.originalPath,
|
|
3849
|
-
currentPath: row.currentPath,
|
|
3850
|
-
})) as Awaited<
|
|
3851
|
-
ReturnType<typeof readMemoryGovernanceRunArtifact>
|
|
3852
|
-
>["appliedActions"];
|
|
3853
|
-
const projectedProposedActions = await buildProjectedGovernanceProposedActions(storage, projected);
|
|
3854
|
-
const projectedArtifact = await (async () => {
|
|
3855
|
-
try {
|
|
3856
|
-
return await readMemoryGovernanceRunArtifact(storage.dir, projected.runId);
|
|
3857
|
-
} catch {
|
|
3858
|
-
return null;
|
|
3859
|
-
}
|
|
3860
|
-
})();
|
|
3861
|
-
const metrics = projected.metrics as Awaited<ReturnType<typeof readMemoryGovernanceRunArtifact>>["metrics"];
|
|
3862
|
-
const fallbackTransitionReport = {
|
|
3863
|
-
proposed: groupActionsByStatus(projectedProposedActions),
|
|
3864
|
-
applied: groupActionsByStatus(projectedAppliedActions),
|
|
3865
|
-
};
|
|
3866
|
-
const transitionReport = projectedArtifact?.transitionReport
|
|
3867
|
-
? {
|
|
3868
|
-
proposed:
|
|
3869
|
-
hasGroupedGovernanceActions(projectedArtifact.transitionReport.proposed) || projectedProposedActions.length === 0
|
|
3870
|
-
? projectedArtifact.transitionReport.proposed
|
|
3871
|
-
: fallbackTransitionReport.proposed,
|
|
3872
|
-
applied:
|
|
3873
|
-
hasGroupedGovernanceActions(projectedArtifact.transitionReport.applied) || projectedAppliedActions.length === 0
|
|
3874
|
-
? projectedArtifact.transitionReport.applied
|
|
3875
|
-
: fallbackTransitionReport.applied,
|
|
3876
|
-
}
|
|
3877
|
-
: fallbackTransitionReport;
|
|
3878
|
-
const qualityScore = projectedArtifact?.qualityScore ?? metrics?.qualityScore ?? buildQualityScore(metrics?.reviewReasons ?? {
|
|
3879
|
-
exact_duplicate: 0,
|
|
3880
|
-
semantic_duplicate_candidate: 0,
|
|
3881
|
-
disputed_memory: 0,
|
|
3882
|
-
speculative_low_confidence: 0,
|
|
3883
|
-
archive_candidate: 0,
|
|
3884
|
-
explicit_capture_review: 0,
|
|
3885
|
-
malformed_import: 0,
|
|
3886
|
-
});
|
|
3887
|
-
const effectiveMetrics = metrics ? { ...metrics, qualityScore: metrics.qualityScore ?? qualityScore } : metrics;
|
|
3888
|
-
|
|
3889
|
-
return {
|
|
3890
|
-
found: true,
|
|
3891
|
-
namespace: resolvedNamespace,
|
|
3892
|
-
runId: projected.runId,
|
|
3893
|
-
summary: projected.summary as Awaited<ReturnType<typeof readMemoryGovernanceRunArtifact>>["summary"],
|
|
3894
|
-
metrics: effectiveMetrics,
|
|
3895
|
-
qualityScore,
|
|
3896
|
-
reviewQueue: projected.reviewQueueRows.map((row) => ({
|
|
3897
|
-
entryId: row.entryId,
|
|
3898
|
-
memoryId: row.memoryId,
|
|
3899
|
-
path: row.path,
|
|
3900
|
-
reasonCode: row.reasonCode,
|
|
3901
|
-
severity: row.severity,
|
|
3902
|
-
suggestedAction: row.suggestedAction,
|
|
3903
|
-
suggestedStatus: row.suggestedStatus,
|
|
3904
|
-
relatedMemoryIds: row.relatedMemoryIds,
|
|
3905
|
-
})) as Awaited<
|
|
3906
|
-
ReturnType<typeof readMemoryGovernanceRunArtifact>
|
|
3907
|
-
>["reviewQueue"],
|
|
3908
|
-
appliedActions: projectedAppliedActions,
|
|
3909
|
-
transitionReport,
|
|
3910
|
-
report: projected.report,
|
|
3911
|
-
};
|
|
3912
|
-
}
|
|
3913
|
-
|
|
3914
|
-
const resolvedRunId = runId?.trim() || (await listMemoryGovernanceRuns(storage.dir))[0];
|
|
3915
|
-
if (!resolvedRunId) return { found: false, namespace: resolvedNamespace };
|
|
3916
|
-
const artifact = await readMemoryGovernanceRunArtifact(storage.dir, resolvedRunId);
|
|
3917
|
-
return {
|
|
3918
|
-
found: true,
|
|
3919
|
-
namespace: resolvedNamespace,
|
|
3920
|
-
runId: resolvedRunId,
|
|
3921
|
-
summary: artifact.summary,
|
|
3922
|
-
metrics: artifact.metrics,
|
|
3923
|
-
qualityScore: artifact.qualityScore,
|
|
3924
|
-
reviewQueue: artifact.reviewQueue,
|
|
3925
|
-
appliedActions: artifact.appliedActions,
|
|
3926
|
-
transitionReport: artifact.transitionReport,
|
|
3927
|
-
report: artifact.report,
|
|
3928
|
-
};
|
|
3864
|
+
return this.accessAdminOpsSurface.reviewQueue(
|
|
3865
|
+
runId,
|
|
3866
|
+
namespace,
|
|
3867
|
+
principal,
|
|
3868
|
+
);
|
|
3929
3869
|
}
|
|
3930
3870
|
|
|
3931
3871
|
async maintenance(namespace?: string, principal?: string): Promise<EngramAccessMaintenanceResponse> {
|
|
@@ -4010,56 +3950,10 @@ export class EngramAccessService {
|
|
|
4010
3950
|
summaryPath: string;
|
|
4011
3951
|
reportPath: string;
|
|
4012
3952
|
}> {
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
|
|
4016
|
-
}
|
|
4017
|
-
const resolvedNamespace = this.writableNamespaceFor(
|
|
4018
|
-
request.namespace,
|
|
4019
|
-
undefined,
|
|
4020
|
-
request.authenticatedPrincipal ?? principal,
|
|
3953
|
+
return this.accessAdminOpsSurface.governanceRun(
|
|
3954
|
+
request,
|
|
3955
|
+
principal,
|
|
4021
3956
|
);
|
|
4022
|
-
const storage = await this.orchestrator.getStorage(resolvedNamespace);
|
|
4023
|
-
const mode = request.mode === "apply" ? "apply" : "shadow";
|
|
4024
|
-
const boundedBatchSize =
|
|
4025
|
-
typeof request.batchSize === "number" && Number.isFinite(request.batchSize)
|
|
4026
|
-
? Math.max(1, Math.floor(request.batchSize))
|
|
4027
|
-
: undefined;
|
|
4028
|
-
const result = await runMemoryGovernance({
|
|
4029
|
-
memoryDir: storage.dir,
|
|
4030
|
-
mode,
|
|
4031
|
-
recentDays:
|
|
4032
|
-
typeof request.recentDays === "number" && Number.isFinite(request.recentDays)
|
|
4033
|
-
? Math.max(1, Math.floor(request.recentDays))
|
|
4034
|
-
: undefined,
|
|
4035
|
-
maxMemories:
|
|
4036
|
-
typeof request.maxMemories === "number" && Number.isFinite(request.maxMemories)
|
|
4037
|
-
? Math.max(1, Math.floor(request.maxMemories))
|
|
4038
|
-
: undefined,
|
|
4039
|
-
batchSize: boundedBatchSize,
|
|
4040
|
-
});
|
|
4041
|
-
if (mode === "apply") {
|
|
4042
|
-
try {
|
|
4043
|
-
await this.orchestrator.processEntitySynthesisQueue(
|
|
4044
|
-
resolvedNamespace,
|
|
4045
|
-
Math.min(boundedBatchSize ?? 5, 5),
|
|
4046
|
-
);
|
|
4047
|
-
} catch (error) {
|
|
4048
|
-
log.debug(`governanceRun: entity synthesis refresh failed after governance apply: ${error}`);
|
|
4049
|
-
}
|
|
4050
|
-
}
|
|
4051
|
-
|
|
4052
|
-
return {
|
|
4053
|
-
namespace: resolvedNamespace,
|
|
4054
|
-
runId: result.runId,
|
|
4055
|
-
traceId: result.traceId,
|
|
4056
|
-
mode: result.mode,
|
|
4057
|
-
reviewQueueCount: result.reviewQueue.length,
|
|
4058
|
-
proposedActionCount: result.proposedActions.length,
|
|
4059
|
-
appliedActionCount: result.appliedActions.length,
|
|
4060
|
-
summaryPath: result.summaryPath,
|
|
4061
|
-
reportPath: result.reportPath,
|
|
4062
|
-
};
|
|
4063
3957
|
}
|
|
4064
3958
|
|
|
4065
3959
|
async procedureMiningRun(
|
|
@@ -4225,160 +4119,17 @@ export class EngramAccessService {
|
|
|
4225
4119
|
reason?: string;
|
|
4226
4120
|
retryAfterMs?: number;
|
|
4227
4121
|
}> {
|
|
4228
|
-
|
|
4229
|
-
|
|
4230
|
-
|
|
4231
|
-
sessions: 0,
|
|
4232
|
-
chunks: 0,
|
|
4233
|
-
skipped: 0,
|
|
4234
|
-
skippedSessionKeys: [],
|
|
4235
|
-
embeddedRuns: 0,
|
|
4236
|
-
reason: "disabled",
|
|
4237
|
-
};
|
|
4238
|
-
}
|
|
4239
|
-
|
|
4240
|
-
const hours =
|
|
4241
|
-
typeof request.hours === "number" && Number.isFinite(request.hours)
|
|
4242
|
-
? Math.max(1, Math.floor(request.hours))
|
|
4243
|
-
: 24;
|
|
4244
|
-
|
|
4245
|
-
let sessionKey: string | undefined;
|
|
4246
|
-
if (request.sessionKey !== undefined) {
|
|
4247
|
-
if (typeof request.sessionKey !== "string" || request.sessionKey.trim().length === 0) {
|
|
4248
|
-
throw new EngramAccessInputError("sessionKey must be a non-empty string when provided");
|
|
4249
|
-
}
|
|
4250
|
-
sessionKey = request.sessionKey.trim();
|
|
4251
|
-
}
|
|
4252
|
-
|
|
4253
|
-
if (sessionKey) {
|
|
4254
|
-
const result = await this.orchestrator.updateConversationIndex(
|
|
4255
|
-
sessionKey,
|
|
4256
|
-
hours,
|
|
4257
|
-
{ embed: request.embed },
|
|
4258
|
-
);
|
|
4259
|
-
return {
|
|
4260
|
-
enabled: true,
|
|
4261
|
-
sessionKey,
|
|
4262
|
-
sessions: 1,
|
|
4263
|
-
chunks: result.chunks,
|
|
4264
|
-
skipped: result.skipped ? 1 : 0,
|
|
4265
|
-
skippedSessionKeys: result.skipped ? [sessionKey] : [],
|
|
4266
|
-
embeddedRuns: result.embedded ? 1 : 0,
|
|
4267
|
-
reason: result.reason,
|
|
4268
|
-
retryAfterMs: result.retryAfterMs,
|
|
4269
|
-
};
|
|
4270
|
-
}
|
|
4271
|
-
|
|
4272
|
-
const sessionKeys = await this.orchestrator.transcript.listSessionKeys();
|
|
4273
|
-
let chunks = 0;
|
|
4274
|
-
let skipped = 0;
|
|
4275
|
-
const skippedSessionKeys: string[] = [];
|
|
4276
|
-
let embeddedRuns = 0;
|
|
4277
|
-
|
|
4278
|
-
for (const sessionKey of sessionKeys) {
|
|
4279
|
-
const result = await this.orchestrator.updateConversationIndex(
|
|
4280
|
-
sessionKey,
|
|
4281
|
-
hours,
|
|
4282
|
-
{ embed: request.embed },
|
|
4283
|
-
);
|
|
4284
|
-
chunks += result.chunks;
|
|
4285
|
-
if (result.skipped) {
|
|
4286
|
-
skipped += 1;
|
|
4287
|
-
skippedSessionKeys.push(sessionKey);
|
|
4288
|
-
}
|
|
4289
|
-
if (result.embedded) {
|
|
4290
|
-
embeddedRuns += 1;
|
|
4291
|
-
}
|
|
4292
|
-
}
|
|
4293
|
-
|
|
4294
|
-
return {
|
|
4295
|
-
enabled: true,
|
|
4296
|
-
sessions: sessionKeys.length,
|
|
4297
|
-
chunks,
|
|
4298
|
-
skipped,
|
|
4299
|
-
skippedSessionKeys,
|
|
4300
|
-
embeddedRuns,
|
|
4301
|
-
};
|
|
4122
|
+
return this.accessAdminOpsSurface.conversationIndexUpdate(
|
|
4123
|
+
request,
|
|
4124
|
+
);
|
|
4302
4125
|
}
|
|
4303
4126
|
|
|
4304
4127
|
async profilingReport(
|
|
4305
4128
|
request: AccessProfilingReportRequest = {},
|
|
4306
4129
|
): Promise<AccessProfilingReportResponse> {
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
enabled: false,
|
|
4311
|
-
reason: "disabled",
|
|
4312
|
-
message: "Profiling is disabled. Set profilingEnabled: true in your plugin config to enable.",
|
|
4313
|
-
};
|
|
4314
|
-
}
|
|
4315
|
-
|
|
4316
|
-
const format = request.format ?? "ascii";
|
|
4317
|
-
if (format !== "ascii" && format !== "json") {
|
|
4318
|
-
throw new EngramAccessInputError("format must be one of: ascii, json");
|
|
4319
|
-
}
|
|
4320
|
-
|
|
4321
|
-
const limit = request.limit ?? 5;
|
|
4322
|
-
if (!Number.isInteger(limit) || limit < 1 || limit > 20) {
|
|
4323
|
-
throw new EngramAccessInputError("limit must be an integer between 1 and 20");
|
|
4324
|
-
}
|
|
4325
|
-
|
|
4326
|
-
const traces = profiler.getRecentTraces(limit);
|
|
4327
|
-
const stats = profiler.getStats();
|
|
4328
|
-
const bottleneck = profiler.identifyBottleneck();
|
|
4329
|
-
|
|
4330
|
-
if (format === "json") {
|
|
4331
|
-
return {
|
|
4332
|
-
enabled: true,
|
|
4333
|
-
format,
|
|
4334
|
-
traces,
|
|
4335
|
-
stats,
|
|
4336
|
-
bottleneck,
|
|
4337
|
-
};
|
|
4338
|
-
}
|
|
4339
|
-
|
|
4340
|
-
const lines: string[] = [];
|
|
4341
|
-
lines.push("Engram Profiling Report");
|
|
4342
|
-
lines.push("=".repeat(60));
|
|
4343
|
-
lines.push("");
|
|
4344
|
-
|
|
4345
|
-
type BucketEntry = { count: number; avgMs: number; p50Ms: number; p95Ms: number; maxMs: number };
|
|
4346
|
-
const allBuckets: Array<[string, Record<string, BucketEntry>]> = [
|
|
4347
|
-
["byKind", stats.byKind],
|
|
4348
|
-
["bySpan", stats.bySpan],
|
|
4349
|
-
];
|
|
4350
|
-
const hasStats = allBuckets.some(([, entries]) => Object.keys(entries).length > 0);
|
|
4351
|
-
if (hasStats) {
|
|
4352
|
-
lines.push("Aggregate Stats (all retained traces):");
|
|
4353
|
-
for (const [bucket, entries] of allBuckets) {
|
|
4354
|
-
for (const [key, summary] of Object.entries(entries)) {
|
|
4355
|
-
lines.push(
|
|
4356
|
-
` ${bucket}/${key}: avg=${summary.avgMs}ms p50=${summary.p50Ms}ms p95=${summary.p95Ms}ms max=${summary.maxMs}ms (n=${summary.count})`,
|
|
4357
|
-
);
|
|
4358
|
-
}
|
|
4359
|
-
}
|
|
4360
|
-
lines.push("");
|
|
4361
|
-
}
|
|
4362
|
-
|
|
4363
|
-
if (bottleneck) {
|
|
4364
|
-
lines.push(`Bottleneck: ${bottleneck}`);
|
|
4365
|
-
lines.push("");
|
|
4366
|
-
}
|
|
4367
|
-
|
|
4368
|
-
if (traces.length === 0) {
|
|
4369
|
-
lines.push("No traces recorded yet. Trigger a recall or extraction to see timing data.");
|
|
4370
|
-
} else {
|
|
4371
|
-
for (const trace of traces) {
|
|
4372
|
-
lines.push(formatProfileTraceAscii(trace));
|
|
4373
|
-
lines.push("");
|
|
4374
|
-
}
|
|
4375
|
-
}
|
|
4376
|
-
|
|
4377
|
-
return {
|
|
4378
|
-
enabled: true,
|
|
4379
|
-
format,
|
|
4380
|
-
report: lines.join("\n"),
|
|
4381
|
-
};
|
|
4130
|
+
return this.accessAdminOpsSurface.profilingReport(
|
|
4131
|
+
request,
|
|
4132
|
+
);
|
|
4382
4133
|
}
|
|
4383
4134
|
|
|
4384
4135
|
async trustZoneStatus(namespace?: string, principal?: string): Promise<EngramAccessTrustZoneStatusResponse> {
|
|
@@ -4865,212 +4616,9 @@ export class EngramAccessService {
|
|
|
4865
4616
|
}
|
|
4866
4617
|
|
|
4867
4618
|
async lcmSearch(request: EngramAccessLcmSearchRequest): Promise<EngramAccessLcmSearchResponse> {
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
}
|
|
4871
|
-
|
|
4872
|
-
const principal = this.resolveRequestPrincipal(request.sessionKey, request.authenticatedPrincipal);
|
|
4873
|
-
const hasExplicitNamespace =
|
|
4874
|
-
typeof request.namespace === "string" &&
|
|
4875
|
-
request.namespace.trim().length > 0;
|
|
4876
|
-
// Resolve the readable base namespace WITHOUT pre-authorizing `default`
|
|
4877
|
-
// (#1505 thread NBHWz). An EXPLICIT namespace is still authorized strictly
|
|
4878
|
-
// via `resolveReadableNamespace` (explicit reads must pass the ACL — throws
|
|
4879
|
-
// on an unreadable explicit namespace). For an IMPLICIT read, derive the
|
|
4880
|
-
// fallback from the ALREADY read-authorized recall namespace set instead of
|
|
4881
|
-
// read-authorizing `config.defaultNamespace`: under a restrictive `default`
|
|
4882
|
-
// READ policy where the principal's self namespace is readable, normal recall
|
|
4883
|
-
// still succeeds via `recallNamespacesForPrincipal`, so `lcmSearch` must too
|
|
4884
|
-
// (the same defect class the raw-excerpt path fixes). `undefined` ⇒ no
|
|
4885
|
-
// readable LCM namespace exists, so return NO rows rather than throwing.
|
|
4886
|
-
const profileLcmReadNamespaces = hasExplicitNamespace
|
|
4887
|
-
? null
|
|
4888
|
-
: this.resolveScopeProfileLcmReadNamespaces(
|
|
4889
|
-
request.sessionKey,
|
|
4890
|
-
request.authenticatedPrincipal,
|
|
4891
|
-
);
|
|
4892
|
-
const namespace = hasExplicitNamespace
|
|
4893
|
-
? this.resolveReadableNamespace(request.namespace, principal)
|
|
4894
|
-
: profileLcmReadNamespaces !== null
|
|
4895
|
-
? profileLcmReadNamespaces[0]
|
|
4896
|
-
: this.resolveImplicitLcmReadFallbackNamespace(principal);
|
|
4897
|
-
|
|
4898
|
-
if (!this.orchestrator.lcmEngine || !this.orchestrator.lcmEngine.enabled) {
|
|
4899
|
-
return {
|
|
4900
|
-
query: request.query,
|
|
4901
|
-
namespace: namespace ?? this.orchestrator.config.defaultNamespace,
|
|
4902
|
-
results: [],
|
|
4903
|
-
count: 0,
|
|
4904
|
-
lcmEnabled: false,
|
|
4905
|
-
};
|
|
4906
|
-
}
|
|
4907
|
-
|
|
4908
|
-
// An active scope profile with no readable layers is authoritative: search
|
|
4909
|
-
// no legacy/default LCM keys instead of falling back around the profile.
|
|
4910
|
-
if (profileLcmReadNamespaces !== null && profileLcmReadNamespaces.length === 0) {
|
|
4911
|
-
return {
|
|
4912
|
-
query: request.query,
|
|
4913
|
-
namespace: this.orchestrator.config.defaultNamespace,
|
|
4914
|
-
results: [],
|
|
4915
|
-
count: 0,
|
|
4916
|
-
lcmEnabled: true,
|
|
4917
|
-
};
|
|
4918
|
-
}
|
|
4919
|
-
|
|
4920
|
-
// No readable LCM namespace for an IMPLICIT read (restrictive `default` READ
|
|
4921
|
-
// policy, no readable overlay/self) ⇒ return NO rows instead of pre-
|
|
4922
|
-
// authorizing the denied default (#1505 thread NBHWz). Normal recall still
|
|
4923
|
-
// succeeds through the readable self namespace; LCM search degrades to empty.
|
|
4924
|
-
if (namespace === undefined) {
|
|
4925
|
-
return {
|
|
4926
|
-
query: request.query,
|
|
4927
|
-
namespace: this.orchestrator.config.defaultNamespace,
|
|
4928
|
-
results: [],
|
|
4929
|
-
count: 0,
|
|
4930
|
-
lcmEnabled: true,
|
|
4931
|
-
};
|
|
4932
|
-
}
|
|
4933
|
-
|
|
4934
|
-
const limit = Math.max(1, Math.min(request.limit ?? 10, 100));
|
|
4935
|
-
// Route the LCM read session_id AND prefix through the SAME overlay-aware
|
|
4936
|
-
// namespace `observe`'s write key and compaction use (#1505 round 3). A
|
|
4937
|
-
// project-scoped `observe` with no explicit namespace archived under the
|
|
4938
|
-
// coding-overlay namespace; deriving the prefix only from the readable
|
|
4939
|
-
// `namespace` (as before) would search the raw key and miss those turns.
|
|
4940
|
-
// The effective namespace is resolved ONCE from the real session
|
|
4941
|
-
// (`request.sessionKey`) — the prefix is a search fragment with no bound
|
|
4942
|
-
// coding context, so it inherits the same namespace. Collapses to the raw key
|
|
4943
|
-
// for single-store / no-overlay / explicit-default flows (existing behavior).
|
|
4944
|
-
const lcmReadNamespace = profileLcmReadNamespaces !== null
|
|
4945
|
-
? profileLcmReadNamespaces[0] ?? this.orchestrator.config.defaultNamespace
|
|
4946
|
-
: this.resolveLcmReadNamespace(
|
|
4947
|
-
request.namespace,
|
|
4948
|
-
namespace,
|
|
4949
|
-
request.sessionKey,
|
|
4950
|
-
request.authenticatedPrincipal,
|
|
4951
|
-
);
|
|
4952
|
-
// Ordered, read-authorized LCM read key SET for a concrete `sessionKey`
|
|
4953
|
-
// (#1505 fallback unification + #1501 scope profiles). A branch-scoped
|
|
4954
|
-
// session whose rows were archived at project/root scope is found by querying
|
|
4955
|
-
// the primary overlay key first, then each fallback. When a scope profile is
|
|
4956
|
-
// active, the profile's expanded read namespace set is authoritative,
|
|
4957
|
-
// including the empty set.
|
|
4958
|
-
const lcmSessionKeyIds = request.sessionKey
|
|
4959
|
-
? profileLcmReadNamespaces !== null
|
|
4960
|
-
? this.lcmSessionIdsForNamespaces(
|
|
4961
|
-
profileLcmReadNamespaces,
|
|
4962
|
-
request.sessionKey,
|
|
4963
|
-
)
|
|
4964
|
-
: this.resolveLcmReadSessionIds(
|
|
4965
|
-
request.namespace,
|
|
4966
|
-
namespace,
|
|
4967
|
-
request.sessionKey,
|
|
4968
|
-
request.authenticatedPrincipal,
|
|
4969
|
-
)
|
|
4970
|
-
: [undefined];
|
|
4971
|
-
const lcmSessionPrefixes = request.sessionPrefix
|
|
4972
|
-
? profileLcmReadNamespaces !== null && !request.sessionKey
|
|
4973
|
-
? this.lcmSessionIdsForNamespaces(
|
|
4974
|
-
profileLcmReadNamespaces,
|
|
4975
|
-
request.sessionPrefix,
|
|
4976
|
-
)
|
|
4977
|
-
: [
|
|
4978
|
-
lcmSessionKeyForNamespace(
|
|
4979
|
-
lcmReadNamespace,
|
|
4980
|
-
request.sessionPrefix,
|
|
4981
|
-
this.orchestrator.config.defaultNamespace,
|
|
4982
|
-
) ?? request.sessionPrefix,
|
|
4983
|
-
]
|
|
4984
|
-
: [undefined];
|
|
4985
|
-
// SECURITY (#1495 P1 + codex P1 r2 "Require a scoped LCM filter before
|
|
4986
|
-
// archive searches"): a sessionless, prefixless `lcmSearch` issues
|
|
4987
|
-
// `searchContextFull(query, limit, undefined, undefined)`, an archive-wide
|
|
4988
|
-
// FTS scan over EVERY `session_id`, including the sentinel-framed
|
|
4989
|
-
// `<ns>`-scoped overlay/tenant rows. The LCM archive is keyed by the
|
|
4990
|
-
// `session_id` STRING and is NOT partitioned by namespace, so an unscoped
|
|
4991
|
-
// scan CANNOT be constrained to the caller's authorized namespace — neither
|
|
4992
|
-
// an explicit `namespace` nor a readable `default` confines its results to
|
|
4993
|
-
// rows the caller may read. The scan is therefore safe ONLY in single-store
|
|
4994
|
-
// mode (namespaces disabled, one shared archive owned by the caller). When
|
|
4995
|
-
// namespaces are ENABLED, an unscoped `lcmSearch` (no `sessionKey` AND no
|
|
4996
|
-
// `sessionPrefix`) must be SUPPRESSED — return EMPTY — regardless of an
|
|
4997
|
-
// explicit namespace or default-readability, so a caller authorized for
|
|
4998
|
-
// `default` (or for one explicit namespace) cannot read other namespaces'
|
|
4999
|
-
// transcript rows via the archive-wide scan (cross-tenant read leak). A
|
|
5000
|
-
// SCOPED call (sessionKey or sessionPrefix present) is unaffected: it carries
|
|
5001
|
-
// a namespace-framed `session_id` / prefix filter that already constrains the
|
|
5002
|
-
// search to the caller's authorized, read-gated namespace.
|
|
5003
|
-
const hasScopedSession =
|
|
5004
|
-
(typeof request.sessionKey === "string" &&
|
|
5005
|
-
request.sessionKey.length > 0) ||
|
|
5006
|
-
lcmSessionPrefixes.some((prefix) => typeof prefix === "string" && prefix.length > 0);
|
|
5007
|
-
if (!hasScopedSession && resolveNamespaceCapabilities(this.orchestrator.config).namespaces === true) {
|
|
5008
|
-
return {
|
|
5009
|
-
query: request.query,
|
|
5010
|
-
namespace,
|
|
5011
|
-
results: [],
|
|
5012
|
-
count: 0,
|
|
5013
|
-
lcmEnabled: true,
|
|
5014
|
-
};
|
|
5015
|
-
}
|
|
5016
|
-
// Query each LCM read key in order, merging + deduping rows (by
|
|
5017
|
-
// sessionId+turnIndex) and preserving first-seen order, capped at `limit`.
|
|
5018
|
-
// Use allSettled so one corrupt/failed namespace key cannot discard sibling
|
|
5019
|
-
// results from other authorized profile namespaces.
|
|
5020
|
-
const seenRows = new Set<string>();
|
|
5021
|
-
const results: Array<{ sessionId: string; content: string; turnIndex: number }> = [];
|
|
5022
|
-
const lcmSearches: Array<{
|
|
5023
|
-
key: string | undefined;
|
|
5024
|
-
prefix: string | undefined;
|
|
5025
|
-
promise: Promise<Array<{ session_id: string; content: string; turn_index: number }>>;
|
|
5026
|
-
}> = [];
|
|
5027
|
-
for (const lcmSessionKey of lcmSessionKeyIds) {
|
|
5028
|
-
for (const lcmSessionPrefix of lcmSessionPrefixes) {
|
|
5029
|
-
lcmSearches.push({
|
|
5030
|
-
key: lcmSessionKey,
|
|
5031
|
-
prefix: lcmSessionPrefix,
|
|
5032
|
-
promise: this.orchestrator.lcmEngine.searchContextFull(
|
|
5033
|
-
request.query,
|
|
5034
|
-
limit,
|
|
5035
|
-
lcmSessionKey,
|
|
5036
|
-
lcmSessionPrefix,
|
|
5037
|
-
) as Promise<Array<{ session_id: string; content: string; turn_index: number }>>,
|
|
5038
|
-
});
|
|
5039
|
-
}
|
|
5040
|
-
}
|
|
5041
|
-
const settledSearches = await Promise.allSettled(
|
|
5042
|
-
lcmSearches.map((search) => search.promise),
|
|
4619
|
+
return this.accessLcmSurface.lcmSearch(
|
|
4620
|
+
request,
|
|
5043
4621
|
);
|
|
5044
|
-
for (let i = 0; i < settledSearches.length; i += 1) {
|
|
5045
|
-
if (results.length >= limit) break;
|
|
5046
|
-
const settled = settledSearches[i];
|
|
5047
|
-
if (!settled || settled.status === "rejected") {
|
|
5048
|
-
const failed = lcmSearches[i];
|
|
5049
|
-
log.warn(
|
|
5050
|
-
`lcmSearch: failed for key=${failed?.key ?? "<none>"} prefix=${failed?.prefix ?? "<none>"}: ${settled?.status === "rejected" ? settled.reason : "missing result"}`,
|
|
5051
|
-
);
|
|
5052
|
-
continue;
|
|
5053
|
-
}
|
|
5054
|
-
for (const r of settled.value) {
|
|
5055
|
-
const dedupeKey = `${r.session_id}\0${r.turn_index}`;
|
|
5056
|
-
if (seenRows.has(dedupeKey)) continue;
|
|
5057
|
-
seenRows.add(dedupeKey);
|
|
5058
|
-
results.push({
|
|
5059
|
-
sessionId: r.session_id,
|
|
5060
|
-
content: r.content,
|
|
5061
|
-
turnIndex: r.turn_index,
|
|
5062
|
-
});
|
|
5063
|
-
if (results.length >= limit) break;
|
|
5064
|
-
}
|
|
5065
|
-
}
|
|
5066
|
-
|
|
5067
|
-
return {
|
|
5068
|
-
query: request.query,
|
|
5069
|
-
namespace,
|
|
5070
|
-
results,
|
|
5071
|
-
count: results.length,
|
|
5072
|
-
lcmEnabled: true,
|
|
5073
|
-
};
|
|
5074
4622
|
}
|
|
5075
4623
|
|
|
5076
4624
|
/**
|
|
@@ -5095,38 +4643,6 @@ export class EngramAccessService {
|
|
|
5095
4643
|
* so the read key is byte-for-byte what the LCM write and the recall readers
|
|
5096
4644
|
* use.
|
|
5097
4645
|
*/
|
|
5098
|
-
/**
|
|
5099
|
-
* Resolve the effective LCM NAMESPACE a same-session operation must prefix
|
|
5100
|
-
* with (the namespace half of {@link resolveLcmReadSessionKey}). Split out so
|
|
5101
|
-
* `lcmSearch` can apply ONE namespace to BOTH its `sessionKey` and its
|
|
5102
|
-
* `sessionPrefix` — the prefix is a search fragment, not a real session, so its
|
|
5103
|
-
* own coding context can't be looked up; it must inherit the namespace resolved
|
|
5104
|
-
* from the real session (`sessionKeyForOverlay`).
|
|
5105
|
-
*
|
|
5106
|
-
* `purpose` selects the AUTHORIZATION gate applied before honouring the
|
|
5107
|
-
* coding overlay (#1505 round 3 + round 4, codex P2):
|
|
5108
|
-
*
|
|
5109
|
-
* - `"read"` (`lcmSearch` / raw-excerpt recall): the overlay rows are only
|
|
5110
|
-
* visible when the principal SELF base is in the READABLE RECALL SET — the
|
|
5111
|
-
* same gate the orchestrator's `lcmReadNamespaceForSession` and the recall
|
|
5112
|
-
* namespace set use (`recallNamespacesForPrincipal`, gated by both
|
|
5113
|
-
* `defaultRecallNamespaces.includes("self")` AND `canReadNamespace`). A
|
|
5114
|
-
* caller that passed the default read check must NOT receive
|
|
5115
|
-
* `<principal>-project-*` rows the policy never granted (cross-tenant read
|
|
5116
|
-
* leak). When the self base is not readable, keep the just-authorized
|
|
5117
|
-
* namespace (collapses to the raw key on the default store).
|
|
5118
|
-
*
|
|
5119
|
-
* - `"write"` (`lcmCompactionFlush` / `lcmCompactionRecord`): these are
|
|
5120
|
-
* write/maintenance operations on the SAME queue `observe` just wrote, so
|
|
5121
|
-
* the gate must mirror observe's WRITE authorization (`canWriteNamespace`
|
|
5122
|
-
* on the self base), NOT readability. A principal that can WRITE but not
|
|
5123
|
-
* READ its self namespace (or whose `defaultRecallNamespaces` omits `self`)
|
|
5124
|
-
* archived under the overlay key via `observe`; gating compaction by
|
|
5125
|
-
* readability would fall back to the default/raw key and leave that queue
|
|
5126
|
-
* never flushed/recorded (round-4 codex P2). Write-authorized ⇒ overlay
|
|
5127
|
-
* key, matching the observe write key (rule 42 read/write parity; rule 39
|
|
5128
|
-
* identical gates across paths).
|
|
5129
|
-
*/
|
|
5130
4646
|
private resolveLcmReadNamespace(
|
|
5131
4647
|
explicitNamespace: string | undefined,
|
|
5132
4648
|
resolvedNamespace: string,
|
|
@@ -5134,134 +4650,24 @@ export class EngramAccessService {
|
|
|
5134
4650
|
authenticatedPrincipal: string | undefined,
|
|
5135
4651
|
purpose: "read" | "write" = "read",
|
|
5136
4652
|
): string {
|
|
5137
|
-
|
|
5138
|
-
|
|
5139
|
-
|
|
5140
|
-
// Mirror observe's write resolution: use the coding-overlay namespace when
|
|
5141
|
-
// one applies, else the default store. NOT the principal self base — an
|
|
5142
|
-
// unqualified observe archives under the default store, so a self-base prefix
|
|
5143
|
-
// here would target a queue observe never wrote to (#1495).
|
|
5144
|
-
const principal = this.resolveRequestPrincipal(
|
|
4653
|
+
return this.accessLcmSurface.resolveLcmReadNamespace(
|
|
4654
|
+
explicitNamespace,
|
|
4655
|
+
resolvedNamespace,
|
|
5145
4656
|
sessionKeyForOverlay,
|
|
5146
4657
|
authenticatedPrincipal,
|
|
4658
|
+
purpose,
|
|
5147
4659
|
);
|
|
5148
|
-
const base = defaultNamespaceForPrincipal(principal, this.orchestrator.config);
|
|
5149
|
-
const overlaid = this.orchestrator.applyCodingNamespaceOverlay(
|
|
5150
|
-
sessionKeyForOverlay,
|
|
5151
|
-
base,
|
|
5152
|
-
);
|
|
5153
|
-
// No overlay → the default store (raw sessionKey), as before.
|
|
5154
|
-
if (overlaid === base) return this.orchestrator.config.defaultNamespace;
|
|
5155
|
-
// Overlay applied. Authorize access to the principal's `<principal>-project-*`
|
|
5156
|
-
// overlay base before switching the LCM key to it. The gate differs by
|
|
5157
|
-
// operation purpose (see the doc comment): reads use the readable-recall-set
|
|
5158
|
-
// gate (no cross-tenant read leak), writes use observe's write authorization
|
|
5159
|
-
// (so compaction targets the same overlay queue observe wrote to).
|
|
5160
|
-
const authorized =
|
|
5161
|
-
purpose === "write"
|
|
5162
|
-
? canWriteNamespace(principal, base, this.orchestrator.config)
|
|
5163
|
-
: recallNamespacesForPrincipal(
|
|
5164
|
-
principal,
|
|
5165
|
-
this.orchestrator.config,
|
|
5166
|
-
).includes(base);
|
|
5167
|
-
if (authorized) return overlaid;
|
|
5168
|
-
// Unauthorized overlay base. For READS, collapse to the DEFAULT STORE (the
|
|
5169
|
-
// raw sessionKey) EXACTLY like the orchestrator's `lcmReadNamespaceForSession`
|
|
5170
|
-
// (rule 39 / 42) — NOT the caller's `resolvedNamespace`, which for an implicit
|
|
5171
|
-
// read can be a readable recall namespace (e.g. `shared`). Returning that
|
|
5172
|
-
// would prefix LCM reads with `shared:sessionKey` while in-prompt recall uses
|
|
5173
|
-
// the raw `sessionKey`, diverging `lcmSearch`/raw disclosure from orchestrator
|
|
5174
|
-
// LCM reads (cursor "LCM read gate wrong fallback"). For an explicit read the
|
|
5175
|
-
// method already returned at the top, so this only affects implicit reads.
|
|
5176
|
-
// The (currently unused) write purpose preserves its prior `resolvedNamespace`
|
|
5177
|
-
// fallback for backward compatibility.
|
|
5178
|
-
if (purpose === "read") return this.orchestrator.config.defaultNamespace;
|
|
5179
|
-
return resolvedNamespace;
|
|
5180
4660
|
}
|
|
5181
4661
|
|
|
5182
|
-
/**
|
|
5183
|
-
* Resolve the namespace the raw-disclosure excerpt lookup
|
|
5184
|
-
* ({@link fetchRawExcerpts}) must prefix its LCM `session_id` with (#1505
|
|
5185
|
-
* thread 2f7). Raw disclosure reads the SAME LCM archive `lcmSearch` and the
|
|
5186
|
-
* in-prompt LCM sections read, so it MUST pass through the identical
|
|
5187
|
-
* read-authorization gate — NOT `snapshot.namespace`, which records the
|
|
5188
|
-
* effective WRITE/overlay namespace (`<principal>-project-*`) even when the
|
|
5189
|
-
* principal can WRITE but not READ its self base (or `defaultRecallNamespaces`
|
|
5190
|
-
* omits `self`). Routing through `resolveLcmReadNamespace(..., "read")` makes
|
|
5191
|
-
* raw disclosure fall back to the default store exactly like normal recall +
|
|
5192
|
-
* `lcmSearch`, so it never attaches overlay transcript rows the read gate
|
|
5193
|
-
* excludes (cross-tenant read leak). Collapses to the default store / raw
|
|
5194
|
-
* sessionKey for single-store / no-overlay / explicit-default flows, so
|
|
5195
|
-
* single-user recall is byte-for-byte unchanged.
|
|
5196
|
-
*
|
|
5197
|
-
* Returns `undefined` when NO readable LCM namespace exists for an IMPLICIT
|
|
5198
|
-
* (no explicit `namespace`) raw recall — i.e. a restrictive `default` READ
|
|
5199
|
-
* policy denies the principal `default` AND no overlay/self namespace is
|
|
5200
|
-
* readable. In that case the caller emits NO excerpts rather than throwing
|
|
5201
|
-
* `namespace is not readable: default` (#1505 thread NBHWz): normal recall
|
|
5202
|
-
* still succeeds via `recallNamespacesForPrincipal`, so `disclosure: "raw"`
|
|
5203
|
-
* must degrade gracefully (empty excerpts), never pre-authorize `default`.
|
|
5204
|
-
*
|
|
5205
|
-
* IMPLICIT-namespace fallback selection derives from the ALREADY
|
|
5206
|
-
* read-authorized recall namespace set (`recallNamespacesForPrincipal` +
|
|
5207
|
-
* `canReadNamespace`) — the principal's self base when it is in the readable
|
|
5208
|
-
* recall set, else `config.defaultNamespace` ONLY when the principal may read
|
|
5209
|
-
* it. It NEVER pre-authorizes `default`. An EXPLICIT `namespace` is still
|
|
5210
|
-
* authorized strictly via `resolveReadableNamespace` (explicit reads must pass
|
|
5211
|
-
* the ACL — no behavior change).
|
|
5212
|
-
*/
|
|
5213
4662
|
private resolveRawExcerptReadNamespace(
|
|
5214
4663
|
explicitNamespace: string | undefined,
|
|
5215
4664
|
sessionKey: string | undefined,
|
|
5216
4665
|
authenticatedPrincipal: string | undefined,
|
|
5217
4666
|
): string | undefined {
|
|
5218
|
-
|
|
5219
|
-
sessionKey,
|
|
5220
|
-
authenticatedPrincipal,
|
|
5221
|
-
);
|
|
5222
|
-
const hasExplicitNamespace =
|
|
5223
|
-
typeof explicitNamespace === "string" &&
|
|
5224
|
-
explicitNamespace.trim().length > 0;
|
|
5225
|
-
if (hasExplicitNamespace) {
|
|
5226
|
-
// Explicit reads must pass the ACL — authorize strictly, exactly as
|
|
5227
|
-
// `lcmSearch` does (throws on an unreadable explicit namespace).
|
|
5228
|
-
const resolvedNamespace = this.resolveReadableNamespace(
|
|
5229
|
-
explicitNamespace,
|
|
5230
|
-
principal,
|
|
5231
|
-
);
|
|
5232
|
-
return this.resolveLcmReadNamespace(
|
|
5233
|
-
explicitNamespace,
|
|
5234
|
-
resolvedNamespace,
|
|
5235
|
-
sessionKey,
|
|
5236
|
-
authenticatedPrincipal,
|
|
5237
|
-
"read",
|
|
5238
|
-
);
|
|
5239
|
-
}
|
|
5240
|
-
// IMPLICIT raw recall: an active scope profile owns the same LCM read
|
|
5241
|
-
// namespace set used by recall and lcmSearch. Return the first profile
|
|
5242
|
-
// namespace as the legacy raw-excerpt namespace hint; the concrete ordered
|
|
5243
|
-
// key set is still produced by resolveLcmReadSessionIds(), which also treats
|
|
5244
|
-
// an empty profile read set as authoritative.
|
|
5245
|
-
const profileReadNamespaces = this.resolveScopeProfileLcmReadNamespaces(
|
|
5246
|
-
sessionKey,
|
|
5247
|
-
authenticatedPrincipal,
|
|
5248
|
-
);
|
|
5249
|
-
if (profileReadNamespaces !== null) return profileReadNamespaces[0];
|
|
5250
|
-
|
|
5251
|
-
// Otherwise derive the read fallback from the ALREADY read-authorized recall
|
|
5252
|
-
// namespace set — NEVER pre-authorize `default` (#1505 thread NBHWz). When
|
|
5253
|
-
// namespaces are disabled the default store is the only namespace and is
|
|
5254
|
-
// always readable (byte-for-byte single-user path).
|
|
5255
|
-
const fallbackNamespace =
|
|
5256
|
-
this.resolveImplicitLcmReadFallbackNamespace(principal);
|
|
5257
|
-
// No readable LCM namespace at all ⇒ no excerpts (caller short-circuits).
|
|
5258
|
-
if (fallbackNamespace === undefined) return undefined;
|
|
5259
|
-
return this.resolveLcmReadNamespace(
|
|
4667
|
+
return this.accessLcmSurface.resolveRawExcerptReadNamespace(
|
|
5260
4668
|
explicitNamespace,
|
|
5261
|
-
fallbackNamespace,
|
|
5262
4669
|
sessionKey,
|
|
5263
4670
|
authenticatedPrincipal,
|
|
5264
|
-
"read",
|
|
5265
4671
|
);
|
|
5266
4672
|
}
|
|
5267
4673
|
|
|
@@ -5437,76 +4843,12 @@ export class EngramAccessService {
|
|
|
5437
4843
|
sessionKey: string,
|
|
5438
4844
|
authenticatedPrincipal: string | undefined,
|
|
5439
4845
|
): string[] {
|
|
5440
|
-
|
|
4846
|
+
return this.accessLcmSurface.resolveLcmReadSessionIds(
|
|
5441
4847
|
explicitNamespace,
|
|
5442
4848
|
resolvedNamespace,
|
|
5443
4849
|
sessionKey,
|
|
5444
4850
|
authenticatedPrincipal,
|
|
5445
|
-
"read",
|
|
5446
4851
|
);
|
|
5447
|
-
const hasExplicitNamespace =
|
|
5448
|
-
typeof explicitNamespace === "string" &&
|
|
5449
|
-
explicitNamespace.trim().length > 0;
|
|
5450
|
-
// Explicit namespace → no overlay fallbacks (the overlay never applies to an
|
|
5451
|
-
// explicit read). Single key, unchanged.
|
|
5452
|
-
if (hasExplicitNamespace) return [primary];
|
|
5453
|
-
|
|
5454
|
-
const profileReadNamespaces = this.resolveScopeProfileLcmReadNamespaces(
|
|
5455
|
-
sessionKey,
|
|
5456
|
-
authenticatedPrincipal,
|
|
5457
|
-
);
|
|
5458
|
-
if (profileReadNamespaces !== null) {
|
|
5459
|
-
return this.lcmSessionIdsForNamespaces(profileReadNamespaces, sessionKey);
|
|
5460
|
-
}
|
|
5461
|
-
|
|
5462
|
-
const principal = this.resolveRequestPrincipal(
|
|
5463
|
-
sessionKey,
|
|
5464
|
-
authenticatedPrincipal,
|
|
5465
|
-
);
|
|
5466
|
-
const base = defaultNamespaceForPrincipal(
|
|
5467
|
-
principal,
|
|
5468
|
-
this.orchestrator.config,
|
|
5469
|
-
);
|
|
5470
|
-
const overlaid = this.orchestrator.applyCodingNamespaceOverlay(
|
|
5471
|
-
sessionKey,
|
|
5472
|
-
base,
|
|
5473
|
-
);
|
|
5474
|
-
// No overlay → single default-store key, unchanged.
|
|
5475
|
-
if (overlaid === base) return [primary];
|
|
5476
|
-
// Overlay present but self base unreadable → the "read" gate already
|
|
5477
|
-
// collapsed `primary` to the default store; do NOT add overlay fallbacks
|
|
5478
|
-
// (they would be unauthorized `<principal>-project-*` keys). Single key.
|
|
5479
|
-
const selfReadableInRecall = recallNamespacesForPrincipal(
|
|
5480
|
-
principal,
|
|
5481
|
-
this.orchestrator.config,
|
|
5482
|
-
).includes(base);
|
|
5483
|
-
if (!selfReadableInRecall) return [primary];
|
|
5484
|
-
// Self base readable → overlay rows authorized. Append one LCM key per coding
|
|
5485
|
-
// read fallback (project → root), combined with the principal base for
|
|
5486
|
-
// isolation — the SAME ordered set the orchestrator recall path searches.
|
|
5487
|
-
const overlay = resolveCodingNamespaceOverlay(
|
|
5488
|
-
this.orchestrator.getCodingContextForSession(sessionKey),
|
|
5489
|
-
this.orchestrator.config.codingMode,
|
|
5490
|
-
this.orchestrator.config.defaultNamespace,
|
|
5491
|
-
);
|
|
5492
|
-
const fallbackNamespaces = (overlay?.readFallbacks ?? []).map((fallback) =>
|
|
5493
|
-
combineNamespaces(base, fallback),
|
|
5494
|
-
);
|
|
5495
|
-
const out = [primary];
|
|
5496
|
-
const seen = new Set<string>([primary]);
|
|
5497
|
-
for (const ns of fallbackNamespaces) {
|
|
5498
|
-
const key =
|
|
5499
|
-
lcmSessionKeyForNamespace(
|
|
5500
|
-
ns,
|
|
5501
|
-
sessionKey,
|
|
5502
|
-
this.orchestrator.config.defaultNamespace,
|
|
5503
|
-
) ?? sessionKey;
|
|
5504
|
-
if (!seen.has(key)) {
|
|
5505
|
-
seen.add(key);
|
|
5506
|
-
out.push(key);
|
|
5507
|
-
}
|
|
5508
|
-
}
|
|
5509
|
-
return out;
|
|
5510
4852
|
}
|
|
5511
4853
|
|
|
5512
4854
|
async lcmCompactionFlush(
|
|
@@ -6316,134 +5658,14 @@ export class EngramAccessService {
|
|
|
6316
5658
|
return { explanation };
|
|
6317
5659
|
}
|
|
6318
5660
|
|
|
6319
|
-
/**
|
|
6320
|
-
* Read-only graph snapshot for the admin pane (issue #691 PR 2/5).
|
|
6321
|
-
*
|
|
6322
|
-
* Reads adjacency from the JSONL edge store written by `GraphIndex` and
|
|
6323
|
-
* resolves node metadata via the namespaced storage manager. Namespace
|
|
6324
|
-
* resolution mirrors the read-side path used by `recall` /
|
|
6325
|
-
* `procedureStats`, so multi-principal deployments can't leak edges from
|
|
6326
|
-
* a peer namespace (CLAUDE.md rule 42).
|
|
6327
|
-
*/
|
|
6328
5661
|
async graphSnapshot(
|
|
6329
5662
|
request: GraphSnapshotRequest & { namespace?: string },
|
|
6330
5663
|
authenticatedPrincipal?: string,
|
|
6331
5664
|
): Promise<GraphSnapshotResponse> {
|
|
6332
|
-
|
|
6333
|
-
request
|
|
5665
|
+
return this.accessAdminOpsSurface.graphSnapshot(
|
|
5666
|
+
request,
|
|
6334
5667
|
authenticatedPrincipal,
|
|
6335
5668
|
);
|
|
6336
|
-
const storage = await this.orchestrator.getStorage(namespace);
|
|
6337
|
-
const cfg = this.orchestrator.config;
|
|
6338
|
-
const graphCaps = resolveGraphConstructionCapabilities(cfg);
|
|
6339
|
-
// Canonicalize the storage root once — through `realpath` so that any
|
|
6340
|
-
// symlink in the namespace root path itself is resolved before we
|
|
6341
|
-
// compare children against it. This is required because
|
|
6342
|
-
// `GraphEdge.from` / `to` are JSONL-parsed strings — a malformed edge
|
|
6343
|
-
// with an absolute path, a `..` segment, OR a symlink that resolves
|
|
6344
|
-
// to a file outside the namespace would otherwise read a memory file
|
|
6345
|
-
// from a peer namespace, leaking metadata across tenants
|
|
6346
|
-
// (codex P1 + follow-up on PR #734; CLAUDE.md rule 42).
|
|
6347
|
-
let namespaceRootReal: string;
|
|
6348
|
-
try {
|
|
6349
|
-
namespaceRootReal = await nodeFs.realpath(storage.dir);
|
|
6350
|
-
} catch {
|
|
6351
|
-
// If the namespace root itself doesn't exist on disk yet (fresh
|
|
6352
|
-
// install with no memories), fall back to the lexical resolve so
|
|
6353
|
-
// the snapshot can still return an empty result rather than
|
|
6354
|
-
// throwing. No symlink can resolve through a missing path, so
|
|
6355
|
-
// this fallback is safe — every candidate we see will fail the
|
|
6356
|
-
// realpath step below and surface as `null`.
|
|
6357
|
-
namespaceRootReal = nodePath.resolve(storage.dir);
|
|
6358
|
-
}
|
|
6359
|
-
const namespaceRootWithSep = namespaceRootReal.endsWith(nodePath.sep)
|
|
6360
|
-
? namespaceRootReal
|
|
6361
|
-
: namespaceRootReal + nodePath.sep;
|
|
6362
|
-
const loadNode = async (relPath: string): Promise<GraphSnapshotNodeMetadata | null> => {
|
|
6363
|
-
// `GraphEdge.from` / `to` are storage-relative paths; resolve against
|
|
6364
|
-
// the namespaced storage root so the metadata read honors namespace
|
|
6365
|
-
// boundaries even when the same memory id exists in multiple
|
|
6366
|
-
// namespaces.
|
|
6367
|
-
//
|
|
6368
|
-
// Three-stage guard:
|
|
6369
|
-
// 1. Reject absolute paths up front — only relative endpoints are
|
|
6370
|
-
// ever produced by the writer, so anything else is malformed.
|
|
6371
|
-
// 2. Lexical containment check on the resolved path. This catches
|
|
6372
|
-
// `..` traversals before we touch the filesystem.
|
|
6373
|
-
// 3. `fs.realpath` containment check — resolves symlinks so an
|
|
6374
|
-
// in-namespace path that *points* at an out-of-namespace file
|
|
6375
|
-
// is still rejected. Without this step a symlinked endpoint
|
|
6376
|
-
// could leak a peer namespace's frontmatter.
|
|
6377
|
-
// Bad paths surface a length-only warning (never echo the offending
|
|
6378
|
-
// segments — those would themselves cross namespace boundaries
|
|
6379
|
-
// through the log surface) and fall through to a `null` metadata
|
|
6380
|
-
// result.
|
|
6381
|
-
if (nodePath.isAbsolute(relPath)) {
|
|
6382
|
-
log.warn(
|
|
6383
|
-
`graphSnapshot: rejected absolute edge endpoint (len=${relPath.length}) `
|
|
6384
|
-
+ `outside namespace root`,
|
|
6385
|
-
);
|
|
6386
|
-
return null;
|
|
6387
|
-
}
|
|
6388
|
-
const candidate = nodePath.resolve(namespaceRootReal, relPath);
|
|
6389
|
-
if (candidate !== namespaceRootReal && !candidate.startsWith(namespaceRootWithSep)) {
|
|
6390
|
-
log.warn(
|
|
6391
|
-
`graphSnapshot: rejected traversing edge endpoint (len=${relPath.length}) `
|
|
6392
|
-
+ `outside namespace root`,
|
|
6393
|
-
);
|
|
6394
|
-
return null;
|
|
6395
|
-
}
|
|
6396
|
-
let canonical: string;
|
|
6397
|
-
try {
|
|
6398
|
-
canonical = await nodeFs.realpath(candidate);
|
|
6399
|
-
} catch {
|
|
6400
|
-
// Missing file — `readMemoryByPath` will return null too. We
|
|
6401
|
-
// intentionally still call it so callers see a consistent
|
|
6402
|
-
// "unknown" result rather than special-casing missing edges.
|
|
6403
|
-
canonical = candidate;
|
|
6404
|
-
}
|
|
6405
|
-
if (canonical !== namespaceRootReal && !canonical.startsWith(namespaceRootWithSep)) {
|
|
6406
|
-
log.warn(
|
|
6407
|
-
`graphSnapshot: rejected symlinked edge endpoint (len=${relPath.length}) `
|
|
6408
|
-
+ `that resolved outside namespace root`,
|
|
6409
|
-
);
|
|
6410
|
-
return null;
|
|
6411
|
-
}
|
|
6412
|
-
// Both `canonical` (realpath of candidate) and `namespaceRootReal`
|
|
6413
|
-
// (realpath of storage.dir) are fully resolved here, so the
|
|
6414
|
-
// containment check above is comparing apples-to-apples even when
|
|
6415
|
-
// storage.dir (= storage.baseDir) is itself a symlink to the real
|
|
6416
|
-
// directory. Pass `canonical` — not the pre-realpath `candidate` —
|
|
6417
|
-
// so the storage read also uses the stable real path.
|
|
6418
|
-
const memory = await storage.readMemoryByPath(canonical);
|
|
6419
|
-
if (!memory) return null;
|
|
6420
|
-
const fm = memory.frontmatter;
|
|
6421
|
-
return {
|
|
6422
|
-
category: fm.category ?? "unknown",
|
|
6423
|
-
label: fm.id ?? nodePath.basename(canonical, nodePath.extname(canonical)),
|
|
6424
|
-
updated: fm.updated,
|
|
6425
|
-
};
|
|
6426
|
-
};
|
|
6427
|
-
// Use the realpath-resolved namespace root for the edge-file read so
|
|
6428
|
-
// the JSONL location is stable whether storage.dir is a direct path
|
|
6429
|
-
// or a symlink. namespaceRootReal was computed via `fs.realpath`
|
|
6430
|
-
// above; using it here keeps both the graph-file I/O and the loadNode
|
|
6431
|
-
// containment check on the same resolved base path.
|
|
6432
|
-
return buildGraphSnapshot({
|
|
6433
|
-
memoryDir: namespaceRootReal,
|
|
6434
|
-
graphConfig: {
|
|
6435
|
-
entityGraph: graphCaps.entityGraph,
|
|
6436
|
-
timeGraph: graphCaps.timeGraph,
|
|
6437
|
-
causalGraph: graphCaps.causalGraph,
|
|
6438
|
-
},
|
|
6439
|
-
request: {
|
|
6440
|
-
limit: request.limit,
|
|
6441
|
-
since: request.since,
|
|
6442
|
-
focusNodeId: request.focusNodeId,
|
|
6443
|
-
categories: request.categories,
|
|
6444
|
-
},
|
|
6445
|
-
loadNode,
|
|
6446
|
-
});
|
|
6447
5669
|
}
|
|
6448
5670
|
|
|
6449
5671
|
async memoryFeedback(request: {
|
|
@@ -7140,108 +6362,13 @@ export class EngramAccessService {
|
|
|
7140
6362
|
});
|
|
7141
6363
|
}
|
|
7142
6364
|
|
|
7143
|
-
/**
|
|
7144
|
-
* List capsule archives in the namespace-scoped capsule store.
|
|
7145
|
-
*
|
|
7146
|
-
* MCP uses this access-layer method instead of reading arbitrary paths so
|
|
7147
|
-
* capsule discovery remains bound to the same namespace ACLs as export and
|
|
7148
|
-
* import.
|
|
7149
|
-
*/
|
|
7150
6365
|
async capsuleList(options?: {
|
|
7151
6366
|
namespace?: string;
|
|
7152
6367
|
principal?: string;
|
|
7153
6368
|
}): Promise<EngramAccessCapsuleListResponse> {
|
|
7154
|
-
|
|
7155
|
-
|
|
7156
|
-
|
|
7157
|
-
let dirEntries: import("node:fs").Dirent[];
|
|
7158
|
-
try {
|
|
7159
|
-
const capsulesDirStat = await nodeFs.lstat(capsulesDir);
|
|
7160
|
-
if (capsulesDirStat.isSymbolicLink()) {
|
|
7161
|
-
throw new EngramAccessInputError("capsule list failed: capsule store directory must not be a symlink");
|
|
7162
|
-
}
|
|
7163
|
-
if (!capsulesDirStat.isDirectory()) {
|
|
7164
|
-
throw new EngramAccessInputError("capsule list failed: capsule store path must be a directory");
|
|
7165
|
-
}
|
|
7166
|
-
dirEntries = await nodeFs.readdir(capsulesDir, { withFileTypes: true });
|
|
7167
|
-
} catch (err) {
|
|
7168
|
-
const code = typeof err === "object" && err !== null && "code" in err
|
|
7169
|
-
? (err as { code?: unknown }).code
|
|
7170
|
-
: undefined;
|
|
7171
|
-
if (code === "ENOENT") {
|
|
7172
|
-
return { namespace: resolvedNamespace, capsulesDir, capsules: [] };
|
|
7173
|
-
}
|
|
7174
|
-
throw err;
|
|
7175
|
-
}
|
|
7176
|
-
|
|
7177
|
-
const archiveNames = dirEntries
|
|
7178
|
-
.filter(
|
|
7179
|
-
(entry) =>
|
|
7180
|
-
entry.isFile() &&
|
|
7181
|
-
(entry.name.endsWith(".capsule.json.gz") ||
|
|
7182
|
-
entry.name.endsWith(".capsule.json.gz.enc")),
|
|
7183
|
-
)
|
|
7184
|
-
.map((entry) => entry.name)
|
|
7185
|
-
.sort();
|
|
7186
|
-
|
|
7187
|
-
const capsules: CapsuleListEntry[] = [];
|
|
7188
|
-
for (const archiveName of archiveNames) {
|
|
7189
|
-
const archivePath = nodePath.join(capsulesDir, archiveName);
|
|
7190
|
-
const id = archiveName
|
|
7191
|
-
.replace(/\.capsule\.json\.gz\.enc$/, "")
|
|
7192
|
-
.replace(/\.capsule\.json\.gz$/, "");
|
|
7193
|
-
const manifestPath = nodePath.join(capsulesDir, `${id}.manifest.json`);
|
|
7194
|
-
|
|
7195
|
-
let createdAt: string | null = null;
|
|
7196
|
-
let pluginVersion: string | null = null;
|
|
7197
|
-
let fileCount: number | null = null;
|
|
7198
|
-
let description: string | null = null;
|
|
7199
|
-
let manifestPathOrNull: string | null = manifestPath;
|
|
7200
|
-
|
|
7201
|
-
try {
|
|
7202
|
-
const manifestStat = await nodeFs.lstat(manifestPath);
|
|
7203
|
-
if (manifestStat.isSymbolicLink() || !manifestStat.isFile()) {
|
|
7204
|
-
capsules.push({
|
|
7205
|
-
id,
|
|
7206
|
-
archivePath,
|
|
7207
|
-
manifestPath: manifestPathOrNull,
|
|
7208
|
-
createdAt,
|
|
7209
|
-
pluginVersion,
|
|
7210
|
-
fileCount,
|
|
7211
|
-
description,
|
|
7212
|
-
});
|
|
7213
|
-
continue;
|
|
7214
|
-
}
|
|
7215
|
-
const raw = await nodeFs.readFile(manifestPath, "utf-8");
|
|
7216
|
-
const sidecar = JSON.parse(raw) as Record<string, unknown>;
|
|
7217
|
-
createdAt = typeof sidecar.createdAt === "string" ? sidecar.createdAt : null;
|
|
7218
|
-
pluginVersion = typeof sidecar.pluginVersion === "string" ? sidecar.pluginVersion : null;
|
|
7219
|
-
fileCount = Array.isArray(sidecar.files) ? sidecar.files.length : null;
|
|
7220
|
-
const capsule = sidecar.capsule as Record<string, unknown> | undefined;
|
|
7221
|
-
description = capsule && typeof capsule.description === "string"
|
|
7222
|
-
? capsule.description
|
|
7223
|
-
: null;
|
|
7224
|
-
} catch (err) {
|
|
7225
|
-
const code = typeof err === "object" && err !== null && "code" in err
|
|
7226
|
-
? (err as { code?: unknown }).code
|
|
7227
|
-
: undefined;
|
|
7228
|
-
if (code === "ENOENT") {
|
|
7229
|
-
manifestPathOrNull = null;
|
|
7230
|
-
}
|
|
7231
|
-
}
|
|
7232
|
-
|
|
7233
|
-
capsules.push({
|
|
7234
|
-
id,
|
|
7235
|
-
archivePath,
|
|
7236
|
-
manifestPath: manifestPathOrNull,
|
|
7237
|
-
createdAt,
|
|
7238
|
-
pluginVersion,
|
|
7239
|
-
fileCount,
|
|
7240
|
-
description,
|
|
7241
|
-
});
|
|
7242
|
-
}
|
|
7243
|
-
|
|
7244
|
-
return { namespace: resolvedNamespace, capsulesDir, capsules };
|
|
6369
|
+
return this.accessAdminOpsSurface.capsuleList(
|
|
6370
|
+
options,
|
|
6371
|
+
);
|
|
7245
6372
|
}
|
|
7246
6373
|
|
|
7247
6374
|
/**
|
|
@@ -7484,87 +6611,15 @@ export class EngramAccessService {
|
|
|
7484
6611
|
return getDreamsStatus(storage.dir, windowHours);
|
|
7485
6612
|
}
|
|
7486
6613
|
|
|
7487
|
-
/**
|
|
7488
|
-
* Manually invoke a single Dreams phase pass (PR 4/4).
|
|
7489
|
-
*
|
|
7490
|
-
* Deep-sleep delegates to memory governance (shadow → dry-run, apply → live).
|
|
7491
|
-
* Light-sleep and REM scan the observation ledger and memory corpus
|
|
7492
|
-
* respectively, returning the same telemetry shape as a scheduled run.
|
|
7493
|
-
*/
|
|
7494
6614
|
async dreamsRun(options: {
|
|
7495
6615
|
phase: import("./types.js").DreamsPhase;
|
|
7496
6616
|
dryRun?: boolean;
|
|
7497
6617
|
namespace?: string;
|
|
7498
6618
|
authenticatedPrincipal?: string;
|
|
7499
6619
|
}): Promise<import("./types.js").DreamsRunResult> {
|
|
7500
|
-
|
|
7501
|
-
|
|
7502
|
-
if (!validPhases.includes(options.phase)) {
|
|
7503
|
-
throw new EngramAccessInputError(
|
|
7504
|
-
`Invalid phase: ${String(options.phase)}. Must be one of: ${validPhases.join(", ")}`,
|
|
7505
|
-
);
|
|
7506
|
-
}
|
|
7507
|
-
const deepSleep = this.orchestrator.config.dreamsPhases.deepSleep;
|
|
7508
|
-
if (
|
|
7509
|
-
options.phase === "deepSleep" &&
|
|
7510
|
-
deepSleep.enabled === false &&
|
|
7511
|
-
deepSleep.enabledExplicitlySet === true
|
|
7512
|
-
) {
|
|
7513
|
-
throw new EngramAccessInputError(
|
|
7514
|
-
"memory governance is disabled by dreams.phases.deepSleep.enabled=false",
|
|
7515
|
-
);
|
|
7516
|
-
}
|
|
7517
|
-
const dryRun = options.dryRun === true;
|
|
7518
|
-
const resolvedNamespace = this.writableNamespaceFor(
|
|
7519
|
-
options.namespace,
|
|
7520
|
-
undefined,
|
|
7521
|
-
options.authenticatedPrincipal,
|
|
7522
|
-
);
|
|
7523
|
-
const storage = await this.orchestrator.getStorage(resolvedNamespace);
|
|
7524
|
-
const memoryDir = storage.dir;
|
|
7525
|
-
const phaseRunner = dryRun || options.phase === "deepSleep"
|
|
7526
|
-
? undefined
|
|
7527
|
-
: async (_opts: { memoryDir: string; phase: "lightSleep" | "rem" }) => {
|
|
7528
|
-
if (_opts.phase === "lightSleep") {
|
|
7529
|
-
const result = await this.orchestrator.runLifecyclePolicyNow(storage);
|
|
7530
|
-
return {
|
|
7531
|
-
itemsProcessed: result.memoriesAssessed,
|
|
7532
|
-
notes: `scored ${result.memoriesAssessed} memories`,
|
|
7533
|
-
};
|
|
7534
|
-
}
|
|
7535
|
-
const result = await this.orchestrator.runSemanticConsolidationNow({
|
|
7536
|
-
dryRun: false,
|
|
7537
|
-
storage,
|
|
7538
|
-
});
|
|
7539
|
-
const itemsProcessed = result.clusters.reduce(
|
|
7540
|
-
(sum, cluster) => sum + cluster.memories.length,
|
|
7541
|
-
0,
|
|
7542
|
-
);
|
|
7543
|
-
return {
|
|
7544
|
-
itemsProcessed,
|
|
7545
|
-
notes: `REM consolidation found ${result.clustersFound} clusters`,
|
|
7546
|
-
};
|
|
7547
|
-
};
|
|
7548
|
-
const governanceRunner = options.phase === "deepSleep"
|
|
7549
|
-
? async (_opts: { memoryDir: string; dryRun: boolean }) => {
|
|
7550
|
-
return this.orchestrator.runDeepSleepGovernanceNow({
|
|
7551
|
-
storage,
|
|
7552
|
-
dryRun: _opts.dryRun,
|
|
7553
|
-
});
|
|
7554
|
-
}
|
|
7555
|
-
: undefined;
|
|
7556
|
-
const result = await runDreamsPhase(
|
|
7557
|
-
{ memoryDir, phase: options.phase, dryRun },
|
|
7558
|
-
governanceRunner,
|
|
7559
|
-
phaseRunner,
|
|
6620
|
+
return this.accessAdminOpsSurface.dreamsRun(
|
|
6621
|
+
options,
|
|
7560
6622
|
);
|
|
7561
|
-
return {
|
|
7562
|
-
phase: result.phase,
|
|
7563
|
-
dryRun: result.dryRun,
|
|
7564
|
-
durationMs: result.durationMs,
|
|
7565
|
-
itemsProcessed: result.itemsProcessed,
|
|
7566
|
-
notes: result.notes,
|
|
7567
|
-
};
|
|
7568
6623
|
}
|
|
7569
6624
|
|
|
7570
6625
|
// ---------------------------------------------------------------------------
|
|
@@ -7723,12 +6778,6 @@ export class EngramAccessService {
|
|
|
7723
6778
|
return redactSensitive(result);
|
|
7724
6779
|
}
|
|
7725
6780
|
|
|
7726
|
-
/**
|
|
7727
|
-
* Manually promote a memory into one or more authorized targets. Requires
|
|
7728
|
-
* a non-empty reason (audit-logged). Reuses the scope-profile promotion
|
|
7729
|
-
* resolution and `canWriteNamespace` gate — there is no dashboard-only
|
|
7730
|
-
* write path.
|
|
7731
|
-
*/
|
|
7732
6781
|
async adminPromoteMemory(request: {
|
|
7733
6782
|
sourceMemoryId: string;
|
|
7734
6783
|
namespace?: string;
|
|
@@ -7738,111 +6787,9 @@ export class EngramAccessService {
|
|
|
7738
6787
|
reason: string;
|
|
7739
6788
|
actor?: never; // ignored — actor is derived from the authenticated principal
|
|
7740
6789
|
}) {
|
|
7741
|
-
|
|
7742
|
-
|
|
7743
|
-
|
|
7744
|
-
// scope plan (principal self / scope-profile write layer / coding overlay)
|
|
7745
|
-
// instead of falling through to config.defaultNamespace. This matches the
|
|
7746
|
-
// runtime observe/write path.
|
|
7747
|
-
let sourceNamespace: string;
|
|
7748
|
-
if (request.namespace) {
|
|
7749
|
-
sourceNamespace = this.resolveReadableNamespace(
|
|
7750
|
-
request.namespace,
|
|
7751
|
-
request.principal,
|
|
7752
|
-
);
|
|
7753
|
-
} else {
|
|
7754
|
-
const codingContext = request.sessionKey
|
|
7755
|
-
? this.orchestrator.getCodingContextForSession(request.sessionKey) ?? null
|
|
7756
|
-
: null;
|
|
7757
|
-
const plan = resolveScopePlan({
|
|
7758
|
-
config,
|
|
7759
|
-
sessionKey: request.sessionKey,
|
|
7760
|
-
principalOverride: request.principal,
|
|
7761
|
-
codingContext,
|
|
7762
|
-
namespacesEnabled,
|
|
7763
|
-
});
|
|
7764
|
-
sourceNamespace = this.resolveReadableNamespace(
|
|
7765
|
-
plan.baseNamespace,
|
|
7766
|
-
request.principal,
|
|
7767
|
-
);
|
|
7768
|
-
}
|
|
7769
|
-
// Fix OdB0c: thread coding context into the scope-profile plan so
|
|
7770
|
-
// userProject/teamProject promotion targets resolve for project-scoped
|
|
7771
|
-
// sessions (previously hard-coded to null).
|
|
7772
|
-
const codingContext = request.sessionKey
|
|
7773
|
-
? this.orchestrator.getCodingContextForSession(request.sessionKey) ?? null
|
|
7774
|
-
: null;
|
|
7775
|
-
const codingOverlay = codingContext
|
|
7776
|
-
? resolveCodingNamespaceOverlay(
|
|
7777
|
-
codingContext,
|
|
7778
|
-
config.codingMode,
|
|
7779
|
-
config.defaultNamespace,
|
|
7780
|
-
)
|
|
7781
|
-
: null;
|
|
7782
|
-
const scopeProfilePlan = resolveScopeProfilePlan({
|
|
7783
|
-
config,
|
|
7784
|
-
principal: request.principal,
|
|
7785
|
-
codingContext,
|
|
7786
|
-
codingOverlay,
|
|
7787
|
-
});
|
|
7788
|
-
const storage: PromotionStorageProvider = {
|
|
7789
|
-
readMemory: async (namespace, memoryId) => {
|
|
7790
|
-
const resolved = await this.orchestrator.getStorage(namespace);
|
|
7791
|
-
const memory = await resolved.getMemoryById(memoryId);
|
|
7792
|
-
if (!memory) return null;
|
|
7793
|
-
return {
|
|
7794
|
-
category: memory.frontmatter.category,
|
|
7795
|
-
content: memory.content,
|
|
7796
|
-
frontmatter: memory.frontmatter,
|
|
7797
|
-
};
|
|
7798
|
-
},
|
|
7799
|
-
writePromotedMemory: async (namespace, memory) => {
|
|
7800
|
-
const resolved = await this.orchestrator.getStorage(namespace);
|
|
7801
|
-
const { id, tombstoneBlocked } = await resolved.writeMemory(
|
|
7802
|
-
memory.category,
|
|
7803
|
-
memory.content,
|
|
7804
|
-
{
|
|
7805
|
-
confidence: memory.confidence,
|
|
7806
|
-
tags: memory.tags,
|
|
7807
|
-
entityRef: memory.entityRef,
|
|
7808
|
-
source: `admin-promotion:${memory.sourceNamespace}:${memory.reason.slice(0, 120)}`,
|
|
7809
|
-
lineage: memory.lineage,
|
|
7810
|
-
sourceMemoryId: memory.sourceMemoryId,
|
|
7811
|
-
actor: memory.actor,
|
|
7812
|
-
validAt: memory.validAt,
|
|
7813
|
-
},
|
|
7814
|
-
);
|
|
7815
|
-
// #1645: a tombstone-blocked promotion lands pending_review (no active
|
|
7816
|
-
// copy in the target). Report it as a failed promotion so the admin
|
|
7817
|
-
// sees an honest result — the content is queued for review, not
|
|
7818
|
-
// actively promoted. promoteMemory's catch block sanitizes this into
|
|
7819
|
-
// a generic "promotion write failed" audit entry.
|
|
7820
|
-
if (tombstoneBlocked) {
|
|
7821
|
-
throw new Error(
|
|
7822
|
-
"target namespace tombstone-blocked the promoted content (pending_review)",
|
|
7823
|
-
);
|
|
7824
|
-
}
|
|
7825
|
-
return id;
|
|
7826
|
-
},
|
|
7827
|
-
};
|
|
7828
|
-
try {
|
|
7829
|
-
return await promoteMemory({
|
|
7830
|
-
config,
|
|
7831
|
-
sourceMemoryId: request.sourceMemoryId,
|
|
7832
|
-
sourceNamespace,
|
|
7833
|
-
principal: request.principal,
|
|
7834
|
-
targets: request.targets,
|
|
7835
|
-
reason: request.reason,
|
|
7836
|
-
actor: request.principal ?? "admin-console",
|
|
7837
|
-
storage,
|
|
7838
|
-
scopeProfilePlan,
|
|
7839
|
-
});
|
|
7840
|
-
} catch (err) {
|
|
7841
|
-
if (err instanceof AdminPromotionError) {
|
|
7842
|
-
throw new EngramAccessInputError(err.message);
|
|
7843
|
-
}
|
|
7844
|
-
throw err;
|
|
7845
|
-
}
|
|
6790
|
+
return this.accessAdminOpsSurface.adminPromoteMemory(
|
|
6791
|
+
request,
|
|
6792
|
+
);
|
|
7846
6793
|
}
|
|
7847
6794
|
}
|
|
7848
6795
|
|