-- Migration 014: stop encoding diagnostics and lifecycle records as scratchpad. -- Historical rows stay immutable; projections recognize their legacy payload types. PRAGMA foreign_keys = OFF; BEGIN IMMEDIATE; CREATE TABLE events_v2 ( seq INTEGER PRIMARY KEY AUTOINCREMENT, session_id TEXT NOT NULL REFERENCES sessions(id), kind TEXT NOT NULL CHECK(kind IN ( 'input','scratchpad','context.receipt','model.usage','tool.result','turn.failed','turn.outcome', 'execution.started','execution.completed','execution.unknown', 'local.sent','delivery.held','kernel.reset','session.waited', 'session.woke','hooks.activated','kernel.placement','remote.repair', 'runtime.slice','runtime.task_paused','lcm_frontier', 'frontier.install_failed','frontier.selected','frontier.deferred', 'frontier.abandoned','frontier.quiet','orientation.adopted', 'maintenance.attempt_completed','maintenance.attempt_failed' )), source_key TEXT, payload TEXT NOT NULL CHECK(json_valid(payload)), created_ms INTEGER NOT NULL CHECK(created_ms >= 0), UNIQUE(session_id, source_key) ) STRICT; INSERT INTO events_v2 (seq, session_id, kind, source_key, payload, created_ms) SELECT seq, session_id, kind, source_key, payload, created_ms FROM events; DROP TABLE events; ALTER TABLE events_v2 RENAME TO events; CREATE INDEX events_session_order ON events(session_id, seq); CREATE TRIGGER events_no_update BEFORE UPDATE ON events BEGIN SELECT RAISE(ABORT, 'historical events are immutable'); END; CREATE TRIGGER events_no_delete BEFORE DELETE ON events BEGIN SELECT RAISE(ABORT, 'historical events are immutable'); END; CREATE TEMP TABLE _orphan_guard (reason TEXT CHECK (reason IS NULL)); INSERT INTO _orphan_guard (reason) SELECT 'orphaned ' || "table" || ' row ' || rowid || ' via fk ' || fkid || ' -> parent ' || parent FROM pragma_foreign_key_check; DROP TABLE _orphan_guard; PRAGMA user_version = 14; COMMIT; PRAGMA foreign_keys = ON;