-- Migration 008: extend the events kind vocabulary with 'kernel.placement'
-- so a placement change is a committed, immutable transition event, not an
-- in-place session mutation. SQLite cannot ALTER a CHECK constraint, so the
-- events table is rebuilt with identical columns/indexes/triggers plus the
-- new kind; all rows and their sequence numbers are preserved.
--
-- PRAGMA ORDERING MATTERS: foreign_keys may only be toggled OUTSIDE any
-- transaction (the pragma is a no-op inside one), and this rebuild drops a
-- table that executions, effects, inbox and the migration tables reference.
-- The toggle therefore brackets the whole rebuild, and the rebuild must
-- pass an orphan guard before it commits: a rebuild that silently orphans
-- a reference is the one failure mode worse than refusing to upgrade.
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','execution.started','execution.completed',
'local.sent','delivery.held','kernel.reset','session.waited',
'session.woke','hooks.activated','kernel.placement'
)),
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;
-- FATAL orphan guard: pragma_foreign_key_check must be EMPTY. The insert
-- below only fires when there are rows to insert, and the CHECK rejects
-- every row, so any orphan aborts the migration before COMMIT.
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 = 8;
COMMIT;
PRAGMA foreign_keys = ON;