import type { Database } from "./schema.js"; import { type ExpiryReason } from "./note-archival.js"; export interface ConsolidationReport { episodesProcessed: number; notesCreated: number; durationMs: number; details: string[]; } export interface ConsolidationLog { episodesProcessed: number; notesCreated: number; durationMs: number; } export interface PruningReport { notesScanned: number; notesExpired: number; notesMerged: number; durationMs: number; details: string[]; } export interface RawNoteRow { note_id: string; type: string; content: string; keywords: string; confidence: number; priority: number; access_count: number; created_at: string; updated_at: string; valid_to: string | null; superseded_by: string | null; is_guardrail: number; pinned: number; thread_id: number | null; } export declare function getUnconsolidatedThreadIds(db: Database): number[]; export declare function logConsolidation(db: Database, entry: ConsolidationLog): void; export declare function cleanupConsolidationHousekeeping(db: Database): void; export declare function getCandidateNotesForPruning(db: Database, maxNotes: number): RawNoteRow[]; export declare function hasActiveNote(db: Database, noteId: string): boolean; export declare function getActiveNoteContent(db: Database, noteId: string): { noteId: string; content: string; } | null; export declare function expireNote(db: Database, noteId: string, now: string, reason: Extract): void; /** * TTL sweep: soft-expire notes whose write-time `expires_at` has elapsed. Runs * in the consolidation cycle alongside pruning. Reversible — sets valid_to + * expiry_reason='ttl' and prepends [EXPIRED]; never hard-deletes. Applies to * pinned/guardrail notes too (a soft expiry can be restored). Notes with * expires_at IS NULL — the default — are never touched, so pre-TTL behavior is * unchanged. Returns the number of notes expired. */ export declare function sweepExpiredNotes(db: Database): number; /** * Merge a duplicate note into a kept one, retiring the duplicate (expiry_reason * 'merged'). Returns true if the merge happened, false if it was refused. * * A guardrail or pinned note is NEVER the retired side: dedup must not silently * drop an enforced rule or a pinned invariant. When the expire target is * protected the whole operation is a no-op (no content rewrite, no retirement) — * the protected note stays active — mirroring supersedeNote's guard. This is the * "exclude protected notes from the retired side" option. */ export declare function mergeDuplicateNote(db: Database, keepId: string, expireId: string, now: string, mergedContent?: string): boolean; /** * Delete note_embeddings rows only for notes that are gone entirely or * permanently dead (superseded / merged / pruned). Vectors of archived, * worker-cleanup and legacy-expired notes are deliberately KEPT: those notes * are restorable, and this sweep destroying their vectors is what turned the * 2026 archiving incident into a store-wide embedding outage (re-embedding is * expensive to notice needing; ~6 KB/note of disk is not). Expired vectors are * already invisible to search — loadAllEmbeddings filters on the live note. * Returns the number of rows deleted. */ export declare function sweepOrphanedEmbeddings(db: Database): number; export declare function sweepOrphanedNotes(db: Database): number; //# sourceMappingURL=consolidation.d.ts.map