SET LOCAL lock_timeout = '10s'; SET LOCAL statement_timeout = '60s'; ALTER TABLE gateway_identity_onboarding_exchanges DROP CONSTRAINT gateway_identity_onboarding_exchanges_status_check; ALTER TABLE gateway_identity_onboarding_exchanges ADD CONSTRAINT gateway_identity_onboarding_exchanges_status_check CHECK (status IN ('metadata_pending','preparing','ready','credentials_saved','completed','failed','expired','cancelled')), ADD COLUMN cleanup_status text NOT NULL DEFAULT 'none', ADD COLUMN cancelled_at timestamptz, ADD COLUMN cleanup_completed_at timestamptz; ALTER TABLE gateway_identity_onboarding_exchanges ADD CONSTRAINT gateway_identity_onboarding_cleanup_status_check CHECK (cleanup_status IN ('none','pending','completed')), ADD CONSTRAINT gateway_identity_onboarding_cleanup_lifecycle_check CHECK ( (status <> 'cancelled' AND cleanup_status = 'none' AND cancelled_at IS NULL AND cleanup_completed_at IS NULL) OR (status = 'cancelled' AND cancelled_at IS NOT NULL AND ( (cleanup_status = 'pending' AND cleanup_completed_at IS NULL) OR (cleanup_status = 'completed' AND cleanup_completed_at IS NOT NULL) )) ); UPDATE gateway_identity_onboarding_exchanges SET last_error_category = 'pairing_step_failed' WHERE last_error_category IS NOT NULL AND last_error_category NOT IN ( 'metadata_submission_failed','exchange_status_unavailable','credential_delivery_failed', 'exchange_completion_failed','exchange_expired','remote_exchange_failed','remote_state_invalid', 'security_event_configuration_invalid','security_event_connection_conflict', 'security_event_discovery_failed','security_event_management_token_failed', 'security_event_stream_create_failed','security_event_stream_response_invalid', 'security_event_receiver_activation_failed','security_event_preparation_failed', 'security_event_retirement_pending','pairing_step_failed', 'cleanup_revision_unavailable','cleanup_security_event_unavailable', 'cleanup_security_event_configuration_invalid','cleanup_security_event_connection_conflict', 'cleanup_security_event_discovery_failed','cleanup_security_event_management_token_failed', 'cleanup_security_event_stream_create_failed','cleanup_security_event_stream_response_invalid', 'cleanup_security_event_receiver_activation_failed','cleanup_security_event_preparation_failed', 'cleanup_security_event_retirement_pending','cleanup_security_event_connection_cleanup_failed', 'cleanup_security_event_secret_cleanup_failed','cleanup_security_event_failed', 'cleanup_secret_store_failed','cleanup_finalize_failed' ); ALTER TABLE gateway_identity_onboarding_exchanges ADD CONSTRAINT gateway_identity_onboarding_error_category_check CHECK (last_error_category IS NULL OR last_error_category IN ( 'metadata_submission_failed','exchange_status_unavailable','credential_delivery_failed', 'exchange_completion_failed','exchange_expired','remote_exchange_failed','remote_state_invalid', 'security_event_configuration_invalid','security_event_connection_conflict', 'security_event_discovery_failed','security_event_management_token_failed', 'security_event_stream_create_failed','security_event_stream_response_invalid', 'security_event_receiver_activation_failed','security_event_preparation_failed', 'security_event_retirement_pending','pairing_step_failed', 'cleanup_revision_unavailable','cleanup_security_event_unavailable', 'cleanup_security_event_configuration_invalid','cleanup_security_event_connection_conflict', 'cleanup_security_event_discovery_failed','cleanup_security_event_management_token_failed', 'cleanup_security_event_stream_create_failed','cleanup_security_event_stream_response_invalid', 'cleanup_security_event_receiver_activation_failed','cleanup_security_event_preparation_failed', 'cleanup_security_event_retirement_pending','cleanup_security_event_connection_cleanup_failed', 'cleanup_security_event_secret_cleanup_failed','cleanup_security_event_failed', 'cleanup_secret_store_failed','cleanup_finalize_failed' )); CREATE INDEX IF NOT EXISTS idx_gateway_identity_onboarding_cleanup ON gateway_identity_onboarding_exchanges(cleanup_status, updated_at) WHERE cleanup_status = 'pending';