@remnic/core 9.3.729 → 9.3.731
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-boundary.d.ts +6 -5
- package/dist/access-boundary.js +13 -13
- package/dist/access-cli.js +34 -33
- package/dist/access-cli.js.map +1 -1
- package/dist/access-http.d.ts +6 -5
- package/dist/access-http.js +19 -19
- package/dist/access-mcp.d.ts +6 -5
- package/dist/access-mcp.js +18 -18
- package/dist/access-operations-batch.js +16 -16
- package/dist/access-operations.d.ts +11 -10
- package/dist/access-operations.js +17 -17
- package/dist/access-schema.d.ts +42 -42
- package/dist/{access-service-BXMJqkTA.d.ts → access-service-Byoe3HsT.d.ts} +18 -3
- package/dist/access-service.d.ts +6 -5
- package/dist/access-service.js +12 -12
- package/dist/access-surface-catalog.d.ts +6 -5
- package/dist/action-confidence.d.ts +1 -1
- package/dist/active-memory-bridge.d.ts +1 -1
- package/dist/active-recall.d.ts +1 -1
- package/dist/active-recall.js +2 -2
- package/dist/{auto-sync-F3KCSQFJ.js → auto-sync-G3V5AN4C.js} +2 -2
- package/dist/behavior-learner.d.ts +1 -1
- package/dist/behavior-signals.d.ts +1 -1
- package/dist/bootstrap.d.ts +5 -4
- package/dist/briefing.d.ts +1 -1
- package/dist/briefing.js +3 -3
- package/dist/buffer-surprise-report.d.ts +1 -1
- package/dist/buffer.d.ts +1 -1
- package/dist/calibration.d.ts +1 -1
- package/dist/capabilities.d.ts +55 -2
- package/dist/capabilities.js +5 -1
- package/dist/{catalog-bMczlO2G.d.ts → catalog-DM1nk7cM.d.ts} +1 -1
- package/dist/causal-behavior.d.ts +1 -1
- package/dist/causal-consolidation.d.ts +1 -1
- package/dist/causal-consolidation.js +4 -4
- package/dist/causal-trajectory-graph.d.ts +1 -1
- package/dist/{chunk-4NOI577P.js → chunk-24ZLC5QN.js} +2 -2
- package/dist/{chunk-DMQWV6SQ.js → chunk-5RZOFIDL.js} +2 -2
- package/dist/{chunk-UM5AWJNQ.js → chunk-646B5ERJ.js} +62 -37
- package/dist/chunk-646B5ERJ.js.map +1 -0
- package/dist/{chunk-H5BWGCRZ.js → chunk-6TUWSUUD.js} +51 -47
- package/dist/{chunk-H5BWGCRZ.js.map → chunk-6TUWSUUD.js.map} +1 -1
- package/dist/{chunk-36SEDFAU.js → chunk-C5WN74HH.js} +2 -2
- package/dist/{chunk-MLKWJOAJ.js → chunk-CGPHMNL4.js} +2 -2
- package/dist/{chunk-R6OVFAX6.js → chunk-DJECGBBM.js} +7 -2
- package/dist/{chunk-R6OVFAX6.js.map → chunk-DJECGBBM.js.map} +1 -1
- package/dist/{chunk-3RCBIOOJ.js → chunk-ESF7TRYJ.js} +18 -2
- package/dist/{chunk-3RCBIOOJ.js.map → chunk-ESF7TRYJ.js.map} +1 -1
- package/dist/{chunk-EY6MDMHK.js → chunk-F6OEXJQQ.js} +2 -2
- package/dist/{chunk-M4V2JVSZ.js → chunk-FFUCCKPN.js} +2 -2
- package/dist/{chunk-O6YH5F47.js → chunk-FYWUNVFZ.js} +8 -8
- package/dist/{chunk-37436GML.js → chunk-GEXI357K.js} +2 -2
- package/dist/{chunk-YGIQORJ3.js → chunk-GGL34GCW.js} +3 -3
- package/dist/{chunk-4H4F3BFL.js → chunk-GXTYEG7Q.js} +3 -3
- package/dist/{chunk-4H4F3BFL.js.map → chunk-GXTYEG7Q.js.map} +1 -1
- package/dist/{chunk-WAS3NV46.js → chunk-H3MB3F62.js} +2 -2
- package/dist/{chunk-UTHQPSRC.js → chunk-HHNSLPX7.js} +11 -8
- package/dist/chunk-HHNSLPX7.js.map +1 -0
- package/dist/{chunk-76NHR6ZL.js → chunk-HJWQJUKQ.js} +4 -4
- package/dist/{chunk-Y4YD5TYW.js → chunk-IIBFCZA7.js} +3 -3
- package/dist/{chunk-UVPL565C.js → chunk-IQOEW5YV.js} +2 -2
- package/dist/{chunk-V4GNSDFH.js → chunk-KQYGNGON.js} +2 -2
- package/dist/{chunk-CBWI22JN.js → chunk-KSJCXXOU.js} +2 -2
- package/dist/{chunk-M4AYVEWS.js → chunk-LUCARK4W.js} +12 -11
- package/dist/chunk-LUCARK4W.js.map +1 -0
- package/dist/{chunk-I5REUWLH.js → chunk-NIZQH6AU.js} +3 -3
- package/dist/{chunk-4ESAR77N.js → chunk-NOU77OHX.js} +2 -2
- package/dist/{chunk-BQCHEV7O.js → chunk-O4ZIBPIW.js} +3 -3
- package/dist/{chunk-HOHVIVDR.js → chunk-OBJUKYDO.js} +2 -2
- package/dist/{chunk-YKBHOBJK.js → chunk-OEHCMALU.js} +56 -4
- package/dist/chunk-OEHCMALU.js.map +1 -0
- package/dist/{chunk-YOLZS7NY.js → chunk-OTQE66IX.js} +2 -2
- package/dist/{chunk-HEDZUSCS.js → chunk-OUITHS6V.js} +246 -368
- package/dist/chunk-OUITHS6V.js.map +1 -0
- package/dist/{chunk-4T3BMHKD.js → chunk-OZECYVGI.js} +20 -7
- package/dist/chunk-OZECYVGI.js.map +1 -0
- package/dist/{chunk-C2PG7IEH.js → chunk-P3VJCTVE.js} +2 -2
- package/dist/{chunk-EH5ED3C6.js → chunk-PMAQRUN4.js} +4 -4
- package/dist/chunk-PMAQRUN4.js.map +1 -0
- package/dist/{chunk-7RLCCNHU.js → chunk-Q6BAA57B.js} +4 -3
- package/dist/chunk-Q6BAA57B.js.map +1 -0
- package/dist/{chunk-HGNOCPZX.js → chunk-QZHF4BWN.js} +6 -6
- package/dist/chunk-SYX73XD7.js +283 -0
- package/dist/chunk-SYX73XD7.js.map +1 -0
- package/dist/{chunk-ASKXIAHD.js → chunk-WDJCZQB4.js} +2 -2
- package/dist/{chunk-AQLOP5F4.js → chunk-WNGXQMRI.js} +95 -6
- package/dist/chunk-WNGXQMRI.js.map +1 -0
- package/dist/{chunk-JYLFZWUX.js → chunk-XYUFGHUW.js} +2 -2
- package/dist/{chunk-3TSTGI6F.js → chunk-ZQUAVZNG.js} +2 -2
- package/dist/{chunk-4NR2PDZ5.js → chunk-ZVHRSR2R.js} +14 -4
- package/dist/chunk-ZVHRSR2R.js.map +1 -0
- package/dist/{cli-DmAiDd8A.d.ts → cli-Dt-tuiYH.d.ts} +3 -3
- package/dist/cli.d.ts +7 -6
- package/dist/cli.js +35 -35
- package/dist/compounding/engine.d.ts +12 -1
- package/dist/compounding/engine.js +3 -3
- package/dist/compounding/preference-consolidator.d.ts +1 -1
- package/dist/compression-optimizer.d.ts +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.js +2 -2
- package/dist/connectors/codex-materialize-runner.d.ts +1 -1
- package/dist/connectors/codex-materialize-runner.js +3 -3
- package/dist/connectors/codex-materialize.d.ts +1 -1
- package/dist/connectors/index.d.ts +1 -1
- package/dist/connectors/index.js +3 -3
- package/dist/consolidation-provenance-check.d.ts +1 -1
- package/dist/consolidation-undo.d.ts +1 -1
- package/dist/contradiction/index.d.ts +1 -1
- package/dist/contradiction/index.js +1 -1
- package/dist/conversation-index/backend.d.ts +1 -1
- package/dist/conversation-index/chunker.d.ts +1 -1
- package/dist/conversation-index/faiss-adapter.d.ts +1 -1
- package/dist/conversation-index/indexer.d.ts +1 -1
- package/dist/conversation-index/search.d.ts +1 -1
- package/dist/day-summary.d.ts +1 -1
- package/dist/delinearize.d.ts +1 -1
- package/dist/direct-answer-wiring.d.ts +1 -1
- package/dist/direct-answer.d.ts +1 -1
- package/dist/embedding-fallback.d.ts +1 -1
- package/dist/embedding-fallback.js +2 -2
- package/dist/enrichment/index.d.ts +1 -1
- package/dist/entity-retrieval.d.ts +1 -1
- package/dist/entity-retrieval.js +3 -3
- package/dist/entity-schema.d.ts +1 -1
- package/dist/explicit-capture.d.ts +6 -4
- package/dist/explicit-capture.js +1 -1
- package/dist/extraction-faithfulness.d.ts +1 -1
- package/dist/extraction-judge-telemetry.d.ts +1 -1
- package/dist/extraction-judge-training.d.ts +1 -1
- package/dist/extraction-judge.d.ts +1 -1
- package/dist/extraction.d.ts +1 -1
- package/dist/extraction.js +3 -3
- package/dist/fallback-llm.d.ts +1 -1
- package/dist/{first-start-migration-22LPFHD5.js → first-start-migration-OOR57AYR.js} +2 -2
- package/dist/graph-dashboard-diff.d.ts +1 -1
- package/dist/graph-dashboard-key.d.ts +1 -1
- package/dist/graph-dashboard-parser.d.ts +1 -1
- package/dist/graph-edge-reinforcement.d.ts +1 -1
- package/dist/graph-snapshot.d.ts +1 -1
- package/dist/graph.d.ts +1 -1
- package/dist/identity-continuity.d.ts +1 -1
- package/dist/importance.d.ts +1 -1
- package/dist/index.d.ts +296 -11
- package/dist/index.js +359 -47
- package/dist/index.js.map +1 -1
- package/dist/intent.d.ts +1 -1
- package/dist/lcm/engine.d.ts +1 -1
- package/dist/lcm/index.d.ts +1 -1
- package/dist/lcm/tools.d.ts +1 -1
- package/dist/lifecycle.d.ts +1 -1
- package/dist/live-connectors-runner.d.ts +1 -1
- package/dist/local-llm.d.ts +1 -1
- package/dist/local-model-endpoint.d.ts +1 -1
- package/dist/maintenance/memory-governance.d.ts +1 -1
- package/dist/maintenance/memory-governance.js +3 -3
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +3 -3
- package/dist/maintenance/rebuild-memory-projection.js +4 -4
- package/dist/mcp-memory-inspector-app.d.ts +6 -5
- package/dist/memory-action-policy.d.ts +1 -1
- package/dist/memory-cache.d.ts +1 -1
- package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
- package/dist/memory-projection-store.d.ts +1 -1
- package/dist/memory-provenance.d.ts +1 -1
- package/dist/memory-worth-outcomes.d.ts +1 -1
- package/dist/models-json.d.ts +1 -1
- package/dist/namespaces/migrate.d.ts +2 -2
- package/dist/namespaces/migrate.js +9 -9
- package/dist/namespaces/principal.d.ts +1 -1
- package/dist/namespaces/search.d.ts +1 -1
- package/dist/namespaces/search.js +5 -5
- package/dist/namespaces/storage.d.ts +2 -2
- package/dist/namespaces/storage.js +3 -3
- package/dist/native-knowledge.d.ts +1 -1
- package/dist/operator-toolkit.d.ts +1 -1
- package/dist/operator-toolkit.js +14 -14
- package/dist/orchestration/compression-guideline-coordinator.d.ts +105 -0
- package/dist/orchestration/compression-guideline-coordinator.js +12 -0
- package/dist/orchestration/maintenance.d.ts +2 -2
- package/dist/orchestration/maintenance.js +5 -5
- package/dist/{orchestrator-BR0sGsME.d.ts → orchestrator-B4KjaOtY.d.ts} +24 -8
- package/dist/orchestrator.d.ts +5 -4
- package/dist/orchestrator.js +28 -26
- package/dist/patterns-cli.d.ts +1 -1
- package/dist/policy-runtime.d.ts +1 -1
- package/dist/provenance.d.ts +1 -1
- package/dist/provenance.js +1 -1
- package/dist/qmd-recall-cache.d.ts +1 -1
- package/dist/qmd.d.ts +1 -1
- package/dist/recall-disclosure-escalation.d.ts +1 -1
- package/dist/recall-explain-renderer.d.ts +1 -1
- package/dist/recall-planner-llm.d.ts +1 -1
- package/dist/recall-state.d.ts +1 -1
- package/dist/recall-tag-filter.d.ts +1 -1
- package/dist/recall-xray-cli.d.ts +1 -1
- package/dist/recall-xray-renderer.d.ts +1 -1
- package/dist/recall-xray.d.ts +1 -1
- package/dist/{resolution-MN36NW5P.js → resolution-33PIX3TT.js} +2 -2
- package/dist/resolution-33PIX3TT.js.map +1 -0
- package/dist/resolve-auth-token.d.ts +1 -1
- package/dist/resume-bundles.js +3 -3
- package/dist/retrieval-agents.d.ts +1 -1
- package/dist/retrieval-tiers.d.ts +1 -1
- package/dist/routing/engine.d.ts +1 -1
- package/dist/routing/store.d.ts +1 -1
- package/dist/schemas.d.ts +84 -84
- package/dist/search/embed-helper.d.ts +1 -1
- package/dist/search/embed-helper.js +2 -2
- package/dist/search/factory.d.ts +1 -1
- package/dist/search/factory.js +4 -4
- package/dist/search/index.d.ts +1 -1
- package/dist/search/index.js +8 -8
- package/dist/search/lancedb-backend.d.ts +1 -1
- package/dist/search/meilisearch-backend.d.ts +1 -1
- package/dist/search/noop-backend.d.ts +1 -1
- package/dist/search/orama-backend.d.ts +1 -1
- package/dist/search/port.d.ts +1 -1
- package/dist/search/remote-backend.d.ts +1 -1
- package/dist/{semantic-consolidation-Cl15ksZy.d.ts → semantic-consolidation-CstTvHPo.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +2 -2
- package/dist/semantic-consolidation.js +4 -4
- package/dist/semantic-rule-promotion.js +3 -3
- package/dist/semantic-rule-verifier.d.ts +1 -1
- package/dist/semantic-rule-verifier.js +3 -3
- package/dist/session-observer-bands.d.ts +1 -1
- package/dist/session-observer-state.d.ts +1 -1
- package/dist/shared-context/manager.d.ts +3 -3
- package/dist/signal.d.ts +1 -1
- package/dist/storage.d.ts +22 -3
- package/dist/storage.js +2 -2
- package/dist/summarizer.d.ts +1 -1
- package/dist/summary-snapshot.d.ts +1 -1
- package/dist/temporal-supersession.d.ts +1 -1
- package/dist/temporal-validity.d.ts +1 -1
- package/dist/threading.d.ts +1 -1
- package/dist/tier-migration.d.ts +1 -1
- package/dist/tier-routing.d.ts +1 -1
- package/dist/topics.d.ts +1 -1
- package/dist/transcript.d.ts +1 -1
- package/dist/transfer/types.d.ts +46 -46
- package/dist/trust-score-stage.d.ts +1 -1
- package/dist/trust-score.d.ts +1 -1
- package/dist/{types-ChQb9D6s.d.ts → types-VkxElCHR.d.ts} +8 -1
- package/dist/types.d.ts +1 -1
- package/dist/utility-runtime.d.ts +1 -1
- package/dist/verified-recall.js +3 -3
- package/package.json +12 -2
- package/src/access-service-coding-write.test.ts +2 -2
- package/src/access-service.ts +33 -14
- package/src/bitemporal-dedup-backfill.test.ts +10 -10
- package/src/bitemporal-frontmatter.test.ts +3 -3
- package/src/capabilities.test.ts +185 -0
- package/src/capabilities.ts +110 -0
- package/src/cli/creation-ledger-commands.ts +22 -21
- package/src/coding/architecture-surfaces.test.ts +25 -1
- package/src/coding/architecture-surfaces.ts +47 -19
- package/src/coding/decision-surfaces.ts +12 -3
- package/src/coding/review-context-structural.test.ts +303 -0
- package/src/coding/review-context.ts +79 -0
- package/src/coding/structural-context.test.ts +259 -0
- package/src/coding/structural-context.ts +315 -0
- package/src/coding/structural-subprocess-provider.test.ts +430 -0
- package/src/coding/structural-subprocess-provider.ts +355 -0
- package/src/compounding/engine.test.ts +90 -0
- package/src/compounding/engine.ts +25 -1
- package/src/contradiction/contradiction.test.ts +1 -1
- package/src/contradiction/resolution.ts +9 -1
- package/src/correction/correction-access-wiring.ts +21 -3
- package/src/correction/correction-contract.ts +7 -0
- package/src/correction/correction-planner.test.ts +231 -0
- package/src/correction/correction-planner.ts +73 -0
- package/src/correction/correction-service.ts +29 -0
- package/src/correction/correction-storage-integration.test.ts +2 -2
- package/src/dedup/semantic.test.ts +1 -1
- package/src/explicit-capture.ts +7 -4
- package/src/extraction-eventtime-wiring.test.ts +3 -3
- package/src/extraction-redaction-rules.test.ts +172 -0
- package/src/index.ts +29 -0
- package/src/maintenance/forget.test.ts +1 -1
- package/src/maintenance/memory-governance.test.ts +1 -1
- package/src/maintenance/pattern-reinforcement.test.ts +2 -2
- package/src/operator-toolkit.ts +4 -3
- package/src/orchestration/compression-guideline-coordinator.ts +449 -0
- package/src/orchestrator.ts +345 -464
- package/src/procedural/procedure-miner.test.ts +2 -2
- package/src/provenance-extraction.test.ts +382 -4
- package/src/provenance.ts +158 -22
- package/src/recall-handles-wiring.test.ts +1 -1
- package/src/search/factory.ts +4 -3
- package/src/semantic-rule-promotion.ts +1 -1
- package/src/source-attribution-roundtrip.test.ts +2 -2
- package/src/storage-contract/atomicity.test.ts +1 -1
- package/src/storage-contract/cache-coherence.test.ts +2 -2
- package/src/storage-contract/content-hash.test.ts +1 -1
- package/src/storage-contract/namespace-routing.test.ts +1 -1
- package/src/storage-contract/round-trip.test.ts +3 -3
- package/src/storage.ts +23 -2
- package/src/temporal-supersession.test.ts +12 -11
- package/src/temporal-validity.test.ts +11 -11
- package/src/wearables/cli.test.ts +30 -0
- package/src/wearables/cli.ts +3 -0
- package/src/wearables/memory-gen.test.ts +57 -1
- package/src/wearables/memory-gen.ts +31 -7
- package/src/wearables/pipeline.test.ts +40 -1
- package/src/wearables/pipeline.ts +4 -0
- package/src/wearables/service.test.ts +2 -2
- package/src/wearables/storage-io.test.ts +3 -3
- package/src/wearables/types.ts +7 -0
- package/dist/chunk-4NR2PDZ5.js.map +0 -1
- package/dist/chunk-4T3BMHKD.js.map +0 -1
- package/dist/chunk-7RLCCNHU.js.map +0 -1
- package/dist/chunk-AQLOP5F4.js.map +0 -1
- package/dist/chunk-EH5ED3C6.js.map +0 -1
- package/dist/chunk-HEDZUSCS.js.map +0 -1
- package/dist/chunk-M4AYVEWS.js.map +0 -1
- package/dist/chunk-UM5AWJNQ.js.map +0 -1
- package/dist/chunk-UTHQPSRC.js.map +0 -1
- package/dist/chunk-YKBHOBJK.js.map +0 -1
- /package/dist/{auto-sync-F3KCSQFJ.js.map → auto-sync-G3V5AN4C.js.map} +0 -0
- /package/dist/{chunk-4NOI577P.js.map → chunk-24ZLC5QN.js.map} +0 -0
- /package/dist/{chunk-DMQWV6SQ.js.map → chunk-5RZOFIDL.js.map} +0 -0
- /package/dist/{chunk-36SEDFAU.js.map → chunk-C5WN74HH.js.map} +0 -0
- /package/dist/{chunk-MLKWJOAJ.js.map → chunk-CGPHMNL4.js.map} +0 -0
- /package/dist/{chunk-EY6MDMHK.js.map → chunk-F6OEXJQQ.js.map} +0 -0
- /package/dist/{chunk-M4V2JVSZ.js.map → chunk-FFUCCKPN.js.map} +0 -0
- /package/dist/{chunk-O6YH5F47.js.map → chunk-FYWUNVFZ.js.map} +0 -0
- /package/dist/{chunk-37436GML.js.map → chunk-GEXI357K.js.map} +0 -0
- /package/dist/{chunk-YGIQORJ3.js.map → chunk-GGL34GCW.js.map} +0 -0
- /package/dist/{chunk-WAS3NV46.js.map → chunk-H3MB3F62.js.map} +0 -0
- /package/dist/{chunk-76NHR6ZL.js.map → chunk-HJWQJUKQ.js.map} +0 -0
- /package/dist/{chunk-Y4YD5TYW.js.map → chunk-IIBFCZA7.js.map} +0 -0
- /package/dist/{chunk-UVPL565C.js.map → chunk-IQOEW5YV.js.map} +0 -0
- /package/dist/{chunk-V4GNSDFH.js.map → chunk-KQYGNGON.js.map} +0 -0
- /package/dist/{chunk-CBWI22JN.js.map → chunk-KSJCXXOU.js.map} +0 -0
- /package/dist/{chunk-I5REUWLH.js.map → chunk-NIZQH6AU.js.map} +0 -0
- /package/dist/{chunk-4ESAR77N.js.map → chunk-NOU77OHX.js.map} +0 -0
- /package/dist/{chunk-BQCHEV7O.js.map → chunk-O4ZIBPIW.js.map} +0 -0
- /package/dist/{chunk-HOHVIVDR.js.map → chunk-OBJUKYDO.js.map} +0 -0
- /package/dist/{chunk-YOLZS7NY.js.map → chunk-OTQE66IX.js.map} +0 -0
- /package/dist/{chunk-C2PG7IEH.js.map → chunk-P3VJCTVE.js.map} +0 -0
- /package/dist/{chunk-HGNOCPZX.js.map → chunk-QZHF4BWN.js.map} +0 -0
- /package/dist/{chunk-ASKXIAHD.js.map → chunk-WDJCZQB4.js.map} +0 -0
- /package/dist/{chunk-JYLFZWUX.js.map → chunk-XYUFGHUW.js.map} +0 -0
- /package/dist/{chunk-3TSTGI6F.js.map → chunk-ZQUAVZNG.js.map} +0 -0
- /package/dist/{first-start-migration-22LPFHD5.js.map → first-start-migration-OOR57AYR.js.map} +0 -0
- /package/dist/{resolution-MN36NW5P.js.map → orchestration/compression-guideline-coordinator.js.map} +0 -0
package/src/orchestrator.ts
CHANGED
|
@@ -100,6 +100,7 @@ import {
|
|
|
100
100
|
import { MaintenanceScheduler } from "./orchestration/maintenance.js";
|
|
101
101
|
import { TierMigrationCoordinator } from "./orchestration/tier-migration-coordinator.js";
|
|
102
102
|
import { ExtractionQueueCoordinator } from "./orchestration/extraction-queue-coordinator.js";
|
|
103
|
+
import { CompressionGuidelineCoordinator } from "./orchestration/compression-guideline-coordinator.js";
|
|
103
104
|
import {
|
|
104
105
|
runLiveConnectorsOnce,
|
|
105
106
|
type LiveConnectorsRunSummary,
|
|
@@ -224,10 +225,8 @@ import { parseMemoryActionEligibilityContext } from "./schemas.js";
|
|
|
224
225
|
import { evaluateMemoryActionPolicy } from "./memory-action-policy.js";
|
|
225
226
|
import {
|
|
226
227
|
buildCompressionGuidelinesMarkdown as buildCompressionGuidelinesMarkdownV2,
|
|
227
|
-
computeCompressionGuidelineCandidate,
|
|
228
|
-
refineCompressionGuidelineCandidateSemantically,
|
|
229
|
-
renderCompressionGuidelinesMarkdown,
|
|
230
228
|
} from "./compression-optimizer.js";
|
|
229
|
+
export { formatCompressionGuidelinesForRecall } from "./orchestration/compression-guideline-coordinator.js";
|
|
231
230
|
import { createRecallSectionMetricRecorder } from "./recall-qos.js";
|
|
232
231
|
import { BoxBuilder, type BoxFrontmatter } from "./boxes.js";
|
|
233
232
|
import { classifyMemoryKind } from "./himem.js";
|
|
@@ -270,9 +269,13 @@ import {
|
|
|
270
269
|
resolveCapabilities,
|
|
271
270
|
resolveGraphConstructionCapabilities,
|
|
272
271
|
resolveMemoryLifecycleCapabilities,
|
|
272
|
+
resolveIndexingCapabilities,
|
|
273
|
+
resolveCreationMemoryCapabilities,
|
|
273
274
|
type CapabilitySet,
|
|
274
275
|
type GraphConstructionCapabilitySet,
|
|
275
276
|
type MemoryLifecycleCapabilitySet,
|
|
277
|
+
type IndexingCapabilitySet,
|
|
278
|
+
type CreationMemoryCapabilitySet,
|
|
276
279
|
} from "./capabilities.js";
|
|
277
280
|
import { DEFAULT_TAXONOMY } from "./taxonomy/index.js";
|
|
278
281
|
import {
|
|
@@ -1202,30 +1205,6 @@ export function buildCompressionGuidelinesMarkdown(
|
|
|
1202
1205
|
return buildCompressionGuidelinesMarkdownV2(events, generatedAtIso);
|
|
1203
1206
|
}
|
|
1204
1207
|
|
|
1205
|
-
export function formatCompressionGuidelinesForRecall(
|
|
1206
|
-
raw: string,
|
|
1207
|
-
maxLines: number = 5,
|
|
1208
|
-
): string | null {
|
|
1209
|
-
if (typeof raw !== "string" || raw.trim().length === 0) return null;
|
|
1210
|
-
const sectionMatch = raw.match(
|
|
1211
|
-
// End the section at `\n## ` or end-of-string. Plain $ (not \s*$): the
|
|
1212
|
-
// \s* branch overlapped the lazy body and backtracked polynomially
|
|
1213
|
-
// (CodeQL js/polynomial-redos). Captured lines are trimmed/filtered below,
|
|
1214
|
-
// so trailing whitespace handling is unchanged.
|
|
1215
|
-
/## Suggested Guidelines\s*\n([\s\S]*?)(?:\n##\s+|$)/i,
|
|
1216
|
-
);
|
|
1217
|
-
if (!sectionMatch) return null;
|
|
1218
|
-
|
|
1219
|
-
const lines = sectionMatch[1]
|
|
1220
|
-
.split("\n")
|
|
1221
|
-
.map((line) => line.trim())
|
|
1222
|
-
.filter((line) => line.startsWith("- "))
|
|
1223
|
-
.slice(0, Math.max(1, Math.floor(maxLines)));
|
|
1224
|
-
if (lines.length === 0) return null;
|
|
1225
|
-
|
|
1226
|
-
return lines.join("\n");
|
|
1227
|
-
}
|
|
1228
|
-
|
|
1229
1208
|
export function filterRecallCandidates(
|
|
1230
1209
|
candidates: QmdSearchResult[],
|
|
1231
1210
|
options: {
|
|
@@ -1916,6 +1895,7 @@ export class Orchestrator {
|
|
|
1916
1895
|
readonly handleHistory: RecallHandleHistoryStore;
|
|
1917
1896
|
readonly tierMigrationStatus: TierMigrationStatusStore;
|
|
1918
1897
|
readonly tierMigrationCoordinator: TierMigrationCoordinator;
|
|
1898
|
+
readonly compressionGuidelineCoordinator: CompressionGuidelineCoordinator;
|
|
1919
1899
|
/**
|
|
1920
1900
|
* In-memory X-ray snapshot from the most recent `recall()` call that
|
|
1921
1901
|
* was invoked with `xrayCapture: true` (issue #570 PR 1). Scope is
|
|
@@ -3033,6 +3013,12 @@ export class Orchestrator {
|
|
|
3033
3013
|
getCompounding: () => this.compounding,
|
|
3034
3014
|
createColdStorage: (parentDir) => new StorageManager(parentDir),
|
|
3035
3015
|
});
|
|
3016
|
+
this.compressionGuidelineCoordinator = new CompressionGuidelineCoordinator({
|
|
3017
|
+
config,
|
|
3018
|
+
getStorage: () => this.storage,
|
|
3019
|
+
fastChatCompletion: (messages, options) =>
|
|
3020
|
+
this.fastChatCompletion(messages, options),
|
|
3021
|
+
});
|
|
3036
3022
|
this.sessionObserver = new SessionObserverState({
|
|
3037
3023
|
memoryDir: config.memoryDir,
|
|
3038
3024
|
debounceMs: config.sessionObserverDebounceMs ?? 120_000,
|
|
@@ -3474,6 +3460,31 @@ export class Orchestrator {
|
|
|
3474
3460
|
// never break initialization (rule #13, #40).
|
|
3475
3461
|
await this.namespaceCatalog.registerConfiguredNamespaces().catch(() => undefined);
|
|
3476
3462
|
}
|
|
3463
|
+
// #1713 Item 2: recover stale `applying` correction plans left behind
|
|
3464
|
+
// by a process that died mid-apply. Best-effort — a failure here must
|
|
3465
|
+
// never block initialization (rule 13). Runs for every configured
|
|
3466
|
+
// namespace since correction plans can exist in any of them.
|
|
3467
|
+
try {
|
|
3468
|
+
// #1713 Item 2 + P2 (cursor): sweep ALL known namespaces — configured
|
|
3469
|
+
// + catalog-discovered — so stale applying plans in derived namespaces
|
|
3470
|
+
// (coding-scoped, session-derived) are also recovered.
|
|
3471
|
+
const correctionNamespaces = new Set(this.configuredNamespaceList());
|
|
3472
|
+
if (this.namespaceCatalog.enabled) {
|
|
3473
|
+
try {
|
|
3474
|
+
for (const rec of await this.namespaceCatalog.listNamespaces()) {
|
|
3475
|
+
correctionNamespaces.add(rec.namespace);
|
|
3476
|
+
}
|
|
3477
|
+
} catch { /* best-effort */ }
|
|
3478
|
+
}
|
|
3479
|
+
const recovered = await this.passiveCorrectionService().recoverStaleApplyingPlans(
|
|
3480
|
+
[...correctionNamespaces],
|
|
3481
|
+
);
|
|
3482
|
+
if (recovered > 0) {
|
|
3483
|
+
log.info(`correction: recovered ${recovered} stale applying plan(s) on startup`);
|
|
3484
|
+
}
|
|
3485
|
+
} catch (staleErr) {
|
|
3486
|
+
log.debug(`correction: stale-plan recovery skipped: ${staleErr instanceof Error ? staleErr.message : String(staleErr)}`);
|
|
3487
|
+
}
|
|
3477
3488
|
await this.relevance.load();
|
|
3478
3489
|
await this.negatives.load();
|
|
3479
3490
|
await this.lastRecall.load();
|
|
@@ -3756,7 +3767,7 @@ export class Orchestrator {
|
|
|
3756
3767
|
await Promise.all(cacheWarmups);
|
|
3757
3768
|
if (signal.aborted) return;
|
|
3758
3769
|
|
|
3759
|
-
if (this.config.
|
|
3770
|
+
if (resolveIndexingCapabilities(this.config).conversationIndex && this.conversationIndexBackend) {
|
|
3760
3771
|
try {
|
|
3761
3772
|
const init = await this.conversationIndexBackend.initialize();
|
|
3762
3773
|
if (!init.enabled) {
|
|
@@ -4566,7 +4577,7 @@ export class Orchestrator {
|
|
|
4566
4577
|
}
|
|
4567
4578
|
|
|
4568
4579
|
// Write the canonical memory
|
|
4569
|
-
const canonicalId = await targetStorage.writeMemory(
|
|
4580
|
+
const { id: canonicalId, tombstoneBlocked: canonicalBlocked } = await targetStorage.writeMemory(
|
|
4570
4581
|
newest.frontmatter.category,
|
|
4571
4582
|
canonicalContent,
|
|
4572
4583
|
{
|
|
@@ -4583,6 +4594,12 @@ export class Orchestrator {
|
|
|
4583
4594
|
derivedVia: operator,
|
|
4584
4595
|
},
|
|
4585
4596
|
);
|
|
4597
|
+
if (canonicalBlocked) {
|
|
4598
|
+
// #1645: canonical matched a tombstone (pending_review). Don't archive
|
|
4599
|
+
// the sources — consolidation must never delete the only active copy.
|
|
4600
|
+
log.info(`[semantic-consolidation] cluster in "${cluster.category}" tombstone-blocked — keeping ${cluster.memories.length} source(s) active (pending_review ${canonicalId})`);
|
|
4601
|
+
continue;
|
|
4602
|
+
}
|
|
4586
4603
|
canonicalWriteCompleted = true;
|
|
4587
4604
|
|
|
4588
4605
|
result.memoriesConsolidated++;
|
|
@@ -4609,7 +4626,7 @@ export class Orchestrator {
|
|
|
4609
4626
|
try {
|
|
4610
4627
|
await this.embeddingFallback.removeFromIndex(m.frontmatter.id);
|
|
4611
4628
|
if (
|
|
4612
|
-
this.config.
|
|
4629
|
+
resolveIndexingCapabilities(this.config).queryAwareIndexing &&
|
|
4613
4630
|
m.path &&
|
|
4614
4631
|
m.frontmatter?.created
|
|
4615
4632
|
) {
|
|
@@ -5648,7 +5665,7 @@ export class Orchestrator {
|
|
|
5648
5665
|
const lastUpdateAt =
|
|
5649
5666
|
lastUpdateAtMs > 0 ? new Date(lastUpdateAtMs).toISOString() : null;
|
|
5650
5667
|
|
|
5651
|
-
if (!this.config.
|
|
5668
|
+
if (!resolveIndexingCapabilities(this.config).conversationIndex) {
|
|
5652
5669
|
return {
|
|
5653
5670
|
enabled: false,
|
|
5654
5671
|
backend: this.config.conversationIndexBackend,
|
|
@@ -5688,7 +5705,7 @@ export class Orchestrator {
|
|
|
5688
5705
|
const lastUpdateAt =
|
|
5689
5706
|
lastUpdateAtMs > 0 ? new Date(lastUpdateAtMs).toISOString() : null;
|
|
5690
5707
|
|
|
5691
|
-
if (!this.config.
|
|
5708
|
+
if (!resolveIndexingCapabilities(this.config).conversationIndex) {
|
|
5692
5709
|
return {
|
|
5693
5710
|
enabled: false,
|
|
5694
5711
|
backend: this.config.conversationIndexBackend,
|
|
@@ -5750,7 +5767,7 @@ export class Orchestrator {
|
|
|
5750
5767
|
retryAfterMs?: number;
|
|
5751
5768
|
embedded?: boolean;
|
|
5752
5769
|
}> {
|
|
5753
|
-
if (!this.config.
|
|
5770
|
+
if (!resolveIndexingCapabilities(this.config).conversationIndex) {
|
|
5754
5771
|
return { chunks: 0, skipped: true, reason: "disabled", embedded: false };
|
|
5755
5772
|
}
|
|
5756
5773
|
const enforceMinInterval = opts?.enforceMinInterval !== false;
|
|
@@ -5811,7 +5828,7 @@ export class Orchestrator {
|
|
|
5811
5828
|
embedded?: boolean;
|
|
5812
5829
|
rebuilt?: boolean;
|
|
5813
5830
|
}> {
|
|
5814
|
-
if (!this.config.
|
|
5831
|
+
if (!resolveIndexingCapabilities(this.config).conversationIndex) {
|
|
5815
5832
|
return {
|
|
5816
5833
|
chunks: 0,
|
|
5817
5834
|
skipped: true,
|
|
@@ -6416,7 +6433,7 @@ export class Orchestrator {
|
|
|
6416
6433
|
prompt: string,
|
|
6417
6434
|
recallNamespaces: string[],
|
|
6418
6435
|
): Promise<QueryAwarePrefilter> {
|
|
6419
|
-
if (!this.config.
|
|
6436
|
+
if (!resolveIndexingCapabilities(this.config).queryAwareIndexing || !prompt.trim()) {
|
|
6420
6437
|
return {
|
|
6421
6438
|
candidatePaths: null,
|
|
6422
6439
|
temporalFromDate: null,
|
|
@@ -9208,7 +9225,7 @@ export class Orchestrator {
|
|
|
9208
9225
|
const workProductsPromise = (async (): Promise<string | null> => {
|
|
9209
9226
|
const t0 = Date.now();
|
|
9210
9227
|
if (
|
|
9211
|
-
!this.config.
|
|
9228
|
+
!resolveCreationMemoryCapabilities(this.config).creationMemory ||
|
|
9212
9229
|
!this.config.workProductRecallEnabled ||
|
|
9213
9230
|
!this.isRecallSectionEnabled(
|
|
9214
9231
|
"work-products",
|
|
@@ -9283,7 +9300,7 @@ export class Orchestrator {
|
|
|
9283
9300
|
const queryAwarePrefilterPromise =
|
|
9284
9301
|
(async (): Promise<QueryAwarePrefilter> => {
|
|
9285
9302
|
const t0 = Date.now();
|
|
9286
|
-
if (!this.config.
|
|
9303
|
+
if (!resolveIndexingCapabilities(this.config).queryAwareIndexing || !prompt.trim()) {
|
|
9287
9304
|
recordRecallSectionMetric({
|
|
9288
9305
|
section: "queryAware",
|
|
9289
9306
|
priority: "enrichment",
|
|
@@ -10029,7 +10046,7 @@ export class Orchestrator {
|
|
|
10029
10046
|
const conversationRecallPromise = (async (): Promise<string | null> => {
|
|
10030
10047
|
const t0 = Date.now();
|
|
10031
10048
|
if (
|
|
10032
|
-
!this.config.
|
|
10049
|
+
!resolveIndexingCapabilities(this.config).conversationIndex ||
|
|
10033
10050
|
queryPolicy.skipConversationRecall ||
|
|
10034
10051
|
!this.isRecallSectionEnabled("conversation-recall", true)
|
|
10035
10052
|
) {
|
|
@@ -14173,6 +14190,10 @@ export class Orchestrator {
|
|
|
14173
14190
|
sharedProfileLayer.writable &&
|
|
14174
14191
|
sharedPromotionTarget?.authorized,
|
|
14175
14192
|
);
|
|
14193
|
+
// #1713: hoist namespaces-enabled once for the scope-routing mirrors
|
|
14194
|
+
// (pre-judge + write-loop) so no new scattered config.*Enabled read is
|
|
14195
|
+
// introduced (ratchet scatteredConfigFlagReads; see #1523).
|
|
14196
|
+
const namespacesEnabled = this.config.namespacesEnabled;
|
|
14176
14197
|
const profileAutoPromotionAllows = (
|
|
14177
14198
|
category: string,
|
|
14178
14199
|
confidence: number,
|
|
@@ -14305,7 +14326,7 @@ export class Orchestrator {
|
|
|
14305
14326
|
}
|
|
14306
14327
|
continue;
|
|
14307
14328
|
}
|
|
14308
|
-
const
|
|
14329
|
+
const targetPromotion = await targetStorage.writeMemory(
|
|
14309
14330
|
options.category as any,
|
|
14310
14331
|
citedContent,
|
|
14311
14332
|
{
|
|
@@ -14331,7 +14352,11 @@ export class Orchestrator {
|
|
|
14331
14352
|
...(options.provenance ? { provenance: options.provenance } : {}),
|
|
14332
14353
|
},
|
|
14333
14354
|
);
|
|
14355
|
+
const promotedId = targetPromotion.id;
|
|
14356
|
+
// #1645: if the TARGET namespace's own tombstone blocked this promotion,
|
|
14357
|
+
// the row lands pending_review — do NOT supersede active target memories.
|
|
14334
14358
|
if (
|
|
14359
|
+
!targetPromotion.tombstoneBlocked &&
|
|
14335
14360
|
lifecycleCaps.temporalSupersession &&
|
|
14336
14361
|
options.category === "fact" &&
|
|
14337
14362
|
options.entityRef &&
|
|
@@ -14353,19 +14378,23 @@ export class Orchestrator {
|
|
|
14353
14378
|
);
|
|
14354
14379
|
}
|
|
14355
14380
|
}
|
|
14356
|
-
|
|
14357
|
-
|
|
14358
|
-
|
|
14359
|
-
targetStorage,
|
|
14360
|
-
|
|
14361
|
-
|
|
14362
|
-
|
|
14363
|
-
|
|
14364
|
-
|
|
14365
|
-
|
|
14366
|
-
|
|
14367
|
-
|
|
14368
|
-
|
|
14381
|
+
// #1645 TV6: a tombstone-blocked promotion is pending_review (no
|
|
14382
|
+
// active copy) — skip catalog/index/behavior like postWriteGuard.
|
|
14383
|
+
if (!targetPromotion.tombstoneBlocked) {
|
|
14384
|
+
trackPersistedId(targetStorage, promotedId, { includeReturnedIds: false });
|
|
14385
|
+
await this.indexPersistedMemory(targetStorage, promotedId);
|
|
14386
|
+
trackBehaviorSignals(
|
|
14387
|
+
targetStorage,
|
|
14388
|
+
buildBehaviorSignalsForMemory({
|
|
14389
|
+
memoryId: promotedId,
|
|
14390
|
+
category: options.category as any,
|
|
14391
|
+
content: options.content,
|
|
14392
|
+
namespace: target.namespace,
|
|
14393
|
+
confidence: options.confidence,
|
|
14394
|
+
source: "extraction",
|
|
14395
|
+
}),
|
|
14396
|
+
);
|
|
14397
|
+
}
|
|
14369
14398
|
} catch (err) {
|
|
14370
14399
|
log.warn(
|
|
14371
14400
|
`persistExtraction: ${target.target} promotion failed open for ${options.sourceMemoryId}: ${err}`,
|
|
@@ -14624,7 +14653,7 @@ export class Orchestrator {
|
|
|
14624
14653
|
return;
|
|
14625
14654
|
}
|
|
14626
14655
|
}
|
|
14627
|
-
const
|
|
14656
|
+
const sharedPromotion = await sharedStorage.writeMemory(
|
|
14628
14657
|
options.category as any,
|
|
14629
14658
|
citedContent,
|
|
14630
14659
|
{
|
|
@@ -14651,6 +14680,9 @@ export class Orchestrator {
|
|
|
14651
14680
|
...(options.provenance ? { provenance: options.provenance } : {}),
|
|
14652
14681
|
},
|
|
14653
14682
|
);
|
|
14683
|
+
const promotedId = sharedPromotion.id;
|
|
14684
|
+
// #1645: if the shared namespace's own tombstone blocked this promotion,
|
|
14685
|
+
// leave the row pending_review but do NOT supersede active shared memories.
|
|
14654
14686
|
// PR #402 Finding 3 fix: run temporal supersession against the shared
|
|
14655
14687
|
// namespace after the promoted write lands so stale shared-namespace
|
|
14656
14688
|
// copies of the same entity attribute are retired. Without this,
|
|
@@ -14658,6 +14690,7 @@ export class Orchestrator {
|
|
|
14658
14690
|
// shared recall continues returning the stale state. Reuses the same
|
|
14659
14691
|
// applyTemporalSupersession helper — no logic duplication.
|
|
14660
14692
|
if (
|
|
14693
|
+
!sharedPromotion.tombstoneBlocked &&
|
|
14661
14694
|
lifecycleCaps.temporalSupersession &&
|
|
14662
14695
|
options.entityRef &&
|
|
14663
14696
|
options.structuredAttributes &&
|
|
@@ -14687,21 +14720,24 @@ export class Orchestrator {
|
|
|
14687
14720
|
// the same promotion pass. The hot-path source-namespace touch uses a
|
|
14688
14721
|
// different storage dir, so this does not double-count the source.
|
|
14689
14722
|
// Best-effort and failure-tolerant — it must never crash the promotion.
|
|
14690
|
-
|
|
14691
|
-
|
|
14692
|
-
|
|
14693
|
-
|
|
14694
|
-
|
|
14695
|
-
sharedStorage,
|
|
14696
|
-
|
|
14697
|
-
|
|
14698
|
-
|
|
14699
|
-
|
|
14700
|
-
|
|
14701
|
-
|
|
14702
|
-
|
|
14703
|
-
|
|
14704
|
-
|
|
14723
|
+
// #1645 TV6: same guard as the profile-target promotion above.
|
|
14724
|
+
if (!sharedPromotion.tombstoneBlocked) {
|
|
14725
|
+
trackPersistedId(sharedStorage, promotedId, {
|
|
14726
|
+
includeReturnedIds: false,
|
|
14727
|
+
});
|
|
14728
|
+
await this.indexPersistedMemory(sharedStorage, promotedId);
|
|
14729
|
+
trackBehaviorSignals(
|
|
14730
|
+
sharedStorage,
|
|
14731
|
+
buildBehaviorSignalsForMemory({
|
|
14732
|
+
memoryId: promotedId,
|
|
14733
|
+
category: options.category as any,
|
|
14734
|
+
content: options.content,
|
|
14735
|
+
namespace: this.config.sharedNamespace,
|
|
14736
|
+
confidence: options.confidence,
|
|
14737
|
+
source: "extraction",
|
|
14738
|
+
}),
|
|
14739
|
+
);
|
|
14740
|
+
}
|
|
14705
14741
|
} catch (err) {
|
|
14706
14742
|
log.warn(
|
|
14707
14743
|
`persistExtraction: shared promotion failed open for ${options.sourceMemoryId}: ${err}`,
|
|
@@ -14928,6 +14964,10 @@ export class Orchestrator {
|
|
|
14928
14964
|
// these pre-computed results so routing is evaluated exactly once per
|
|
14929
14965
|
// fact (no duplicated logic).
|
|
14930
14966
|
const preRoutedCategories: Array<string | undefined> = new Array(facts.length);
|
|
14967
|
+
// #1713 Item 1: collect routed target namespaces so the pre-judge redaction
|
|
14968
|
+
// filter can consult rules from cross-namespace targets, not just the source.
|
|
14969
|
+
// #1713 P2 (cursor): track per-fact routed namespace for per-fact pre-judge rules
|
|
14970
|
+
const preRoutedNamespaceByFact: Array<string | undefined> = new Array(facts.length);
|
|
14931
14971
|
if (routeRules.length > 0) {
|
|
14932
14972
|
for (let fi = 0; fi < facts.length; fi++) {
|
|
14933
14973
|
const f = facts[fi];
|
|
@@ -14947,6 +14987,9 @@ export class Orchestrator {
|
|
|
14947
14987
|
if (selected?.target.category) {
|
|
14948
14988
|
preRoutedCategories[fi] = selected.target.category;
|
|
14949
14989
|
}
|
|
14990
|
+
if (selected?.target.namespace) {
|
|
14991
|
+
preRoutedNamespaceByFact[fi] = selected.target.namespace;
|
|
14992
|
+
}
|
|
14950
14993
|
} catch {
|
|
14951
14994
|
// Fail-open: routing errors fall through to the extracted category.
|
|
14952
14995
|
}
|
|
@@ -14969,10 +15012,18 @@ export class Orchestrator {
|
|
|
14969
15012
|
// into the caller's buffer-retention decision.
|
|
14970
15013
|
this.lastPersistExtractionDeferredCount = 0;
|
|
14971
15014
|
if (lifecycleCaps.extractionJudge) {
|
|
14972
|
-
// #1669 P1: pre-filter redacted facts from judge candidates
|
|
14973
|
-
// content is not persisted as judge training data.
|
|
15015
|
+
// #1669 P1 + #1713 Item 1: pre-filter redacted facts from judge candidates
|
|
15016
|
+
// so never-store content is not persisted as judge training data.
|
|
15017
|
+
// Consult source + shared + routed target namespace rules so a
|
|
15018
|
+
// never-store pattern registered under a cross-namespace target is
|
|
15019
|
+
// caught at the batch pre-filter point, not just at the persist gate.
|
|
14974
15020
|
let preJudgeRedactionRules: CompiledRedactionRule[] = [];
|
|
14975
|
-
try {
|
|
15021
|
+
try {
|
|
15022
|
+
// #1713: base rules are source-only. Per-fact routed target rules
|
|
15023
|
+
// (including shared when a fact is routed there) are checked in the
|
|
15024
|
+
// fact loop, matching the write-time gate's per-fact scoping exactly.
|
|
15025
|
+
preJudgeRedactionRules = await redactionRulesFor(storage.dir);
|
|
15026
|
+
} catch { /* fail open */ }
|
|
14976
15027
|
try {
|
|
14977
15028
|
const judgeCandidates: JudgeCandidate[] = [];
|
|
14978
15029
|
const candidateToFactIndex: number[] = [];
|
|
@@ -15013,10 +15064,42 @@ export class Orchestrator {
|
|
|
15013
15064
|
) {
|
|
15014
15065
|
continue;
|
|
15015
15066
|
}
|
|
15016
|
-
|
|
15067
|
+
// #1713 P2 (cursor): per-fact rules — load this fact's routed target
|
|
15068
|
+
// namespace rules FIRST, then check. This catches target-only rules
|
|
15069
|
+
// even when the base (source+shared) rules are empty (threads acc58c42
|
|
15070
|
+
// + PBJEe/PBKAj).
|
|
15071
|
+
let factRedactionRules = preJudgeRedactionRules;
|
|
15072
|
+
let factNs = preRoutedNamespaceByFact[fi];
|
|
15073
|
+
// #1713 (codex PRRT_kwDORJXyws6PBj5X): scope classification can route
|
|
15074
|
+
// a scope=global fact to the shared namespace independent of routing
|
|
15075
|
+
// rules. If so, the pre-judge filter must consult the shared
|
|
15076
|
+
// namespace's rules too, or a never-store pattern under shared is
|
|
15077
|
+
// missed at pre-judge and only caught at the write gate — letting the
|
|
15078
|
+
// content reach the extraction judge/training path. Mirror the write
|
|
15079
|
+
// loop's scope-routing conditions exactly.
|
|
15080
|
+
if (
|
|
15081
|
+
!factNs &&
|
|
15082
|
+
lifecycleCaps.extractionScopeClassification &&
|
|
15083
|
+
namespacesEnabled &&
|
|
15084
|
+
f.scope === "global" &&
|
|
15085
|
+
profileAllowsSharedWrites &&
|
|
15086
|
+
this.storageDirNamespace(storage.dir) !== this.config.sharedNamespace
|
|
15087
|
+
) {
|
|
15088
|
+
factNs = this.config.sharedNamespace;
|
|
15089
|
+
}
|
|
15090
|
+
if (factNs) {
|
|
15091
|
+
try {
|
|
15092
|
+
const factDir = (await this.storageRouter.storageFor(factNs)).dir;
|
|
15093
|
+
if (factDir !== storage.dir) {
|
|
15094
|
+
const targetRules = await redactionRulesFor(factDir);
|
|
15095
|
+
if (targetRules.length) factRedactionRules = [...preJudgeRedactionRules, ...targetRules];
|
|
15096
|
+
}
|
|
15097
|
+
} catch { /* fail open */ }
|
|
15098
|
+
}
|
|
15099
|
+
if (factRedactionRules.length > 0) {
|
|
15017
15100
|
const rc = f.content + (f.structuredAttributes ? " " + JSON.stringify(f.structuredAttributes) : "")
|
|
15018
15101
|
+ (f.procedureSteps ? " " + f.procedureSteps.map((s) => `${s.intent} ${s.expectedOutcome ?? ""} ${s.toolCall ? `${s.toolCall.kind} ${s.toolCall.signature}` : ""}`.trim()).join(" ") : "");
|
|
15019
|
-
if (contentMatchesRedactionRules(rc,
|
|
15102
|
+
if (contentMatchesRedactionRules(rc, factRedactionRules)) continue;
|
|
15020
15103
|
}
|
|
15021
15104
|
judgeCandidates.push({
|
|
15022
15105
|
text: f.content,
|
|
@@ -15246,7 +15329,7 @@ export class Orchestrator {
|
|
|
15246
15329
|
// extractionScopeClassificationEnabled.
|
|
15247
15330
|
if (
|
|
15248
15331
|
lifecycleCaps.extractionScopeClassification &&
|
|
15249
|
-
|
|
15332
|
+
namespacesEnabled &&
|
|
15250
15333
|
fact.scope === "global" &&
|
|
15251
15334
|
!routedNamespaceExplicit
|
|
15252
15335
|
) {
|
|
@@ -15603,6 +15686,16 @@ export class Orchestrator {
|
|
|
15603
15686
|
// `supersedes` is intentionally left unset to avoid retiring the old
|
|
15604
15687
|
// memory without user confirmation).
|
|
15605
15688
|
let contradictionDetected = false;
|
|
15689
|
+
// #1645: hoist the contradiction result so the deferred auto-resolve
|
|
15690
|
+
// (post-write, gated on tombstone status) can read its fields.
|
|
15691
|
+
let contradiction: {
|
|
15692
|
+
supersededId: string;
|
|
15693
|
+
confidence: number;
|
|
15694
|
+
reason: string;
|
|
15695
|
+
supersededPath: string;
|
|
15696
|
+
supersededCreated: string;
|
|
15697
|
+
supersededTags: string[];
|
|
15698
|
+
} | null | undefined;
|
|
15606
15699
|
|
|
15607
15700
|
// Faithfulness gate (#1576, chatgpt P2): skip contradiction detection
|
|
15608
15701
|
// for a pending_review fact — an unfaithful extraction in the review queue
|
|
@@ -15613,7 +15706,7 @@ export class Orchestrator {
|
|
|
15613
15706
|
faithfulnessEnforceStatus !== "pending_review"
|
|
15614
15707
|
) {
|
|
15615
15708
|
const targetNamespace = this.storageDirNamespace(targetStorage.dir);
|
|
15616
|
-
|
|
15709
|
+
contradiction = await this.checkForContradiction(
|
|
15617
15710
|
fact.content,
|
|
15618
15711
|
writeCategory,
|
|
15619
15712
|
targetNamespace,
|
|
@@ -15635,22 +15728,10 @@ export class Orchestrator {
|
|
|
15635
15728
|
strength: contradiction.confidence,
|
|
15636
15729
|
reason: contradiction.reason,
|
|
15637
15730
|
});
|
|
15638
|
-
//
|
|
15639
|
-
//
|
|
15640
|
-
//
|
|
15641
|
-
//
|
|
15642
|
-
if (
|
|
15643
|
-
this.config.contradictionAutoResolve &&
|
|
15644
|
-
this.config.queryAwareIndexingEnabled &&
|
|
15645
|
-
contradiction.supersededPath
|
|
15646
|
-
) {
|
|
15647
|
-
deindexMemory(
|
|
15648
|
-
this.config.memoryDir,
|
|
15649
|
-
contradiction.supersededPath,
|
|
15650
|
-
contradiction.supersededCreated,
|
|
15651
|
-
contradiction.supersededTags,
|
|
15652
|
-
);
|
|
15653
|
-
}
|
|
15731
|
+
// #1645: deindex + supersede are deferred to after writeMemory so the
|
|
15732
|
+
// caller can gate them on the new write's tombstone status. A
|
|
15733
|
+
// tombstone-blocked write (pending_review) must not deindex or retire
|
|
15734
|
+
// the existing active memory — see the post-write guard below.
|
|
15654
15735
|
}
|
|
15655
15736
|
}
|
|
15656
15737
|
|
|
@@ -15765,7 +15846,7 @@ export class Orchestrator {
|
|
|
15765
15846
|
? stripCitationForTemplate(fact.content, citationTemplate)
|
|
15766
15847
|
: fact.content;
|
|
15767
15848
|
const citedChunkedContent = applyInlineCitation(rawChunkedContent);
|
|
15768
|
-
const
|
|
15849
|
+
const parentWrite = await targetStorage.writeMemory(
|
|
15769
15850
|
writeCategory,
|
|
15770
15851
|
citedChunkedContent,
|
|
15771
15852
|
{
|
|
@@ -15792,6 +15873,20 @@ export class Orchestrator {
|
|
|
15792
15873
|
...(fact.provenance ? { provenance: fact.provenance } : {}),
|
|
15793
15874
|
},
|
|
15794
15875
|
);
|
|
15876
|
+
const parentId = parentWrite.id;
|
|
15877
|
+
// #1645: surface the tombstone block and gate active post-write paths
|
|
15878
|
+
// (chunks, supersession, shared promotion, graph/artifact) like #1576.
|
|
15879
|
+
const tombstoneBlocked = parentWrite.tombstoneBlocked;
|
|
15880
|
+
const postWriteGuard =
|
|
15881
|
+
faithfulnessEnforceStatus === "pending_review" || tombstoneBlocked;
|
|
15882
|
+
// #1645: defer contradiction auto-resolve until tombstone status is
|
|
15883
|
+
// known (see applyDeferredContradictionResolve).
|
|
15884
|
+
await this.applyDeferredContradictionResolve(
|
|
15885
|
+
contradiction,
|
|
15886
|
+
targetStorage,
|
|
15887
|
+
parentId,
|
|
15888
|
+
postWriteGuard,
|
|
15889
|
+
);
|
|
15795
15890
|
try {
|
|
15796
15891
|
// Write individual chunks with parent reference
|
|
15797
15892
|
for (const chunk of chunkResult.chunks) {
|
|
@@ -15839,7 +15934,13 @@ export class Orchestrator {
|
|
|
15839
15934
|
// fact's verdict + enforce status so a pending_review fact
|
|
15840
15935
|
// is not indexed as active through its chunks (chatgpt P2).
|
|
15841
15936
|
...(faithfulnessFm ? { faithfulness: faithfulnessFm } : {}),
|
|
15842
|
-
|
|
15937
|
+
// #1645 (OchiE): inherit pending_review + blockedBy so no chunk lands active.
|
|
15938
|
+
...(postWriteGuard
|
|
15939
|
+
? { status: "pending_review" as const }
|
|
15940
|
+
: (faithfulnessEnforceStatus ? { status: faithfulnessEnforceStatus } : {})),
|
|
15941
|
+
...(tombstoneBlocked && parentWrite.blockedBy
|
|
15942
|
+
? { blockedBy: parentWrite.blockedBy }
|
|
15943
|
+
: {}),
|
|
15843
15944
|
// Claim-level provenance (issue #1575 PR 2): mirror the
|
|
15844
15945
|
// parent's spans onto each chunk so a chunk surfaced
|
|
15845
15946
|
// independently (memory_get/x-ray on a chunk ID) preserves
|
|
@@ -15866,24 +15967,28 @@ export class Orchestrator {
|
|
|
15866
15967
|
`chunked memory ${parentId} into ${chunkResult.chunks.length} chunks`,
|
|
15867
15968
|
);
|
|
15868
15969
|
trackPersistedId(targetStorage, parentId, {
|
|
15869
|
-
pendingReview:
|
|
15970
|
+
pendingReview: postWriteGuard,
|
|
15870
15971
|
});
|
|
15871
15972
|
// #1576 (cursor Medium): keep pending_review ids out of threadEpisodeIdsForGraph — else later active facts build thread-predecessor edges to an unfaithful memory.
|
|
15872
15973
|
if (
|
|
15873
|
-
|
|
15974
|
+
!postWriteGuard &&
|
|
15874
15975
|
threadEpisodeIdsForGraph &&
|
|
15875
15976
|
!threadEpisodeIdsForGraph.includes(parentId)
|
|
15876
15977
|
) {
|
|
15877
15978
|
threadEpisodeIdsForGraph.push(parentId);
|
|
15878
15979
|
}
|
|
15879
|
-
|
|
15980
|
+
// #1645: same gate as the non-chunked path — a blocked chunked parent
|
|
15981
|
+
// must not enter the embedding-fallback index (resurrection).
|
|
15982
|
+
if (!postWriteGuard) {
|
|
15983
|
+
await this.indexPersistedMemory(targetStorage, parentId);
|
|
15984
|
+
}
|
|
15880
15985
|
// PR #402 Thread 1 fix: run source-namespace temporal supersession for
|
|
15881
15986
|
// chunked writes, matching the non-chunked path. Without this the
|
|
15882
15987
|
// source namespace retains stale facts that should have been superseded.
|
|
15883
15988
|
// Faithfulness gate (#1576, cursor High): skip supersession for a
|
|
15884
15989
|
// pending_review fact — an unfaithful extraction in the review queue
|
|
15885
15990
|
// must NOT retire older active memories.
|
|
15886
|
-
if (
|
|
15991
|
+
if (!postWriteGuard) {
|
|
15887
15992
|
try {
|
|
15888
15993
|
const supersessionEntityRef =
|
|
15889
15994
|
typeof (fact as any).entityRef === "string"
|
|
@@ -15908,7 +16013,7 @@ export class Orchestrator {
|
|
|
15908
16013
|
// Faithfulness gate (#1576, chatgpt P2): do not promote a
|
|
15909
16014
|
// pending_review fact to shared/profile — it must enter the review
|
|
15910
16015
|
// queue without active copies that bypass the gate.
|
|
15911
|
-
if (
|
|
16016
|
+
if (!postWriteGuard) await promoteMemoryToShared({
|
|
15912
16017
|
sourceStorage: targetStorage,
|
|
15913
16018
|
category: writeCategory,
|
|
15914
16019
|
content: fact.content,
|
|
@@ -15943,7 +16048,13 @@ export class Orchestrator {
|
|
|
15943
16048
|
hasCitationForTemplate(fact.content, citationTemplate)
|
|
15944
16049
|
? stripCitationForTemplate(fact.content, citationTemplate)
|
|
15945
16050
|
: fact.content;
|
|
15946
|
-
|
|
16051
|
+
// #1645: do NOT register a tombstone-blocked fact's content in the
|
|
16052
|
+
// dedup index — writeMemory already skipped it (rule 44). Re-adding
|
|
16053
|
+
// would let the next extraction dedup-skip the tombstone chokepoint
|
|
16054
|
+
// and silently ban the retired content (no pending_review row).
|
|
16055
|
+
if (!tombstoneBlocked) {
|
|
16056
|
+
await this.addContentHashDedup(targetStorage, canonicalChunkedContent);
|
|
16057
|
+
}
|
|
15947
16058
|
} catch (err) {
|
|
15948
16059
|
log.warn(
|
|
15949
16060
|
`content-hash dedup registration failed for chunked memory ${parentId}: ${err}`,
|
|
@@ -15956,14 +16067,18 @@ export class Orchestrator {
|
|
|
15956
16067
|
// into boxBuilder.onExtraction() or threading.processTurn(), which
|
|
15957
16068
|
// only expect canonical parent memory IDs. Call indexPersistedMemory
|
|
15958
16069
|
// directly for embedding-fallback sync of each chunk document.
|
|
15959
|
-
|
|
16070
|
+
// #1645: chunks inherit pending_review under postWriteGuard — don't
|
|
16071
|
+
// index them into the embedding fallback (resurrection).
|
|
16072
|
+
if (!postWriteGuard) {
|
|
16073
|
+
await this.indexPersistedMemory(targetStorage, chunkId);
|
|
16074
|
+
}
|
|
15960
16075
|
}
|
|
15961
16076
|
try {
|
|
15962
16077
|
if (
|
|
15963
16078
|
this.config.verbatimArtifactsEnabled &&
|
|
15964
16079
|
this.config.verbatimArtifactCategories.includes(writeCategory) &&
|
|
15965
16080
|
fact.confidence >= this.config.verbatimArtifactsMinConfidence &&
|
|
15966
|
-
|
|
16081
|
+
!postWriteGuard
|
|
15967
16082
|
) {
|
|
15968
16083
|
// Reuse citedChunkedContent so the artifact carries the same citation
|
|
15969
16084
|
// timestamp as the parent memory write above (Fix #3 — duplicate-citation).
|
|
@@ -15978,7 +16093,7 @@ export class Orchestrator {
|
|
|
15978
16093
|
});
|
|
15979
16094
|
}
|
|
15980
16095
|
// v8.2: graph edge building for chunked memories. #1576: skip pending_review.
|
|
15981
|
-
if (graphCaps.multiGraphMemory &&
|
|
16096
|
+
if (graphCaps.multiGraphMemory && !postWriteGuard) {
|
|
15982
16097
|
try {
|
|
15983
16098
|
const graphContext = await ensureGraphContext(targetStorage);
|
|
15984
16099
|
const entityRef =
|
|
@@ -16080,7 +16195,7 @@ export class Orchestrator {
|
|
|
16080
16195
|
? buildProcedurePersistBody(fact.content, fact.procedureSteps)
|
|
16081
16196
|
: fact.content;
|
|
16082
16197
|
const citedFactContent = applyInlineCitation(rawPersistBody);
|
|
16083
|
-
const
|
|
16198
|
+
const factWrite = await targetStorage.writeMemory(
|
|
16084
16199
|
writeCategory,
|
|
16085
16200
|
citedFactContent,
|
|
16086
16201
|
{
|
|
@@ -16112,6 +16227,20 @@ export class Orchestrator {
|
|
|
16112
16227
|
...(fact.provenance ? { provenance: fact.provenance } : {}),
|
|
16113
16228
|
},
|
|
16114
16229
|
);
|
|
16230
|
+
const memoryId = factWrite.id;
|
|
16231
|
+
// #1645: surface the tombstone block; gate active post-write paths like #1576
|
|
16232
|
+
// so a blocked fact creates no active shared copy / supersession / graph entry.
|
|
16233
|
+
const tombstoneBlocked = factWrite.tombstoneBlocked;
|
|
16234
|
+
const postWriteGuard =
|
|
16235
|
+
faithfulnessEnforceStatus === "pending_review" || tombstoneBlocked;
|
|
16236
|
+
// #1645: defer contradiction auto-resolve until tombstone status is
|
|
16237
|
+
// known (see applyDeferredContradictionResolve).
|
|
16238
|
+
await this.applyDeferredContradictionResolve(
|
|
16239
|
+
contradiction,
|
|
16240
|
+
targetStorage,
|
|
16241
|
+
memoryId,
|
|
16242
|
+
postWriteGuard,
|
|
16243
|
+
);
|
|
16115
16244
|
if (routedRuleId) {
|
|
16116
16245
|
log.debug(
|
|
16117
16246
|
`routing applied for memory ${memoryId}: rule=${routedRuleId} category=${writeCategory} storage=${targetStorage.dir}`,
|
|
@@ -16122,7 +16251,7 @@ export class Orchestrator {
|
|
|
16122
16251
|
// key that has a conflicting value. Faithfulness gate (#1576, cursor
|
|
16123
16252
|
// High): skip for a pending_review fact — an unfaithful extraction in
|
|
16124
16253
|
// the review queue must NOT retire older active memories.
|
|
16125
|
-
if (
|
|
16254
|
+
if (!postWriteGuard) {
|
|
16126
16255
|
try {
|
|
16127
16256
|
const supersessionEntityRef =
|
|
16128
16257
|
typeof (fact as any).entityRef === "string"
|
|
@@ -16154,19 +16283,25 @@ export class Orchestrator {
|
|
|
16154
16283
|
}),
|
|
16155
16284
|
);
|
|
16156
16285
|
trackPersistedId(targetStorage, memoryId, {
|
|
16157
|
-
pendingReview:
|
|
16286
|
+
pendingReview: postWriteGuard,
|
|
16158
16287
|
});
|
|
16159
16288
|
if (
|
|
16160
|
-
|
|
16289
|
+
!postWriteGuard &&
|
|
16161
16290
|
threadEpisodeIdsForGraph &&
|
|
16162
16291
|
!threadEpisodeIdsForGraph.includes(memoryId)
|
|
16163
16292
|
) {
|
|
16164
16293
|
threadEpisodeIdsForGraph.push(memoryId);
|
|
16165
16294
|
}
|
|
16166
|
-
|
|
16295
|
+
// #1645: a tombstone-blocked / pending_review fact must NOT enter the
|
|
16296
|
+
// embedding-fallback index — otherwise embedding recall surfaces the
|
|
16297
|
+
// pending_review row (resurrection). Gate on postWriteGuard like the
|
|
16298
|
+
// surrounding supersession / promotion / graph paths.
|
|
16299
|
+
if (!postWriteGuard) {
|
|
16300
|
+
await this.indexPersistedMemory(targetStorage, memoryId);
|
|
16301
|
+
}
|
|
16167
16302
|
// Faithfulness gate (#1576, chatgpt P2): skip promotion for a
|
|
16168
16303
|
// pending_review fact so no active shared/profile copy bypasses the gate.
|
|
16169
|
-
if (
|
|
16304
|
+
if (!postWriteGuard) await promoteMemoryToShared({
|
|
16170
16305
|
sourceStorage: targetStorage,
|
|
16171
16306
|
category: writeCategory,
|
|
16172
16307
|
content: fact.content,
|
|
@@ -16196,7 +16331,7 @@ export class Orchestrator {
|
|
|
16196
16331
|
...(fact.provenance ? { provenance: fact.provenance } : {}),
|
|
16197
16332
|
});
|
|
16198
16333
|
// v8.2: graph edge building (fail-open). #1576: skip pending_review facts.
|
|
16199
|
-
if (graphCaps.multiGraphMemory &&
|
|
16334
|
+
if (graphCaps.multiGraphMemory && !postWriteGuard) {
|
|
16200
16335
|
try {
|
|
16201
16336
|
const graphContext = await ensureGraphContext(targetStorage);
|
|
16202
16337
|
const entityRef =
|
|
@@ -16240,7 +16375,7 @@ export class Orchestrator {
|
|
|
16240
16375
|
this.config.verbatimArtifactsEnabled &&
|
|
16241
16376
|
this.config.verbatimArtifactCategories.includes(writeCategory) &&
|
|
16242
16377
|
fact.confidence >= this.config.verbatimArtifactsMinConfidence &&
|
|
16243
|
-
|
|
16378
|
+
!postWriteGuard
|
|
16244
16379
|
) {
|
|
16245
16380
|
// Reuse citedFactContent so the artifact carries the same citation
|
|
16246
16381
|
// timestamp as the memory write above (Fix #3 — duplicate-citation).
|
|
@@ -16267,7 +16402,11 @@ export class Orchestrator {
|
|
|
16267
16402
|
writeCategory === "procedure"
|
|
16268
16403
|
? buildProcedurePersistBody(fact.content, fact.procedureSteps)
|
|
16269
16404
|
: canonicalFactContent;
|
|
16270
|
-
|
|
16405
|
+
// #1645: do NOT register a tombstone-blocked fact's content in the dedup
|
|
16406
|
+
// index (rule 44 defeat) — see chunked path comment.
|
|
16407
|
+
if (!tombstoneBlocked) {
|
|
16408
|
+
await this.addContentHashDedup(targetStorage, hashRegisterKey);
|
|
16409
|
+
}
|
|
16271
16410
|
} catch (err) {
|
|
16272
16411
|
log.warn(
|
|
16273
16412
|
`content-hash dedup registration failed for memory ${memoryId}: ${err}`,
|
|
@@ -16617,7 +16756,7 @@ export class Orchestrator {
|
|
|
16617
16756
|
// Enabling only parallelRetrievalEnabled without queryAwareIndexingEnabled would silently
|
|
16618
16757
|
// produce an empty temporal index, leaving the temporal agent with no data to work from.
|
|
16619
16758
|
if (
|
|
16620
|
-
!this.config.
|
|
16759
|
+
!resolveIndexingCapabilities(this.config).queryAwareIndexing &&
|
|
16621
16760
|
!caps.parallelRetrieval
|
|
16622
16761
|
)
|
|
16623
16762
|
return;
|
|
@@ -16732,7 +16871,7 @@ export class Orchestrator {
|
|
|
16732
16871
|
|
|
16733
16872
|
// Build a lookup map from the already-loaded corpus to avoid repeated
|
|
16734
16873
|
// readAllMemories() scans inside getMemoryById for pre-action deindex reads.
|
|
16735
|
-
const memoryLookup = this.config.
|
|
16874
|
+
const memoryLookup = resolveIndexingCapabilities(this.config).queryAwareIndexing
|
|
16736
16875
|
? new Map(allMemories.map((m) => [m.frontmatter.id, m]))
|
|
16737
16876
|
: null;
|
|
16738
16877
|
|
|
@@ -16740,7 +16879,7 @@ export class Orchestrator {
|
|
|
16740
16879
|
switch (item.action) {
|
|
16741
16880
|
case "INVALIDATE": {
|
|
16742
16881
|
// Capture path/frontmatter before invalidation for index cleanup
|
|
16743
|
-
const toInvalidate = this.config.
|
|
16882
|
+
const toInvalidate = resolveIndexingCapabilities(this.config).queryAwareIndexing
|
|
16744
16883
|
? (memoryLookup?.get(item.existingId) ?? null)
|
|
16745
16884
|
: null;
|
|
16746
16885
|
if (await this.storage.invalidateMemory(item.existingId)) {
|
|
@@ -16788,7 +16927,7 @@ export class Orchestrator {
|
|
|
16788
16927
|
// updateMemory() only changes content/updated/supersedes/lineage — path, created, and tags
|
|
16789
16928
|
// are preserved, so the temporal/tag index entry for the survivor is already correct.
|
|
16790
16929
|
// Capture before invalidation for index cleanup
|
|
16791
|
-
const toMergeInvalidate = this.config.
|
|
16930
|
+
const toMergeInvalidate = resolveIndexingCapabilities(this.config).queryAwareIndexing
|
|
16792
16931
|
? (memoryLookup?.get(item.mergeWith) ?? null)
|
|
16793
16932
|
: null;
|
|
16794
16933
|
if (await this.storage.invalidateMemory(item.mergeWith)) {
|
|
@@ -16874,7 +17013,7 @@ export class Orchestrator {
|
|
|
16874
17013
|
if (deletedCommitments.length > 0) {
|
|
16875
17014
|
memoryItemMutated = true;
|
|
16876
17015
|
log.info(`cleaned ${deletedCommitments.length} expired commitments`);
|
|
16877
|
-
if (this.config.
|
|
17016
|
+
if (resolveIndexingCapabilities(this.config).queryAwareIndexing) {
|
|
16878
17017
|
for (const m of deletedCommitments) {
|
|
16879
17018
|
deindexMemory(
|
|
16880
17019
|
this.config.memoryDir,
|
|
@@ -16887,9 +17026,9 @@ export class Orchestrator {
|
|
|
16887
17026
|
}
|
|
16888
17027
|
|
|
16889
17028
|
if (
|
|
16890
|
-
this.config.
|
|
16891
|
-
this.config.
|
|
16892
|
-
this.config.
|
|
17029
|
+
resolveCreationMemoryCapabilities(this.config).creationMemory &&
|
|
17030
|
+
resolveCreationMemoryCapabilities(this.config).commitmentLedger &&
|
|
17031
|
+
resolveCreationMemoryCapabilities(this.config).commitmentLifecycle
|
|
16893
17032
|
) {
|
|
16894
17033
|
try {
|
|
16895
17034
|
const lifecycle = await applyCommitmentLedgerLifecycle({
|
|
@@ -16917,7 +17056,7 @@ export class Orchestrator {
|
|
|
16917
17056
|
if (deletedTTL.length > 0) {
|
|
16918
17057
|
memoryItemMutated = true;
|
|
16919
17058
|
log.info(`cleaned ${deletedTTL.length} TTL-expired memories`);
|
|
16920
|
-
if (this.config.
|
|
17059
|
+
if (resolveIndexingCapabilities(this.config).queryAwareIndexing) {
|
|
16921
17060
|
for (const m of deletedTTL) {
|
|
16922
17061
|
deindexMemory(
|
|
16923
17062
|
this.config.memoryDir,
|
|
@@ -17195,347 +17334,26 @@ export class Orchestrator {
|
|
|
17195
17334
|
async optimizeCompressionGuidelines(options?: {
|
|
17196
17335
|
dryRun?: boolean;
|
|
17197
17336
|
eventLimit?: number;
|
|
17198
|
-
})
|
|
17199
|
-
|
|
17200
|
-
dryRun: boolean;
|
|
17201
|
-
eventCount: number;
|
|
17202
|
-
previousGuidelineVersion: number | null;
|
|
17203
|
-
nextGuidelineVersion: number;
|
|
17204
|
-
changedRules: number;
|
|
17205
|
-
semanticRefinementApplied: boolean;
|
|
17206
|
-
persisted: boolean;
|
|
17207
|
-
draftContentHash: string | null;
|
|
17208
|
-
}> {
|
|
17209
|
-
const dryRun = options?.dryRun === true;
|
|
17210
|
-
const eventLimit =
|
|
17211
|
-
typeof options?.eventLimit === "number"
|
|
17212
|
-
? Math.max(0, Math.floor(options.eventLimit))
|
|
17213
|
-
: 500;
|
|
17214
|
-
|
|
17215
|
-
const [activeState, draftState] = await Promise.all([
|
|
17216
|
-
this.storage.readCompressionGuidelineOptimizerState(),
|
|
17217
|
-
this.storage.readCompressionGuidelineDraftState().catch(() => null),
|
|
17218
|
-
]);
|
|
17219
|
-
const previousState =
|
|
17220
|
-
draftState &&
|
|
17221
|
-
((activeState?.guidelineVersion ?? 0) < draftState.guidelineVersion ||
|
|
17222
|
-
(activeState?.guidelineVersion ?? 0) === draftState.guidelineVersion)
|
|
17223
|
-
? draftState
|
|
17224
|
-
: activeState;
|
|
17225
|
-
|
|
17226
|
-
if (!this.config.compressionGuidelineLearningEnabled) {
|
|
17227
|
-
return {
|
|
17228
|
-
enabled: false,
|
|
17229
|
-
dryRun,
|
|
17230
|
-
eventCount: 0,
|
|
17231
|
-
previousGuidelineVersion: previousState?.guidelineVersion ?? null,
|
|
17232
|
-
nextGuidelineVersion: previousState?.guidelineVersion ?? 0,
|
|
17233
|
-
changedRules: 0,
|
|
17234
|
-
semanticRefinementApplied: false,
|
|
17235
|
-
persisted: false,
|
|
17236
|
-
draftContentHash: null,
|
|
17237
|
-
};
|
|
17238
|
-
}
|
|
17239
|
-
|
|
17240
|
-
let events = await this.storage.readMemoryActionEvents(eventLimit);
|
|
17241
|
-
if (eventLimit > 0) {
|
|
17242
|
-
let effectiveEvents = events.filter((event) => event.dryRun !== true);
|
|
17243
|
-
let fetchLimit = eventLimit;
|
|
17244
|
-
while (
|
|
17245
|
-
effectiveEvents.length < eventLimit &&
|
|
17246
|
-
events.length === fetchLimit
|
|
17247
|
-
) {
|
|
17248
|
-
fetchLimit = Math.min(fetchLimit * 2, fetchLimit + 1000);
|
|
17249
|
-
if (fetchLimit <= events.length) break;
|
|
17250
|
-
events = await this.storage.readMemoryActionEvents(fetchLimit);
|
|
17251
|
-
effectiveEvents = events.filter((event) => event.dryRun !== true);
|
|
17252
|
-
}
|
|
17253
|
-
events = effectiveEvents.slice(-eventLimit);
|
|
17254
|
-
}
|
|
17255
|
-
const generatedAt = new Date().toISOString();
|
|
17256
|
-
const candidate = computeCompressionGuidelineCandidate(events, {
|
|
17257
|
-
generatedAtIso: generatedAt,
|
|
17258
|
-
previousState,
|
|
17259
|
-
});
|
|
17260
|
-
if (candidate.eventCounts.total === 0) {
|
|
17261
|
-
return {
|
|
17262
|
-
enabled: true,
|
|
17263
|
-
dryRun,
|
|
17264
|
-
eventCount: 0,
|
|
17265
|
-
previousGuidelineVersion: previousState?.guidelineVersion ?? null,
|
|
17266
|
-
nextGuidelineVersion: previousState?.guidelineVersion ?? 0,
|
|
17267
|
-
changedRules: 0,
|
|
17268
|
-
semanticRefinementApplied: false,
|
|
17269
|
-
persisted: false,
|
|
17270
|
-
draftContentHash: null,
|
|
17271
|
-
};
|
|
17272
|
-
}
|
|
17273
|
-
const refinedCandidate =
|
|
17274
|
-
await refineCompressionGuidelineCandidateSemantically(candidate, {
|
|
17275
|
-
enabled: this.config.compressionGuidelineSemanticRefinementEnabled,
|
|
17276
|
-
timeoutMs: this.config.compressionGuidelineSemanticTimeoutMs,
|
|
17277
|
-
runRefinement: async (baseline) => {
|
|
17278
|
-
const prompt = [
|
|
17279
|
-
"You refine compression policy suggestions conservatively.",
|
|
17280
|
-
"Return JSON only in this shape:",
|
|
17281
|
-
'{"updates":[{"action":"summarize_node","delta":0.02,"confidence":"medium","note":"..."}]}',
|
|
17282
|
-
"Constraints:",
|
|
17283
|
-
"- Keep updates sparse and conservative.",
|
|
17284
|
-
"- delta must stay between -0.15 and 0.15.",
|
|
17285
|
-
"- Only include actions present in the input.",
|
|
17286
|
-
"Input candidate:",
|
|
17287
|
-
JSON.stringify(baseline),
|
|
17288
|
-
].join("\n");
|
|
17289
|
-
|
|
17290
|
-
const response = await this.fastChatCompletion(
|
|
17291
|
-
[
|
|
17292
|
-
{
|
|
17293
|
-
role: "system",
|
|
17294
|
-
content: "Respond with strict JSON only. No markdown.",
|
|
17295
|
-
},
|
|
17296
|
-
{ role: "user", content: prompt },
|
|
17297
|
-
],
|
|
17298
|
-
{
|
|
17299
|
-
temperature: 0.1,
|
|
17300
|
-
maxTokens: 400,
|
|
17301
|
-
operation: "compression_guideline_semantic_refinement",
|
|
17302
|
-
priority: "background",
|
|
17303
|
-
},
|
|
17304
|
-
);
|
|
17305
|
-
|
|
17306
|
-
return this.parseCompressionSemanticRefinement(
|
|
17307
|
-
response?.content ?? "",
|
|
17308
|
-
);
|
|
17309
|
-
},
|
|
17310
|
-
});
|
|
17311
|
-
|
|
17312
|
-
const content = renderCompressionGuidelinesMarkdown(refinedCandidate);
|
|
17313
|
-
const contentHash = createHash("sha256").update(content).digest("hex");
|
|
17314
|
-
const semanticRefinementApplied =
|
|
17315
|
-
JSON.stringify(refinedCandidate.ruleUpdates) !==
|
|
17316
|
-
JSON.stringify(candidate.ruleUpdates);
|
|
17317
|
-
const changedRules = refinedCandidate.ruleUpdates.filter(
|
|
17318
|
-
(rule) => rule.delta !== 0,
|
|
17319
|
-
).length;
|
|
17320
|
-
|
|
17321
|
-
if (!dryRun) {
|
|
17322
|
-
await this.storage.writeCompressionGuidelineDraft(content);
|
|
17323
|
-
await this.storage.writeCompressionGuidelineDraftState({
|
|
17324
|
-
version: refinedCandidate.optimizerVersion,
|
|
17325
|
-
updatedAt: refinedCandidate.generatedAt,
|
|
17326
|
-
sourceWindow: refinedCandidate.sourceWindow,
|
|
17327
|
-
eventCounts: refinedCandidate.eventCounts,
|
|
17328
|
-
guidelineVersion: refinedCandidate.guidelineVersion,
|
|
17329
|
-
contentHash,
|
|
17330
|
-
activationState: "draft",
|
|
17331
|
-
actionSummaries: refinedCandidate.actionSummaries,
|
|
17332
|
-
ruleUpdates: refinedCandidate.ruleUpdates,
|
|
17333
|
-
});
|
|
17334
|
-
}
|
|
17335
|
-
|
|
17336
|
-
return {
|
|
17337
|
-
enabled: true,
|
|
17338
|
-
dryRun,
|
|
17339
|
-
eventCount: candidate.eventCounts.total,
|
|
17340
|
-
previousGuidelineVersion: previousState?.guidelineVersion ?? null,
|
|
17341
|
-
nextGuidelineVersion: refinedCandidate.guidelineVersion,
|
|
17342
|
-
changedRules,
|
|
17343
|
-
semanticRefinementApplied,
|
|
17344
|
-
persisted: !dryRun,
|
|
17345
|
-
draftContentHash: dryRun ? null : contentHash,
|
|
17346
|
-
};
|
|
17337
|
+
}) {
|
|
17338
|
+
return this.compressionGuidelineCoordinator.optimizeCompressionGuidelines(options);
|
|
17347
17339
|
}
|
|
17348
17340
|
|
|
17349
17341
|
async activateCompressionGuidelineDraft(options?: {
|
|
17350
17342
|
expectedContentHash?: string;
|
|
17351
17343
|
expectedGuidelineVersion?: number;
|
|
17352
|
-
})
|
|
17353
|
-
|
|
17354
|
-
activated: boolean;
|
|
17355
|
-
guidelineVersion: number | null;
|
|
17356
|
-
reason?:
|
|
17357
|
-
| "disabled"
|
|
17358
|
-
| "missing_draft"
|
|
17359
|
-
| "expected_revision_required"
|
|
17360
|
-
| "content_hash_mismatch"
|
|
17361
|
-
| "guideline_version_mismatch"
|
|
17362
|
-
| "draft_changed";
|
|
17363
|
-
}> {
|
|
17364
|
-
if (!this.config.compressionGuidelineLearningEnabled) {
|
|
17365
|
-
return {
|
|
17366
|
-
enabled: false,
|
|
17367
|
-
activated: false,
|
|
17368
|
-
guidelineVersion: null,
|
|
17369
|
-
reason: "disabled",
|
|
17370
|
-
};
|
|
17371
|
-
}
|
|
17372
|
-
|
|
17373
|
-
const draftState = await this.storage.readCompressionGuidelineDraftState();
|
|
17374
|
-
if (!draftState) {
|
|
17375
|
-
return {
|
|
17376
|
-
enabled: true,
|
|
17377
|
-
activated: false,
|
|
17378
|
-
guidelineVersion: null,
|
|
17379
|
-
reason: "missing_draft",
|
|
17380
|
-
};
|
|
17381
|
-
}
|
|
17382
|
-
|
|
17383
|
-
const expectedContentHash = options?.expectedContentHash?.trim();
|
|
17384
|
-
const expectedGuidelineVersion = options?.expectedGuidelineVersion;
|
|
17385
|
-
|
|
17386
|
-
if (
|
|
17387
|
-
(!expectedContentHash || expectedContentHash.length === 0) &&
|
|
17388
|
-
typeof expectedGuidelineVersion !== "number"
|
|
17389
|
-
) {
|
|
17390
|
-
return {
|
|
17391
|
-
enabled: true,
|
|
17392
|
-
activated: false,
|
|
17393
|
-
guidelineVersion: null,
|
|
17394
|
-
reason: "expected_revision_required",
|
|
17395
|
-
};
|
|
17396
|
-
}
|
|
17397
|
-
|
|
17398
|
-
if (expectedContentHash && draftState.contentHash !== expectedContentHash) {
|
|
17399
|
-
return {
|
|
17400
|
-
enabled: true,
|
|
17401
|
-
activated: false,
|
|
17402
|
-
guidelineVersion: null,
|
|
17403
|
-
reason: "content_hash_mismatch",
|
|
17404
|
-
};
|
|
17405
|
-
}
|
|
17406
|
-
|
|
17407
|
-
if (
|
|
17408
|
-
typeof expectedGuidelineVersion === "number" &&
|
|
17409
|
-
draftState.guidelineVersion !== expectedGuidelineVersion
|
|
17410
|
-
) {
|
|
17411
|
-
return {
|
|
17412
|
-
enabled: true,
|
|
17413
|
-
activated: false,
|
|
17414
|
-
guidelineVersion: null,
|
|
17415
|
-
reason: "guideline_version_mismatch",
|
|
17416
|
-
};
|
|
17417
|
-
}
|
|
17418
|
-
|
|
17419
|
-
const activated = await this.storage.activateCompressionGuidelineDraft({
|
|
17420
|
-
...(expectedContentHash ? { expectedContentHash } : {}),
|
|
17421
|
-
...(typeof expectedGuidelineVersion === "number"
|
|
17422
|
-
? { expectedGuidelineVersion }
|
|
17423
|
-
: {}),
|
|
17424
|
-
});
|
|
17425
|
-
return {
|
|
17426
|
-
enabled: true,
|
|
17427
|
-
activated,
|
|
17428
|
-
guidelineVersion: activated ? draftState.guidelineVersion : null,
|
|
17429
|
-
...(activated ? {} : { reason: "draft_changed" as const }),
|
|
17430
|
-
};
|
|
17344
|
+
}) {
|
|
17345
|
+
return this.compressionGuidelineCoordinator.activateCompressionGuidelineDraft(options);
|
|
17431
17346
|
}
|
|
17432
17347
|
|
|
17348
|
+
// Issue #1526 (seam 4): compression-guideline learning moved to
|
|
17349
|
+
// CompressionGuidelineCoordinator. Thin delegation keeps the
|
|
17350
|
+
// consolidation-loop hook + recall-section hook call sites stable.
|
|
17433
17351
|
private async runCompressionGuidelineLearningPass(): Promise<void> {
|
|
17434
|
-
|
|
17435
|
-
try {
|
|
17436
|
-
const result = await this.optimizeCompressionGuidelines({
|
|
17437
|
-
dryRun: false,
|
|
17438
|
-
eventLimit: 500,
|
|
17439
|
-
});
|
|
17440
|
-
log.info(
|
|
17441
|
-
`compression guideline learning updated (${result.eventCount} events)`,
|
|
17442
|
-
);
|
|
17443
|
-
} catch (err) {
|
|
17444
|
-
log.warn(`compression guideline learning failed (ignored): ${err}`);
|
|
17445
|
-
}
|
|
17352
|
+
return this.compressionGuidelineCoordinator.runCompressionGuidelineLearningPass();
|
|
17446
17353
|
}
|
|
17447
17354
|
|
|
17448
|
-
private async buildCompressionGuidelineRecallSection(): Promise<
|
|
17449
|
-
|
|
17450
|
-
> {
|
|
17451
|
-
if (!this.config.contextCompressionActionsEnabled) return null;
|
|
17452
|
-
if (!this.config.compressionGuidelineLearningEnabled) return null;
|
|
17453
|
-
|
|
17454
|
-
const state = await this.storage
|
|
17455
|
-
.readCompressionGuidelineOptimizerState()
|
|
17456
|
-
.catch(() => null);
|
|
17457
|
-
if (!state || state.guidelineVersion <= 0) return null;
|
|
17458
|
-
|
|
17459
|
-
const raw = await this.storage
|
|
17460
|
-
.readCompressionGuidelines()
|
|
17461
|
-
.catch(() => null);
|
|
17462
|
-
const summary = raw ? formatCompressionGuidelinesForRecall(raw, 5) : null;
|
|
17463
|
-
if (!summary) return null;
|
|
17464
|
-
|
|
17465
|
-
return [
|
|
17466
|
-
"## Active Compression Guidelines",
|
|
17467
|
-
"",
|
|
17468
|
-
`Guideline version: ${state.guidelineVersion}`,
|
|
17469
|
-
`Updated: ${state.updatedAt}`,
|
|
17470
|
-
"",
|
|
17471
|
-
summary,
|
|
17472
|
-
].join("\n");
|
|
17473
|
-
}
|
|
17474
|
-
|
|
17475
|
-
private parseCompressionSemanticRefinement(raw: string): {
|
|
17476
|
-
updates: Array<{
|
|
17477
|
-
action: MemoryActionType;
|
|
17478
|
-
delta?: number;
|
|
17479
|
-
confidence?: "low" | "medium" | "high";
|
|
17480
|
-
note?: string;
|
|
17481
|
-
}>;
|
|
17482
|
-
} | null {
|
|
17483
|
-
if (typeof raw !== "string" || raw.trim().length === 0) return null;
|
|
17484
|
-
const trimmed = raw.trim();
|
|
17485
|
-
const start = trimmed.indexOf("{");
|
|
17486
|
-
const end = trimmed.lastIndexOf("}");
|
|
17487
|
-
if (start === -1 || end === -1 || end <= start) return null;
|
|
17488
|
-
|
|
17489
|
-
try {
|
|
17490
|
-
const parsed = JSON.parse(trimmed.slice(start, end + 1)) as {
|
|
17491
|
-
updates?: Array<{
|
|
17492
|
-
action?: unknown;
|
|
17493
|
-
delta?: unknown;
|
|
17494
|
-
confidence?: unknown;
|
|
17495
|
-
note?: unknown;
|
|
17496
|
-
}>;
|
|
17497
|
-
};
|
|
17498
|
-
if (!Array.isArray(parsed?.updates)) return null;
|
|
17499
|
-
|
|
17500
|
-
const validActions = new Set<MemoryActionType>([
|
|
17501
|
-
"store_episode",
|
|
17502
|
-
"store_note",
|
|
17503
|
-
"update_note",
|
|
17504
|
-
"create_artifact",
|
|
17505
|
-
"summarize_node",
|
|
17506
|
-
"discard",
|
|
17507
|
-
"link_graph",
|
|
17508
|
-
]);
|
|
17509
|
-
|
|
17510
|
-
const updates = parsed.updates
|
|
17511
|
-
.filter(
|
|
17512
|
-
(item) =>
|
|
17513
|
-
item &&
|
|
17514
|
-
typeof item.action === "string" &&
|
|
17515
|
-
validActions.has(item.action as MemoryActionType),
|
|
17516
|
-
)
|
|
17517
|
-
.map((item) => {
|
|
17518
|
-
const confidence: "low" | "medium" | "high" | undefined =
|
|
17519
|
-
item.confidence === "low" ||
|
|
17520
|
-
item.confidence === "medium" ||
|
|
17521
|
-
item.confidence === "high"
|
|
17522
|
-
? item.confidence
|
|
17523
|
-
: undefined;
|
|
17524
|
-
return {
|
|
17525
|
-
action: item.action as MemoryActionType,
|
|
17526
|
-
delta:
|
|
17527
|
-
typeof item.delta === "number" && Number.isFinite(item.delta)
|
|
17528
|
-
? item.delta
|
|
17529
|
-
: undefined,
|
|
17530
|
-
confidence,
|
|
17531
|
-
note: typeof item.note === "string" ? item.note : undefined,
|
|
17532
|
-
};
|
|
17533
|
-
});
|
|
17534
|
-
|
|
17535
|
-
return { updates };
|
|
17536
|
-
} catch {
|
|
17537
|
-
return null;
|
|
17538
|
-
}
|
|
17355
|
+
private async buildCompressionGuidelineRecallSection(): Promise<string | null> {
|
|
17356
|
+
return this.compressionGuidelineCoordinator.buildCompressionGuidelineRecallSection();
|
|
17539
17357
|
}
|
|
17540
17358
|
|
|
17541
17359
|
private actionOutcomePriorDelta(event: MemoryActionEvent): number {
|
|
@@ -17805,7 +17623,7 @@ export class Orchestrator {
|
|
|
17805
17623
|
);
|
|
17806
17624
|
await this.embeddingFallback.removeFromIndex(memory.frontmatter.id);
|
|
17807
17625
|
if (
|
|
17808
|
-
this.config.
|
|
17626
|
+
resolveIndexingCapabilities(this.config).queryAwareIndexing &&
|
|
17809
17627
|
memory.path &&
|
|
17810
17628
|
memory.frontmatter?.created
|
|
17811
17629
|
) {
|
|
@@ -20190,7 +20008,7 @@ export class Orchestrator {
|
|
|
20190
20008
|
);
|
|
20191
20009
|
let temporalFromDate: string | null = null;
|
|
20192
20010
|
let promptTags: string[] = [];
|
|
20193
|
-
if (this.config.
|
|
20011
|
+
if (resolveIndexingCapabilities(this.config).queryAwareIndexing && prompt) {
|
|
20194
20012
|
if (isTemporalQuery(prompt)) {
|
|
20195
20013
|
temporalFromDate = recencyWindowFromPrompt(prompt, now);
|
|
20196
20014
|
}
|
|
@@ -20215,7 +20033,7 @@ export class Orchestrator {
|
|
|
20215
20033
|
// Scope to result paths first so cross-namespace paths don't consume the cap.
|
|
20216
20034
|
let temporalCandidates: Set<string> | null = null;
|
|
20217
20035
|
let tagCandidates: Set<string> | null = null;
|
|
20218
|
-
if (this.config.
|
|
20036
|
+
if (resolveIndexingCapabilities(this.config).queryAwareIndexing && prompt) {
|
|
20219
20037
|
const maxCandidates = this.config.queryAwareIndexingMaxCandidates;
|
|
20220
20038
|
const capSet = (s: Set<string> | null): Set<string> | null => {
|
|
20221
20039
|
if (!s) return null;
|
|
@@ -20324,7 +20142,7 @@ export class Orchestrator {
|
|
|
20324
20142
|
|
|
20325
20143
|
// v8.1: Temporal + Tag index boost
|
|
20326
20144
|
// Results that match the detected temporal window or tag query get a small additive boost.
|
|
20327
|
-
if (this.config.
|
|
20145
|
+
if (resolveIndexingCapabilities(this.config).queryAwareIndexing && r.path) {
|
|
20328
20146
|
if (temporalCandidates?.has(r.path)) {
|
|
20329
20147
|
score += applyUtilityRankingRuntimeDelta(
|
|
20330
20148
|
0.08,
|
|
@@ -20561,15 +20379,13 @@ export class Orchestrator {
|
|
|
20561
20379
|
}
|
|
20562
20380
|
|
|
20563
20381
|
// The new fact is newer than the existing one. When auto-resolve is
|
|
20564
|
-
// enabled,
|
|
20565
|
-
//
|
|
20566
|
-
|
|
20567
|
-
|
|
20568
|
-
|
|
20569
|
-
|
|
20570
|
-
|
|
20571
|
-
);
|
|
20572
|
-
}
|
|
20382
|
+
// enabled, the caller retires the old memory AFTER the new write lands
|
|
20383
|
+
// and its tombstone status is known (#1645: defer auto-resolve until
|
|
20384
|
+
// tombstone status is known — a tombstone-blocked new write must not
|
|
20385
|
+
// retire the only active copy, leaving neither memory active). When
|
|
20386
|
+
// disabled, the old memory stays active for manual review. The
|
|
20387
|
+
// contradiction info is returned in both cases so the caller can apply
|
|
20388
|
+
// the deferred retire post-write.
|
|
20573
20389
|
|
|
20574
20390
|
// Return the contradiction info regardless of auto-resolve setting.
|
|
20575
20391
|
// The caller uses this to set `contradictionDetected=true` which
|
|
@@ -20592,6 +20408,71 @@ export class Orchestrator {
|
|
|
20592
20408
|
return null;
|
|
20593
20409
|
}
|
|
20594
20410
|
|
|
20411
|
+
/**
|
|
20412
|
+
* #1645: Complete the deferred contradiction auto-resolve after writeMemory
|
|
20413
|
+
* returns and the new write's tombstone status is known. Retires the old
|
|
20414
|
+
* memory + deindexes it ONLY when the new write is genuinely active (not
|
|
20415
|
+
* tombstone-blocked / pending_review). A blocked write must not retire the
|
|
20416
|
+
* only active copy — deferring here closes the "contradictionAutoResolve
|
|
20417
|
+
* supersedes before tombstone status is known" defect class.
|
|
20418
|
+
*/
|
|
20419
|
+
private async applyDeferredContradictionResolve(
|
|
20420
|
+
contradiction: {
|
|
20421
|
+
supersededId: string;
|
|
20422
|
+
reason: string;
|
|
20423
|
+
supersededPath: string;
|
|
20424
|
+
supersededCreated: string;
|
|
20425
|
+
supersededTags: string[];
|
|
20426
|
+
} | null | undefined,
|
|
20427
|
+
storage: StorageManager,
|
|
20428
|
+
newMemoryId: string,
|
|
20429
|
+
postWriteGuard: boolean,
|
|
20430
|
+
): Promise<void> {
|
|
20431
|
+
// #1645 yG2: clear the pre-write `supersedes` link from a blocked row so
|
|
20432
|
+
// it doesn't claim to supersede a still-active memory (best-effort).
|
|
20433
|
+
if (postWriteGuard && contradiction && this.config.contradictionAutoResolve) {
|
|
20434
|
+
try {
|
|
20435
|
+
const blockedRow = await storage.getMemoryById(newMemoryId);
|
|
20436
|
+
if (blockedRow?.frontmatter?.supersedes) {
|
|
20437
|
+
await storage.writeMemoryFrontmatter(blockedRow, { supersedes: undefined });
|
|
20438
|
+
}
|
|
20439
|
+
} catch (err) {
|
|
20440
|
+
log.warn(
|
|
20441
|
+
`contradiction auto-resolve supersedes clear failed for blocked ${newMemoryId}: ${err}`,
|
|
20442
|
+
);
|
|
20443
|
+
}
|
|
20444
|
+
}
|
|
20445
|
+
if (
|
|
20446
|
+
!contradiction ||
|
|
20447
|
+
!this.config.contradictionAutoResolve ||
|
|
20448
|
+
postWriteGuard
|
|
20449
|
+
) {
|
|
20450
|
+
return;
|
|
20451
|
+
}
|
|
20452
|
+
try {
|
|
20453
|
+
await storage.supersedeMemory(
|
|
20454
|
+
contradiction.supersededId,
|
|
20455
|
+
newMemoryId,
|
|
20456
|
+
contradiction.reason,
|
|
20457
|
+
);
|
|
20458
|
+
if (
|
|
20459
|
+
resolveIndexingCapabilities(this.config).queryAwareIndexing &&
|
|
20460
|
+
contradiction.supersededPath
|
|
20461
|
+
) {
|
|
20462
|
+
deindexMemory(
|
|
20463
|
+
this.config.memoryDir,
|
|
20464
|
+
contradiction.supersededPath,
|
|
20465
|
+
contradiction.supersededCreated,
|
|
20466
|
+
contradiction.supersededTags,
|
|
20467
|
+
);
|
|
20468
|
+
}
|
|
20469
|
+
} catch (err) {
|
|
20470
|
+
log.warn(
|
|
20471
|
+
`contradiction auto-resolve supersede failed for ${contradiction.supersededId}: ${err}`,
|
|
20472
|
+
);
|
|
20473
|
+
}
|
|
20474
|
+
}
|
|
20475
|
+
|
|
20595
20476
|
// ---------------------------------------------------------------------------
|
|
20596
20477
|
// Memory Linking (Phase 3A)
|
|
20597
20478
|
// ---------------------------------------------------------------------------
|