-- OTIVM player database FK repair script -- File: data/repair_player_db_fk.sql -- Applies to: player databases created under schema v3 or v4 -- Problem: actor_profile used composite PRIMARY KEY (actor_id, recorded_at) -- without UNIQUE(actor_id), causing SQLite to reject FK references -- from child tables (actor_parameters, events, etc.) to actor_id alone. -- Fix: recreate actor_profile with UNIQUE(actor_id) added. -- Uses the SQLite rename-recreate-copy-drop pattern. -- Safe to run on any v3/v4 player database. Idempotent for data. PRAGMA journal_mode = WAL; PRAGMA foreign_keys = OFF; BEGIN; -- Clean up any partial previous repair attempt DROP TABLE IF EXISTS actor_profile_old; -- Step 1: Rename existing broken table ALTER TABLE actor_profile RENAME TO actor_profile_old; -- Step 2: Create corrected table with UNIQUE(actor_id) CREATE TABLE actor_profile ( actor_id TEXT NOT NULL, session_id TEXT NOT NULL, background_id TEXT NOT NULL, actor_name TEXT NOT NULL, epoch TEXT NOT NULL DEFAULT 'roman_14bce', schema_version INTEGER NOT NULL DEFAULT 5, recorded_at TEXT NOT NULL, session_anchor_at TEXT, PRIMARY KEY (actor_id, recorded_at), UNIQUE (actor_id) ); -- Step 3: Copy all data from old table. -- session_anchor_at is supplied as NULL for v3 databases that lack the column -- (v3 predates session_anchor_at). For v4 databases that have the column, -- the value would be NULL anyway (no player has dispatched on a broken save). INSERT INTO actor_profile ( actor_id, session_id, background_id, actor_name, epoch, schema_version, recorded_at, session_anchor_at ) SELECT actor_id, session_id, background_id, actor_name, epoch, schema_version, recorded_at, NULL FROM actor_profile_old; -- Step 4: Drop the broken old table DROP TABLE actor_profile_old; -- Step 5: Record the repair in schema_changelog INSERT OR IGNORE INTO schema_changelog VALUES (5, 'OTIVM-V: Add UNIQUE(actor_id) to actor_profile to fix FK references', '2026-05-02T00:00:00Z'); -- Step 6: Bump schema version PRAGMA user_version = 5; COMMIT; PRAGMA foreign_keys = ON;