@remnic/core 9.65.2 → 9.65.4
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 +44 -44
- package/dist/access-admin-ops-surface.js +21 -19
- package/dist/access-authorization-probe.d.ts +38 -38
- package/dist/access-authorization-probe.js +22 -20
- package/dist/access-boundary.d.ts +40 -40
- package/dist/access-boundary.js +21 -19
- package/dist/access-cli.js +62 -60
- package/dist/access-cli.js.map +1 -1
- package/dist/access-coding-context-resolution.d.ts +3 -1
- package/dist/access-extraction-force-flush.d.ts +25 -25
- package/dist/access-extraction-force-flush.js +21 -19
- package/dist/access-health-types.d.ts +3 -1
- package/dist/access-http-lcm-compaction.d.ts +39 -39
- package/dist/access-http-lifecycle-flush.d.ts +39 -39
- package/dist/access-http-offline-stream.d.ts +25 -25
- package/dist/access-http-query.d.ts +4 -2
- package/dist/access-http-query.js +23 -21
- package/dist/access-http.d.ts +51 -44
- package/dist/access-http.js +37 -35
- package/dist/access-identity-continuity-surface.d.ts +12 -12
- package/dist/access-identity-continuity-surface.js +21 -19
- package/dist/access-lcm-surface.d.ts +27 -27
- package/dist/access-lcm-surface.js +21 -19
- package/dist/access-mcp-admin-tools.d.ts +9 -1
- package/dist/access-mcp-admin-tools.js +3 -1
- package/dist/access-mcp-output-schemas.js +1 -1
- package/dist/access-mcp.d.ts +39 -39
- package/dist/access-mcp.js +31 -29
- package/dist/access-memory-search-fanout.d.ts +4 -2
- package/dist/{access-namespace-preflight-Dhvcl-T0.d.ts → access-namespace-preflight-D_6mo8ms.d.ts} +1 -1
- package/dist/access-namespace-preflight.d.ts +5 -3
- package/dist/access-namespace-preflight.js +21 -19
- package/dist/access-observe-write-surface.d.ts +39 -39
- package/dist/access-observe-write-surface.js +21 -19
- package/dist/access-offline-manifest.d.ts +12 -12
- package/dist/access-offline-manifest.js +3 -3
- package/dist/access-operations-batch.js +25 -23
- package/dist/access-operations.d.ts +40 -40
- package/dist/access-operations.js +28 -26
- package/dist/access-recall-concurrency.d.ts +40 -40
- package/dist/access-recall-concurrency.js +21 -19
- package/dist/access-recall-response.d.ts +24 -24
- package/dist/access-recall-response.js +21 -19
- package/dist/access-recall-surface.d.ts +24 -24
- package/dist/access-recall-surface.js +21 -19
- package/dist/access-schema.d.ts +45 -45
- package/dist/{access-service-Bke1alZO.d.ts → access-service-DqPa3hy4.d.ts} +219 -75
- package/dist/access-service-helpers.d.ts +40 -40
- package/dist/access-service.d.ts +47 -47
- package/dist/access-service.js +21 -19
- package/dist/access-surface-catalog.d.ts +40 -40
- package/dist/access-surface-catalog.js +27 -21
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/access-wearables-meetings-surface.d.ts +5 -3
- package/dist/action-confidence.d.ts +3 -1
- package/dist/active-memory-bridge.d.ts +3 -1
- package/dist/active-recall.d.ts +3 -1
- package/dist/active-recall.js +10 -1
- package/dist/active-recall.js.map +1 -1
- package/dist/ambient-provenance.d.ts +3 -1
- package/dist/artifact-search.d.ts +3 -1
- package/dist/{auto-sync-H64ZCNIR.js → auto-sync-XVMLL2RH.js} +5 -5
- package/dist/behavior-learner.d.ts +3 -1
- package/dist/behavior-signals.d.ts +3 -1
- package/dist/bootstrap.d.ts +12 -12
- package/dist/briefing-window.d.ts +4 -2
- package/dist/briefing.d.ts +4 -2
- package/dist/briefing.js +4 -4
- package/dist/buffer-surprise-report.d.ts +3 -1
- package/dist/buffer-turn-helpers.d.ts +3 -1
- package/dist/buffer.d.ts +4 -2
- package/dist/bulk-import/index.d.ts +5 -3
- package/dist/calibration.d.ts +3 -1
- package/dist/capabilities.d.ts +3 -1
- package/dist/{catalog-DV6qnbr7.d.ts → catalog-DO_7zfkv.d.ts} +1 -1
- package/dist/causal-behavior.d.ts +1 -1
- package/dist/causal-consolidation.d.ts +3 -1
- package/dist/causal-consolidation.js +12 -9
- package/dist/causal-consolidation.js.map +1 -1
- package/dist/causal-trajectory-graph.d.ts +1 -1
- package/dist/chunk-236PXYG7.js +232 -0
- package/dist/chunk-236PXYG7.js.map +1 -0
- package/dist/{chunk-YB42WZCY.js → chunk-2IXQSGCU.js} +2 -2
- package/dist/{chunk-PE255F4T.js → chunk-2MVTAIL3.js} +2 -2
- package/dist/{chunk-LGO6A7GJ.js → chunk-3JZBPTLD.js} +338 -80
- package/dist/chunk-3JZBPTLD.js.map +1 -0
- package/dist/{chunk-GDFVPUJ5.js → chunk-3NH3VP3U.js} +2 -2
- package/dist/{chunk-TBOJ76ER.js → chunk-AB3A7EFH.js} +18 -2
- package/dist/{chunk-TBOJ76ER.js.map → chunk-AB3A7EFH.js.map} +1 -1
- package/dist/{chunk-GNCCUR6K.js → chunk-AXGFOFNY.js} +2 -2
- package/dist/{chunk-SB7D4BT7.js → chunk-AZLLH6YA.js} +1554 -114
- package/dist/chunk-AZLLH6YA.js.map +1 -0
- package/dist/{chunk-5YQ63T4B.js → chunk-BK5G2MHO.js} +2 -2
- package/dist/{chunk-LZH5FR2W.js → chunk-CQBIN77D.js} +2 -2
- package/dist/{chunk-35NN3ZFA.js → chunk-CTVWELNK.js} +21 -3
- package/dist/chunk-CTVWELNK.js.map +1 -0
- package/dist/{chunk-NKKD4ZAU.js → chunk-DORFF5N5.js} +2 -2
- package/dist/{chunk-BWLRUMOG.js → chunk-DPNXADEI.js} +441 -2
- package/dist/chunk-DPNXADEI.js.map +1 -0
- package/dist/{chunk-SQI57UCJ.js → chunk-DUEDOYZD.js} +2 -2
- package/dist/{chunk-5NM4OH4P.js → chunk-DUZARALI.js} +3 -3
- package/dist/{chunk-2E36UXVW.js → chunk-ECLJ4LA2.js} +2 -2
- package/dist/{chunk-TZNQUNKL.js → chunk-FC7TIRFS.js} +15 -1
- package/dist/chunk-FC7TIRFS.js.map +1 -0
- package/dist/{chunk-IID2CMUU.js → chunk-GHD2LLG4.js} +2 -2
- package/dist/{chunk-ZQHI2BZB.js → chunk-HF5BUTI6.js} +2 -2
- package/dist/{chunk-3DVBKTSO.js → chunk-HSZMX3ZJ.js} +4 -4
- package/dist/{chunk-S2DPMJXH.js → chunk-I23ZHYSL.js} +2 -2
- package/dist/{chunk-ODZG724P.js → chunk-I2HTKOOP.js} +2 -2
- package/dist/chunk-I32NKXE2.js +879 -0
- package/dist/chunk-I32NKXE2.js.map +1 -0
- package/dist/{chunk-NTWN6HB2.js → chunk-IURMJBGP.js} +2 -2
- package/dist/{chunk-OCZIYAE5.js → chunk-IWKGOCL6.js} +3 -3
- package/dist/{chunk-UXO5IMBK.js → chunk-J3ATBB7M.js} +2 -2
- package/dist/{chunk-Y7DK7HHJ.js → chunk-JPAKBNTM.js} +2 -2
- package/dist/{chunk-SPUJNJJC.js → chunk-KFIOPZ25.js} +2 -2
- package/dist/{chunk-JYYBA7TF.js → chunk-KOO37E4Y.js} +2 -2
- package/dist/{chunk-OTHZWLUD.js → chunk-KPB2QHJZ.js} +2 -2
- package/dist/{chunk-SBDCZ2AX.js → chunk-LBFFNDFM.js} +1 -1
- package/dist/chunk-LBFFNDFM.js.map +1 -0
- package/dist/{chunk-CT56C22C.js → chunk-LYBIHM4N.js} +4 -4
- package/dist/{chunk-3I7ASZN3.js → chunk-MFOSZUIT.js} +2 -2
- package/dist/{chunk-DZUJ46DO.js → chunk-NLEH4RTB.js} +2 -2
- package/dist/{chunk-ZO6AXLEH.js → chunk-OCCHUEZB.js} +2 -2
- package/dist/{chunk-EILZG5VC.js → chunk-OU34IQXV.js} +2 -2
- package/dist/{chunk-2XDWWPTN.js → chunk-OZDFB22S.js} +2 -2
- package/dist/{chunk-UIN2BWDD.js → chunk-PTZQYCJ4.js} +2 -2
- package/dist/{chunk-7BY7V4YX.js → chunk-Q4WONDMJ.js} +4 -3
- package/dist/{chunk-7BY7V4YX.js.map → chunk-Q4WONDMJ.js.map} +1 -1
- package/dist/{chunk-Z7PBQPJ4.js → chunk-QJW4MZSW.js} +2 -2
- package/dist/{chunk-R7JAM2XF.js → chunk-R2MZCYA6.js} +3 -3
- package/dist/{chunk-TF77C7SV.js → chunk-SR5LNI6Q.js} +7 -5
- package/dist/chunk-SR5LNI6Q.js.map +1 -0
- package/dist/{chunk-LBWQ65SX.js → chunk-T42L3S6A.js} +4 -4
- package/dist/{chunk-J275IYMG.js → chunk-THVI4Y7X.js} +34 -7
- package/dist/chunk-THVI4Y7X.js.map +1 -0
- package/dist/{chunk-QOS5LBZN.js → chunk-TJFI3K2O.js} +15 -3
- package/dist/chunk-TJFI3K2O.js.map +1 -0
- package/dist/{chunk-2YI72KM3.js → chunk-UCKG36HO.js} +2 -2
- package/dist/{chunk-SIHSCCUQ.js → chunk-UFR6HX7A.js} +1 -1
- package/dist/{chunk-CDUUDBWJ.js → chunk-VFYRYFLL.js} +2 -2
- package/dist/{chunk-XRYZRW54.js → chunk-WDXD6ITO.js} +2 -2
- package/dist/{chunk-4KYOLI6M.js → chunk-XGM3VQWG.js} +120 -14
- package/dist/chunk-XGM3VQWG.js.map +1 -0
- package/dist/{chunk-MN4KB2A4.js → chunk-YDKF4MSJ.js} +3 -3
- package/dist/{chunk-YLDXWCZP.js → chunk-YHGCT462.js} +14 -9
- package/dist/chunk-YHGCT462.js.map +1 -0
- package/dist/{chunk-7YQ4IYS2.js → chunk-YOXVZJFM.js} +2 -2
- package/dist/{chunk-ZWXJBFZU.js → chunk-YZJM6CLF.js} +8 -8
- package/dist/chunk-ZCUTSMR2.js +61 -0
- package/dist/chunk-ZCUTSMR2.js.map +1 -0
- package/dist/{chunk-LUNJ3WFO.js → chunk-ZK4BFABK.js} +4 -4
- package/dist/{chunk-V3MXUL3D.js → chunk-ZPOHEB5Z.js} +329 -653
- package/dist/chunk-ZPOHEB5Z.js.map +1 -0
- package/dist/{chunk-RDFF2NAU.js → chunk-ZXBTTMGZ.js} +184 -88
- package/dist/chunk-ZXBTTMGZ.js.map +1 -0
- package/dist/{cli-cShQ13XG.d.ts → cli-DO3i14pM.d.ts} +5 -5
- package/dist/cli.d.ts +25 -25
- package/dist/cli.js +51 -48
- package/dist/coding/pre-action-gate.d.ts +2 -60
- package/dist/compounding/engine.d.ts +4 -2
- package/dist/compounding/engine.js +4 -4
- package/dist/compounding/preference-consolidator.d.ts +3 -1
- package/dist/compression-optimizer.d.ts +3 -1
- package/dist/config.d.ts +3 -1
- package/dist/config.js +10 -1
- package/dist/connectors/codex-materialize-runner.d.ts +3 -1
- package/dist/connectors/codex-materialize-runner.js +8 -5
- package/dist/connectors/codex-materialize.d.ts +16 -1
- package/dist/connectors/codex-materialize.js +10 -1
- package/dist/connectors/index.d.ts +3 -1
- package/dist/connectors/index.js +8 -5
- package/dist/consolidation-provenance-check.d.ts +4 -2
- package/dist/consolidation-undo.d.ts +4 -2
- package/dist/contradiction/index.d.ts +10 -270
- package/dist/contradiction/index.js +12 -7
- package/dist/{contradiction-review-QKJH5DKD.js → contradiction-review-WRVLRWHS.js} +6 -2
- package/dist/{contradiction-scan-VOTQRRSX.js → contradiction-scan-AKUWPX5N.js} +5 -3
- package/dist/converge-config.d.ts +3 -1
- package/dist/convergence-refresh.d.ts +4 -2
- package/dist/convergence-refresh.js +6 -6
- package/dist/conversation-index/backend.d.ts +3 -1
- package/dist/conversation-index/chunker.d.ts +3 -1
- package/dist/conversation-index/faiss-adapter.d.ts +3 -1
- package/dist/conversation-index/indexer.d.ts +3 -1
- package/dist/conversation-index/search.d.ts +3 -1
- package/dist/corpus-watermark.d.ts +3 -1
- package/dist/corpus-watermark.js +6 -6
- package/dist/cross-lingual-recall.d.ts +3 -1
- package/dist/day-summary.d.ts +3 -1
- package/dist/delinearize.d.ts +3 -1
- package/dist/dependency-propagation-config.d.ts +3 -1
- package/dist/{dependency-propagation-delivery-CsGg-VwS.d.ts → dependency-propagation-delivery-D23_x-s5.d.ts} +1 -1
- package/dist/direct-answer-wiring.d.ts +3 -1
- package/dist/direct-answer.d.ts +3 -1
- package/dist/embedding-fallback.d.ts +3 -1
- package/dist/enrichment/index.d.ts +3 -1
- package/dist/entity-origin-fields.d.ts +3 -1
- package/dist/entity-retrieval.d.ts +4 -2
- package/dist/entity-retrieval.js +4 -4
- package/dist/entity-schema.d.ts +3 -1
- package/dist/episodic-context.d.ts +3 -1
- package/dist/explicit-capture.d.ts +12 -12
- package/dist/explicit-capture.js +1 -1
- package/dist/external-wiki-access.d.ts +40 -40
- package/dist/external-wiki-access.js +22 -20
- package/dist/external-wiki-collection-registration.d.ts +3 -1
- package/dist/external-wiki-collection.d.ts +3 -1
- package/dist/external-wiki-mcp-tools.d.ts +40 -40
- package/dist/extraction-error-classification.d.ts +3 -1
- package/dist/extraction-faithfulness.d.ts +3 -1
- package/dist/extraction-judge-telemetry.d.ts +3 -1
- package/dist/extraction-judge-training.d.ts +3 -1
- package/dist/extraction-judge.d.ts +3 -1
- package/dist/extraction-judge.js +2 -2
- package/dist/extraction-liveness.d.ts +3 -1
- package/dist/extraction-normalization.d.ts +3 -1
- package/dist/extraction-prompt.d.ts +3 -1
- package/dist/extraction-source-grounding-rules.d.ts +3 -1
- package/dist/extraction-source-grounding.d.ts +3 -1
- package/dist/extraction.d.ts +3 -1
- package/dist/extraction.js +9 -7
- package/dist/fallback-llm.d.ts +3 -1
- package/dist/graph-dashboard-diff.d.ts +3 -1
- package/dist/graph-dashboard-key.d.ts +3 -1
- package/dist/graph-dashboard-parser.d.ts +3 -1
- package/dist/graph-edge-reinforcement.d.ts +3 -1
- package/dist/graph-path-reconstruction.d.ts +3 -1
- package/dist/graph-path-scoring.d.ts +3 -1
- package/dist/graph-snapshot.d.ts +3 -1
- package/dist/graph.d.ts +3 -1
- package/dist/harmonic-retrieval.js +1 -1
- package/dist/importance.d.ts +3 -1
- package/dist/importers/index.d.ts +3 -1
- package/dist/in-flight-reads.d.ts +3 -1
- package/dist/index--QhGIXF2.d.ts +284 -0
- package/dist/index.d.ts +314 -45
- package/dist/index.js +163 -88
- package/dist/intent.d.ts +3 -1
- package/dist/lcm/engine.d.ts +3 -1
- package/dist/lcm/index.d.ts +3 -1
- package/dist/lcm/tools.d.ts +3 -1
- package/dist/lifecycle.d.ts +3 -1
- package/dist/live-connectors-runner.d.ts +3 -1
- package/dist/local-llm.d.ts +3 -1
- package/dist/local-model-endpoint.d.ts +3 -1
- package/dist/maintenance/memory-governance.d.ts +3 -1
- package/dist/maintenance/memory-governance.js +4 -4
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +4 -2
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +4 -4
- package/dist/maintenance/rebuild-memory-projection.d.ts +4 -2
- package/dist/maintenance/rebuild-memory-projection.js +5 -5
- package/dist/{maintenance-jhMpeGne.d.ts → maintenance-PFvY1Pw_.d.ts} +3 -3
- package/dist/mcp-memory-inspector-app.d.ts +37 -37
- package/dist/memory-action-policy.d.ts +3 -1
- package/dist/memory-cache.d.ts +3 -1
- package/dist/memory-lifecycle-ledger-utils.d.ts +3 -1
- package/dist/memory-projection-store.d.ts +3 -1
- package/dist/memory-provenance.d.ts +3 -1
- package/dist/memory-snapshot.d.ts +3 -1
- package/dist/memory-subject-cli.d.ts +40 -40
- package/dist/memory-subject.d.ts +42 -42
- package/dist/memory-worth-outcomes.d.ts +4 -2
- package/dist/models-json.d.ts +3 -1
- package/dist/namespaces/migrate.d.ts +5 -3
- package/dist/namespaces/migrate.js +5 -5
- package/dist/namespaces/principal.d.ts +3 -1
- package/dist/namespaces/search.d.ts +3 -1
- package/dist/namespaces/storage.d.ts +5 -3
- package/dist/namespaces/storage.js +4 -4
- package/dist/native-knowledge.d.ts +3 -1
- package/dist/offline-sync-impression-drain.d.ts +3 -1
- package/dist/operator-doctor-corpus.d.ts +3 -1
- package/dist/operator-doctor-corpus.js +7 -7
- package/dist/operator-doctor-replica.d.ts +3 -1
- package/dist/operator-toolkit.d.ts +5 -3
- package/dist/operator-toolkit.js +19 -13
- package/dist/orchestration/compression-guideline-coordinator.d.ts +4 -2
- package/dist/orchestration/maintenance.d.ts +6 -4
- package/dist/orchestration/maintenance.js +10 -10
- package/dist/{orchestrator-DyGUC7re.d.ts → orchestrator-4wzJrPVm.d.ts} +23 -9
- package/dist/orchestrator.d.ts +12 -12
- package/dist/orchestrator.js +62 -60
- package/dist/patterns-cli.d.ts +3 -1
- package/dist/{pipeline-C25Oxtp1.d.ts → pipeline-CgXgdIrF.d.ts} +1 -1
- package/dist/policy-runtime.d.ts +3 -1
- package/dist/proactive-contention.d.ts +3 -1
- package/dist/provenance.d.ts +3 -1
- package/dist/{public-http-CMe7NQzj.d.ts → public-http-DhIXYBYI.d.ts} +1 -1
- package/dist/{qmd-DkDVCbgF.d.ts → qmd-BppGGxsi.d.ts} +1 -1
- package/dist/qmd-preflight.d.ts +4 -2
- package/dist/qmd-recall-cache.d.ts +3 -1
- package/dist/qmd.d.ts +4 -2
- package/dist/recall-concurrency-config.d.ts +3 -1
- package/dist/recall-disclosure-escalation.d.ts +3 -1
- package/dist/recall-explain-renderer.d.ts +3 -1
- package/dist/recall-explain-renderer.js +3 -3
- package/dist/recall-memory-map.d.ts +3 -1
- package/dist/recall-planner-llm.d.ts +3 -1
- package/dist/recall-state.d.ts +3 -1
- package/dist/recall-tag-filter.d.ts +3 -1
- package/dist/recall-timings.d.ts +3 -1
- package/dist/recall-xray-cli.d.ts +3 -1
- package/dist/recall-xray-cli.js +4 -4
- package/dist/recall-xray-renderer.d.ts +3 -1
- package/dist/recall-xray-renderer.js +3 -3
- package/dist/recall-xray.d.ts +3 -1
- package/dist/recall-xray.js +2 -2
- package/dist/reconcile/cursor.d.ts +3 -1
- package/dist/reconcile/manifest.d.ts +3 -1
- package/dist/reconcile/manifest.js +2 -2
- package/dist/reconcile/plan.d.ts +3 -1
- package/dist/replay/normalizers/chatgpt.d.ts +3 -1
- package/dist/replay/normalizers/claude.d.ts +3 -1
- package/dist/replay/normalizers/openclaw.d.ts +3 -1
- package/dist/replay/normalizers/shared.d.ts +3 -1
- package/dist/replay/runner.d.ts +3 -1
- package/dist/replay/types.d.ts +3 -1
- package/dist/replica-divergence.d.ts +3 -1
- package/dist/replica-peers-config.d.ts +3 -1
- package/dist/{resolution-MFY72STR.js → resolution-4552BNRV.js} +14 -4
- package/dist/resolve-auth-token.d.ts +3 -1
- package/dist/resume-bundles.js +8 -2
- package/dist/retrieval-agents.d.ts +4 -2
- package/dist/retrieval-tiers.d.ts +3 -1
- package/dist/routing/engine.d.ts +3 -1
- package/dist/routing/store.d.ts +3 -1
- package/dist/salvage-envelope.d.ts +3 -1
- package/dist/salvage-envelope.js +1 -1
- package/dist/schemas.d.ts +44 -44
- package/dist/{scope-profiles-B9xMoFO-.d.ts → scope-profiles-ChZUtxDU.d.ts} +1 -1
- package/dist/search/embed-helper.d.ts +3 -1
- package/dist/search/factory.d.ts +3 -1
- package/dist/search/index.d.ts +3 -1
- package/dist/search/lancedb-backend.d.ts +3 -1
- package/dist/search/meilisearch-backend.d.ts +3 -1
- package/dist/search/noop-backend.d.ts +3 -1
- package/dist/search/orama-backend.d.ts +3 -1
- package/dist/search/port.d.ts +3 -1
- package/dist/search/remote-backend.d.ts +3 -1
- package/dist/{semantic-TddhF0y7.d.ts → semantic-BalR6EXU.d.ts} +1 -1
- package/dist/{semantic-consolidation-C4uykW84.d.ts → semantic-consolidation-mSPwQSmF.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +4 -2
- package/dist/semantic-consolidation.js +9 -6
- package/dist/semantic-rule-promotion.js +4 -4
- package/dist/semantic-rule-verifier.d.ts +3 -1
- package/dist/semantic-rule-verifier.js +4 -4
- package/dist/{service-DCZDZNcV.d.ts → service-BICWLwSP.d.ts} +2 -2
- package/dist/session-observer-bands.d.ts +3 -1
- package/dist/session-observer-state.d.ts +3 -1
- package/dist/shared-context/manager.d.ts +3 -1
- package/dist/signal.d.ts +3 -1
- package/dist/skills-registry.js +4 -56
- package/dist/skills-registry.js.map +1 -1
- package/dist/source-agent-qualifier.d.ts +3 -1
- package/dist/source-agent-qualifier.js +8 -5
- package/dist/{storage-CcKmEjL8.d.ts → storage-B7urx1K3.d.ts} +1 -1
- package/dist/storage.d.ts +4 -2
- package/dist/storage.js +6 -6
- package/dist/subject-config.d.ts +3 -1
- package/dist/summarizer.d.ts +3 -1
- package/dist/summary-snapshot.d.ts +3 -1
- package/dist/support-passport/index.d.ts +43 -43
- package/dist/support-passport/index.js +24 -22
- package/dist/temporal-supersession.d.ts +4 -2
- package/dist/temporal-timeline-recall.d.ts +3 -1
- package/dist/temporal-validity.d.ts +3 -1
- package/dist/threading.d.ts +3 -1
- package/dist/tier-migration.d.ts +4 -2
- package/dist/tier-routing.d.ts +3 -1
- package/dist/topics.d.ts +3 -1
- package/dist/transcript.d.ts +3 -1
- package/dist/transfer/types.d.ts +20 -20
- package/dist/trust-score-stage.d.ts +3 -1
- package/dist/trust-score.d.ts +3 -1
- package/dist/{types-Pi0lfaEt.d.ts → types-ETU5N6nB.d.ts} +433 -7
- package/dist/types.d.ts +3 -1
- package/dist/types.js +1 -1
- package/dist/utility-runtime.d.ts +3 -1
- package/dist/verified-recall.js +4 -4
- package/dist/who-knows-cli.d.ts +40 -40
- package/dist/who-knows-cli.js +5 -5
- package/dist/who-knows.d.ts +42 -42
- package/dist/who-knows.js +4 -4
- package/dist/write-envelope.d.ts +3 -1
- package/dist/write-envelope.js +1 -1
- package/package.json +2 -2
- package/src/access-boundary.ts +4 -0
- package/src/access-http.ts +6 -5
- package/src/access-mcp-admin-tools.ts +24 -0
- package/src/access-mcp-output-schemas.ts +14 -0
- package/src/access-mcp.ts +2 -2
- package/src/access-operations-batch.ts +5 -0
- package/src/access-service.ts +27 -0
- package/src/access-surface-catalog.test.ts +24 -0
- package/src/access-surface-catalog.ts +4 -0
- package/src/cli/skills-commands.ts +150 -0
- package/src/cli.ts +4 -2
- package/src/coding/action-gate.test.ts +341 -0
- package/src/coding/action-gate.ts +556 -0
- package/src/config.ts +9 -2
- package/src/connectors/codex-materialize-runner.ts +16 -0
- package/src/connectors/codex-materialize-skills.test.ts +141 -0
- package/src/connectors/codex-materialize.ts +58 -40
- package/src/connectors/materialize-paths.ts +50 -0
- package/src/connectors/materialize-skills.ts +127 -0
- package/src/contradiction/contradiction-review.ts +50 -4
- package/src/contradiction/contradiction-scan.ts +14 -3
- package/src/contradiction/resolution.ts +50 -2
- package/src/index.ts +9 -13
- package/src/orchestration/recall-rerank-coordinator.ts +123 -4
- package/src/orchestration/recall-result-formatter.ts +6 -2
- package/src/orchestration/recall-search-pipeline.ts +14 -1
- package/src/preferences/drift-config.ts +118 -0
- package/src/preferences/drift-recall.ts +133 -0
- package/src/preferences/drift-types.ts +87 -0
- package/src/preferences/index.ts +12 -0
- package/src/preferences/preference-drift.test.ts +690 -0
- package/src/preferences/preference-drift.ts +724 -0
- package/src/procedural/skill-io.test.ts +190 -0
- package/src/procedural/skill-io.ts +220 -0
- package/src/procedural/skill-projection.test.ts +214 -0
- package/src/procedural/skill-projection.ts +356 -0
- package/src/review/review-deck-access.test.ts +325 -0
- package/src/review/review-deck-http-base.ts +133 -0
- package/src/review/review-deck-mutation.test.ts +417 -0
- package/src/review/review-deck-mutation.ts +677 -0
- package/src/review/review-deck-snapshot.ts +196 -0
- package/src/review/review-deck-surface.ts +117 -0
- package/src/review/review-deck.test.ts +347 -0
- package/src/review/review-deck.ts +311 -0
- package/src/storage.ts +4 -6
- package/src/types.ts +9 -6
- package/dist/chunk-35NN3ZFA.js.map +0 -1
- package/dist/chunk-4KYOLI6M.js.map +0 -1
- package/dist/chunk-BWLRUMOG.js.map +0 -1
- package/dist/chunk-J275IYMG.js.map +0 -1
- package/dist/chunk-LGO6A7GJ.js.map +0 -1
- package/dist/chunk-QOS5LBZN.js.map +0 -1
- package/dist/chunk-RDFF2NAU.js.map +0 -1
- package/dist/chunk-SB7D4BT7.js.map +0 -1
- package/dist/chunk-SBDCZ2AX.js.map +0 -1
- package/dist/chunk-TF77C7SV.js.map +0 -1
- package/dist/chunk-TZNQUNKL.js.map +0 -1
- package/dist/chunk-V3MXUL3D.js.map +0 -1
- package/dist/chunk-XCTXS7VY.js +0 -402
- package/dist/chunk-XCTXS7VY.js.map +0 -1
- package/dist/chunk-YLDXWCZP.js.map +0 -1
- /package/dist/{auto-sync-H64ZCNIR.js.map → auto-sync-XVMLL2RH.js.map} +0 -0
- /package/dist/{chunk-YB42WZCY.js.map → chunk-2IXQSGCU.js.map} +0 -0
- /package/dist/{chunk-PE255F4T.js.map → chunk-2MVTAIL3.js.map} +0 -0
- /package/dist/{chunk-GDFVPUJ5.js.map → chunk-3NH3VP3U.js.map} +0 -0
- /package/dist/{chunk-GNCCUR6K.js.map → chunk-AXGFOFNY.js.map} +0 -0
- /package/dist/{chunk-5YQ63T4B.js.map → chunk-BK5G2MHO.js.map} +0 -0
- /package/dist/{chunk-LZH5FR2W.js.map → chunk-CQBIN77D.js.map} +0 -0
- /package/dist/{chunk-NKKD4ZAU.js.map → chunk-DORFF5N5.js.map} +0 -0
- /package/dist/{chunk-SQI57UCJ.js.map → chunk-DUEDOYZD.js.map} +0 -0
- /package/dist/{chunk-5NM4OH4P.js.map → chunk-DUZARALI.js.map} +0 -0
- /package/dist/{chunk-2E36UXVW.js.map → chunk-ECLJ4LA2.js.map} +0 -0
- /package/dist/{chunk-IID2CMUU.js.map → chunk-GHD2LLG4.js.map} +0 -0
- /package/dist/{chunk-ZQHI2BZB.js.map → chunk-HF5BUTI6.js.map} +0 -0
- /package/dist/{chunk-3DVBKTSO.js.map → chunk-HSZMX3ZJ.js.map} +0 -0
- /package/dist/{chunk-S2DPMJXH.js.map → chunk-I23ZHYSL.js.map} +0 -0
- /package/dist/{chunk-ODZG724P.js.map → chunk-I2HTKOOP.js.map} +0 -0
- /package/dist/{chunk-NTWN6HB2.js.map → chunk-IURMJBGP.js.map} +0 -0
- /package/dist/{chunk-OCZIYAE5.js.map → chunk-IWKGOCL6.js.map} +0 -0
- /package/dist/{chunk-UXO5IMBK.js.map → chunk-J3ATBB7M.js.map} +0 -0
- /package/dist/{chunk-Y7DK7HHJ.js.map → chunk-JPAKBNTM.js.map} +0 -0
- /package/dist/{chunk-SPUJNJJC.js.map → chunk-KFIOPZ25.js.map} +0 -0
- /package/dist/{chunk-JYYBA7TF.js.map → chunk-KOO37E4Y.js.map} +0 -0
- /package/dist/{chunk-OTHZWLUD.js.map → chunk-KPB2QHJZ.js.map} +0 -0
- /package/dist/{chunk-CT56C22C.js.map → chunk-LYBIHM4N.js.map} +0 -0
- /package/dist/{chunk-3I7ASZN3.js.map → chunk-MFOSZUIT.js.map} +0 -0
- /package/dist/{chunk-DZUJ46DO.js.map → chunk-NLEH4RTB.js.map} +0 -0
- /package/dist/{chunk-ZO6AXLEH.js.map → chunk-OCCHUEZB.js.map} +0 -0
- /package/dist/{chunk-EILZG5VC.js.map → chunk-OU34IQXV.js.map} +0 -0
- /package/dist/{chunk-2XDWWPTN.js.map → chunk-OZDFB22S.js.map} +0 -0
- /package/dist/{chunk-UIN2BWDD.js.map → chunk-PTZQYCJ4.js.map} +0 -0
- /package/dist/{chunk-Z7PBQPJ4.js.map → chunk-QJW4MZSW.js.map} +0 -0
- /package/dist/{chunk-R7JAM2XF.js.map → chunk-R2MZCYA6.js.map} +0 -0
- /package/dist/{chunk-LBWQ65SX.js.map → chunk-T42L3S6A.js.map} +0 -0
- /package/dist/{chunk-2YI72KM3.js.map → chunk-UCKG36HO.js.map} +0 -0
- /package/dist/{chunk-SIHSCCUQ.js.map → chunk-UFR6HX7A.js.map} +0 -0
- /package/dist/{chunk-CDUUDBWJ.js.map → chunk-VFYRYFLL.js.map} +0 -0
- /package/dist/{chunk-XRYZRW54.js.map → chunk-WDXD6ITO.js.map} +0 -0
- /package/dist/{chunk-MN4KB2A4.js.map → chunk-YDKF4MSJ.js.map} +0 -0
- /package/dist/{chunk-7YQ4IYS2.js.map → chunk-YOXVZJFM.js.map} +0 -0
- /package/dist/{chunk-ZWXJBFZU.js.map → chunk-YZJM6CLF.js.map} +0 -0
- /package/dist/{chunk-LUNJ3WFO.js.map → chunk-ZK4BFABK.js.map} +0 -0
- /package/dist/{contradiction-review-QKJH5DKD.js.map → contradiction-review-WRVLRWHS.js.map} +0 -0
- /package/dist/{contradiction-scan-VOTQRRSX.js.map → contradiction-scan-AKUWPX5N.js.map} +0 -0
- /package/dist/{resolution-MFY72STR.js.map → resolution-4552BNRV.js.map} +0 -0
|
@@ -10,7 +10,13 @@ import { composeMemoryEnvelope } from "../write-envelope.js";
|
|
|
10
10
|
import type { StorageManager } from "../storage.js";
|
|
11
11
|
import type { MemoryCategory, MemoryFile } from "../types.js";
|
|
12
12
|
import type { ResolutionVerb } from "./contradiction-review.js";
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
CONTRADICTION_VERBS,
|
|
15
|
+
PREFERENCE_DRIFT_VERBS,
|
|
16
|
+
readPair,
|
|
17
|
+
resolvePair,
|
|
18
|
+
} from "./contradiction-review.js";
|
|
19
|
+
import { resolvePreferenceDrift } from "../preferences/preference-drift.js";
|
|
14
20
|
|
|
15
21
|
export interface ResolutionResult {
|
|
16
22
|
pairId: string;
|
|
@@ -50,7 +56,14 @@ export interface ExecuteResolutionOptions {
|
|
|
50
56
|
onMergedMemoryWritten?: (namespace: string | undefined, storageDir: string) => void;
|
|
51
57
|
}
|
|
52
58
|
|
|
53
|
-
|
|
59
|
+
/**
|
|
60
|
+
* Every verb the `review_resolve` surface accepts, across both review-item
|
|
61
|
+
* kinds (issue #2371). This is a *surface-level* gate only: per-kind validity
|
|
62
|
+
* is enforced inside {@link executeResolution}, which is the first place the
|
|
63
|
+
* item's `kind` is known. Callers therefore reject an unknown verb early and
|
|
64
|
+
* a cross-kind verb precisely.
|
|
65
|
+
*/
|
|
66
|
+
const VALID_VERBS: readonly ResolutionVerb[] = [...CONTRADICTION_VERBS, ...PREFERENCE_DRIFT_VERBS];
|
|
54
67
|
|
|
55
68
|
export function isValidResolutionVerb(value: string): value is ResolutionVerb {
|
|
56
69
|
return VALID_VERBS.includes(value as ResolutionVerb);
|
|
@@ -94,6 +107,41 @@ export async function executeResolution(
|
|
|
94
107
|
if (pair.resolution && pair.resolution !== "needs-more-context") {
|
|
95
108
|
return { pairId, verb, affectedIds: [], message: `Pair already resolved with verb "${pair.resolution}"` };
|
|
96
109
|
}
|
|
110
|
+
// Verb validity is per review-item kind (issue #2371). A preference-drift
|
|
111
|
+
// item never accepts keep-a/keep-b/merge (there is no "B" to keep — the
|
|
112
|
+
// second id is witness evidence, not a competing claim), and a contradiction
|
|
113
|
+
// pair never accepts keep/supersede/archive. Rejecting the cross-kind verb
|
|
114
|
+
// here, after the record is loaded, is the only place both kinds are known.
|
|
115
|
+
const isDriftItem = pair.kind === "preference-drift";
|
|
116
|
+
const verbMatchesKind = isDriftItem
|
|
117
|
+
? PREFERENCE_DRIFT_VERBS.includes(verb)
|
|
118
|
+
: CONTRADICTION_VERBS.includes(verb);
|
|
119
|
+
if (!verbMatchesKind) {
|
|
120
|
+
const allowed = (isDriftItem ? PREFERENCE_DRIFT_VERBS : CONTRADICTION_VERBS).join(", ");
|
|
121
|
+
return {
|
|
122
|
+
pairId,
|
|
123
|
+
verb,
|
|
124
|
+
affectedIds: [],
|
|
125
|
+
message: `Verb "${verb}" is not valid for a ${isDriftItem ? "preference-drift" : "contradiction"} item. Valid: ${allowed}`,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (isDriftItem) {
|
|
130
|
+
const outcome = await resolvePreferenceDrift(
|
|
131
|
+
resolutionStorage,
|
|
132
|
+
pair,
|
|
133
|
+
verb as "keep" | "supersede" | "archive",
|
|
134
|
+
{
|
|
135
|
+
mergedContent: options.mergedContent,
|
|
136
|
+
onMemoryWritten: options.onMergedMemoryWritten,
|
|
137
|
+
},
|
|
138
|
+
);
|
|
139
|
+
// Only record the terminal resolution when memories actually changed;
|
|
140
|
+
// a refused resolution must stay actionable in the queue.
|
|
141
|
+
if (outcome.affectedIds.length > 0) resolvePair(memoryDir, pairId, verb);
|
|
142
|
+
return { pairId, verb, affectedIds: outcome.affectedIds, message: outcome.message };
|
|
143
|
+
}
|
|
144
|
+
|
|
97
145
|
|
|
98
146
|
const [idA, idB] = pair.memoryIds;
|
|
99
147
|
const affectedIds: string[] = [];
|
package/src/index.ts
CHANGED
|
@@ -219,17 +219,13 @@ export {
|
|
|
219
219
|
} from "./procedural/procedure-types.js";
|
|
220
220
|
|
|
221
221
|
// Procedural stats surface (issue #567 PR 5/5).
|
|
222
|
-
export {
|
|
223
|
-
|
|
224
|
-
formatProcedureStatsText,
|
|
225
|
-
} from "./procedural/procedure-stats.js";
|
|
226
|
-
export type {
|
|
227
|
-
ProcedureStatsReport,
|
|
228
|
-
ProcedureStatusCounts,
|
|
229
|
-
ProcedureStatsConfigSnapshot,
|
|
230
|
-
ProcedureStatsRecent,
|
|
231
|
-
} from "./procedural/procedure-stats.js";
|
|
222
|
+
export { computeProcedureStats, formatProcedureStatsText } from "./procedural/procedure-stats.js";
|
|
223
|
+
export type { ProcedureStatsReport, ProcedureStatusCounts, ProcedureStatsConfigSnapshot, ProcedureStatsRecent } from "./procedural/procedure-stats.js";
|
|
232
224
|
export { runProcedureLibraryMaintenance, type ProcedureLibraryMaintenanceReport, type ProcedureMaintenanceAction, type ProcedureMaintenanceActionKind, type ProcedureMaintenanceReasonCode, type ProcedureMaintenanceEvidence, type ProcedureMaintenanceMarker } from "./procedural/library-maintenance.js";
|
|
225
|
+
// Portable procedural skill bundles (issue #2369).
|
|
226
|
+
export { parseSkillProjectionConfig, projectProceduresToSkills, renderSkillBundle, parseSkillBundle, sanitizeSkillSlug, SKILL_FILE_NAME, type SkillBundle, type SkillProjectionConfig, type ParsedSkillBundle } from "./procedural/skill-projection.js";
|
|
227
|
+
export { exportSkillBundles, readSkillBundlesFromDir, persistImportedSkills, type ExportSkillsResult, type ImportSkillsResult, type ReadSkillBundle } from "./procedural/skill-io.js";
|
|
228
|
+
export * from "./preferences/index.js";
|
|
233
229
|
// ---------------------------------------------------------------------------
|
|
234
230
|
// Direct-answer retrieval tier (issue #518)
|
|
235
231
|
// ---------------------------------------------------------------------------
|
|
@@ -515,6 +511,7 @@ export {
|
|
|
515
511
|
type RemnicChatGptMemoryInspectorResult,
|
|
516
512
|
} from "./mcp-memory-inspector-app.js";
|
|
517
513
|
export * from "./coding/pre-action-gate.js";
|
|
514
|
+
export * from "./coding/action-gate.js";
|
|
518
515
|
export * from "./causal-trajectory.js";
|
|
519
516
|
// Coding-agent subsystem (issue #569)
|
|
520
517
|
export {
|
|
@@ -805,10 +802,7 @@ export {
|
|
|
805
802
|
type SemanticDedupDecision,
|
|
806
803
|
} from "./dedup/semantic.js";
|
|
807
804
|
|
|
808
|
-
// ---------------------------------------------------------------------------
|
|
809
805
|
// Review Inbox
|
|
810
|
-
// ---------------------------------------------------------------------------
|
|
811
|
-
|
|
812
806
|
export {
|
|
813
807
|
listReviewItems,
|
|
814
808
|
performReview,
|
|
@@ -818,6 +812,8 @@ export {
|
|
|
818
812
|
type ReviewListResult,
|
|
819
813
|
type ReviewOptions,
|
|
820
814
|
} from "./review/index.js";
|
|
815
|
+
export * from "./review/review-deck.js";
|
|
816
|
+
export * from "./review/review-deck-snapshot.js";
|
|
821
817
|
|
|
822
818
|
// ---------------------------------------------------------------------------
|
|
823
819
|
// Diff-Aware Sync
|
|
@@ -24,6 +24,11 @@ import {
|
|
|
24
24
|
buildMemoryWorthCounterMap,
|
|
25
25
|
type MemoryWorthCounters,
|
|
26
26
|
} from "../memory-worth-filter.js";
|
|
27
|
+
import {
|
|
28
|
+
applyPreferenceDriftRanking,
|
|
29
|
+
isPreferenceDriftStageActive,
|
|
30
|
+
type DriftRecallFrontmatter,
|
|
31
|
+
} from "../preferences/drift-recall.js";
|
|
27
32
|
import {
|
|
28
33
|
applyTrustScoreStage,
|
|
29
34
|
buildTrustSignalsForRerank,
|
|
@@ -470,9 +475,16 @@ export class RecallRerankCoordinator {
|
|
|
470
475
|
results: QmdSearchResult[];
|
|
471
476
|
trustByPath: Map<string, TrustStageResultItem> | null;
|
|
472
477
|
}> {
|
|
478
|
+
// The trust stage and the Memory Worth multiplier are mutually exclusive
|
|
479
|
+
// (rule 39); the preference-drift stage runs AFTER whichever one applied,
|
|
480
|
+
// on every branch, so its gate is uniform across recall paths (§27).
|
|
481
|
+
let staged = results;
|
|
482
|
+
let trustByPath: Map<string, TrustStageResultItem> | null = null;
|
|
473
483
|
if (caps.recallTrustScore && results.length > 0) {
|
|
474
484
|
try {
|
|
475
|
-
|
|
485
|
+
const outcome = await this.applyTrustScoreRerank(results, namespaces, preloadedFrontmatter, abortSignal);
|
|
486
|
+
staged = outcome.results;
|
|
487
|
+
trustByPath = outcome.trustByPath;
|
|
476
488
|
} catch (err) {
|
|
477
489
|
log.debug(`trust-score stage (${label}) failed open`, {
|
|
478
490
|
error: (err as Error).message,
|
|
@@ -480,20 +492,127 @@ export class RecallRerankCoordinator {
|
|
|
480
492
|
}
|
|
481
493
|
} else if (caps.recallMemoryWorthFilter && results.length > 0) {
|
|
482
494
|
try {
|
|
483
|
-
|
|
495
|
+
staged = await this.applyMemoryWorthRerank(
|
|
484
496
|
results,
|
|
485
497
|
namespaces,
|
|
486
498
|
preloadedFrontmatter,
|
|
487
499
|
abortSignal,
|
|
488
500
|
);
|
|
489
|
-
return { results: filtered, trustByPath: null };
|
|
490
501
|
} catch (err) {
|
|
491
502
|
log.debug(`memory-worth filter (${label}) failed open`, {
|
|
492
503
|
error: (err as Error).message,
|
|
493
504
|
});
|
|
494
505
|
}
|
|
495
506
|
}
|
|
496
|
-
|
|
507
|
+
const damped = await this.applyPreferenceDriftStage(
|
|
508
|
+
staged,
|
|
509
|
+
namespaces,
|
|
510
|
+
preloadedFrontmatter,
|
|
511
|
+
abortSignal,
|
|
512
|
+
);
|
|
513
|
+
return { results: damped, trustByPath };
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Issue #2371 — stale-preference damping + injection annotation.
|
|
518
|
+
*
|
|
519
|
+
* Runs immediately after the trust/Memory-Worth stage on EVERY recall branch
|
|
520
|
+
* (hot QMD, embedding fallback, recent scan, cold fallback), so the feature
|
|
521
|
+
* gate applies uniformly and fallback parity holds (§27, AGENTS.md retrieval
|
|
522
|
+
* guardrails). Fully inert on the default config: when neither damping nor
|
|
523
|
+
* annotation is active the input array is returned untouched and NO
|
|
524
|
+
* frontmatter is read, so recall ordering and injected text stay
|
|
525
|
+
* byte-identical to pre-#2371.
|
|
526
|
+
*
|
|
527
|
+
* Fail-open: any lookup error leaves the branch's results unchanged.
|
|
528
|
+
*/
|
|
529
|
+
async applyPreferenceDriftStage(
|
|
530
|
+
results: QmdSearchResult[],
|
|
531
|
+
namespaces: string[],
|
|
532
|
+
preloadedFrontmatter?: ReadonlyMap<string, MemoryFile>,
|
|
533
|
+
abortSignal?: AbortSignal,
|
|
534
|
+
): Promise<QmdSearchResult[]> {
|
|
535
|
+
const config = this.getConfig();
|
|
536
|
+
if (!isPreferenceDriftStageActive(config.driftDetection)) return results;
|
|
537
|
+
if (results.length === 0) return results;
|
|
538
|
+
|
|
539
|
+
try {
|
|
540
|
+
const frontmatterByKey = new Map<string, DriftRecallFrontmatter>();
|
|
541
|
+
const missing: QmdSearchResult[] = [];
|
|
542
|
+
for (const r of results) {
|
|
543
|
+
const key = memoryMapKey(r);
|
|
544
|
+
const preloaded = preloadedFrontmatter?.get(key) ?? preloadedFrontmatter?.get(r.path);
|
|
545
|
+
if (preloaded) {
|
|
546
|
+
frontmatterByKey.set(key, preloaded.frontmatter);
|
|
547
|
+
} else {
|
|
548
|
+
missing.push(r);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// Branches without a preloaded map (embedding fallback) read the
|
|
553
|
+
// candidates directly. Bounded-parallel at the same batch size the
|
|
554
|
+
// Memory Worth stage uses, and only for the handful of candidates the
|
|
555
|
+
// branch actually returned — never a corpus scan.
|
|
556
|
+
if (missing.length > 0) {
|
|
557
|
+
let reader: StorageManager | null = null;
|
|
558
|
+
for (const ns of namespaces) {
|
|
559
|
+
try {
|
|
560
|
+
reader = await this.getStorage(ns);
|
|
561
|
+
break;
|
|
562
|
+
} catch {
|
|
563
|
+
// try next namespace
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
if (reader) {
|
|
567
|
+
const readerNn = reader;
|
|
568
|
+
const BATCH = 16;
|
|
569
|
+
for (let off = 0; off < missing.length; off += BATCH) {
|
|
570
|
+
if (abortSignal?.aborted) break;
|
|
571
|
+
await Promise.all(
|
|
572
|
+
missing.slice(off, off + BATCH).map(async (r) => {
|
|
573
|
+
try {
|
|
574
|
+
const memory = await this.readQmdResultMemory(r.path, readerNn, namespaces, r.namespace);
|
|
575
|
+
if (memory) frontmatterByKey.set(memoryMapKey(r), memory.frontmatter);
|
|
576
|
+
} catch (err) {
|
|
577
|
+
log.debug("preference-drift: direct path lookup failed", {
|
|
578
|
+
path: r.path,
|
|
579
|
+
error: (err as Error).message,
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
}),
|
|
583
|
+
);
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
// Synthetic monotone-decreasing rank score so neutral candidates keep
|
|
589
|
+
// their upstream order and only the damped ones move — same technique the
|
|
590
|
+
// Memory Worth stage uses, for the same reason.
|
|
591
|
+
const ranked = results.map((r, i) => ({
|
|
592
|
+
key: memoryMapKey(r),
|
|
593
|
+
rank: results.length - i,
|
|
594
|
+
frontmatter: frontmatterByKey.get(memoryMapKey(r)),
|
|
595
|
+
}));
|
|
596
|
+
const ordered = applyPreferenceDriftRanking(ranked, {
|
|
597
|
+
config: config.driftDetection,
|
|
598
|
+
now: new Date(),
|
|
599
|
+
});
|
|
600
|
+
|
|
601
|
+
const byKey = new Map(results.map((r) => [memoryMapKey(r), r]));
|
|
602
|
+
const reordered: QmdSearchResult[] = [];
|
|
603
|
+
for (const item of ordered) {
|
|
604
|
+
const original = byKey.get(item.key);
|
|
605
|
+
if (!original) continue;
|
|
606
|
+
// `driftNote` is copied onto a NEW result object — never mutated in
|
|
607
|
+
// place — so a shared upstream result can't leak an annotation into an
|
|
608
|
+
// unrelated branch.
|
|
609
|
+
reordered.push(item.note ? { ...original, driftNote: item.note } : original);
|
|
610
|
+
}
|
|
611
|
+
return reordered;
|
|
612
|
+
} catch (err) {
|
|
613
|
+
log.debug("preference-drift stage failed open", { error: (err as Error).message });
|
|
614
|
+
return results;
|
|
615
|
+
}
|
|
497
616
|
}
|
|
498
617
|
|
|
499
618
|
diversifyRecallResultsWithHeadroom(
|
|
@@ -230,14 +230,18 @@ export class RecallResultFormatter {
|
|
|
230
230
|
const withHandle = handle ? `${head.trimEnd()} ${handle}` : head.trimEnd();
|
|
231
231
|
const connectorLabel = renderConnectorLabel(r.sourceConnector);
|
|
232
232
|
const withConnector = connectorLabel ? `${withHandle} [agent: ${connectorLabel}]` : withHandle;
|
|
233
|
+
// Preference age note (issue #2371). Set only when
|
|
234
|
+
// `driftDetection.annotateAfterDays` is on, so this suffix is absent —
|
|
235
|
+
// and the rendered line byte-identical to pre-#2371 — by default.
|
|
236
|
+
const withDrift = r.driftNote ? `${withConnector} ${r.driftNote}` : withConnector;
|
|
233
237
|
if (hedgeMap) {
|
|
234
238
|
const item = trustResultFor(hedgeMap, r);
|
|
235
239
|
if (item) {
|
|
236
240
|
const hedge = renderEpistemicHedge(item.trust);
|
|
237
|
-
if (hedge.length > 0) return `${
|
|
241
|
+
if (hedge.length > 0) return `${withDrift} ${hedge}`;
|
|
238
242
|
}
|
|
239
243
|
}
|
|
240
|
-
return
|
|
244
|
+
return withDrift;
|
|
241
245
|
});
|
|
242
246
|
return { heading: `## ${title}`, entries };
|
|
243
247
|
}
|
|
@@ -113,7 +113,10 @@ export interface RecallSearchPipelineDeps {
|
|
|
113
113
|
recallNamespaces: string[],
|
|
114
114
|
): Promise<QueryAwarePrefilter>;
|
|
115
115
|
readonly config: PluginConfig;
|
|
116
|
-
readonly recallRerankCoordinator: Pick<
|
|
116
|
+
readonly recallRerankCoordinator: Pick<
|
|
117
|
+
RecallRerankCoordinator,
|
|
118
|
+
"diversifyRecallResultsWithHeadroom" | "applyPreferenceDriftStage"
|
|
119
|
+
>;
|
|
117
120
|
diversifyAndLimitRecallResults(
|
|
118
121
|
sectionId: string,
|
|
119
122
|
results: QmdSearchResult[],
|
|
@@ -954,6 +957,16 @@ export class RecallSearchPipelineCoordinator {
|
|
|
954
957
|
});
|
|
955
958
|
}
|
|
956
959
|
}
|
|
960
|
+
// Cold fallback boosts inline rather than through applyTrustScoreToBranch,
|
|
961
|
+
// so the preference-drift stage is applied here explicitly — otherwise
|
|
962
|
+
// damping would silently not apply to this branch (§27 fallback parity).
|
|
963
|
+
if (results.length > 0) {
|
|
964
|
+
results = await this.deps.recallRerankCoordinator.applyPreferenceDriftStage(
|
|
965
|
+
results,
|
|
966
|
+
options.recallNamespaces,
|
|
967
|
+
boostInput.memoryByPath,
|
|
968
|
+
);
|
|
969
|
+
}
|
|
957
970
|
|
|
958
971
|
if (options.xrayPoolSizeSink) {
|
|
959
972
|
options.xrayPoolSizeSink.size = Math.max(
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Preference drift detection config (issue #2371).
|
|
3
|
+
*
|
|
4
|
+
* Standalone top-level block, parsed the same way `contradictionScan` and
|
|
5
|
+
* `procedural.maintenance` are: shape-validated, string-coercion safe (§24),
|
|
6
|
+
* and honoring documented zero/no-op values (§33) rather than clamping them
|
|
7
|
+
* to something non-zero.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { coerceBool, coerceNumber } from "../connectors/coerce.js";
|
|
11
|
+
|
|
12
|
+
export interface DriftDetectionConfig {
|
|
13
|
+
/** Master switch for drift classification and its apply mode. Default false. */
|
|
14
|
+
enabled: boolean;
|
|
15
|
+
/** A preference younger than this is never a scan candidate. Default 60. */
|
|
16
|
+
minAgeDays: number;
|
|
17
|
+
/** Evidence-gathering window, in days back from the run instant. Default 45. */
|
|
18
|
+
lookbackDays: number;
|
|
19
|
+
/** Cap on preferences classified per run. `0` disables the scan entirely. Default 25. */
|
|
20
|
+
maxCandidatesPerRun: number;
|
|
21
|
+
/** When true, recall damps `driftState: stale` preferences. Default false. */
|
|
22
|
+
recallDamping: boolean;
|
|
23
|
+
/** Multiplier applied to stale preferences in (0, 1]; `1` is a documented no-op. Default 0.8. */
|
|
24
|
+
stalePenalty: number;
|
|
25
|
+
/** Annotate injected preferences uncorroborated for this many days. `0` = off. Default 0. */
|
|
26
|
+
annotateAfterDays: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const DRIFT_DETECTION_DEFAULTS: DriftDetectionConfig = {
|
|
30
|
+
enabled: false,
|
|
31
|
+
minAgeDays: 60,
|
|
32
|
+
lookbackDays: 45,
|
|
33
|
+
maxCandidatesPerRun: 25,
|
|
34
|
+
recallDamping: false,
|
|
35
|
+
stalePenalty: 0.8,
|
|
36
|
+
annotateAfterDays: 0,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
function parseFlag(src: Record<string, unknown>, key: string, fallback: boolean): boolean {
|
|
40
|
+
const value = src[key];
|
|
41
|
+
if (value === undefined || value === null) return fallback;
|
|
42
|
+
const coerced = coerceBool(value);
|
|
43
|
+
if (coerced === undefined) {
|
|
44
|
+
throw new Error(
|
|
45
|
+
`driftDetection.${key} must be a boolean or one of "true"/"false"/"1"/"0"/"yes"/"no"/"on"/"off" (got ${JSON.stringify(value)}).`,
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
return coerced;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function parseDayCount(src: Record<string, unknown>, key: string, fallback: number): number {
|
|
52
|
+
const value = src[key];
|
|
53
|
+
if (value === undefined || value === null) return fallback;
|
|
54
|
+
const coerced = coerceNumber(value);
|
|
55
|
+
if (coerced === undefined || !Number.isFinite(coerced)) {
|
|
56
|
+
throw new Error(`driftDetection.${key} must be a finite number (got ${JSON.stringify(value)}).`);
|
|
57
|
+
}
|
|
58
|
+
if (!Number.isInteger(coerced)) {
|
|
59
|
+
throw new Error(`driftDetection.${key} must be an integer (got ${JSON.stringify(value)}).`);
|
|
60
|
+
}
|
|
61
|
+
if (coerced < 0 || coerced > 36_500) {
|
|
62
|
+
throw new Error(`driftDetection.${key} must be between 0 and 36500 (got ${JSON.stringify(value)}).`);
|
|
63
|
+
}
|
|
64
|
+
return coerced;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function parseDriftDetectionConfig(raw: unknown): DriftDetectionConfig {
|
|
68
|
+
if (raw === undefined || raw === null) return { ...DRIFT_DETECTION_DEFAULTS };
|
|
69
|
+
if (typeof raw !== "object" || Array.isArray(raw)) {
|
|
70
|
+
throw new Error(
|
|
71
|
+
`driftDetection must be an object (got ${JSON.stringify(raw)}). Omit the key to keep drift detection disabled (issue #2371).`,
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
const src = raw as Record<string, unknown>;
|
|
75
|
+
|
|
76
|
+
// `0` disables the scan and MUST survive as zero — the documented disable
|
|
77
|
+
// value, never coerced up to a minimum (§33).
|
|
78
|
+
const rawMax = src.maxCandidatesPerRun;
|
|
79
|
+
let maxCandidatesPerRun = DRIFT_DETECTION_DEFAULTS.maxCandidatesPerRun;
|
|
80
|
+
if (rawMax !== undefined && rawMax !== null) {
|
|
81
|
+
const coerced = coerceNumber(rawMax);
|
|
82
|
+
if (coerced === undefined || !Number.isInteger(coerced) || coerced < 0) {
|
|
83
|
+
throw new Error(
|
|
84
|
+
`driftDetection.maxCandidatesPerRun must be an integer >= 0 (got ${JSON.stringify(rawMax)}). Use 0 to disable the scan.`,
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
maxCandidatesPerRun = coerced;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// stalePenalty is a multiplier in (0, 1]. `1` is the documented no-op; `0`
|
|
91
|
+
// would erase a memory's rank entirely and is rejected rather than accepted
|
|
92
|
+
// as a silent "delete from recall".
|
|
93
|
+
const rawPenalty = src.stalePenalty;
|
|
94
|
+
let stalePenalty = DRIFT_DETECTION_DEFAULTS.stalePenalty;
|
|
95
|
+
if (rawPenalty !== undefined && rawPenalty !== null) {
|
|
96
|
+
const coerced = coerceNumber(rawPenalty);
|
|
97
|
+
if (coerced === undefined || !Number.isFinite(coerced) || coerced <= 0 || coerced > 1) {
|
|
98
|
+
throw new Error(
|
|
99
|
+
`driftDetection.stalePenalty must be a number in (0, 1] (got ${JSON.stringify(rawPenalty)}). Use 1 to disable damping without changing the flag.`,
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
stalePenalty = coerced;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
enabled: parseFlag(src, "enabled", DRIFT_DETECTION_DEFAULTS.enabled),
|
|
107
|
+
minAgeDays: parseDayCount(src, "minAgeDays", DRIFT_DETECTION_DEFAULTS.minAgeDays),
|
|
108
|
+
lookbackDays: parseDayCount(src, "lookbackDays", DRIFT_DETECTION_DEFAULTS.lookbackDays),
|
|
109
|
+
maxCandidatesPerRun,
|
|
110
|
+
recallDamping: parseFlag(src, "recallDamping", DRIFT_DETECTION_DEFAULTS.recallDamping),
|
|
111
|
+
stalePenalty,
|
|
112
|
+
annotateAfterDays: parseDayCount(
|
|
113
|
+
src,
|
|
114
|
+
"annotateAfterDays",
|
|
115
|
+
DRIFT_DETECTION_DEFAULTS.annotateAfterDays,
|
|
116
|
+
),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stale-preference recall stage (issue #2371).
|
|
3
|
+
*
|
|
4
|
+
* Pure ranking + annotation helpers, deliberately free of storage, LLM, and
|
|
5
|
+
* config-loading imports so the recall hot path can import them without
|
|
6
|
+
* pulling in the drift scan's dependency graph.
|
|
7
|
+
*
|
|
8
|
+
* Two independent, independently-gated effects:
|
|
9
|
+
*
|
|
10
|
+
* 1. `driftDetection.recallDamping` multiplies the rank score of a
|
|
11
|
+
* `category: preference` memory carrying `driftState: stale` by
|
|
12
|
+
* `stalePenalty`, so a stale preference sinks below an otherwise-equal
|
|
13
|
+
* fresh memory. Applied in the same boost stage as the Memory Worth
|
|
14
|
+
* multiplier, so the pipeline-order contract (retrieve → filter →
|
|
15
|
+
* rerank/boost → cap → format) is untouched.
|
|
16
|
+
* 2. `driftDetection.annotateAfterDays` emits a compact age note for a
|
|
17
|
+
* preference whose last corroboration is older than the configured
|
|
18
|
+
* window. Formatting-stage only — it never mutates the stored memory.
|
|
19
|
+
*
|
|
20
|
+
* Both are off by default, and with both off this module returns the input
|
|
21
|
+
* order and no notes, so recall output is byte-identical to pre-#2371.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import type { DriftDetectionConfig } from "./drift-config.js";
|
|
25
|
+
import type { MemoryDriftState } from "./drift-types.js";
|
|
26
|
+
|
|
27
|
+
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
28
|
+
|
|
29
|
+
/** The only frontmatter fields this stage reads. */
|
|
30
|
+
export interface DriftRecallFrontmatter {
|
|
31
|
+
category?: string;
|
|
32
|
+
driftState?: MemoryDriftState;
|
|
33
|
+
lastCorroborated?: string;
|
|
34
|
+
created?: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface DriftRankInput {
|
|
38
|
+
/** Opaque candidate identity — the caller's composite (namespace, path) key. */
|
|
39
|
+
key: string;
|
|
40
|
+
/** Monotone-decreasing rank score preserving upstream order. */
|
|
41
|
+
rank: number;
|
|
42
|
+
frontmatter?: DriftRecallFrontmatter;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface DriftRankOutput {
|
|
46
|
+
key: string;
|
|
47
|
+
/** `1` when untouched, `stalePenalty` when damped. */
|
|
48
|
+
multiplier: number;
|
|
49
|
+
/** Injection annotation, when the age gate fired. */
|
|
50
|
+
note?: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* True when this stage would change nothing. Callers use it to skip the
|
|
55
|
+
* frontmatter lookups entirely on the default (all-off) configuration.
|
|
56
|
+
*
|
|
57
|
+
* `stalePenalty === 1` is the documented no-op (§33): damping stays "enabled"
|
|
58
|
+
* but multiplies by one, so it must not by itself activate the stage.
|
|
59
|
+
*/
|
|
60
|
+
export function isPreferenceDriftStageActive(config: DriftDetectionConfig | undefined): boolean {
|
|
61
|
+
if (!config) return false;
|
|
62
|
+
// `recallDamping` is a real boolean here: parseDriftDetectionConfig already
|
|
63
|
+
// coerced the string forms and threw on anything unrecognized, so no further
|
|
64
|
+
// coercion is needed at this boundary.
|
|
65
|
+
const damping = config.recallDamping && config.stalePenalty < 1;
|
|
66
|
+
return damping || config.annotateAfterDays > 0;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Render the age note for an uncorroborated preference, or `undefined` when
|
|
71
|
+
* the gate is off or the preference is inside the window.
|
|
72
|
+
*
|
|
73
|
+
* `lastCorroborated` absent falls back to `created`: a preference the scan has
|
|
74
|
+
* never corroborated is measured from when it was stated, which is exactly the
|
|
75
|
+
* "stated 2026-01; not corroborated since" case the survey describes.
|
|
76
|
+
*/
|
|
77
|
+
export function driftAgeNote(
|
|
78
|
+
frontmatter: DriftRecallFrontmatter | undefined,
|
|
79
|
+
config: DriftDetectionConfig,
|
|
80
|
+
now: Date,
|
|
81
|
+
): string | undefined {
|
|
82
|
+
if (config.annotateAfterDays <= 0) return undefined;
|
|
83
|
+
if (!frontmatter || frontmatter.category !== "preference") return undefined;
|
|
84
|
+
const anchor = frontmatter.lastCorroborated ?? frontmatter.created;
|
|
85
|
+
if (typeof anchor !== "string") return undefined;
|
|
86
|
+
const anchorMs = Date.parse(anchor);
|
|
87
|
+
if (!Number.isFinite(anchorMs)) return undefined;
|
|
88
|
+
const ageDays = Math.floor((now.getTime() - anchorMs) / DAY_MS);
|
|
89
|
+
if (ageDays < config.annotateAfterDays) return undefined;
|
|
90
|
+
const stated = new Date(anchorMs).toISOString().slice(0, 7);
|
|
91
|
+
return frontmatter.lastCorroborated
|
|
92
|
+
? `(corroborated ${stated}; not since)`
|
|
93
|
+
: `(stated ${stated}; not corroborated since)`;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Rank and annotate one recall branch's candidates.
|
|
98
|
+
*
|
|
99
|
+
* Returns one output per input, ordered by damped rank descending with a
|
|
100
|
+
* stable key tiebreak so the comparator is total and the ordering is identical
|
|
101
|
+
* across runs (§12).
|
|
102
|
+
*/
|
|
103
|
+
export function applyPreferenceDriftRanking(
|
|
104
|
+
inputs: readonly DriftRankInput[],
|
|
105
|
+
options: { config: DriftDetectionConfig; now: Date },
|
|
106
|
+
): DriftRankOutput[] {
|
|
107
|
+
const { config, now } = options;
|
|
108
|
+
const damping = config.recallDamping && config.stalePenalty < 1;
|
|
109
|
+
|
|
110
|
+
const scored = inputs.map((input, index) => {
|
|
111
|
+
const fm = input.frontmatter;
|
|
112
|
+
const isStalePreference = fm?.category === "preference" && fm.driftState === "stale";
|
|
113
|
+
const multiplier = damping && isStalePreference ? config.stalePenalty : 1;
|
|
114
|
+
return {
|
|
115
|
+
key: input.key,
|
|
116
|
+
index,
|
|
117
|
+
multiplier,
|
|
118
|
+
damped: input.rank * multiplier,
|
|
119
|
+
note: driftAgeNote(fm, config, now),
|
|
120
|
+
};
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
scored.sort((a, b) => {
|
|
124
|
+
if (a.damped !== b.damped) return a.damped > b.damped ? -1 : 1;
|
|
125
|
+
// Equal damped score → preserve upstream order, then key, so the
|
|
126
|
+
// comparator returns 0 only for genuinely identical entries.
|
|
127
|
+
if (a.index !== b.index) return a.index < b.index ? -1 : 1;
|
|
128
|
+
if (a.key !== b.key) return a.key < b.key ? -1 : 1;
|
|
129
|
+
return 0;
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
return scored.map((s) => (s.note ? { key: s.key, multiplier: s.multiplier, note: s.note } : { key: s.key, multiplier: s.multiplier }));
|
|
133
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared preference-drift type surfaces (issue #2371).
|
|
3
|
+
*
|
|
4
|
+
* These live in the preferences module rather than in `types.ts` so the
|
|
5
|
+
* cross-cutting fields drift detection introduces are declared next to the
|
|
6
|
+
* subsystem that owns them, and `types.ts` composes them through `extends`
|
|
7
|
+
* instead of growing another inline block.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { DriftDetectionConfig } from "./drift-config.js";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Drift verdict persisted on `preference` memories. `corroborated` is
|
|
14
|
+
* deliberately NOT a member: a corroborated preference clears `driftState` and
|
|
15
|
+
* stamps `lastCorroborated`, so the stored enum only carries a negative
|
|
16
|
+
* verdict.
|
|
17
|
+
*/
|
|
18
|
+
export type MemoryDriftState = "stale" | "drifted";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Derived drift provenance stamped by the scan AFTER a memory exists — never
|
|
22
|
+
* supplied at compose time, which is why these fields stay outside the sealed
|
|
23
|
+
* write envelope for exactly the reason `mw_success` / `mw_fail` do.
|
|
24
|
+
*
|
|
25
|
+
* Mixed into `MemoryFrontmatter`.
|
|
26
|
+
*/
|
|
27
|
+
export interface MemoryDriftProvenance {
|
|
28
|
+
/**
|
|
29
|
+
* `stale` means the lookback window held no corroborating evidence either
|
|
30
|
+
* way; `drifted` means recent evidence pointed away from the preference and
|
|
31
|
+
* a review item was opened. Absent means "not classified".
|
|
32
|
+
*/
|
|
33
|
+
driftState?: MemoryDriftState;
|
|
34
|
+
/** ISO 8601 timestamp of the last run that found corroborating evidence. */
|
|
35
|
+
lastCorroborated?: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Per-recall render hint, mixed into `QmdSearchResult`. Set by the
|
|
40
|
+
* preference-drift recall stage when `driftDetection.annotateAfterDays` is on
|
|
41
|
+
* and absent otherwise. Never persisted — this annotates one injection, it is
|
|
42
|
+
* not memory state.
|
|
43
|
+
*/
|
|
44
|
+
export interface RecallDriftAnnotation {
|
|
45
|
+
driftNote?: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Mixed into `PluginConfig`. */
|
|
49
|
+
export interface DriftDetectionSettings {
|
|
50
|
+
driftDetection: DriftDetectionConfig;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Frontmatter codec for the drift stamps. Lives here, beside the interface it
|
|
55
|
+
* serializes, so `storage.ts` stays a caller rather than growing another
|
|
56
|
+
* field-specific block.
|
|
57
|
+
*/
|
|
58
|
+
export function serializeDriftProvenance(fm: MemoryDriftProvenance): string[] {
|
|
59
|
+
const lines: string[] = [];
|
|
60
|
+
if (fm.driftState !== undefined) {
|
|
61
|
+
// An unrecognized verdict on write is a caller bug that must surface, not
|
|
62
|
+
// something to persist silently.
|
|
63
|
+
if (fm.driftState !== "stale" && fm.driftState !== "drifted") {
|
|
64
|
+
throw new Error(
|
|
65
|
+
`serializeFrontmatter: invalid driftState ${JSON.stringify(fm.driftState)} — expected "stale" | "drifted"`,
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
lines.push(`driftState: ${fm.driftState}`);
|
|
69
|
+
}
|
|
70
|
+
if (fm.lastCorroborated) lines.push(`lastCorroborated: ${fm.lastCorroborated}`);
|
|
71
|
+
return lines;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Read the drift stamps back. A hand-edited or unrecognized stored verdict
|
|
76
|
+
* round-trips to `undefined` rather than poisoning recall damping — the same
|
|
77
|
+
* policy the Memory Worth counters use for corrupt values.
|
|
78
|
+
*/
|
|
79
|
+
export function parseDriftProvenance(
|
|
80
|
+
fm: Record<string, string | undefined>,
|
|
81
|
+
): MemoryDriftProvenance {
|
|
82
|
+
return {
|
|
83
|
+
driftState:
|
|
84
|
+
fm.driftState === "stale" || fm.driftState === "drifted" ? fm.driftState : undefined,
|
|
85
|
+
lastCorroborated: fm.lastCorroborated || undefined,
|
|
86
|
+
};
|
|
87
|
+
}
|