Skip to content

CorpusConsolidationService

Defined in: packages/memory-ltm/src/corpus-consolidation.service.ts:84

Periodic corpus consolidation (G3-T2): clusters NEAR-duplicate long-term memories in the [mergeThreshold, duplicateThreshold) similarity band — the band write-time dedup deliberately leaves alone, which otherwise accumulates unbounded — keeps one canonical per cluster, and supersedes the rest.

NOT the STM→LTM promotion pass: consolidate_memories / ConsolidationService (apps/mcp-server) is a different, unrelated job.

Merge semantics (pinned Decisions 8/9 + WRAPUP-PLAN §2 B5):

  • canonical = highest metadata.importance, tie-break most recent createdAt;
  • the union of every cluster member’s tags is CAS-written onto the canonical;
  • each loser gets EXACTLY the write-time supersede markers (ContradictionDetectionService.annotateSuperseded: status, supersededBy, supersededReason, supersededAt in metadata JSON — zero schema changes), a derived duplicate-of MemoryLink to the canonical, and a system-actor audit row (corpus_consolidation), so the G3-T1 recall exclusion and get_memory retrieval Just Work;
  • every mutation rides the G3-T3 CAS path (MemoryLtmService.casMetadataUpdate): retry ONCE from a fresh read, then skip and count skippedConcurrentEdit — a background merge never clobbers a concurrent user edit.

Exclusions: rows already superseded, contradiction-flagged pairs (status='contradicted' / contradictionWith — deliberately kept by G3-T4), embeddingExcluded rows, and rows without a stored vector are skipped as seeds AND filtered out of candidate sets. Losers stay in the vector index (like write-time supersede) — recall filters them post- hydration, and Postgres remains the source of truth.

Idempotent: a re-run finds nothing new because losers are now superseded. Cursor-resumable using the applyDecayPolicy pattern. REVIEW-GATED (pinned Decision 3): run() defaults to dryRun: true and mutates nothing unless the caller passes dryRun: false explicitly.

new CorpusConsolidationService(prisma, ltmService, contradictionDetection, vectorStore?): CorpusConsolidationService

Defined in: packages/memory-ltm/src/corpus-consolidation.service.ts:89

PrismaService

MemoryLtmService

ContradictionDetectionService

VectorStore

CorpusConsolidationService

getDuplicateThreshold(): number

Defined in: packages/memory-ltm/src/corpus-consolidation.service.ts:114

number


getMergeThreshold(): number

Defined in: packages/memory-ltm/src/corpus-consolidation.service.ts:110

number


run(options?): Promise<CorpusConsolidationResult>

Defined in: packages/memory-ltm/src/corpus-consolidation.service.ts:123

Run one (resumable slice of a) consolidation pass. See the class doc for semantics. Defaults to dryRun: true — the review gate — so calling this without options NEVER mutates.

CorpusConsolidationOptions = {}

Promise<CorpusConsolidationResult>