-- no-transaction -- #211: a waived release could not record which rule it relaxed. The old -- constraint made the rule name an exact synonym for rejection: -- -- CHECK ((verdict = 'rejected') = (rejected_rule IS NOT NULL)) -- -- so §9.3's deck showed a bare `waived` beside rejected rows that each named -- their own rule, and §5.7's "watchable but not what was asked" lost the half -- that says what was not asked for. The relaxed form still demands a rule on -- a rejection and stops demanding its absence elsewhere. -- -- SQLite cannot alter a CHECK, so the table is rebuilt (see 0014). Unlike the -- rebuilds there, `releases` is a parent: `grabs`, `movie_releases`, -- `episode_releases` and `season_releases` all point at it, three of them -- ON DELETE CASCADE. Dropping the old table with foreign keys enforced would -- delete those children (or, for `grabs`, refuse outright), so this follows -- SQLite's own procedure — foreign keys off, the rebuild in one transaction, -- foreign keys back on. `PRAGMA foreign_keys` is a no-op inside a -- transaction, which is why the file opens `-- no-transaction` and manages -- its own; the migration is still all-or-nothing. -- -- Rows are copied verbatim. Every existing `waived` row keeps its NULL and -- goes on reading as it does today; only rows written after this migration -- carry a waived rule. PRAGMA foreign_keys = OFF; BEGIN; CREATE TABLE releases_new ( id INTEGER PRIMARY KEY, -- Prowlarr's indexer id. Not a foreign key: indexers live in Prowlarr. indexer_id INTEGER NOT NULL, guid TEXT NOT NULL, name TEXT NOT NULL, size INTEGER NOT NULL, seeders INTEGER, publish_date TEXT, download_url TEXT NOT NULL, -- §5.6. What the release name claims, before anything is downloaded. parsed TEXT NOT NULL CHECK (json_valid(parsed)), score REAL, -- §9.3. Three buckets. `rejected_rule` names the rule that killed it so -- an over-strict filter is visible without reading release names, and -- §5.7's waiver names the rule it relaxed for the same reason. verdict TEXT CHECK (verdict IN ('eligible', 'waived', 'rejected')), rejected_rule TEXT, created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')), UNIQUE (indexer_id, guid), CHECK (verdict != 'rejected' OR rejected_rule IS NOT NULL) ) STRICT; INSERT INTO releases_new ( id, indexer_id, guid, name, size, seeders, publish_date, download_url, parsed, score, verdict, rejected_rule, created_at ) SELECT id, indexer_id, guid, name, size, seeders, publish_date, download_url, parsed, score, verdict, rejected_rule, created_at FROM releases; DROP TABLE releases; ALTER TABLE releases_new RENAME TO releases; CREATE INDEX releases_verdict ON releases (verdict, score); COMMIT; PRAGMA foreign_keys = ON;