-- Migration 000015: Agent retirement (I-004 fail-closed coverage-gap fix). -- -- Adds a soft-delete surface for agents and their deployment_targets, and -- replaces the fail-open DELETE CASCADE on deployment_targets.agent_id (see -- migration 000001 line 104) with a fail-closed DELETE RESTRICT. -- -- Rationale (audit finding I-004): -- Today a bare `DELETE FROM agents WHERE id = $1` silently cascades through -- deployment_targets (CASCADE) and blanks jobs.agent_id (SET NULL, migration -- 000001 line 146). The cascade vaporises the deployment audit trail — "who -- deployed what, to where, when" — and leaves nothing behind to answer -- forensic questions after an operator mis-types an agent ID. Flipping the -- deployment_targets FK to RESTRICT forces any DELETE to fail at the DB -- layer unless dependencies are cleared first; the new retired_at + -- retired_reason pair give the service layer a soft-retirement path that -- preserves history. -- -- Mirrors migration 000005 (revocation) in shape: nullable timestamp + -- nullable reason string. Column type is TEXT (not VARCHAR(50)) so retirement -- reasons can include full operator comments and audit context without -- truncation. -- -- Idempotency guarantees (enforced by migration_000015_test.go Stage 4): -- * ADD COLUMN IF NOT EXISTS → re-running is a no-op -- * DROP CONSTRAINT IF EXISTS + ADD CONSTRAINT → always converges to -- RESTRICT; safe to re-apply after a partial rollback -- * CREATE INDEX IF NOT EXISTS → re-running is a no-op -- Agents: soft-retirement surface. ALTER TABLE agents ADD COLUMN IF NOT EXISTS retired_at TIMESTAMPTZ; ALTER TABLE agents ADD COLUMN IF NOT EXISTS retired_reason TEXT; -- Deployment targets: soft-retirement surface. Cascade-retire via the service -- layer copies the agent's retired_at/retired_reason onto its targets so the -- "who owned this deployment" trail stays intact after an agent is retired. ALTER TABLE deployment_targets ADD COLUMN IF NOT EXISTS retired_at TIMESTAMPTZ; ALTER TABLE deployment_targets ADD COLUMN IF NOT EXISTS retired_reason TEXT; -- Flip deployment_targets.agent_id FK from ON DELETE CASCADE (migration 000001 -- line 104) to ON DELETE RESTRICT. Auto-named constraint per Postgres default -- (`