-- +goose Up -- Add the fourth watch loop trigger type, collision, to the alerts.alert_type closed set. Cross opportunity -- collision deconfliction flags when a candidate (most sharply a scarce cleared one) is proposed or approved on -- the slates of two or more DISTINCT competing OPEN opportunities at once, so a capture team never quietly -- double commits the same scarce cleared person across competing bids. It is an ADVISORY finding surfaced like -- every other alert (unread, read, dismissed), with a deterministic suggested primary a human resolves; it -- never auto rejects a slate member. No new table: it rides the existing alerts table, sweep, audit, and -- endpoints. Only the alert_type CHECK widens by one value. ALTER TABLE alerts DROP CONSTRAINT IF EXISTS alerts_alert_type_check; ALTER TABLE alerts ADD CONSTRAINT alerts_alert_type_check CHECK (alert_type IN ('recompete_winnable', 'clearance_expiring', 'gap_fillable', 'collision')); -- +goose Down -- Clear the rows the narrower vocabulary cannot express BEFORE narrowing it. Without this the ADD fails -- with a check violation and the whole rollback aborts: goose runs a migration in a transaction, so the -- DROP above rolls back with it and nothing is corrupted, but the rollback is BLOCKED, which is the worst -- moment to discover it since a rollback is usually being attempted under pressure. -- -- Deleted rather than remapped: a collision alert has no meaning in a schema that does not know the type, -- and the sweep that produced it regenerates from live data on its next run. DELETE FROM alerts WHERE alert_type = 'collision'; ALTER TABLE alerts DROP CONSTRAINT IF EXISTS alerts_alert_type_check; ALTER TABLE alerts ADD CONSTRAINT alerts_alert_type_check CHECK (alert_type IN ('recompete_winnable', 'clearance_expiring', 'gap_fillable'));