import { Database } from 'better-sqlite3'; import { Logger } from '../observability/logger.js'; /** * v15 step 1: retype legacy contradiction-proxy entities from the free-form * type 'memory' to the reserved 'memory_proxy'. An entity is retyped iff it * carries the complete fingerprint the pre-v0.29.5 code left behind: * 1. legacy type 'memory' and the 'memory:' name prefix; * 2. linked with role 'subject' to a memory whose legacy proxy name * (legacyProxyEntityName(content)) equals the entity name exactly; * 3. an automatic 'contradicts' relation (metadata.auto = true) touches * it and was created within PROXY_CO_CREATION_WINDOW_S after the * entity — the co-creation signature of the old code path. * * This is a DEFINITION, not a provenance proof: legacy rows carry no origin * marker, and an entity a caller created with exactly the internal name, * the internal type, the internal link role and a contradiction on it * within seconds is — by every fact the database holds — a proxy, and is * treated as one (Codex PR-18 rounds 3–5). What the fingerprint DOES rule * out: "memory:working" of type memory, an exact-name coincidence linked * as 'mention', an entity without an automatic edge, and a user entity the * system reused as an endpoint later than 5 s after its creation. The * retype is reversible: metadata.retyped_from records it, every retyped * name is logged, and create_entity on that name promotes it back to a * visible type. Because the legacy 60-character name let memories with * the same opening share one proxy, EVERY matching memory is recorded * (proxy_for_memory_ids). Exported for the migration test. */ declare function retypeProvenMemoryProxies(db: Database): number; /** Names of the entities step 1 would retype — logged so the change is inspectable. */ declare function listRetypedProxyNames(db: Database): readonly string[]; /** * v15 step 2: soft-delete automatic 'contradicts' edges that the current * rule would not create. Since v0.29.5 an edge requires claim-level * evidence (predicatesAllowSupersede); legacy edges were created on * keyword heuristics alone and feed explain.contradictions in every * search result. Only edges whose BOTH endpoints are proxies are judged; * an edge touching a real entity is left as is. Because a legacy proxy may * represent several memories, ALL memories linked to each endpoint with * role 'subject' are considered and the edge is kept if ANY pair carries * evidence (Codex PR-18 round 4 [P2]). Soft delete (is_deleted = 1, * metadata.removed_by) — nothing is destroyed. Exported for the test. */ declare function pruneUnsupportedAutoContradictions(db: Database): number; /** * Run an idempotent ALTER TABLE ... ADD COLUMN. Swallows ONLY the * "duplicate column name" error (the re-run case); every other failure — * SQLITE_BUSY, I/O errors, missing table — propagates so the migration * aborts BEFORE the schema version is stamped. The old blanket catch{} * could leave a DB permanently marked migrated with the migration half * applied. */ declare function tryAlterAddColumn(db: Database, stmt: string): void; /** * Consistent point-in-time backup of a live database. copyFileSync on a * WAL-mode DB can miss recent commits that only exist in the -wal file (or * tear mid-checkpoint); VACUUM INTO produces a transactionally consistent * snapshot regardless of WAL state. */ declare function backupDatabase(db: Database, backupPath: string): void; declare function runMigrations(db: Database, dbPath: string, logger: Logger): void; export { backupDatabase, listRetypedProxyNames, pruneUnsupportedAutoContradictions, retypeProvenMemoryProxies, runMigrations, tryAlterAddColumn };