@remnic/core 9.3.728 → 9.3.730
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 +7 -6
- package/dist/access-operations.js +17 -17
- package/dist/access-schema.d.ts +4 -4
- package/dist/{access-service-Bgpjxo4f.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-QNEUZIAH.js → chunk-OUITHS6V.js} +381 -433
- 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-BLME420h.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-DqPAz8ot.d.ts → orchestrator-B4KjaOtY.d.ts} +128 -34
- 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 +32 -32
- 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 +1 -1
- 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 +22 -22
- 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/orchestration/extraction-queue-coordinator.ts +175 -0
- package/src/orchestrator-extraction-queue.test.ts +26 -38
- package/src/orchestrator-flush.test.ts +10 -15
- package/src/orchestrator.ts +359 -542
- 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-M4AYVEWS.js.map +0 -1
- package/dist/chunk-QNEUZIAH.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
|
@@ -99,6 +99,8 @@ import {
|
|
|
99
99
|
} from "./fallback-llm.js";
|
|
100
100
|
import { MaintenanceScheduler } from "./orchestration/maintenance.js";
|
|
101
101
|
import { TierMigrationCoordinator } from "./orchestration/tier-migration-coordinator.js";
|
|
102
|
+
import { ExtractionQueueCoordinator } from "./orchestration/extraction-queue-coordinator.js";
|
|
103
|
+
import { CompressionGuidelineCoordinator } from "./orchestration/compression-guideline-coordinator.js";
|
|
102
104
|
import {
|
|
103
105
|
runLiveConnectorsOnce,
|
|
104
106
|
type LiveConnectorsRunSummary,
|
|
@@ -171,7 +173,6 @@ import {
|
|
|
171
173
|
import { SessionObserverState } from "./session-observer-state.js";
|
|
172
174
|
import {
|
|
173
175
|
abortError as sharedAbortError,
|
|
174
|
-
isAbortError,
|
|
175
176
|
throwIfAborted as sharedThrowIfAborted,
|
|
176
177
|
} from "./abort-error.js";
|
|
177
178
|
import { CODEX_THREAD_KEY_PREFIX } from "./thread-key.js";
|
|
@@ -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
|
|
@@ -2021,10 +2001,14 @@ export class Orchestrator {
|
|
|
2021
2001
|
suppressedReasonCounts: Record<string, number>;
|
|
2022
2002
|
} = { detected: 0, queued: 0, autoApplied: 0, suppressedReasonCounts: {} };
|
|
2023
2003
|
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2004
|
+
/**
|
|
2005
|
+
* Background serial extraction queue coordinator (issue #1526 — moved
|
|
2006
|
+
* from inline `extractionQueue`/`queueProcessing` fields). Owns queue
|
|
2007
|
+
* state + scheduling + the serial drain + failure classification; the
|
|
2008
|
+
* orchestrator builds each task closure in `queueBufferedExtraction` and
|
|
2009
|
+
* hands it to `enqueue`.
|
|
2010
|
+
*/
|
|
2011
|
+
readonly extractionQueueCoordinator: ExtractionQueueCoordinator;
|
|
2028
2012
|
private heartbeatObserverChains = new Map<string, Promise<void>>();
|
|
2029
2013
|
private recentExtractionFingerprints = new Map<string, number>();
|
|
2030
2014
|
private readonly consolidationObservers = new Set<
|
|
@@ -2991,6 +2975,8 @@ export class Orchestrator {
|
|
|
2991
2975
|
namespaceSearchRouter: this.namespaceSearchRouter,
|
|
2992
2976
|
namespaceCatalog: this.namespaceCatalog,
|
|
2993
2977
|
});
|
|
2978
|
+
// Issue #1526: background extraction queue lives on its own coordinator.
|
|
2979
|
+
this.extractionQueueCoordinator = new ExtractionQueueCoordinator();
|
|
2994
2980
|
const conversationIndexRuntime = createConversationIndexRuntime(config, {
|
|
2995
2981
|
getQmd: () => this.conversationQmd,
|
|
2996
2982
|
getFaiss: () => this.conversationFaiss,
|
|
@@ -3027,6 +3013,12 @@ export class Orchestrator {
|
|
|
3027
3013
|
getCompounding: () => this.compounding,
|
|
3028
3014
|
createColdStorage: (parentDir) => new StorageManager(parentDir),
|
|
3029
3015
|
});
|
|
3016
|
+
this.compressionGuidelineCoordinator = new CompressionGuidelineCoordinator({
|
|
3017
|
+
config,
|
|
3018
|
+
getStorage: () => this.storage,
|
|
3019
|
+
fastChatCompletion: (messages, options) =>
|
|
3020
|
+
this.fastChatCompletion(messages, options),
|
|
3021
|
+
});
|
|
3030
3022
|
this.sessionObserver = new SessionObserverState({
|
|
3031
3023
|
memoryDir: config.memoryDir,
|
|
3032
3024
|
debounceMs: config.sessionObserverDebounceMs ?? 120_000,
|
|
@@ -3468,6 +3460,31 @@ export class Orchestrator {
|
|
|
3468
3460
|
// never break initialization (rule #13, #40).
|
|
3469
3461
|
await this.namespaceCatalog.registerConfiguredNamespaces().catch(() => undefined);
|
|
3470
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
|
+
}
|
|
3471
3488
|
await this.relevance.load();
|
|
3472
3489
|
await this.negatives.load();
|
|
3473
3490
|
await this.lastRecall.load();
|
|
@@ -3750,7 +3767,7 @@ export class Orchestrator {
|
|
|
3750
3767
|
await Promise.all(cacheWarmups);
|
|
3751
3768
|
if (signal.aborted) return;
|
|
3752
3769
|
|
|
3753
|
-
if (this.config.
|
|
3770
|
+
if (resolveIndexingCapabilities(this.config).conversationIndex && this.conversationIndexBackend) {
|
|
3754
3771
|
try {
|
|
3755
3772
|
const init = await this.conversationIndexBackend.initialize();
|
|
3756
3773
|
if (!init.enabled) {
|
|
@@ -4560,7 +4577,7 @@ export class Orchestrator {
|
|
|
4560
4577
|
}
|
|
4561
4578
|
|
|
4562
4579
|
// Write the canonical memory
|
|
4563
|
-
const canonicalId = await targetStorage.writeMemory(
|
|
4580
|
+
const { id: canonicalId, tombstoneBlocked: canonicalBlocked } = await targetStorage.writeMemory(
|
|
4564
4581
|
newest.frontmatter.category,
|
|
4565
4582
|
canonicalContent,
|
|
4566
4583
|
{
|
|
@@ -4577,6 +4594,12 @@ export class Orchestrator {
|
|
|
4577
4594
|
derivedVia: operator,
|
|
4578
4595
|
},
|
|
4579
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
|
+
}
|
|
4580
4603
|
canonicalWriteCompleted = true;
|
|
4581
4604
|
|
|
4582
4605
|
result.memoriesConsolidated++;
|
|
@@ -4603,7 +4626,7 @@ export class Orchestrator {
|
|
|
4603
4626
|
try {
|
|
4604
4627
|
await this.embeddingFallback.removeFromIndex(m.frontmatter.id);
|
|
4605
4628
|
if (
|
|
4606
|
-
this.config.
|
|
4629
|
+
resolveIndexingCapabilities(this.config).queryAwareIndexing &&
|
|
4607
4630
|
m.path &&
|
|
4608
4631
|
m.frontmatter?.created
|
|
4609
4632
|
) {
|
|
@@ -4720,15 +4743,8 @@ export class Orchestrator {
|
|
|
4720
4743
|
}
|
|
4721
4744
|
|
|
4722
4745
|
async waitForExtractionIdle(timeoutMs: number = 60_000): Promise<boolean> {
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
if (Date.now() - started > timeoutMs) {
|
|
4726
|
-
log.warn(`waitForExtractionIdle timed out after ${timeoutMs}ms`);
|
|
4727
|
-
return false;
|
|
4728
|
-
}
|
|
4729
|
-
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
4730
|
-
}
|
|
4731
|
-
return true;
|
|
4746
|
+
// Issue #1526: queue state + idle wait moved to ExtractionQueueCoordinator.
|
|
4747
|
+
return this.extractionQueueCoordinator.waitForIdle(timeoutMs);
|
|
4732
4748
|
}
|
|
4733
4749
|
|
|
4734
4750
|
async waitForConsolidationIdle(timeoutMs: number = 60_000): Promise<boolean> {
|
|
@@ -5649,7 +5665,7 @@ export class Orchestrator {
|
|
|
5649
5665
|
const lastUpdateAt =
|
|
5650
5666
|
lastUpdateAtMs > 0 ? new Date(lastUpdateAtMs).toISOString() : null;
|
|
5651
5667
|
|
|
5652
|
-
if (!this.config.
|
|
5668
|
+
if (!resolveIndexingCapabilities(this.config).conversationIndex) {
|
|
5653
5669
|
return {
|
|
5654
5670
|
enabled: false,
|
|
5655
5671
|
backend: this.config.conversationIndexBackend,
|
|
@@ -5689,7 +5705,7 @@ export class Orchestrator {
|
|
|
5689
5705
|
const lastUpdateAt =
|
|
5690
5706
|
lastUpdateAtMs > 0 ? new Date(lastUpdateAtMs).toISOString() : null;
|
|
5691
5707
|
|
|
5692
|
-
if (!this.config.
|
|
5708
|
+
if (!resolveIndexingCapabilities(this.config).conversationIndex) {
|
|
5693
5709
|
return {
|
|
5694
5710
|
enabled: false,
|
|
5695
5711
|
backend: this.config.conversationIndexBackend,
|
|
@@ -5751,7 +5767,7 @@ export class Orchestrator {
|
|
|
5751
5767
|
retryAfterMs?: number;
|
|
5752
5768
|
embedded?: boolean;
|
|
5753
5769
|
}> {
|
|
5754
|
-
if (!this.config.
|
|
5770
|
+
if (!resolveIndexingCapabilities(this.config).conversationIndex) {
|
|
5755
5771
|
return { chunks: 0, skipped: true, reason: "disabled", embedded: false };
|
|
5756
5772
|
}
|
|
5757
5773
|
const enforceMinInterval = opts?.enforceMinInterval !== false;
|
|
@@ -5812,7 +5828,7 @@ export class Orchestrator {
|
|
|
5812
5828
|
embedded?: boolean;
|
|
5813
5829
|
rebuilt?: boolean;
|
|
5814
5830
|
}> {
|
|
5815
|
-
if (!this.config.
|
|
5831
|
+
if (!resolveIndexingCapabilities(this.config).conversationIndex) {
|
|
5816
5832
|
return {
|
|
5817
5833
|
chunks: 0,
|
|
5818
5834
|
skipped: true,
|
|
@@ -6417,7 +6433,7 @@ export class Orchestrator {
|
|
|
6417
6433
|
prompt: string,
|
|
6418
6434
|
recallNamespaces: string[],
|
|
6419
6435
|
): Promise<QueryAwarePrefilter> {
|
|
6420
|
-
if (!this.config.
|
|
6436
|
+
if (!resolveIndexingCapabilities(this.config).queryAwareIndexing || !prompt.trim()) {
|
|
6421
6437
|
return {
|
|
6422
6438
|
candidatePaths: null,
|
|
6423
6439
|
temporalFromDate: null,
|
|
@@ -9209,7 +9225,7 @@ export class Orchestrator {
|
|
|
9209
9225
|
const workProductsPromise = (async (): Promise<string | null> => {
|
|
9210
9226
|
const t0 = Date.now();
|
|
9211
9227
|
if (
|
|
9212
|
-
!this.config.
|
|
9228
|
+
!resolveCreationMemoryCapabilities(this.config).creationMemory ||
|
|
9213
9229
|
!this.config.workProductRecallEnabled ||
|
|
9214
9230
|
!this.isRecallSectionEnabled(
|
|
9215
9231
|
"work-products",
|
|
@@ -9284,7 +9300,7 @@ export class Orchestrator {
|
|
|
9284
9300
|
const queryAwarePrefilterPromise =
|
|
9285
9301
|
(async (): Promise<QueryAwarePrefilter> => {
|
|
9286
9302
|
const t0 = Date.now();
|
|
9287
|
-
if (!this.config.
|
|
9303
|
+
if (!resolveIndexingCapabilities(this.config).queryAwareIndexing || !prompt.trim()) {
|
|
9288
9304
|
recordRecallSectionMetric({
|
|
9289
9305
|
section: "queryAware",
|
|
9290
9306
|
priority: "enrichment",
|
|
@@ -10030,7 +10046,7 @@ export class Orchestrator {
|
|
|
10030
10046
|
const conversationRecallPromise = (async (): Promise<string | null> => {
|
|
10031
10047
|
const t0 = Date.now();
|
|
10032
10048
|
if (
|
|
10033
|
-
!this.config.
|
|
10049
|
+
!resolveIndexingCapabilities(this.config).conversationIndex ||
|
|
10034
10050
|
queryPolicy.skipConversationRecall ||
|
|
10035
10051
|
!this.isRecallSectionEnabled("conversation-recall", true)
|
|
10036
10052
|
) {
|
|
@@ -13165,7 +13181,7 @@ export class Orchestrator {
|
|
|
13165
13181
|
}, remainingMs);
|
|
13166
13182
|
}
|
|
13167
13183
|
|
|
13168
|
-
this.
|
|
13184
|
+
this.extractionQueueCoordinator.enqueue(async () => {
|
|
13169
13185
|
if (settled) return;
|
|
13170
13186
|
if (
|
|
13171
13187
|
typeof extractionDeadlineMs === "number" &&
|
|
@@ -13196,13 +13212,6 @@ export class Orchestrator {
|
|
|
13196
13212
|
}
|
|
13197
13213
|
});
|
|
13198
13214
|
|
|
13199
|
-
if (!this.queueProcessing) {
|
|
13200
|
-
this.queueProcessing = true;
|
|
13201
|
-
this.processQueue().catch((err) => {
|
|
13202
|
-
this.logExtractionQueueFailure(err, "processor");
|
|
13203
|
-
this.queueProcessing = false;
|
|
13204
|
-
});
|
|
13205
|
-
}
|
|
13206
13215
|
log.debug(`queued extraction from ${reason}`);
|
|
13207
13216
|
}
|
|
13208
13217
|
|
|
@@ -13270,62 +13279,6 @@ export class Orchestrator {
|
|
|
13270
13279
|
return true;
|
|
13271
13280
|
}
|
|
13272
13281
|
|
|
13273
|
-
/**
|
|
13274
|
-
* Background serial queue processor.
|
|
13275
|
-
* Processes extractions one at a time to avoid race conditions.
|
|
13276
|
-
* Called automatically when items are queued.
|
|
13277
|
-
*/
|
|
13278
|
-
private async processQueue(): Promise<void> {
|
|
13279
|
-
while (this.extractionQueue.length > 0) {
|
|
13280
|
-
const task = this.extractionQueue.shift();
|
|
13281
|
-
if (task) {
|
|
13282
|
-
try {
|
|
13283
|
-
await task();
|
|
13284
|
-
} catch (err) {
|
|
13285
|
-
this.logExtractionQueueFailure(err, "task");
|
|
13286
|
-
}
|
|
13287
|
-
}
|
|
13288
|
-
}
|
|
13289
|
-
|
|
13290
|
-
this.queueProcessing = false;
|
|
13291
|
-
}
|
|
13292
|
-
|
|
13293
|
-
/**
|
|
13294
|
-
* Classify + log a failure from either the per-task catch inside
|
|
13295
|
-
* `processQueue()` or the outer `processQueue().catch(...)` in
|
|
13296
|
-
* `queueBufferedExtraction()`. Issue #549: `throwIfRecallAborted`
|
|
13297
|
-
* (used throughout `runExtraction`) raises an Error whose `name` is
|
|
13298
|
-
* `"AbortError"`. That path fires when `before_reset` aborts a
|
|
13299
|
-
* queued task to avoid duplicate extraction — it is intentional
|
|
13300
|
-
* cancellation, not a failure. Downgrading the log to debug
|
|
13301
|
-
* prevents spurious `error`-level lines that routinely appear
|
|
13302
|
-
* right next to a successful `persisted: N facts, M entities` log
|
|
13303
|
-
* and that confuse operators into thinking extraction is broken.
|
|
13304
|
-
* Genuine extraction failures (network, parse, I/O) still log at
|
|
13305
|
-
* `error`.
|
|
13306
|
-
*
|
|
13307
|
-
* Source differentiates the two call sites so the log message
|
|
13308
|
-
* names the right layer (`task` vs `processor`).
|
|
13309
|
-
*/
|
|
13310
|
-
private logExtractionQueueFailure(
|
|
13311
|
-
err: unknown,
|
|
13312
|
-
source: "task" | "processor",
|
|
13313
|
-
): void {
|
|
13314
|
-
const aborted =
|
|
13315
|
-
source === "task"
|
|
13316
|
-
? "background extraction task aborted (session transition)"
|
|
13317
|
-
: "background extraction queue processor aborted (session transition)";
|
|
13318
|
-
const failed =
|
|
13319
|
-
source === "task"
|
|
13320
|
-
? "background extraction task failed"
|
|
13321
|
-
: "background extraction queue processor failed";
|
|
13322
|
-
if (isAbortError(err)) {
|
|
13323
|
-
log.debug(aborted);
|
|
13324
|
-
} else {
|
|
13325
|
-
log.error(failed, err);
|
|
13326
|
-
}
|
|
13327
|
-
}
|
|
13328
|
-
|
|
13329
13282
|
/**
|
|
13330
13283
|
* Passive correction capture (issue #1581) — detects corrections expressed
|
|
13331
13284
|
* passively in conversation turns and routes them to the Correction Contract
|
|
@@ -14237,6 +14190,10 @@ export class Orchestrator {
|
|
|
14237
14190
|
sharedProfileLayer.writable &&
|
|
14238
14191
|
sharedPromotionTarget?.authorized,
|
|
14239
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;
|
|
14240
14197
|
const profileAutoPromotionAllows = (
|
|
14241
14198
|
category: string,
|
|
14242
14199
|
confidence: number,
|
|
@@ -14369,7 +14326,7 @@ export class Orchestrator {
|
|
|
14369
14326
|
}
|
|
14370
14327
|
continue;
|
|
14371
14328
|
}
|
|
14372
|
-
const
|
|
14329
|
+
const targetPromotion = await targetStorage.writeMemory(
|
|
14373
14330
|
options.category as any,
|
|
14374
14331
|
citedContent,
|
|
14375
14332
|
{
|
|
@@ -14395,7 +14352,11 @@ export class Orchestrator {
|
|
|
14395
14352
|
...(options.provenance ? { provenance: options.provenance } : {}),
|
|
14396
14353
|
},
|
|
14397
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.
|
|
14398
14358
|
if (
|
|
14359
|
+
!targetPromotion.tombstoneBlocked &&
|
|
14399
14360
|
lifecycleCaps.temporalSupersession &&
|
|
14400
14361
|
options.category === "fact" &&
|
|
14401
14362
|
options.entityRef &&
|
|
@@ -14417,19 +14378,23 @@ export class Orchestrator {
|
|
|
14417
14378
|
);
|
|
14418
14379
|
}
|
|
14419
14380
|
}
|
|
14420
|
-
|
|
14421
|
-
|
|
14422
|
-
|
|
14423
|
-
targetStorage,
|
|
14424
|
-
|
|
14425
|
-
|
|
14426
|
-
|
|
14427
|
-
|
|
14428
|
-
|
|
14429
|
-
|
|
14430
|
-
|
|
14431
|
-
|
|
14432
|
-
|
|
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
|
+
}
|
|
14433
14398
|
} catch (err) {
|
|
14434
14399
|
log.warn(
|
|
14435
14400
|
`persistExtraction: ${target.target} promotion failed open for ${options.sourceMemoryId}: ${err}`,
|
|
@@ -14688,7 +14653,7 @@ export class Orchestrator {
|
|
|
14688
14653
|
return;
|
|
14689
14654
|
}
|
|
14690
14655
|
}
|
|
14691
|
-
const
|
|
14656
|
+
const sharedPromotion = await sharedStorage.writeMemory(
|
|
14692
14657
|
options.category as any,
|
|
14693
14658
|
citedContent,
|
|
14694
14659
|
{
|
|
@@ -14715,6 +14680,9 @@ export class Orchestrator {
|
|
|
14715
14680
|
...(options.provenance ? { provenance: options.provenance } : {}),
|
|
14716
14681
|
},
|
|
14717
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.
|
|
14718
14686
|
// PR #402 Finding 3 fix: run temporal supersession against the shared
|
|
14719
14687
|
// namespace after the promoted write lands so stale shared-namespace
|
|
14720
14688
|
// copies of the same entity attribute are retired. Without this,
|
|
@@ -14722,6 +14690,7 @@ export class Orchestrator {
|
|
|
14722
14690
|
// shared recall continues returning the stale state. Reuses the same
|
|
14723
14691
|
// applyTemporalSupersession helper — no logic duplication.
|
|
14724
14692
|
if (
|
|
14693
|
+
!sharedPromotion.tombstoneBlocked &&
|
|
14725
14694
|
lifecycleCaps.temporalSupersession &&
|
|
14726
14695
|
options.entityRef &&
|
|
14727
14696
|
options.structuredAttributes &&
|
|
@@ -14751,21 +14720,24 @@ export class Orchestrator {
|
|
|
14751
14720
|
// the same promotion pass. The hot-path source-namespace touch uses a
|
|
14752
14721
|
// different storage dir, so this does not double-count the source.
|
|
14753
14722
|
// Best-effort and failure-tolerant — it must never crash the promotion.
|
|
14754
|
-
|
|
14755
|
-
|
|
14756
|
-
|
|
14757
|
-
|
|
14758
|
-
|
|
14759
|
-
sharedStorage,
|
|
14760
|
-
|
|
14761
|
-
|
|
14762
|
-
|
|
14763
|
-
|
|
14764
|
-
|
|
14765
|
-
|
|
14766
|
-
|
|
14767
|
-
|
|
14768
|
-
|
|
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
|
+
}
|
|
14769
14741
|
} catch (err) {
|
|
14770
14742
|
log.warn(
|
|
14771
14743
|
`persistExtraction: shared promotion failed open for ${options.sourceMemoryId}: ${err}`,
|
|
@@ -14992,6 +14964,10 @@ export class Orchestrator {
|
|
|
14992
14964
|
// these pre-computed results so routing is evaluated exactly once per
|
|
14993
14965
|
// fact (no duplicated logic).
|
|
14994
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);
|
|
14995
14971
|
if (routeRules.length > 0) {
|
|
14996
14972
|
for (let fi = 0; fi < facts.length; fi++) {
|
|
14997
14973
|
const f = facts[fi];
|
|
@@ -15011,6 +14987,9 @@ export class Orchestrator {
|
|
|
15011
14987
|
if (selected?.target.category) {
|
|
15012
14988
|
preRoutedCategories[fi] = selected.target.category;
|
|
15013
14989
|
}
|
|
14990
|
+
if (selected?.target.namespace) {
|
|
14991
|
+
preRoutedNamespaceByFact[fi] = selected.target.namespace;
|
|
14992
|
+
}
|
|
15014
14993
|
} catch {
|
|
15015
14994
|
// Fail-open: routing errors fall through to the extracted category.
|
|
15016
14995
|
}
|
|
@@ -15033,10 +15012,18 @@ export class Orchestrator {
|
|
|
15033
15012
|
// into the caller's buffer-retention decision.
|
|
15034
15013
|
this.lastPersistExtractionDeferredCount = 0;
|
|
15035
15014
|
if (lifecycleCaps.extractionJudge) {
|
|
15036
|
-
// #1669 P1: pre-filter redacted facts from judge candidates
|
|
15037
|
-
// 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.
|
|
15038
15020
|
let preJudgeRedactionRules: CompiledRedactionRule[] = [];
|
|
15039
|
-
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 */ }
|
|
15040
15027
|
try {
|
|
15041
15028
|
const judgeCandidates: JudgeCandidate[] = [];
|
|
15042
15029
|
const candidateToFactIndex: number[] = [];
|
|
@@ -15077,10 +15064,42 @@ export class Orchestrator {
|
|
|
15077
15064
|
) {
|
|
15078
15065
|
continue;
|
|
15079
15066
|
}
|
|
15080
|
-
|
|
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) {
|
|
15081
15100
|
const rc = f.content + (f.structuredAttributes ? " " + JSON.stringify(f.structuredAttributes) : "")
|
|
15082
15101
|
+ (f.procedureSteps ? " " + f.procedureSteps.map((s) => `${s.intent} ${s.expectedOutcome ?? ""} ${s.toolCall ? `${s.toolCall.kind} ${s.toolCall.signature}` : ""}`.trim()).join(" ") : "");
|
|
15083
|
-
if (contentMatchesRedactionRules(rc,
|
|
15102
|
+
if (contentMatchesRedactionRules(rc, factRedactionRules)) continue;
|
|
15084
15103
|
}
|
|
15085
15104
|
judgeCandidates.push({
|
|
15086
15105
|
text: f.content,
|
|
@@ -15310,7 +15329,7 @@ export class Orchestrator {
|
|
|
15310
15329
|
// extractionScopeClassificationEnabled.
|
|
15311
15330
|
if (
|
|
15312
15331
|
lifecycleCaps.extractionScopeClassification &&
|
|
15313
|
-
|
|
15332
|
+
namespacesEnabled &&
|
|
15314
15333
|
fact.scope === "global" &&
|
|
15315
15334
|
!routedNamespaceExplicit
|
|
15316
15335
|
) {
|
|
@@ -15667,6 +15686,16 @@ export class Orchestrator {
|
|
|
15667
15686
|
// `supersedes` is intentionally left unset to avoid retiring the old
|
|
15668
15687
|
// memory without user confirmation).
|
|
15669
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;
|
|
15670
15699
|
|
|
15671
15700
|
// Faithfulness gate (#1576, chatgpt P2): skip contradiction detection
|
|
15672
15701
|
// for a pending_review fact — an unfaithful extraction in the review queue
|
|
@@ -15677,7 +15706,7 @@ export class Orchestrator {
|
|
|
15677
15706
|
faithfulnessEnforceStatus !== "pending_review"
|
|
15678
15707
|
) {
|
|
15679
15708
|
const targetNamespace = this.storageDirNamespace(targetStorage.dir);
|
|
15680
|
-
|
|
15709
|
+
contradiction = await this.checkForContradiction(
|
|
15681
15710
|
fact.content,
|
|
15682
15711
|
writeCategory,
|
|
15683
15712
|
targetNamespace,
|
|
@@ -15699,22 +15728,10 @@ export class Orchestrator {
|
|
|
15699
15728
|
strength: contradiction.confidence,
|
|
15700
15729
|
reason: contradiction.reason,
|
|
15701
15730
|
});
|
|
15702
|
-
//
|
|
15703
|
-
//
|
|
15704
|
-
//
|
|
15705
|
-
//
|
|
15706
|
-
if (
|
|
15707
|
-
this.config.contradictionAutoResolve &&
|
|
15708
|
-
this.config.queryAwareIndexingEnabled &&
|
|
15709
|
-
contradiction.supersededPath
|
|
15710
|
-
) {
|
|
15711
|
-
deindexMemory(
|
|
15712
|
-
this.config.memoryDir,
|
|
15713
|
-
contradiction.supersededPath,
|
|
15714
|
-
contradiction.supersededCreated,
|
|
15715
|
-
contradiction.supersededTags,
|
|
15716
|
-
);
|
|
15717
|
-
}
|
|
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.
|
|
15718
15735
|
}
|
|
15719
15736
|
}
|
|
15720
15737
|
|
|
@@ -15829,7 +15846,7 @@ export class Orchestrator {
|
|
|
15829
15846
|
? stripCitationForTemplate(fact.content, citationTemplate)
|
|
15830
15847
|
: fact.content;
|
|
15831
15848
|
const citedChunkedContent = applyInlineCitation(rawChunkedContent);
|
|
15832
|
-
const
|
|
15849
|
+
const parentWrite = await targetStorage.writeMemory(
|
|
15833
15850
|
writeCategory,
|
|
15834
15851
|
citedChunkedContent,
|
|
15835
15852
|
{
|
|
@@ -15856,6 +15873,20 @@ export class Orchestrator {
|
|
|
15856
15873
|
...(fact.provenance ? { provenance: fact.provenance } : {}),
|
|
15857
15874
|
},
|
|
15858
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
|
+
);
|
|
15859
15890
|
try {
|
|
15860
15891
|
// Write individual chunks with parent reference
|
|
15861
15892
|
for (const chunk of chunkResult.chunks) {
|
|
@@ -15903,7 +15934,13 @@ export class Orchestrator {
|
|
|
15903
15934
|
// fact's verdict + enforce status so a pending_review fact
|
|
15904
15935
|
// is not indexed as active through its chunks (chatgpt P2).
|
|
15905
15936
|
...(faithfulnessFm ? { faithfulness: faithfulnessFm } : {}),
|
|
15906
|
-
|
|
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
|
+
: {}),
|
|
15907
15944
|
// Claim-level provenance (issue #1575 PR 2): mirror the
|
|
15908
15945
|
// parent's spans onto each chunk so a chunk surfaced
|
|
15909
15946
|
// independently (memory_get/x-ray on a chunk ID) preserves
|
|
@@ -15930,24 +15967,28 @@ export class Orchestrator {
|
|
|
15930
15967
|
`chunked memory ${parentId} into ${chunkResult.chunks.length} chunks`,
|
|
15931
15968
|
);
|
|
15932
15969
|
trackPersistedId(targetStorage, parentId, {
|
|
15933
|
-
pendingReview:
|
|
15970
|
+
pendingReview: postWriteGuard,
|
|
15934
15971
|
});
|
|
15935
15972
|
// #1576 (cursor Medium): keep pending_review ids out of threadEpisodeIdsForGraph — else later active facts build thread-predecessor edges to an unfaithful memory.
|
|
15936
15973
|
if (
|
|
15937
|
-
|
|
15974
|
+
!postWriteGuard &&
|
|
15938
15975
|
threadEpisodeIdsForGraph &&
|
|
15939
15976
|
!threadEpisodeIdsForGraph.includes(parentId)
|
|
15940
15977
|
) {
|
|
15941
15978
|
threadEpisodeIdsForGraph.push(parentId);
|
|
15942
15979
|
}
|
|
15943
|
-
|
|
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
|
+
}
|
|
15944
15985
|
// PR #402 Thread 1 fix: run source-namespace temporal supersession for
|
|
15945
15986
|
// chunked writes, matching the non-chunked path. Without this the
|
|
15946
15987
|
// source namespace retains stale facts that should have been superseded.
|
|
15947
15988
|
// Faithfulness gate (#1576, cursor High): skip supersession for a
|
|
15948
15989
|
// pending_review fact — an unfaithful extraction in the review queue
|
|
15949
15990
|
// must NOT retire older active memories.
|
|
15950
|
-
if (
|
|
15991
|
+
if (!postWriteGuard) {
|
|
15951
15992
|
try {
|
|
15952
15993
|
const supersessionEntityRef =
|
|
15953
15994
|
typeof (fact as any).entityRef === "string"
|
|
@@ -15972,7 +16013,7 @@ export class Orchestrator {
|
|
|
15972
16013
|
// Faithfulness gate (#1576, chatgpt P2): do not promote a
|
|
15973
16014
|
// pending_review fact to shared/profile — it must enter the review
|
|
15974
16015
|
// queue without active copies that bypass the gate.
|
|
15975
|
-
if (
|
|
16016
|
+
if (!postWriteGuard) await promoteMemoryToShared({
|
|
15976
16017
|
sourceStorage: targetStorage,
|
|
15977
16018
|
category: writeCategory,
|
|
15978
16019
|
content: fact.content,
|
|
@@ -16007,7 +16048,13 @@ export class Orchestrator {
|
|
|
16007
16048
|
hasCitationForTemplate(fact.content, citationTemplate)
|
|
16008
16049
|
? stripCitationForTemplate(fact.content, citationTemplate)
|
|
16009
16050
|
: fact.content;
|
|
16010
|
-
|
|
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
|
+
}
|
|
16011
16058
|
} catch (err) {
|
|
16012
16059
|
log.warn(
|
|
16013
16060
|
`content-hash dedup registration failed for chunked memory ${parentId}: ${err}`,
|
|
@@ -16020,14 +16067,18 @@ export class Orchestrator {
|
|
|
16020
16067
|
// into boxBuilder.onExtraction() or threading.processTurn(), which
|
|
16021
16068
|
// only expect canonical parent memory IDs. Call indexPersistedMemory
|
|
16022
16069
|
// directly for embedding-fallback sync of each chunk document.
|
|
16023
|
-
|
|
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
|
+
}
|
|
16024
16075
|
}
|
|
16025
16076
|
try {
|
|
16026
16077
|
if (
|
|
16027
16078
|
this.config.verbatimArtifactsEnabled &&
|
|
16028
16079
|
this.config.verbatimArtifactCategories.includes(writeCategory) &&
|
|
16029
16080
|
fact.confidence >= this.config.verbatimArtifactsMinConfidence &&
|
|
16030
|
-
|
|
16081
|
+
!postWriteGuard
|
|
16031
16082
|
) {
|
|
16032
16083
|
// Reuse citedChunkedContent so the artifact carries the same citation
|
|
16033
16084
|
// timestamp as the parent memory write above (Fix #3 — duplicate-citation).
|
|
@@ -16042,7 +16093,7 @@ export class Orchestrator {
|
|
|
16042
16093
|
});
|
|
16043
16094
|
}
|
|
16044
16095
|
// v8.2: graph edge building for chunked memories. #1576: skip pending_review.
|
|
16045
|
-
if (graphCaps.multiGraphMemory &&
|
|
16096
|
+
if (graphCaps.multiGraphMemory && !postWriteGuard) {
|
|
16046
16097
|
try {
|
|
16047
16098
|
const graphContext = await ensureGraphContext(targetStorage);
|
|
16048
16099
|
const entityRef =
|
|
@@ -16144,7 +16195,7 @@ export class Orchestrator {
|
|
|
16144
16195
|
? buildProcedurePersistBody(fact.content, fact.procedureSteps)
|
|
16145
16196
|
: fact.content;
|
|
16146
16197
|
const citedFactContent = applyInlineCitation(rawPersistBody);
|
|
16147
|
-
const
|
|
16198
|
+
const factWrite = await targetStorage.writeMemory(
|
|
16148
16199
|
writeCategory,
|
|
16149
16200
|
citedFactContent,
|
|
16150
16201
|
{
|
|
@@ -16176,6 +16227,20 @@ export class Orchestrator {
|
|
|
16176
16227
|
...(fact.provenance ? { provenance: fact.provenance } : {}),
|
|
16177
16228
|
},
|
|
16178
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
|
+
);
|
|
16179
16244
|
if (routedRuleId) {
|
|
16180
16245
|
log.debug(
|
|
16181
16246
|
`routing applied for memory ${memoryId}: rule=${routedRuleId} category=${writeCategory} storage=${targetStorage.dir}`,
|
|
@@ -16186,7 +16251,7 @@ export class Orchestrator {
|
|
|
16186
16251
|
// key that has a conflicting value. Faithfulness gate (#1576, cursor
|
|
16187
16252
|
// High): skip for a pending_review fact — an unfaithful extraction in
|
|
16188
16253
|
// the review queue must NOT retire older active memories.
|
|
16189
|
-
if (
|
|
16254
|
+
if (!postWriteGuard) {
|
|
16190
16255
|
try {
|
|
16191
16256
|
const supersessionEntityRef =
|
|
16192
16257
|
typeof (fact as any).entityRef === "string"
|
|
@@ -16218,19 +16283,25 @@ export class Orchestrator {
|
|
|
16218
16283
|
}),
|
|
16219
16284
|
);
|
|
16220
16285
|
trackPersistedId(targetStorage, memoryId, {
|
|
16221
|
-
pendingReview:
|
|
16286
|
+
pendingReview: postWriteGuard,
|
|
16222
16287
|
});
|
|
16223
16288
|
if (
|
|
16224
|
-
|
|
16289
|
+
!postWriteGuard &&
|
|
16225
16290
|
threadEpisodeIdsForGraph &&
|
|
16226
16291
|
!threadEpisodeIdsForGraph.includes(memoryId)
|
|
16227
16292
|
) {
|
|
16228
16293
|
threadEpisodeIdsForGraph.push(memoryId);
|
|
16229
16294
|
}
|
|
16230
|
-
|
|
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
|
+
}
|
|
16231
16302
|
// Faithfulness gate (#1576, chatgpt P2): skip promotion for a
|
|
16232
16303
|
// pending_review fact so no active shared/profile copy bypasses the gate.
|
|
16233
|
-
if (
|
|
16304
|
+
if (!postWriteGuard) await promoteMemoryToShared({
|
|
16234
16305
|
sourceStorage: targetStorage,
|
|
16235
16306
|
category: writeCategory,
|
|
16236
16307
|
content: fact.content,
|
|
@@ -16260,7 +16331,7 @@ export class Orchestrator {
|
|
|
16260
16331
|
...(fact.provenance ? { provenance: fact.provenance } : {}),
|
|
16261
16332
|
});
|
|
16262
16333
|
// v8.2: graph edge building (fail-open). #1576: skip pending_review facts.
|
|
16263
|
-
if (graphCaps.multiGraphMemory &&
|
|
16334
|
+
if (graphCaps.multiGraphMemory && !postWriteGuard) {
|
|
16264
16335
|
try {
|
|
16265
16336
|
const graphContext = await ensureGraphContext(targetStorage);
|
|
16266
16337
|
const entityRef =
|
|
@@ -16304,7 +16375,7 @@ export class Orchestrator {
|
|
|
16304
16375
|
this.config.verbatimArtifactsEnabled &&
|
|
16305
16376
|
this.config.verbatimArtifactCategories.includes(writeCategory) &&
|
|
16306
16377
|
fact.confidence >= this.config.verbatimArtifactsMinConfidence &&
|
|
16307
|
-
|
|
16378
|
+
!postWriteGuard
|
|
16308
16379
|
) {
|
|
16309
16380
|
// Reuse citedFactContent so the artifact carries the same citation
|
|
16310
16381
|
// timestamp as the memory write above (Fix #3 — duplicate-citation).
|
|
@@ -16331,7 +16402,11 @@ export class Orchestrator {
|
|
|
16331
16402
|
writeCategory === "procedure"
|
|
16332
16403
|
? buildProcedurePersistBody(fact.content, fact.procedureSteps)
|
|
16333
16404
|
: canonicalFactContent;
|
|
16334
|
-
|
|
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
|
+
}
|
|
16335
16410
|
} catch (err) {
|
|
16336
16411
|
log.warn(
|
|
16337
16412
|
`content-hash dedup registration failed for memory ${memoryId}: ${err}`,
|
|
@@ -16681,7 +16756,7 @@ export class Orchestrator {
|
|
|
16681
16756
|
// Enabling only parallelRetrievalEnabled without queryAwareIndexingEnabled would silently
|
|
16682
16757
|
// produce an empty temporal index, leaving the temporal agent with no data to work from.
|
|
16683
16758
|
if (
|
|
16684
|
-
!this.config.
|
|
16759
|
+
!resolveIndexingCapabilities(this.config).queryAwareIndexing &&
|
|
16685
16760
|
!caps.parallelRetrieval
|
|
16686
16761
|
)
|
|
16687
16762
|
return;
|
|
@@ -16796,7 +16871,7 @@ export class Orchestrator {
|
|
|
16796
16871
|
|
|
16797
16872
|
// Build a lookup map from the already-loaded corpus to avoid repeated
|
|
16798
16873
|
// readAllMemories() scans inside getMemoryById for pre-action deindex reads.
|
|
16799
|
-
const memoryLookup = this.config.
|
|
16874
|
+
const memoryLookup = resolveIndexingCapabilities(this.config).queryAwareIndexing
|
|
16800
16875
|
? new Map(allMemories.map((m) => [m.frontmatter.id, m]))
|
|
16801
16876
|
: null;
|
|
16802
16877
|
|
|
@@ -16804,7 +16879,7 @@ export class Orchestrator {
|
|
|
16804
16879
|
switch (item.action) {
|
|
16805
16880
|
case "INVALIDATE": {
|
|
16806
16881
|
// Capture path/frontmatter before invalidation for index cleanup
|
|
16807
|
-
const toInvalidate = this.config.
|
|
16882
|
+
const toInvalidate = resolveIndexingCapabilities(this.config).queryAwareIndexing
|
|
16808
16883
|
? (memoryLookup?.get(item.existingId) ?? null)
|
|
16809
16884
|
: null;
|
|
16810
16885
|
if (await this.storage.invalidateMemory(item.existingId)) {
|
|
@@ -16852,7 +16927,7 @@ export class Orchestrator {
|
|
|
16852
16927
|
// updateMemory() only changes content/updated/supersedes/lineage — path, created, and tags
|
|
16853
16928
|
// are preserved, so the temporal/tag index entry for the survivor is already correct.
|
|
16854
16929
|
// Capture before invalidation for index cleanup
|
|
16855
|
-
const toMergeInvalidate = this.config.
|
|
16930
|
+
const toMergeInvalidate = resolveIndexingCapabilities(this.config).queryAwareIndexing
|
|
16856
16931
|
? (memoryLookup?.get(item.mergeWith) ?? null)
|
|
16857
16932
|
: null;
|
|
16858
16933
|
if (await this.storage.invalidateMemory(item.mergeWith)) {
|
|
@@ -16938,7 +17013,7 @@ export class Orchestrator {
|
|
|
16938
17013
|
if (deletedCommitments.length > 0) {
|
|
16939
17014
|
memoryItemMutated = true;
|
|
16940
17015
|
log.info(`cleaned ${deletedCommitments.length} expired commitments`);
|
|
16941
|
-
if (this.config.
|
|
17016
|
+
if (resolveIndexingCapabilities(this.config).queryAwareIndexing) {
|
|
16942
17017
|
for (const m of deletedCommitments) {
|
|
16943
17018
|
deindexMemory(
|
|
16944
17019
|
this.config.memoryDir,
|
|
@@ -16951,9 +17026,9 @@ export class Orchestrator {
|
|
|
16951
17026
|
}
|
|
16952
17027
|
|
|
16953
17028
|
if (
|
|
16954
|
-
this.config.
|
|
16955
|
-
this.config.
|
|
16956
|
-
this.config.
|
|
17029
|
+
resolveCreationMemoryCapabilities(this.config).creationMemory &&
|
|
17030
|
+
resolveCreationMemoryCapabilities(this.config).commitmentLedger &&
|
|
17031
|
+
resolveCreationMemoryCapabilities(this.config).commitmentLifecycle
|
|
16957
17032
|
) {
|
|
16958
17033
|
try {
|
|
16959
17034
|
const lifecycle = await applyCommitmentLedgerLifecycle({
|
|
@@ -16981,7 +17056,7 @@ export class Orchestrator {
|
|
|
16981
17056
|
if (deletedTTL.length > 0) {
|
|
16982
17057
|
memoryItemMutated = true;
|
|
16983
17058
|
log.info(`cleaned ${deletedTTL.length} TTL-expired memories`);
|
|
16984
|
-
if (this.config.
|
|
17059
|
+
if (resolveIndexingCapabilities(this.config).queryAwareIndexing) {
|
|
16985
17060
|
for (const m of deletedTTL) {
|
|
16986
17061
|
deindexMemory(
|
|
16987
17062
|
this.config.memoryDir,
|
|
@@ -17259,347 +17334,26 @@ export class Orchestrator {
|
|
|
17259
17334
|
async optimizeCompressionGuidelines(options?: {
|
|
17260
17335
|
dryRun?: boolean;
|
|
17261
17336
|
eventLimit?: number;
|
|
17262
|
-
})
|
|
17263
|
-
|
|
17264
|
-
dryRun: boolean;
|
|
17265
|
-
eventCount: number;
|
|
17266
|
-
previousGuidelineVersion: number | null;
|
|
17267
|
-
nextGuidelineVersion: number;
|
|
17268
|
-
changedRules: number;
|
|
17269
|
-
semanticRefinementApplied: boolean;
|
|
17270
|
-
persisted: boolean;
|
|
17271
|
-
draftContentHash: string | null;
|
|
17272
|
-
}> {
|
|
17273
|
-
const dryRun = options?.dryRun === true;
|
|
17274
|
-
const eventLimit =
|
|
17275
|
-
typeof options?.eventLimit === "number"
|
|
17276
|
-
? Math.max(0, Math.floor(options.eventLimit))
|
|
17277
|
-
: 500;
|
|
17278
|
-
|
|
17279
|
-
const [activeState, draftState] = await Promise.all([
|
|
17280
|
-
this.storage.readCompressionGuidelineOptimizerState(),
|
|
17281
|
-
this.storage.readCompressionGuidelineDraftState().catch(() => null),
|
|
17282
|
-
]);
|
|
17283
|
-
const previousState =
|
|
17284
|
-
draftState &&
|
|
17285
|
-
((activeState?.guidelineVersion ?? 0) < draftState.guidelineVersion ||
|
|
17286
|
-
(activeState?.guidelineVersion ?? 0) === draftState.guidelineVersion)
|
|
17287
|
-
? draftState
|
|
17288
|
-
: activeState;
|
|
17289
|
-
|
|
17290
|
-
if (!this.config.compressionGuidelineLearningEnabled) {
|
|
17291
|
-
return {
|
|
17292
|
-
enabled: false,
|
|
17293
|
-
dryRun,
|
|
17294
|
-
eventCount: 0,
|
|
17295
|
-
previousGuidelineVersion: previousState?.guidelineVersion ?? null,
|
|
17296
|
-
nextGuidelineVersion: previousState?.guidelineVersion ?? 0,
|
|
17297
|
-
changedRules: 0,
|
|
17298
|
-
semanticRefinementApplied: false,
|
|
17299
|
-
persisted: false,
|
|
17300
|
-
draftContentHash: null,
|
|
17301
|
-
};
|
|
17302
|
-
}
|
|
17303
|
-
|
|
17304
|
-
let events = await this.storage.readMemoryActionEvents(eventLimit);
|
|
17305
|
-
if (eventLimit > 0) {
|
|
17306
|
-
let effectiveEvents = events.filter((event) => event.dryRun !== true);
|
|
17307
|
-
let fetchLimit = eventLimit;
|
|
17308
|
-
while (
|
|
17309
|
-
effectiveEvents.length < eventLimit &&
|
|
17310
|
-
events.length === fetchLimit
|
|
17311
|
-
) {
|
|
17312
|
-
fetchLimit = Math.min(fetchLimit * 2, fetchLimit + 1000);
|
|
17313
|
-
if (fetchLimit <= events.length) break;
|
|
17314
|
-
events = await this.storage.readMemoryActionEvents(fetchLimit);
|
|
17315
|
-
effectiveEvents = events.filter((event) => event.dryRun !== true);
|
|
17316
|
-
}
|
|
17317
|
-
events = effectiveEvents.slice(-eventLimit);
|
|
17318
|
-
}
|
|
17319
|
-
const generatedAt = new Date().toISOString();
|
|
17320
|
-
const candidate = computeCompressionGuidelineCandidate(events, {
|
|
17321
|
-
generatedAtIso: generatedAt,
|
|
17322
|
-
previousState,
|
|
17323
|
-
});
|
|
17324
|
-
if (candidate.eventCounts.total === 0) {
|
|
17325
|
-
return {
|
|
17326
|
-
enabled: true,
|
|
17327
|
-
dryRun,
|
|
17328
|
-
eventCount: 0,
|
|
17329
|
-
previousGuidelineVersion: previousState?.guidelineVersion ?? null,
|
|
17330
|
-
nextGuidelineVersion: previousState?.guidelineVersion ?? 0,
|
|
17331
|
-
changedRules: 0,
|
|
17332
|
-
semanticRefinementApplied: false,
|
|
17333
|
-
persisted: false,
|
|
17334
|
-
draftContentHash: null,
|
|
17335
|
-
};
|
|
17336
|
-
}
|
|
17337
|
-
const refinedCandidate =
|
|
17338
|
-
await refineCompressionGuidelineCandidateSemantically(candidate, {
|
|
17339
|
-
enabled: this.config.compressionGuidelineSemanticRefinementEnabled,
|
|
17340
|
-
timeoutMs: this.config.compressionGuidelineSemanticTimeoutMs,
|
|
17341
|
-
runRefinement: async (baseline) => {
|
|
17342
|
-
const prompt = [
|
|
17343
|
-
"You refine compression policy suggestions conservatively.",
|
|
17344
|
-
"Return JSON only in this shape:",
|
|
17345
|
-
'{"updates":[{"action":"summarize_node","delta":0.02,"confidence":"medium","note":"..."}]}',
|
|
17346
|
-
"Constraints:",
|
|
17347
|
-
"- Keep updates sparse and conservative.",
|
|
17348
|
-
"- delta must stay between -0.15 and 0.15.",
|
|
17349
|
-
"- Only include actions present in the input.",
|
|
17350
|
-
"Input candidate:",
|
|
17351
|
-
JSON.stringify(baseline),
|
|
17352
|
-
].join("\n");
|
|
17353
|
-
|
|
17354
|
-
const response = await this.fastChatCompletion(
|
|
17355
|
-
[
|
|
17356
|
-
{
|
|
17357
|
-
role: "system",
|
|
17358
|
-
content: "Respond with strict JSON only. No markdown.",
|
|
17359
|
-
},
|
|
17360
|
-
{ role: "user", content: prompt },
|
|
17361
|
-
],
|
|
17362
|
-
{
|
|
17363
|
-
temperature: 0.1,
|
|
17364
|
-
maxTokens: 400,
|
|
17365
|
-
operation: "compression_guideline_semantic_refinement",
|
|
17366
|
-
priority: "background",
|
|
17367
|
-
},
|
|
17368
|
-
);
|
|
17369
|
-
|
|
17370
|
-
return this.parseCompressionSemanticRefinement(
|
|
17371
|
-
response?.content ?? "",
|
|
17372
|
-
);
|
|
17373
|
-
},
|
|
17374
|
-
});
|
|
17375
|
-
|
|
17376
|
-
const content = renderCompressionGuidelinesMarkdown(refinedCandidate);
|
|
17377
|
-
const contentHash = createHash("sha256").update(content).digest("hex");
|
|
17378
|
-
const semanticRefinementApplied =
|
|
17379
|
-
JSON.stringify(refinedCandidate.ruleUpdates) !==
|
|
17380
|
-
JSON.stringify(candidate.ruleUpdates);
|
|
17381
|
-
const changedRules = refinedCandidate.ruleUpdates.filter(
|
|
17382
|
-
(rule) => rule.delta !== 0,
|
|
17383
|
-
).length;
|
|
17384
|
-
|
|
17385
|
-
if (!dryRun) {
|
|
17386
|
-
await this.storage.writeCompressionGuidelineDraft(content);
|
|
17387
|
-
await this.storage.writeCompressionGuidelineDraftState({
|
|
17388
|
-
version: refinedCandidate.optimizerVersion,
|
|
17389
|
-
updatedAt: refinedCandidate.generatedAt,
|
|
17390
|
-
sourceWindow: refinedCandidate.sourceWindow,
|
|
17391
|
-
eventCounts: refinedCandidate.eventCounts,
|
|
17392
|
-
guidelineVersion: refinedCandidate.guidelineVersion,
|
|
17393
|
-
contentHash,
|
|
17394
|
-
activationState: "draft",
|
|
17395
|
-
actionSummaries: refinedCandidate.actionSummaries,
|
|
17396
|
-
ruleUpdates: refinedCandidate.ruleUpdates,
|
|
17397
|
-
});
|
|
17398
|
-
}
|
|
17399
|
-
|
|
17400
|
-
return {
|
|
17401
|
-
enabled: true,
|
|
17402
|
-
dryRun,
|
|
17403
|
-
eventCount: candidate.eventCounts.total,
|
|
17404
|
-
previousGuidelineVersion: previousState?.guidelineVersion ?? null,
|
|
17405
|
-
nextGuidelineVersion: refinedCandidate.guidelineVersion,
|
|
17406
|
-
changedRules,
|
|
17407
|
-
semanticRefinementApplied,
|
|
17408
|
-
persisted: !dryRun,
|
|
17409
|
-
draftContentHash: dryRun ? null : contentHash,
|
|
17410
|
-
};
|
|
17337
|
+
}) {
|
|
17338
|
+
return this.compressionGuidelineCoordinator.optimizeCompressionGuidelines(options);
|
|
17411
17339
|
}
|
|
17412
17340
|
|
|
17413
17341
|
async activateCompressionGuidelineDraft(options?: {
|
|
17414
17342
|
expectedContentHash?: string;
|
|
17415
17343
|
expectedGuidelineVersion?: number;
|
|
17416
|
-
})
|
|
17417
|
-
|
|
17418
|
-
activated: boolean;
|
|
17419
|
-
guidelineVersion: number | null;
|
|
17420
|
-
reason?:
|
|
17421
|
-
| "disabled"
|
|
17422
|
-
| "missing_draft"
|
|
17423
|
-
| "expected_revision_required"
|
|
17424
|
-
| "content_hash_mismatch"
|
|
17425
|
-
| "guideline_version_mismatch"
|
|
17426
|
-
| "draft_changed";
|
|
17427
|
-
}> {
|
|
17428
|
-
if (!this.config.compressionGuidelineLearningEnabled) {
|
|
17429
|
-
return {
|
|
17430
|
-
enabled: false,
|
|
17431
|
-
activated: false,
|
|
17432
|
-
guidelineVersion: null,
|
|
17433
|
-
reason: "disabled",
|
|
17434
|
-
};
|
|
17435
|
-
}
|
|
17436
|
-
|
|
17437
|
-
const draftState = await this.storage.readCompressionGuidelineDraftState();
|
|
17438
|
-
if (!draftState) {
|
|
17439
|
-
return {
|
|
17440
|
-
enabled: true,
|
|
17441
|
-
activated: false,
|
|
17442
|
-
guidelineVersion: null,
|
|
17443
|
-
reason: "missing_draft",
|
|
17444
|
-
};
|
|
17445
|
-
}
|
|
17446
|
-
|
|
17447
|
-
const expectedContentHash = options?.expectedContentHash?.trim();
|
|
17448
|
-
const expectedGuidelineVersion = options?.expectedGuidelineVersion;
|
|
17449
|
-
|
|
17450
|
-
if (
|
|
17451
|
-
(!expectedContentHash || expectedContentHash.length === 0) &&
|
|
17452
|
-
typeof expectedGuidelineVersion !== "number"
|
|
17453
|
-
) {
|
|
17454
|
-
return {
|
|
17455
|
-
enabled: true,
|
|
17456
|
-
activated: false,
|
|
17457
|
-
guidelineVersion: null,
|
|
17458
|
-
reason: "expected_revision_required",
|
|
17459
|
-
};
|
|
17460
|
-
}
|
|
17461
|
-
|
|
17462
|
-
if (expectedContentHash && draftState.contentHash !== expectedContentHash) {
|
|
17463
|
-
return {
|
|
17464
|
-
enabled: true,
|
|
17465
|
-
activated: false,
|
|
17466
|
-
guidelineVersion: null,
|
|
17467
|
-
reason: "content_hash_mismatch",
|
|
17468
|
-
};
|
|
17469
|
-
}
|
|
17470
|
-
|
|
17471
|
-
if (
|
|
17472
|
-
typeof expectedGuidelineVersion === "number" &&
|
|
17473
|
-
draftState.guidelineVersion !== expectedGuidelineVersion
|
|
17474
|
-
) {
|
|
17475
|
-
return {
|
|
17476
|
-
enabled: true,
|
|
17477
|
-
activated: false,
|
|
17478
|
-
guidelineVersion: null,
|
|
17479
|
-
reason: "guideline_version_mismatch",
|
|
17480
|
-
};
|
|
17481
|
-
}
|
|
17482
|
-
|
|
17483
|
-
const activated = await this.storage.activateCompressionGuidelineDraft({
|
|
17484
|
-
...(expectedContentHash ? { expectedContentHash } : {}),
|
|
17485
|
-
...(typeof expectedGuidelineVersion === "number"
|
|
17486
|
-
? { expectedGuidelineVersion }
|
|
17487
|
-
: {}),
|
|
17488
|
-
});
|
|
17489
|
-
return {
|
|
17490
|
-
enabled: true,
|
|
17491
|
-
activated,
|
|
17492
|
-
guidelineVersion: activated ? draftState.guidelineVersion : null,
|
|
17493
|
-
...(activated ? {} : { reason: "draft_changed" as const }),
|
|
17494
|
-
};
|
|
17344
|
+
}) {
|
|
17345
|
+
return this.compressionGuidelineCoordinator.activateCompressionGuidelineDraft(options);
|
|
17495
17346
|
}
|
|
17496
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.
|
|
17497
17351
|
private async runCompressionGuidelineLearningPass(): Promise<void> {
|
|
17498
|
-
|
|
17499
|
-
try {
|
|
17500
|
-
const result = await this.optimizeCompressionGuidelines({
|
|
17501
|
-
dryRun: false,
|
|
17502
|
-
eventLimit: 500,
|
|
17503
|
-
});
|
|
17504
|
-
log.info(
|
|
17505
|
-
`compression guideline learning updated (${result.eventCount} events)`,
|
|
17506
|
-
);
|
|
17507
|
-
} catch (err) {
|
|
17508
|
-
log.warn(`compression guideline learning failed (ignored): ${err}`);
|
|
17509
|
-
}
|
|
17510
|
-
}
|
|
17511
|
-
|
|
17512
|
-
private async buildCompressionGuidelineRecallSection(): Promise<
|
|
17513
|
-
string | null
|
|
17514
|
-
> {
|
|
17515
|
-
if (!this.config.contextCompressionActionsEnabled) return null;
|
|
17516
|
-
if (!this.config.compressionGuidelineLearningEnabled) return null;
|
|
17517
|
-
|
|
17518
|
-
const state = await this.storage
|
|
17519
|
-
.readCompressionGuidelineOptimizerState()
|
|
17520
|
-
.catch(() => null);
|
|
17521
|
-
if (!state || state.guidelineVersion <= 0) return null;
|
|
17522
|
-
|
|
17523
|
-
const raw = await this.storage
|
|
17524
|
-
.readCompressionGuidelines()
|
|
17525
|
-
.catch(() => null);
|
|
17526
|
-
const summary = raw ? formatCompressionGuidelinesForRecall(raw, 5) : null;
|
|
17527
|
-
if (!summary) return null;
|
|
17528
|
-
|
|
17529
|
-
return [
|
|
17530
|
-
"## Active Compression Guidelines",
|
|
17531
|
-
"",
|
|
17532
|
-
`Guideline version: ${state.guidelineVersion}`,
|
|
17533
|
-
`Updated: ${state.updatedAt}`,
|
|
17534
|
-
"",
|
|
17535
|
-
summary,
|
|
17536
|
-
].join("\n");
|
|
17352
|
+
return this.compressionGuidelineCoordinator.runCompressionGuidelineLearningPass();
|
|
17537
17353
|
}
|
|
17538
17354
|
|
|
17539
|
-
private
|
|
17540
|
-
|
|
17541
|
-
action: MemoryActionType;
|
|
17542
|
-
delta?: number;
|
|
17543
|
-
confidence?: "low" | "medium" | "high";
|
|
17544
|
-
note?: string;
|
|
17545
|
-
}>;
|
|
17546
|
-
} | null {
|
|
17547
|
-
if (typeof raw !== "string" || raw.trim().length === 0) return null;
|
|
17548
|
-
const trimmed = raw.trim();
|
|
17549
|
-
const start = trimmed.indexOf("{");
|
|
17550
|
-
const end = trimmed.lastIndexOf("}");
|
|
17551
|
-
if (start === -1 || end === -1 || end <= start) return null;
|
|
17552
|
-
|
|
17553
|
-
try {
|
|
17554
|
-
const parsed = JSON.parse(trimmed.slice(start, end + 1)) as {
|
|
17555
|
-
updates?: Array<{
|
|
17556
|
-
action?: unknown;
|
|
17557
|
-
delta?: unknown;
|
|
17558
|
-
confidence?: unknown;
|
|
17559
|
-
note?: unknown;
|
|
17560
|
-
}>;
|
|
17561
|
-
};
|
|
17562
|
-
if (!Array.isArray(parsed?.updates)) return null;
|
|
17563
|
-
|
|
17564
|
-
const validActions = new Set<MemoryActionType>([
|
|
17565
|
-
"store_episode",
|
|
17566
|
-
"store_note",
|
|
17567
|
-
"update_note",
|
|
17568
|
-
"create_artifact",
|
|
17569
|
-
"summarize_node",
|
|
17570
|
-
"discard",
|
|
17571
|
-
"link_graph",
|
|
17572
|
-
]);
|
|
17573
|
-
|
|
17574
|
-
const updates = parsed.updates
|
|
17575
|
-
.filter(
|
|
17576
|
-
(item) =>
|
|
17577
|
-
item &&
|
|
17578
|
-
typeof item.action === "string" &&
|
|
17579
|
-
validActions.has(item.action as MemoryActionType),
|
|
17580
|
-
)
|
|
17581
|
-
.map((item) => {
|
|
17582
|
-
const confidence: "low" | "medium" | "high" | undefined =
|
|
17583
|
-
item.confidence === "low" ||
|
|
17584
|
-
item.confidence === "medium" ||
|
|
17585
|
-
item.confidence === "high"
|
|
17586
|
-
? item.confidence
|
|
17587
|
-
: undefined;
|
|
17588
|
-
return {
|
|
17589
|
-
action: item.action as MemoryActionType,
|
|
17590
|
-
delta:
|
|
17591
|
-
typeof item.delta === "number" && Number.isFinite(item.delta)
|
|
17592
|
-
? item.delta
|
|
17593
|
-
: undefined,
|
|
17594
|
-
confidence,
|
|
17595
|
-
note: typeof item.note === "string" ? item.note : undefined,
|
|
17596
|
-
};
|
|
17597
|
-
});
|
|
17598
|
-
|
|
17599
|
-
return { updates };
|
|
17600
|
-
} catch {
|
|
17601
|
-
return null;
|
|
17602
|
-
}
|
|
17355
|
+
private async buildCompressionGuidelineRecallSection(): Promise<string | null> {
|
|
17356
|
+
return this.compressionGuidelineCoordinator.buildCompressionGuidelineRecallSection();
|
|
17603
17357
|
}
|
|
17604
17358
|
|
|
17605
17359
|
private actionOutcomePriorDelta(event: MemoryActionEvent): number {
|
|
@@ -17869,7 +17623,7 @@ export class Orchestrator {
|
|
|
17869
17623
|
);
|
|
17870
17624
|
await this.embeddingFallback.removeFromIndex(memory.frontmatter.id);
|
|
17871
17625
|
if (
|
|
17872
|
-
this.config.
|
|
17626
|
+
resolveIndexingCapabilities(this.config).queryAwareIndexing &&
|
|
17873
17627
|
memory.path &&
|
|
17874
17628
|
memory.frontmatter?.created
|
|
17875
17629
|
) {
|
|
@@ -20254,7 +20008,7 @@ export class Orchestrator {
|
|
|
20254
20008
|
);
|
|
20255
20009
|
let temporalFromDate: string | null = null;
|
|
20256
20010
|
let promptTags: string[] = [];
|
|
20257
|
-
if (this.config.
|
|
20011
|
+
if (resolveIndexingCapabilities(this.config).queryAwareIndexing && prompt) {
|
|
20258
20012
|
if (isTemporalQuery(prompt)) {
|
|
20259
20013
|
temporalFromDate = recencyWindowFromPrompt(prompt, now);
|
|
20260
20014
|
}
|
|
@@ -20279,7 +20033,7 @@ export class Orchestrator {
|
|
|
20279
20033
|
// Scope to result paths first so cross-namespace paths don't consume the cap.
|
|
20280
20034
|
let temporalCandidates: Set<string> | null = null;
|
|
20281
20035
|
let tagCandidates: Set<string> | null = null;
|
|
20282
|
-
if (this.config.
|
|
20036
|
+
if (resolveIndexingCapabilities(this.config).queryAwareIndexing && prompt) {
|
|
20283
20037
|
const maxCandidates = this.config.queryAwareIndexingMaxCandidates;
|
|
20284
20038
|
const capSet = (s: Set<string> | null): Set<string> | null => {
|
|
20285
20039
|
if (!s) return null;
|
|
@@ -20388,7 +20142,7 @@ export class Orchestrator {
|
|
|
20388
20142
|
|
|
20389
20143
|
// v8.1: Temporal + Tag index boost
|
|
20390
20144
|
// Results that match the detected temporal window or tag query get a small additive boost.
|
|
20391
|
-
if (this.config.
|
|
20145
|
+
if (resolveIndexingCapabilities(this.config).queryAwareIndexing && r.path) {
|
|
20392
20146
|
if (temporalCandidates?.has(r.path)) {
|
|
20393
20147
|
score += applyUtilityRankingRuntimeDelta(
|
|
20394
20148
|
0.08,
|
|
@@ -20625,15 +20379,13 @@ export class Orchestrator {
|
|
|
20625
20379
|
}
|
|
20626
20380
|
|
|
20627
20381
|
// The new fact is newer than the existing one. When auto-resolve is
|
|
20628
|
-
// enabled,
|
|
20629
|
-
//
|
|
20630
|
-
|
|
20631
|
-
|
|
20632
|
-
|
|
20633
|
-
|
|
20634
|
-
|
|
20635
|
-
);
|
|
20636
|
-
}
|
|
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.
|
|
20637
20389
|
|
|
20638
20390
|
// Return the contradiction info regardless of auto-resolve setting.
|
|
20639
20391
|
// The caller uses this to set `contradictionDetected=true` which
|
|
@@ -20656,6 +20408,71 @@ export class Orchestrator {
|
|
|
20656
20408
|
return null;
|
|
20657
20409
|
}
|
|
20658
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
|
+
|
|
20659
20476
|
// ---------------------------------------------------------------------------
|
|
20660
20477
|
// Memory Linking (Phase 3A)
|
|
20661
20478
|
// ---------------------------------------------------------------------------
|