@remnic/core 9.63.6 → 9.63.8
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 +3 -2
- package/dist/access-admin-ops-surface.js +31 -27
- package/dist/access-authorization-probe.d.ts +3 -2
- package/dist/access-authorization-probe.js +32 -28
- package/dist/access-boundary.d.ts +3 -2
- package/dist/access-boundary.js +31 -27
- package/dist/access-cli.js +98 -95
- package/dist/access-cli.js.map +1 -1
- package/dist/access-extraction-force-flush.d.ts +3 -2
- package/dist/access-extraction-force-flush.js +31 -27
- package/dist/access-http-lcm-compaction.d.ts +3 -2
- package/dist/access-http-lifecycle-flush.d.ts +3 -2
- package/dist/access-http-offline-stream.d.ts +3 -2
- package/dist/access-http-query.js +33 -29
- package/dist/access-http.d.ts +4 -3
- package/dist/access-http.js +47 -43
- package/dist/access-identity-continuity-surface.d.ts +2 -1
- package/dist/access-identity-continuity-surface.js +31 -27
- package/dist/access-lcm-surface.d.ts +3 -2
- package/dist/access-lcm-surface.js +31 -27
- package/dist/access-mcp-output-schemas.js +1 -1
- package/dist/access-mcp.d.ts +3 -2
- package/dist/access-mcp.js +38 -34
- package/dist/access-namespace-preflight.js +31 -27
- package/dist/access-observe-write-surface.d.ts +3 -2
- package/dist/access-observe-write-surface.js +31 -27
- package/dist/access-offline-manifest.d.ts +2 -1
- package/dist/access-offline-manifest.js +5 -4
- package/dist/access-operations-batch.js +32 -28
- package/dist/access-operations.d.ts +3 -2
- package/dist/access-operations.js +36 -32
- package/dist/access-recall-concurrency.d.ts +3 -2
- package/dist/access-recall-concurrency.js +31 -27
- package/dist/access-recall-response.d.ts +3 -2
- package/dist/access-recall-response.js +31 -27
- package/dist/access-recall-surface.d.ts +3 -2
- package/dist/access-recall-surface.js +31 -27
- package/dist/access-schema.js +6 -5
- package/dist/{access-service-cKQrte9Z.d.ts → access-service-BaPa_km6.d.ts} +1 -1
- package/dist/access-service-helpers.d.ts +3 -2
- package/dist/access-service.d.ts +3 -2
- package/dist/access-service.js +31 -27
- package/dist/access-surface-catalog.d.ts +3 -2
- package/dist/access-surface-catalog.js +33 -29
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/active-recall.js +4 -2
- package/dist/active-recall.js.map +1 -1
- package/dist/adapters/index.js +4 -4
- package/dist/adapters/registry.js +2 -2
- package/dist/{auto-sync-BKRJDMKX.js → auto-sync-3SHMZVQS.js} +5 -3
- package/dist/{auto-sync-BKRJDMKX.js.map → auto-sync-3SHMZVQS.js.map} +1 -1
- package/dist/bootstrap.d.ts +2 -1
- package/dist/briefing.js +10 -10
- package/dist/calibration.d.ts +2 -1
- package/dist/calibration.js +7 -0
- package/dist/calibration.js.map +1 -1
- package/dist/{capsule-crypto-7FJQINUR.js → capsule-crypto-YO5QJ6L3.js} +2 -2
- package/dist/causal-consolidation.js +11 -11
- package/dist/census-validation.d.ts +19 -0
- package/dist/census-validation.js +14 -0
- package/dist/census-validation.js.map +1 -0
- package/dist/{chunk-LEPOP46W.js → chunk-227UFSEQ.js} +4 -4
- package/dist/chunk-2YA5N2BY.js +65 -0
- package/dist/chunk-2YA5N2BY.js.map +1 -0
- package/dist/{chunk-PB4WVYGC.js → chunk-3IMYRX3W.js} +2 -2
- package/dist/{chunk-R6UMNP5C.js → chunk-3T6HIIKA.js} +2 -2
- package/dist/{chunk-77QZW2D6.js → chunk-3TDAA7VA.js} +2 -2
- package/dist/{chunk-TWTUGCTY.js → chunk-3YTTAGPB.js} +6 -1
- package/dist/chunk-3YTTAGPB.js.map +1 -0
- package/dist/{chunk-DXDAQZ2K.js → chunk-42TIIO2M.js} +2 -2
- package/dist/{chunk-Y7COCXY2.js → chunk-4F67JJPG.js} +2 -2
- package/dist/{chunk-OW7NVMGQ.js → chunk-5OOTHWGJ.js} +2 -2
- package/dist/{chunk-KYTRF64R.js → chunk-5SCFDQEJ.js} +2 -2
- package/dist/{chunk-DYZR3Z6D.js → chunk-5TF5STAV.js} +4 -4
- package/dist/{chunk-GG4DN63W.js → chunk-62Y5AGCM.js} +2 -2
- package/dist/{chunk-PMVPCZJZ.js → chunk-6433HV72.js} +2 -2
- package/dist/{chunk-KHCUVYCY.js → chunk-6UKSOXAO.js} +3 -3
- package/dist/{chunk-GF7RQWXC.js → chunk-AJRJDXYR.js} +2 -2
- package/dist/{chunk-YEQCMA5L.js → chunk-BOSIHHOH.js} +2 -2
- package/dist/{chunk-IVXVLDNT.js → chunk-BPQ7L27U.js} +77 -92
- package/dist/chunk-BPQ7L27U.js.map +1 -0
- package/dist/{chunk-7LF2OHIJ.js → chunk-BRHKW7GY.js} +2 -2
- package/dist/{chunk-2NLLXCJG.js → chunk-BXLOS5AJ.js} +2 -2
- package/dist/{chunk-LX4TNSAE.js → chunk-CBY54QYW.js} +4 -4
- package/dist/{chunk-CIAI24TQ.js → chunk-DGUVXXAU.js} +3 -3
- package/dist/{chunk-X7Y7WX73.js → chunk-DQEMWVMT.js} +1 -1
- package/dist/{chunk-QI5RDDEL.js → chunk-EDZNW3HE.js} +3 -3
- package/dist/chunk-FEHIOYML.js +168 -0
- package/dist/chunk-FEHIOYML.js.map +1 -0
- package/dist/{chunk-Z4N7SVVF.js → chunk-FZEEWOI2.js} +9 -4
- package/dist/chunk-FZEEWOI2.js.map +1 -0
- package/dist/{chunk-6YMEU6OQ.js → chunk-G72IPMR7.js} +2 -2
- package/dist/{chunk-7AF243WZ.js → chunk-GBVRVYF4.js} +1 -1
- package/dist/{chunk-FPEZ74F7.js → chunk-I2HTKOOP.js} +3 -3
- package/dist/{chunk-R7TZ2HCS.js → chunk-JG22O53B.js} +58 -3
- package/dist/chunk-JG22O53B.js.map +1 -0
- package/dist/{chunk-VPHSMJ2E.js → chunk-JPWSYHLB.js} +2 -2
- package/dist/{chunk-X7LEDA74.js → chunk-KFB4YNXM.js} +2 -2
- package/dist/{chunk-I5FLIB2J.js → chunk-KXWE62IH.js} +2 -2
- package/dist/chunk-LQWOFU6L.js +17 -0
- package/dist/chunk-LQWOFU6L.js.map +1 -0
- package/dist/{chunk-TSTI6A3A.js → chunk-LTYH2L6E.js} +13 -13
- package/dist/{chunk-ZUPKNWRZ.js → chunk-MIUL6AUZ.js} +3 -3
- package/dist/{chunk-EJY3HJMT.js → chunk-MYI3RKI6.js} +2 -2
- package/dist/{chunk-UCLMKNHA.js → chunk-N7V3P4V5.js} +2 -2
- package/dist/{chunk-NA56NSKL.js → chunk-O52TB5SL.js} +2 -2
- package/dist/{chunk-7KQB4EBS.js → chunk-OPPBTPUU.js} +4 -4
- package/dist/{chunk-ERPBRXVZ.js → chunk-PHKU6BZ2.js} +2 -2
- package/dist/{chunk-GTD4Q62X.js → chunk-PQHNZ63P.js} +4 -4
- package/dist/{chunk-FHKXVTM5.js → chunk-Q5XKKDFQ.js} +16 -16
- package/dist/{chunk-QRWMS6SI.js → chunk-Q6OL23WM.js} +2 -2
- package/dist/{chunk-V3KIRICY.js → chunk-QQYHYW2N.js} +3 -3
- package/dist/{chunk-YFCEBB5P.js → chunk-QTXNS3HB.js} +2 -2
- package/dist/{chunk-2QSZNTDO.js → chunk-RKNJBZ55.js} +4 -4
- package/dist/{chunk-E4KMY4KR.js → chunk-SNEUAZ6B.js} +2 -2
- package/dist/{chunk-F6JYBVL6.js → chunk-SY5JUJ2X.js} +52 -52
- package/dist/{chunk-EFKZT6AY.js → chunk-T42L3S6A.js} +6 -11
- package/dist/chunk-T42L3S6A.js.map +1 -0
- package/dist/{chunk-YXMHUBN2.js → chunk-TOP3FSDW.js} +25 -102
- package/dist/chunk-TOP3FSDW.js.map +1 -0
- package/dist/{chunk-PBRCYYO7.js → chunk-ULZFZL7K.js} +2 -2
- package/dist/{chunk-YYQAKIDJ.js → chunk-VD2OT77P.js} +2 -2
- package/dist/chunk-VD2OT77P.js.map +1 -0
- package/dist/{chunk-IPLYGWQF.js → chunk-VDX2J7OX.js} +6 -6
- package/dist/{chunk-UGHCZS6K.js → chunk-VFZQXYN5.js} +2 -2
- package/dist/{chunk-NKB43PGI.js → chunk-VYMICVRA.js} +2 -2
- package/dist/{chunk-OETHJBAL.js → chunk-WBPD6SBZ.js} +109 -116
- package/dist/chunk-WBPD6SBZ.js.map +1 -0
- package/dist/{chunk-2UM6WHME.js → chunk-XE2QCCT2.js} +2 -2
- package/dist/{chunk-SYVGVK4S.js → chunk-XTMYB2HY.js} +2 -2
- package/dist/{chunk-AYVCKGA6.js → chunk-YTXNDEUS.js} +2 -2
- package/dist/{chunk-3Z5TGRFA.js → chunk-ZOAAY2OE.js} +9 -9
- package/dist/{chunk-L3CHRBHE.js → chunk-ZRUEP4IK.js} +17 -11
- package/dist/chunk-ZRUEP4IK.js.map +1 -0
- package/dist/{chunk-PRDJMOST.js → chunk-ZVZHG7AI.js} +65 -15
- package/dist/chunk-ZVZHG7AI.js.map +1 -0
- package/dist/{chunk-RYST72N5.js → chunk-ZWYXSF2T.js} +4 -154
- package/dist/chunk-ZWYXSF2T.js.map +1 -0
- package/dist/{cli-BFBDYV0D.d.ts → cli-D0tV7eeU.d.ts} +2 -2
- package/dist/cli.d.ts +4 -3
- package/dist/cli.js +69 -65
- package/dist/compounding/engine.js +10 -10
- package/dist/config.js +4 -2
- package/dist/connectors/codex-materialize-runner.js +10 -10
- package/dist/connectors/index.js +10 -10
- package/dist/consolidation-provenance-check.js +2 -2
- package/dist/convergence-refresh.js +12 -12
- package/dist/conversation-index/backend.js +2 -2
- package/dist/corpus-watermark.js +12 -12
- package/dist/entity-retrieval.js +10 -10
- package/dist/explicit-capture.d.ts +2 -1
- package/dist/external-wiki-access.d.ts +3 -2
- package/dist/external-wiki-access.js +32 -28
- package/dist/external-wiki-mcp-tools.d.ts +3 -2
- package/dist/extraction-judge.d.ts +2 -1
- package/dist/extraction-judge.js +6 -1
- package/dist/extraction-normalization.js +2 -2
- package/dist/extraction-prompt.d.ts +20 -1
- package/dist/extraction-prompt.js +11 -1
- package/dist/extraction.js +13 -13
- package/dist/harmonic-retrieval.js +1 -1
- package/dist/included-memories.d.ts +11 -0
- package/dist/included-memories.js +14 -0
- package/dist/included-memories.js.map +1 -0
- package/dist/index.d.ts +6 -5
- package/dist/index.js +117 -114
- package/dist/lcm/index.js +3 -3
- package/dist/maintenance/memory-governance.js +10 -10
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +10 -10
- package/dist/maintenance/rebuild-memory-projection.js +11 -11
- package/dist/mcp-memory-inspector-app.d.ts +3 -2
- package/dist/namespaces/migrate.js +11 -11
- package/dist/namespaces/search.js +4 -4
- package/dist/namespaces/storage.js +10 -10
- package/dist/offline-sync.js +2 -1
- package/dist/operator-doctor-corpus.js +13 -13
- package/dist/operator-toolkit.js +23 -21
- package/dist/orchestration/maintenance.js +16 -16
- package/dist/{orchestrator-CSc9GfQv.d.ts → orchestrator-Bay_AofR.d.ts} +2 -3
- package/dist/orchestrator.d.ts +2 -1
- package/dist/orchestrator.js +100 -97
- package/dist/{public-http-8PcrDIYi.d.ts → public-http-BtjiyKah.d.ts} +1 -1
- package/dist/recall-explain-renderer.d.ts +1 -0
- package/dist/recall-state.d.ts +6 -2
- package/dist/recall-state.js +6 -2
- package/dist/reconcile/cursor.js +7 -3
- package/dist/reconcile/cursor.js.map +1 -1
- package/dist/reconcile/manifest.js +3 -7
- package/dist/reconcile/plan.d.ts +15 -1
- package/dist/reconcile/plan.js +6 -10
- package/dist/resume-bundles.js +5 -3
- package/dist/search/factory.js +3 -3
- package/dist/search/index.js +3 -3
- package/dist/semantic-consolidation.js +16 -16
- package/dist/semantic-rule-promotion.js +10 -10
- package/dist/semantic-rule-verifier.js +10 -10
- package/dist/source-agent-qualifier.js +10 -10
- package/dist/storage.js +9 -9
- package/dist/support-passport/index.d.ts +6 -5
- package/dist/support-passport/index.js +34 -30
- package/dist/transfer/autodetect.js +1 -1
- package/dist/transfer/backup.js +2 -2
- package/dist/transfer/capsule-export.js +3 -3
- package/dist/transfer/capsule-import.js +2 -2
- package/dist/verified-recall.js +10 -10
- package/package.json +2 -2
- package/src/access-mcp-output-schemas.ts +1 -1
- package/src/access-recall-response.ts +4 -2
- package/src/access-recall-surface.ts +9 -9
- package/src/access-service-namespace.test.ts +9 -9
- package/src/access-service-raw-excerpt-read-gate.test.ts +1 -1
- package/src/calibration.ts +3 -1
- package/src/census-validation.ts +25 -0
- package/src/coding/architecture-surfaces.test.ts +9 -10
- package/src/coding/architecture-surfaces.ts +2 -35
- package/src/coding/codegraph-runtime-loader.test.ts +228 -0
- package/src/coding/codegraph-runtime.ts +30 -50
- package/src/coding/codegraph-surfaces.ts +2 -2
- package/src/coding/coding-knowledge-config.ts +35 -1
- package/src/coding/decision-surfaces.test.ts +9 -10
- package/src/coding/decision-surfaces.ts +2 -40
- package/src/coding/session-delta-surfaces.test.ts +9 -10
- package/src/coding/session-delta-surfaces.ts +2 -33
- package/src/extraction-judge.ts +3 -1
- package/src/extraction-output-language.test.ts +116 -0
- package/src/extraction-prompt.ts +70 -1
- package/src/extraction.ts +23 -95
- package/src/included-memories.ts +88 -0
- package/src/offline-sync.ts +4 -4
- package/src/orchestration/recall-internal-deps.ts +2 -4
- package/src/orchestration/recall-internal.ts +9 -13
- package/src/orchestration/recall-result-formatter-display-safe.test.ts +13 -16
- package/src/orchestration/recall-result-formatter.ts +32 -45
- package/src/orchestration/recall-section-coordinator.ts +20 -26
- package/src/orchestrator.ts +2 -4
- package/src/recall-explain-renderer.test.ts +4 -0
- package/src/recall-state.test.ts +108 -5
- package/src/recall-state.ts +85 -23
- package/src/recall-token-budget.test.ts +1 -1
- package/src/reconcile/census-parity.test.ts +152 -0
- package/src/reconcile/cursor.ts +5 -5
- package/src/reconcile/manifest.ts +4 -11
- package/src/reconcile/plan.ts +18 -15
- package/dist/chunk-EFKZT6AY.js.map +0 -1
- package/dist/chunk-IVXVLDNT.js.map +0 -1
- package/dist/chunk-L3CHRBHE.js.map +0 -1
- package/dist/chunk-OETHJBAL.js.map +0 -1
- package/dist/chunk-PRDJMOST.js.map +0 -1
- package/dist/chunk-R7TZ2HCS.js.map +0 -1
- package/dist/chunk-RYST72N5.js.map +0 -1
- package/dist/chunk-TWTUGCTY.js.map +0 -1
- package/dist/chunk-YXMHUBN2.js.map +0 -1
- package/dist/chunk-YYQAKIDJ.js.map +0 -1
- package/dist/chunk-Z4N7SVVF.js.map +0 -1
- /package/dist/{capsule-crypto-7FJQINUR.js.map → capsule-crypto-YO5QJ6L3.js.map} +0 -0
- /package/dist/{chunk-LEPOP46W.js.map → chunk-227UFSEQ.js.map} +0 -0
- /package/dist/{chunk-PB4WVYGC.js.map → chunk-3IMYRX3W.js.map} +0 -0
- /package/dist/{chunk-R6UMNP5C.js.map → chunk-3T6HIIKA.js.map} +0 -0
- /package/dist/{chunk-77QZW2D6.js.map → chunk-3TDAA7VA.js.map} +0 -0
- /package/dist/{chunk-DXDAQZ2K.js.map → chunk-42TIIO2M.js.map} +0 -0
- /package/dist/{chunk-Y7COCXY2.js.map → chunk-4F67JJPG.js.map} +0 -0
- /package/dist/{chunk-OW7NVMGQ.js.map → chunk-5OOTHWGJ.js.map} +0 -0
- /package/dist/{chunk-KYTRF64R.js.map → chunk-5SCFDQEJ.js.map} +0 -0
- /package/dist/{chunk-DYZR3Z6D.js.map → chunk-5TF5STAV.js.map} +0 -0
- /package/dist/{chunk-GG4DN63W.js.map → chunk-62Y5AGCM.js.map} +0 -0
- /package/dist/{chunk-PMVPCZJZ.js.map → chunk-6433HV72.js.map} +0 -0
- /package/dist/{chunk-KHCUVYCY.js.map → chunk-6UKSOXAO.js.map} +0 -0
- /package/dist/{chunk-GF7RQWXC.js.map → chunk-AJRJDXYR.js.map} +0 -0
- /package/dist/{chunk-YEQCMA5L.js.map → chunk-BOSIHHOH.js.map} +0 -0
- /package/dist/{chunk-7LF2OHIJ.js.map → chunk-BRHKW7GY.js.map} +0 -0
- /package/dist/{chunk-2NLLXCJG.js.map → chunk-BXLOS5AJ.js.map} +0 -0
- /package/dist/{chunk-LX4TNSAE.js.map → chunk-CBY54QYW.js.map} +0 -0
- /package/dist/{chunk-CIAI24TQ.js.map → chunk-DGUVXXAU.js.map} +0 -0
- /package/dist/{chunk-X7Y7WX73.js.map → chunk-DQEMWVMT.js.map} +0 -0
- /package/dist/{chunk-QI5RDDEL.js.map → chunk-EDZNW3HE.js.map} +0 -0
- /package/dist/{chunk-6YMEU6OQ.js.map → chunk-G72IPMR7.js.map} +0 -0
- /package/dist/{chunk-7AF243WZ.js.map → chunk-GBVRVYF4.js.map} +0 -0
- /package/dist/{chunk-FPEZ74F7.js.map → chunk-I2HTKOOP.js.map} +0 -0
- /package/dist/{chunk-VPHSMJ2E.js.map → chunk-JPWSYHLB.js.map} +0 -0
- /package/dist/{chunk-X7LEDA74.js.map → chunk-KFB4YNXM.js.map} +0 -0
- /package/dist/{chunk-I5FLIB2J.js.map → chunk-KXWE62IH.js.map} +0 -0
- /package/dist/{chunk-TSTI6A3A.js.map → chunk-LTYH2L6E.js.map} +0 -0
- /package/dist/{chunk-ZUPKNWRZ.js.map → chunk-MIUL6AUZ.js.map} +0 -0
- /package/dist/{chunk-EJY3HJMT.js.map → chunk-MYI3RKI6.js.map} +0 -0
- /package/dist/{chunk-UCLMKNHA.js.map → chunk-N7V3P4V5.js.map} +0 -0
- /package/dist/{chunk-NA56NSKL.js.map → chunk-O52TB5SL.js.map} +0 -0
- /package/dist/{chunk-7KQB4EBS.js.map → chunk-OPPBTPUU.js.map} +0 -0
- /package/dist/{chunk-ERPBRXVZ.js.map → chunk-PHKU6BZ2.js.map} +0 -0
- /package/dist/{chunk-GTD4Q62X.js.map → chunk-PQHNZ63P.js.map} +0 -0
- /package/dist/{chunk-FHKXVTM5.js.map → chunk-Q5XKKDFQ.js.map} +0 -0
- /package/dist/{chunk-QRWMS6SI.js.map → chunk-Q6OL23WM.js.map} +0 -0
- /package/dist/{chunk-V3KIRICY.js.map → chunk-QQYHYW2N.js.map} +0 -0
- /package/dist/{chunk-YFCEBB5P.js.map → chunk-QTXNS3HB.js.map} +0 -0
- /package/dist/{chunk-2QSZNTDO.js.map → chunk-RKNJBZ55.js.map} +0 -0
- /package/dist/{chunk-E4KMY4KR.js.map → chunk-SNEUAZ6B.js.map} +0 -0
- /package/dist/{chunk-F6JYBVL6.js.map → chunk-SY5JUJ2X.js.map} +0 -0
- /package/dist/{chunk-PBRCYYO7.js.map → chunk-ULZFZL7K.js.map} +0 -0
- /package/dist/{chunk-IPLYGWQF.js.map → chunk-VDX2J7OX.js.map} +0 -0
- /package/dist/{chunk-UGHCZS6K.js.map → chunk-VFZQXYN5.js.map} +0 -0
- /package/dist/{chunk-NKB43PGI.js.map → chunk-VYMICVRA.js.map} +0 -0
- /package/dist/{chunk-2UM6WHME.js.map → chunk-XE2QCCT2.js.map} +0 -0
- /package/dist/{chunk-SYVGVK4S.js.map → chunk-XTMYB2HY.js.map} +0 -0
- /package/dist/{chunk-AYVCKGA6.js.map → chunk-YTXNDEUS.js.map} +0 -0
- /package/dist/{chunk-3Z5TGRFA.js.map → chunk-ZOAAY2OE.js.map} +0 -0
|
@@ -622,7 +622,7 @@ export class RecallInternalCoordinator {
|
|
|
622
622
|
qmdHybridFetchLimit,
|
|
623
623
|
}),
|
|
624
624
|
latencyMs: Date.now() - recallStart,
|
|
625
|
-
|
|
625
|
+
includedMemories: [],
|
|
626
626
|
policyVersion,
|
|
627
627
|
appendImpression: this.deps.config.recordEmptyRecallImpressions,
|
|
628
628
|
identityInjection: {
|
|
@@ -4944,14 +4944,14 @@ export class RecallInternalCoordinator {
|
|
|
4944
4944
|
const assembledRecall = this.deps.assembleRecallSections(
|
|
4945
4945
|
sectionBuckets, contextBudgetForFooter(recallBudgetChars, curiosityFooter),
|
|
4946
4946
|
);
|
|
4947
|
-
recalledMemoryIds = assembledRecall.
|
|
4948
|
-
recalledMemoryPaths = assembledRecall.
|
|
4949
|
-
recalledMemoryNamespaces = assembledRecall.
|
|
4950
|
-
recalledMemoryCount = assembledRecall.
|
|
4947
|
+
recalledMemoryIds = assembledRecall.includedMemories.map((memory) => memory.id);
|
|
4948
|
+
recalledMemoryPaths = assembledRecall.includedMemories.map((memory) => memory.path);
|
|
4949
|
+
recalledMemoryNamespaces = assembledRecall.includedMemories.map((memory) => memory.namespace);
|
|
4950
|
+
recalledMemoryCount = assembledRecall.includedMemories.length;
|
|
4951
4951
|
this.deps.trackMemoryAccess(
|
|
4952
|
-
|
|
4953
|
-
|
|
4954
|
-
|
|
4952
|
+
recalledMemoryIds,
|
|
4953
|
+
recalledMemoryPaths,
|
|
4954
|
+
recalledMemoryNamespaces,
|
|
4955
4955
|
);
|
|
4956
4956
|
const recalledContext = assembledRecall.sections.join("\n\n---\n\n");
|
|
4957
4957
|
const composition = boundRecallContextComposition({
|
|
@@ -4987,9 +4987,6 @@ export class RecallInternalCoordinator {
|
|
|
4987
4987
|
truncated: assembledRecall.truncated || compositionTruncated || curiosityFooterTruncated,
|
|
4988
4988
|
includedSections,
|
|
4989
4989
|
omittedSections,
|
|
4990
|
-
includedMemoryIds: assembledRecall.includedMemoryIds,
|
|
4991
|
-
includedMemoryPaths: assembledRecall.includedMemoryPaths,
|
|
4992
|
-
includedMemoryNamespaces: assembledRecall.includedMemoryNamespaces,
|
|
4993
4990
|
omittedMemoryIds: assembledRecall.omittedMemoryIds,
|
|
4994
4991
|
});
|
|
4995
4992
|
// X-ray capture (issue #570 PR 1). Only fires when the caller
|
|
@@ -5241,8 +5238,7 @@ export class RecallInternalCoordinator {
|
|
|
5241
5238
|
sourcesUsed,
|
|
5242
5239
|
budgetsApplied,
|
|
5243
5240
|
latencyMs: Date.now() - recallStart,
|
|
5244
|
-
|
|
5245
|
-
resultNamespaces: recalledMemoryNamespaces,
|
|
5241
|
+
includedMemories: assembledRecall.includedMemories,
|
|
5246
5242
|
policyVersion,
|
|
5247
5243
|
appendImpression:
|
|
5248
5244
|
recalledMemoryIds.length > 0 ||
|
|
@@ -2,19 +2,17 @@ import test from "node:test";
|
|
|
2
2
|
import assert from "node:assert/strict";
|
|
3
3
|
import { displaySafeRecallSnapshot } from "./recall-result-formatter.js";
|
|
4
4
|
|
|
5
|
-
test("displaySafeRecallSnapshot relativizes
|
|
5
|
+
test("displaySafeRecallSnapshot relativizes included-memory and tier-anchor paths without mutating input (#2077)", () => {
|
|
6
6
|
const memoryDir = "/srv/memory";
|
|
7
7
|
const flatAbs = `${memoryDir}/facts/2026-07-19/b.md`;
|
|
8
8
|
const nsResultAbs = `${memoryDir}/namespaces/tok-team/facts/2026-07-19/r.md`;
|
|
9
|
-
// An anchor that is NOT among the
|
|
9
|
+
// An anchor that is NOT among the included memories — no authoritative owner.
|
|
10
10
|
const unmatchedAnchorAbs = `${memoryDir}/namespaces/ns-616c706861/facts/2026-07-19/a.md`;
|
|
11
11
|
const snapshot = {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
includedMemoryNamespaces: [undefined, "team-alpha"],
|
|
17
|
-
},
|
|
12
|
+
includedMemories: [
|
|
13
|
+
{ id: "mem-b", path: flatAbs },
|
|
14
|
+
{ id: "mem-r", path: nsResultAbs, namespace: "team-alpha" },
|
|
15
|
+
],
|
|
18
16
|
tierExplain: {
|
|
19
17
|
tier: "direct-answer",
|
|
20
18
|
tierReason: "single high-confidence hit",
|
|
@@ -31,21 +29,20 @@ test("displaySafeRecallSnapshot relativizes result, budget, and tier-anchor path
|
|
|
31
29
|
|
|
32
30
|
const safe = displaySafeRecallSnapshot(snapshot, memoryDir);
|
|
33
31
|
|
|
34
|
-
assert.deepEqual(safe.
|
|
35
|
-
|
|
36
|
-
"facts/2026-07-19/
|
|
37
|
-
"team-alpha/facts/2026-07-19/r.md",
|
|
32
|
+
assert.deepEqual(safe.includedMemories, [
|
|
33
|
+
{ id: "mem-b", path: "facts/2026-07-19/b.md" },
|
|
34
|
+
{ id: "mem-r", path: "team-alpha/facts/2026-07-19/r.md", namespace: "team-alpha" },
|
|
38
35
|
]);
|
|
39
36
|
assert.deepEqual(safe.tierExplain.sourceAnchors, [
|
|
40
|
-
// Anchor coincides with a namespaced
|
|
37
|
+
// Anchor coincides with a namespaced included memory → reuses its authoritative namespace.
|
|
41
38
|
{ path: "team-alpha/facts/2026-07-19/r.md", lineRange: [1, 2] },
|
|
42
|
-
// Anchor not among the
|
|
39
|
+
// Anchor not among the included memories → truthful storage-relative segment, never a decode.
|
|
43
40
|
{ path: "namespaces/ns-616c706861/facts/2026-07-19/a.md" },
|
|
44
|
-
// Anchor coincides with a default-namespace
|
|
41
|
+
// Anchor coincides with a default-namespace included memory → memoryDir-relative.
|
|
45
42
|
{ path: "facts/2026-07-19/b.md" },
|
|
46
43
|
]);
|
|
47
44
|
|
|
48
45
|
// The input snapshot must not be mutated — the live cache keeps absolute paths.
|
|
49
46
|
assert.equal(snapshot.tierExplain.sourceAnchors[0].path, nsResultAbs);
|
|
50
|
-
assert.equal(snapshot.
|
|
47
|
+
assert.equal(snapshot.includedMemories[1].path, nsResultAbs);
|
|
51
48
|
});
|
|
@@ -33,6 +33,7 @@ import type { WorkProductLedgerSearchResult } from "../work-product-ledger.js";
|
|
|
33
33
|
import { trustResultFor, type TrustStageResultItem } from "../trust-score-stage.js";
|
|
34
34
|
import { CONNECTOR_ID_PATTERN, CONNECTOR_LABEL_MAX_LENGTH } from "../connectors/label.js";
|
|
35
35
|
import { isValidConnectorId } from "../connectors/index.js";
|
|
36
|
+
import { coerceIncludedMemories, type IncludedMemory } from "../included-memories.js";
|
|
36
37
|
import type {
|
|
37
38
|
ContinuityIncidentRecord,
|
|
38
39
|
IdentityInjectionMode,
|
|
@@ -112,43 +113,26 @@ export function displayResultPath(
|
|
|
112
113
|
: resultPath;
|
|
113
114
|
}
|
|
114
115
|
|
|
115
|
-
/**
|
|
116
|
-
* Return a copy of budget metadata with `includedMemoryPaths` rendered
|
|
117
|
-
* memoryDir-relative, so recall/last-recall API callers never receive operator
|
|
118
|
-
* filesystem paths via budget output even though the internal snapshot keeps
|
|
119
|
-
* absolute paths for tracking/x-ray (#2020). Other fields are unchanged.
|
|
120
|
-
*/
|
|
121
|
-
export function displaySafeBudgetsApplied<
|
|
122
|
-
T extends {
|
|
123
|
-
includedMemoryPaths?: string[];
|
|
124
|
-
includedMemoryNamespaces?: Array<string | undefined>;
|
|
125
|
-
},
|
|
126
|
-
>(budgetsApplied: T | undefined, memoryDir: string): T | undefined {
|
|
127
|
-
if (!budgetsApplied?.includedMemoryPaths) return budgetsApplied;
|
|
128
|
-
return {
|
|
129
|
-
...budgetsApplied,
|
|
130
|
-
includedMemoryPaths: budgetsApplied.includedMemoryPaths.map((p, i) =>
|
|
131
|
-
displayResultPath(p, memoryDir, budgetsApplied.includedMemoryNamespaces?.[i]),
|
|
132
|
-
),
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
|
|
136
116
|
/**
|
|
137
117
|
* Return a display-safe copy of a recall snapshot for the `includeDebug=true`
|
|
138
|
-
* surface (#2077). `
|
|
139
|
-
*
|
|
140
|
-
* `tierExplain.sourceAnchors[]` entry
|
|
141
|
-
* when its absolute path matches
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
* shallow copy; the input
|
|
118
|
+
* surface (#2077). `includedMemories[].path` is rendered namespace-relative
|
|
119
|
+
* from each memory's own namespace — the same rendering `resultPaths` received
|
|
120
|
+
* before the struct consolidation; a `tierExplain.sourceAnchors[]` entry
|
|
121
|
+
* reuses that SAME authoritative metadata when its absolute path matches an
|
|
122
|
+
* included memory's path, and otherwise falls back to the memoryDir-relative
|
|
123
|
+
* on-disk form. Either way the debug flag never leaks absolute operator
|
|
124
|
+
* paths, and an anchor is never attributed to a decoded (guessed) namespace —
|
|
125
|
+
* an anchor carries no owner of its own. Returns a shallow copy; the input
|
|
126
|
+
* snapshot is never mutated.
|
|
146
127
|
*/
|
|
147
128
|
export function displaySafeRecallSnapshot<
|
|
148
129
|
T extends {
|
|
130
|
+
includedMemories?: IncludedMemory[];
|
|
131
|
+
memoryIds?: string[];
|
|
149
132
|
resultPaths?: string[];
|
|
150
133
|
resultNamespaces?: Array<string | undefined>;
|
|
151
134
|
budgetsApplied?: {
|
|
135
|
+
includedMemoryIds?: string[];
|
|
152
136
|
includedMemoryPaths?: string[];
|
|
153
137
|
includedMemoryNamespaces?: Array<string | undefined>;
|
|
154
138
|
};
|
|
@@ -157,21 +141,14 @@ export function displaySafeRecallSnapshot<
|
|
|
157
141
|
};
|
|
158
142
|
},
|
|
159
143
|
>(snapshot: T, memoryDir: string): T {
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
// tier anchor that coincides with a returned result renders under the SAME
|
|
165
|
-
// namespace as that result instead of the raw storage segment (#2077).
|
|
144
|
+
const includedMemories = coerceIncludedMemories(snapshot).map((memory) => ({
|
|
145
|
+
...memory,
|
|
146
|
+
path: displayResultPath(memory.path, memoryDir, memory.namespace),
|
|
147
|
+
}));
|
|
166
148
|
const namespaceByPath = new Map<string, string | undefined>();
|
|
167
|
-
|
|
168
|
-
if (!namespaceByPath.has(
|
|
169
|
-
}
|
|
170
|
-
snapshot.budgetsApplied?.includedMemoryPaths?.forEach((p, i) => {
|
|
171
|
-
if (!namespaceByPath.has(p)) {
|
|
172
|
-
namespaceByPath.set(p, snapshot.budgetsApplied?.includedMemoryNamespaces?.[i]);
|
|
173
|
-
}
|
|
174
|
-
});
|
|
149
|
+
for (const memory of coerceIncludedMemories(snapshot)) {
|
|
150
|
+
if (!namespaceByPath.has(memory.path)) namespaceByPath.set(memory.path, memory.namespace);
|
|
151
|
+
}
|
|
175
152
|
const tierExplain =
|
|
176
153
|
snapshot.tierExplain?.sourceAnchors
|
|
177
154
|
? {
|
|
@@ -182,11 +159,21 @@ export function displaySafeRecallSnapshot<
|
|
|
182
159
|
})),
|
|
183
160
|
}
|
|
184
161
|
: undefined;
|
|
162
|
+
const resultPaths = includedMemories.map((memory) => memory.path);
|
|
163
|
+
const resultNamespaces = includedMemories.map((memory) => memory.namespace);
|
|
185
164
|
return {
|
|
186
165
|
...snapshot,
|
|
187
|
-
|
|
166
|
+
includedMemories,
|
|
167
|
+
resultPaths,
|
|
168
|
+
resultNamespaces,
|
|
188
169
|
...(snapshot.budgetsApplied
|
|
189
|
-
? {
|
|
170
|
+
? {
|
|
171
|
+
budgetsApplied: {
|
|
172
|
+
...snapshot.budgetsApplied,
|
|
173
|
+
includedMemoryPaths: resultPaths,
|
|
174
|
+
includedMemoryNamespaces: resultNamespaces,
|
|
175
|
+
},
|
|
176
|
+
}
|
|
190
177
|
: {}),
|
|
191
178
|
...(tierExplain ? { tierExplain } : {}),
|
|
192
179
|
};
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* TierMigrationCoordinator accessor pattern.
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
import type { LastRecallBudgetSummary } from "../recall-state.js";
|
|
20
|
+
import type { IncludedMemory, LastRecallBudgetSummary } from "../recall-state.js";
|
|
21
21
|
import { estimateTokenCount } from "../token-estimate.js";
|
|
22
22
|
import { graphemeUnits, truncateGraphemeSafe } from "../whitespace.js";
|
|
23
23
|
import type { PluginConfig, RecallSectionConfig } from "../types.js";
|
|
@@ -273,6 +273,7 @@ export class RecallSectionCoordinator {
|
|
|
273
273
|
omittedIds: string[];
|
|
274
274
|
truncated: boolean;
|
|
275
275
|
finalChars: number;
|
|
276
|
+
includedMemories: IncludedMemory[];
|
|
276
277
|
includedMemoryIds: string[];
|
|
277
278
|
includedMemoryPaths: string[];
|
|
278
279
|
includedMemoryNamespaces: Array<string | undefined>;
|
|
@@ -340,6 +341,7 @@ export class RecallSectionCoordinator {
|
|
|
340
341
|
omittedIds: orderedSections.map((entry) => entry.id),
|
|
341
342
|
truncated: orderedSections.length > 0,
|
|
342
343
|
finalChars: 0,
|
|
344
|
+
includedMemories: [],
|
|
343
345
|
includedMemoryIds: [],
|
|
344
346
|
includedMemoryPaths: [],
|
|
345
347
|
includedMemoryNamespaces: [],
|
|
@@ -372,9 +374,7 @@ export class RecallSectionCoordinator {
|
|
|
372
374
|
break;
|
|
373
375
|
}
|
|
374
376
|
}
|
|
375
|
-
const
|
|
376
|
-
const includedMemoryPaths: string[] = [];
|
|
377
|
-
const includedMemoryNamespaces: Array<string | undefined> = [];
|
|
377
|
+
const includedMemories: IncludedMemory[] = [];
|
|
378
378
|
let usedChars = 0;
|
|
379
379
|
let usedTokens = 0;
|
|
380
380
|
let truncated = false;
|
|
@@ -492,12 +492,12 @@ export class RecallSectionCoordinator {
|
|
|
492
492
|
rendered = chunk.content;
|
|
493
493
|
includedLeadingContent = false;
|
|
494
494
|
includedAtomicCount = 1;
|
|
495
|
-
// Push id/path/namespace together so the parallel tracking arrays
|
|
496
|
-
// never misalign when a chunk carries only one of them (#2020).
|
|
497
495
|
if (chunk.memoryId && chunk.memoryPath) {
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
496
|
+
includedMemories.push(
|
|
497
|
+
chunk.memoryNamespace
|
|
498
|
+
? { id: chunk.memoryId, path: chunk.memoryPath, namespace: chunk.memoryNamespace }
|
|
499
|
+
: { id: chunk.memoryId, path: chunk.memoryPath },
|
|
500
|
+
);
|
|
501
501
|
}
|
|
502
502
|
continue;
|
|
503
503
|
}
|
|
@@ -522,9 +522,11 @@ export class RecallSectionCoordinator {
|
|
|
522
522
|
if (chunk.atomic) {
|
|
523
523
|
includedAtomicCount += 1;
|
|
524
524
|
if (chunk.memoryId && chunk.memoryPath) {
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
525
|
+
includedMemories.push(
|
|
526
|
+
chunk.memoryNamespace
|
|
527
|
+
? { id: chunk.memoryId, path: chunk.memoryPath, namespace: chunk.memoryNamespace }
|
|
528
|
+
: { id: chunk.memoryId, path: chunk.memoryPath },
|
|
529
|
+
);
|
|
528
530
|
}
|
|
529
531
|
} else {
|
|
530
532
|
includedPostAtomicContent = true;
|
|
@@ -574,16 +576,14 @@ export class RecallSectionCoordinator {
|
|
|
574
576
|
omittedIds,
|
|
575
577
|
truncated,
|
|
576
578
|
finalChars: usedChars,
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
579
|
+
includedMemories,
|
|
580
|
+
includedMemoryIds: includedMemories.map((memory) => memory.id),
|
|
581
|
+
includedMemoryPaths: includedMemories.map((memory) => memory.path),
|
|
582
|
+
includedMemoryNamespaces: includedMemories.map((memory) => memory.namespace),
|
|
580
583
|
omittedMemoryIds: (() => {
|
|
581
|
-
// Key by (namespace, id): the same memory id can exist in more than one
|
|
582
|
-
// namespace, so an id-only subtraction would hide a budget-dropped copy
|
|
583
|
-
// when another namespace's copy was included (#2020).
|
|
584
584
|
const includedKeys = new Set(
|
|
585
|
-
|
|
586
|
-
(
|
|
585
|
+
includedMemories.map(
|
|
586
|
+
(memory) => `${memory.namespace ?? ""}\u0000${memory.id}`,
|
|
587
587
|
),
|
|
588
588
|
);
|
|
589
589
|
return candidateMemoryChunks
|
|
@@ -604,9 +604,6 @@ export class RecallSectionCoordinator {
|
|
|
604
604
|
finalContextChars?: number;
|
|
605
605
|
truncated?: boolean;
|
|
606
606
|
includedSections?: string[];
|
|
607
|
-
includedMemoryIds?: string[];
|
|
608
|
-
includedMemoryPaths?: string[];
|
|
609
|
-
includedMemoryNamespaces?: Array<string | undefined>;
|
|
610
607
|
omittedMemoryIds?: string[];
|
|
611
608
|
omittedSections?: string[];
|
|
612
609
|
}): LastRecallBudgetSummary {
|
|
@@ -619,9 +616,6 @@ export class RecallSectionCoordinator {
|
|
|
619
616
|
qmdHybridFetchLimit: options.qmdHybridFetchLimit,
|
|
620
617
|
finalContextChars: options.finalContextChars,
|
|
621
618
|
truncated: options.truncated,
|
|
622
|
-
includedMemoryIds: [...(options.includedMemoryIds ?? [])],
|
|
623
|
-
includedMemoryPaths: [...(options.includedMemoryPaths ?? [])],
|
|
624
|
-
includedMemoryNamespaces: [...(options.includedMemoryNamespaces ?? [])],
|
|
625
619
|
omittedMemoryIds: [...(options.omittedMemoryIds ?? [])],
|
|
626
620
|
includedSections: [...(options.includedSections ?? [])],
|
|
627
621
|
omittedSections: [...(options.omittedSections ?? [])],
|
package/src/orchestrator.ts
CHANGED
|
@@ -260,6 +260,7 @@ import { NegativeExampleStore } from "./negative.js";
|
|
|
260
260
|
import {
|
|
261
261
|
LastRecallStore,
|
|
262
262
|
RecallHandleHistoryStore,
|
|
263
|
+
type IncludedMemory,
|
|
263
264
|
type LastRecallBudgetSummary,
|
|
264
265
|
TierMigrationStatusStore,
|
|
265
266
|
clampGraphRecallExpandedEntries,
|
|
@@ -2716,7 +2717,7 @@ export class Orchestrator {
|
|
|
2716
2717
|
includedIds: string[];
|
|
2717
2718
|
omittedIds: string[];
|
|
2718
2719
|
truncated: boolean;
|
|
2719
|
-
|
|
2720
|
+
includedMemories: IncludedMemory[];
|
|
2720
2721
|
includedMemoryIds: string[];
|
|
2721
2722
|
includedMemoryPaths: string[];
|
|
2722
2723
|
includedMemoryNamespaces: Array<string | undefined>;
|
|
@@ -3542,9 +3543,6 @@ export class Orchestrator {
|
|
|
3542
3543
|
finalContextChars?: number;
|
|
3543
3544
|
truncated?: boolean;
|
|
3544
3545
|
includedSections?: string[];
|
|
3545
|
-
includedMemoryIds?: string[];
|
|
3546
|
-
includedMemoryPaths?: string[];
|
|
3547
|
-
includedMemoryNamespaces?: Array<string | undefined>;
|
|
3548
3546
|
omittedMemoryIds?: string[];
|
|
3549
3547
|
omittedSections?: string[];
|
|
3550
3548
|
}): LastRecallBudgetSummary {
|
|
@@ -17,6 +17,10 @@ function legacySnapshot(
|
|
|
17
17
|
queryHash: "deadbeef",
|
|
18
18
|
queryLen: 21,
|
|
19
19
|
memoryIds: ["mem-1", "mem-2"],
|
|
20
|
+
includedMemories: [
|
|
21
|
+
{ id: "mem-1", path: "" },
|
|
22
|
+
{ id: "mem-2", path: "" },
|
|
23
|
+
],
|
|
20
24
|
source: "hot_qmd",
|
|
21
25
|
sourcesUsed: ["hot_qmd", "memories"],
|
|
22
26
|
namespace: "workspace-a",
|
package/src/recall-state.test.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { chmod, lstat, mkdir, mkdtemp, readFile, readdir, rm, stat, symlink, wri
|
|
|
4
4
|
import os from "node:os";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
|
|
7
|
-
import { clampGraphRecallExpandedEntries, LastRecallStore } from "./recall-state.js";
|
|
7
|
+
import { clampGraphRecallExpandedEntries, LastRecallStore, RecallHandleHistoryStore } from "./recall-state.js";
|
|
8
8
|
import type { RecallTierExplain } from "./types.js";
|
|
9
9
|
import { listContainedSpillFiles } from "./utils/path-containment.js";
|
|
10
10
|
|
|
@@ -83,19 +83,69 @@ test("LastRecallStore.record persists tierExplain and round-trips to JSON on dis
|
|
|
83
83
|
assert.deepEqual(parsed["s1"]?.tierExplain, tierExplain);
|
|
84
84
|
});
|
|
85
85
|
|
|
86
|
-
test("LastRecallStore.record
|
|
86
|
+
test("LastRecallStore.record shims legacy resultPaths/resultNamespaces into includedMemories", async () => {
|
|
87
87
|
const { store } = await freshStore();
|
|
88
|
-
const resultNamespaces = ["main", "shared"] as Array<string | undefined>;
|
|
89
88
|
await store.record({
|
|
90
89
|
sessionKey: "s1",
|
|
91
90
|
query: "namespaced recall",
|
|
92
91
|
memoryIds: ["same-id", "same-id"],
|
|
93
92
|
resultPaths: ["facts/same-id.md", "facts/same-id.md"],
|
|
94
|
-
resultNamespaces,
|
|
93
|
+
resultNamespaces: ["main", "shared"],
|
|
95
94
|
});
|
|
96
95
|
const snap = store.get("s1");
|
|
97
96
|
assert.ok(snap);
|
|
98
|
-
assert.deepEqual(snap.
|
|
97
|
+
assert.deepEqual(snap.includedMemories, [
|
|
98
|
+
{ id: "same-id", path: "facts/same-id.md", namespace: "main" },
|
|
99
|
+
{ id: "same-id", path: "facts/same-id.md", namespace: "shared" },
|
|
100
|
+
]);
|
|
101
|
+
assert.deepEqual(snap.memoryIds, ["same-id", "same-id"]);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// ── Legacy on-disk shapes hydrate to includedMemories (#2476) ─────────────
|
|
105
|
+
|
|
106
|
+
test("LastRecallStore.load shims legacy last_recall.json shapes to includedMemories", async () => {
|
|
107
|
+
const { dir } = await freshStore();
|
|
108
|
+
const fixturePath = path.resolve(
|
|
109
|
+
import.meta.dirname,
|
|
110
|
+
"../../../tests/fixtures/last-recall-legacy-shape.json",
|
|
111
|
+
);
|
|
112
|
+
const fixture = JSON.parse(await readFile(fixturePath, "utf-8")) as Record<string, unknown>;
|
|
113
|
+
|
|
114
|
+
await mkdir(path.join(dir, "state"), { recursive: true });
|
|
115
|
+
await writeFile(
|
|
116
|
+
path.join(dir, "state", "last_recall.json"),
|
|
117
|
+
JSON.stringify(fixture),
|
|
118
|
+
"utf-8",
|
|
119
|
+
);
|
|
120
|
+
const store = new LastRecallStore(dir);
|
|
121
|
+
await store.load();
|
|
122
|
+
|
|
123
|
+
const full = store.get("legacy-full");
|
|
124
|
+
assert.ok(full);
|
|
125
|
+
assert.deepEqual(full.includedMemories, [
|
|
126
|
+
{
|
|
127
|
+
id: "fact-alpha",
|
|
128
|
+
path: "/memory-under-test/namespaces/team-alpha/facts/2026-08-01/fact-alpha.md",
|
|
129
|
+
namespace: "team-alpha",
|
|
130
|
+
},
|
|
131
|
+
{ id: "fact-beta", path: "/memory-under-test/facts/2026-08-01/fact-beta.md" },
|
|
132
|
+
{
|
|
133
|
+
id: "fact-gamma",
|
|
134
|
+
path: "/memory-under-test/namespaces/team-alpha/facts/2026-08-01/fact-gamma.md",
|
|
135
|
+
namespace: "team-alpha",
|
|
136
|
+
},
|
|
137
|
+
]);
|
|
138
|
+
assert.deepEqual(full.memoryIds, ["fact-alpha", "fact-beta", "fact-gamma"]);
|
|
139
|
+
assert.deepEqual(
|
|
140
|
+
full.resultPaths,
|
|
141
|
+
full.includedMemories?.map((memory) => memory.path),
|
|
142
|
+
);
|
|
143
|
+
assert.deepEqual(full.budgetsApplied?.omittedMemoryIds, ["fact-dropped"]);
|
|
144
|
+
|
|
145
|
+
const idsOnly = store.get("legacy-ids-only");
|
|
146
|
+
assert.ok(idsOnly);
|
|
147
|
+
assert.deepEqual(idsOnly.includedMemories, [{ id: "fact-delta", path: "" }]);
|
|
148
|
+
assert.deepEqual(idsOnly.memoryIds, ["fact-delta"]);
|
|
99
149
|
});
|
|
100
150
|
|
|
101
151
|
// ── Defensive copies isolate the stored snapshot from caller mutation ──────
|
|
@@ -1083,3 +1133,56 @@ test("LastRecallStore.drainPendingImpressions reports pendingDeferred when a spi
|
|
|
1083
1133
|
await rm(dir, { recursive: true, force: true });
|
|
1084
1134
|
}
|
|
1085
1135
|
});
|
|
1136
|
+
+
|
|
1137
|
+
test("LastRecallStore rejects unsafe session keys on every read/write path", async () => {
|
|
1138
|
+
const { store, dir } = await freshStore();
|
|
1139
|
+
for (const key of ["__proto__", "constructor", "prototype"]) {
|
|
1140
|
+
await store.record({ sessionKey: key, query: "q", memoryIds: ["m-1"] });
|
|
1141
|
+
assert.equal(store.get(key), null, `get(${key}) must not surface prototype junk`);
|
|
1142
|
+
}
|
|
1143
|
+
assert.equal(store.getMostRecent(), null);
|
|
1144
|
+
|
|
1145
|
+
await store.annotateTierExplain("__proto__", {
|
|
1146
|
+
tier: "direct-answer",
|
|
1147
|
+
tierReason: "",
|
|
1148
|
+
filteredBy: [],
|
|
1149
|
+
candidatesConsidered: 0,
|
|
1150
|
+
latencyMs: 0,
|
|
1151
|
+
});
|
|
1152
|
+
assert.equal(store.get("__proto__"), null);
|
|
1153
|
+
const persistedKeys = await readFile(path.join(dir, "state", "last_recall.json"), "utf-8")
|
|
1154
|
+
.then((raw) => Object.keys(JSON.parse(raw) as object))
|
|
1155
|
+
.catch(() => [] as string[]);
|
|
1156
|
+
assert.deepEqual(persistedKeys, [], "no unsafe key persisted");
|
|
1157
|
+
});
|
|
1158
|
+
|
|
1159
|
+
test("RecallHandleHistoryStore rejects unsafe session keys", async () => {
|
|
1160
|
+
const dir = await mkdtemp(path.join(os.tmpdir(), "engram-handle-history-"));
|
|
1161
|
+
const store = new RecallHandleHistoryStore(dir);
|
|
1162
|
+
await store.load();
|
|
1163
|
+
|
|
1164
|
+
await store.record("__proto__", ["m-1"]);
|
|
1165
|
+
await store.record("constructor", ["m-2"]);
|
|
1166
|
+
assert.deepEqual(store.recent("__proto__"), []);
|
|
1167
|
+
assert.deepEqual(store.recent("constructor"), []);
|
|
1168
|
+
|
|
1169
|
+
await store.record("ok", ["m-3"]);
|
|
1170
|
+
assert.deepEqual(store.recent("ok"), [["m-3"]]);
|
|
1171
|
+
await rm(dir, { recursive: true, force: true });
|
|
1172
|
+
});
|
|
1173
|
+
|
|
1174
|
+
test("RecallHandleHistoryStore.load drops unsafe and malformed entries from persisted state", async () => {
|
|
1175
|
+
const dir = await mkdtemp(path.join(os.tmpdir(), "engram-handle-history-"));
|
|
1176
|
+
await mkdir(path.join(dir, "state"), { recursive: true });
|
|
1177
|
+
// JSON.parse materializes "__proto__" as an OWN key; load must not adopt it.
|
|
1178
|
+
const poisoned =
|
|
1179
|
+
'{"__proto__": [{"at": "t", "ids": ["evil"]}], "bad": "not-an-array", "ok": [{"at": "t", "ids": ["m-1"]}]}';
|
|
1180
|
+
await writeFile(path.join(dir, "state", "handle_history.json"), poisoned, "utf-8");
|
|
1181
|
+
|
|
1182
|
+
const store = new RecallHandleHistoryStore(dir);
|
|
1183
|
+
await store.load();
|
|
1184
|
+
assert.deepEqual(store.recent("__proto__"), []);
|
|
1185
|
+
assert.deepEqual(store.recent("bad"), []);
|
|
1186
|
+
assert.deepEqual(store.recent("ok"), [["m-1"]]);
|
|
1187
|
+
await rm(dir, { recursive: true, force: true });
|
|
1188
|
+
});
|