-- Protected rollback for migration 017. It deliberately refuses to discard any -- review/audit/manual-price fact; use a forward corrective migration instead. BEGIN; DO $$ BEGIN IF current_database() <> 'booking_test' THEN RAISE EXCEPTION 'ARR daily price review rollback is allowed only in booking_test'; END IF; IF to_regclass('ingestion.daily_review_cases') IS NULL THEN RAISE EXCEPTION 'ARR daily price review migration is not applied'; END IF; IF EXISTS (SELECT 1 FROM ingestion.daily_review_cases) OR EXISTS ( SELECT 1 FROM finance.daily_versions WHERE review_case_id IS NOT NULL OR manual_override_sha256 IS NOT NULL OR manually_priced_rows <> 0 ) OR EXISTS ( SELECT 1 FROM ingestion.processing_runs WHERE run_status = 'awaiting_review' ) OR EXISTS ( SELECT 1 FROM ingestion.processing_attempts WHERE attempt_status = 'review_required' ) OR EXISTS ( SELECT 1 FROM ingestion.processing_deliveries WHERE delivery_status = 'recorded_review' OR result_status = 'review_required' ) THEN RAISE EXCEPTION 'refusing destructive rollback: daily review or manual-pricing facts exist'; END IF; END; $$; DO $$ BEGIN IF to_regrole('arr_app') IS NOT NULL THEN EXECUTE 'REVOKE SELECT, INSERT, UPDATE ON ingestion.daily_review_cases, ingestion.daily_review_items, ingestion.daily_review_events FROM arr_app'; EXECUTE 'REVOKE USAGE, SELECT ON SEQUENCE ingestion.daily_review_cases_id_seq, ingestion.daily_review_items_id_seq, ingestion.daily_review_events_id_seq FROM arr_app'; END IF; END; $$; ALTER TABLE finance.daily_versions DROP CONSTRAINT IF EXISTS daily_versions_review_lineage_shape; DROP INDEX IF EXISTS finance.daily_versions_review_case_unique; DROP INDEX IF EXISTS finance.daily_versions_source_rule_override_unique; ALTER TABLE finance.daily_versions DROP COLUMN manually_priced_rows, DROP COLUMN manual_override_sha256, DROP COLUMN review_case_id; CREATE UNIQUE INDEX daily_versions_source_rule_unique ON finance.daily_versions ( source_artifact_id, business_date, processor_version, rule_set_sha256 ) WHERE business_date IS NOT NULL; ALTER TABLE finance.daily_records DROP CONSTRAINT IF EXISTS daily_records_retained_values; ALTER TABLE finance.daily_records ADD CONSTRAINT daily_records_retained_values CHECK ( outcome <> 'retained' OR ( block_code IS NOT NULL AND adults IS NOT NULL AND adults >= 0 AND children IS NOT NULL AND children >= 0 AND company_name IS NOT NULL AND btrim(company_name) <> '' AND company_key IS NOT NULL AND btrim(company_key) <> '' AND confirmation_no IS NOT NULL AND btrim(confirmation_no) <> '' AND disp_room_no IS NOT NULL AND btrim(disp_room_no) <> '' AND effective_rate_amount IS NOT NULL AND effective_rate_amount >= 0 AND full_name IS NOT NULL AND no_of_rooms IS NOT NULL AND no_of_rooms > 0 AND rate_code IS NOT NULL AND normalized_rate_code IS NOT NULL AND arrival IS NOT NULL AND departure IS NOT NULL AND nights IS NOT NULL AND nights >= 0 AND real_price IS NOT NULL AND real_price >= 0 AND total_price IS NOT NULL AND total_price >= 0 AND channel_key IS NOT NULL AND btrim(channel_key) <> '' AND pricing_method IN ('price_reference_exact', 'zero_price_exception') ) ); ALTER TABLE ingestion.processing_deliveries DROP CONSTRAINT IF EXISTS processing_deliveries_review_case_fk, DROP COLUMN review_case_id, DROP COLUMN manual_override_artifact_id; DROP TRIGGER IF EXISTS daily_review_items_mutability_guard ON ingestion.daily_review_items; DROP TRIGGER IF EXISTS daily_review_cases_immutability_guard ON ingestion.daily_review_cases; DROP TRIGGER IF EXISTS daily_review_events_immutability_guard ON ingestion.daily_review_events; DROP FUNCTION IF EXISTS ingestion.enforce_daily_review_item_mutability(); DROP FUNCTION IF EXISTS ingestion.enforce_daily_review_case_immutability(); DROP FUNCTION IF EXISTS ingestion.enforce_daily_review_event_immutability(); DROP TABLE ingestion.daily_review_events; DROP TABLE ingestion.daily_review_items; DROP TABLE ingestion.daily_review_cases; ALTER TABLE ingestion.processing_deliveries DROP CONSTRAINT IF EXISTS processing_deliveries_delivery_status_check, DROP CONSTRAINT IF EXISTS processing_deliveries_result_status_check; ALTER TABLE ingestion.processing_deliveries ADD CONSTRAINT processing_deliveries_delivery_status_check CHECK (delivery_status IN ( 'received', 'validating', 'committed', 'recorded_failure', 'rejected' )), ADD CONSTRAINT processing_deliveries_result_status_check CHECK (result_status IN ( 'success', 'failed' )); ALTER TABLE ingestion.processing_attempts DROP CONSTRAINT IF EXISTS processing_attempts_attempt_status_check, DROP CONSTRAINT IF EXISTS processing_attempts_terminal_shape; ALTER TABLE ingestion.processing_attempts ADD CONSTRAINT processing_attempts_attempt_status_check CHECK (attempt_status IN ( 'queued', 'dispatched', 'running', 'delivered', 'succeeded', 'failed', 'cancelled' )), ADD CONSTRAINT processing_attempts_terminal_shape CHECK ( (attempt_status = 'succeeded' AND failure_code IS NULL AND finished_at IS NOT NULL) OR (attempt_status = 'failed' AND failure_code IS NOT NULL AND finished_at IS NOT NULL) OR (attempt_status = 'cancelled' AND finished_at IS NOT NULL) OR attempt_status IN ('queued', 'dispatched', 'running', 'delivered') ); ALTER TABLE ingestion.processing_runs DROP CONSTRAINT IF EXISTS processing_runs_run_status_check, DROP CONSTRAINT IF EXISTS processing_runs_terminal_shape; ALTER TABLE ingestion.processing_runs ADD CONSTRAINT processing_runs_run_status_check CHECK (run_status IN ( 'received', 'queued', 'running', 'validating', 'accepted', 'rejected', 'failed', 'cancelled' )), ADD CONSTRAINT processing_runs_terminal_shape CHECK ( ( run_status = 'accepted' AND failure_code IS NULL AND validated_at IS NOT NULL AND finished_at IS NOT NULL AND ( pipeline_type <> 'opera_daily' OR ( business_date IS NOT NULL AND delivered_processor_version IS NOT NULL AND delivered_rule_set_sha256 IS NOT NULL AND result_schema_version IS NOT NULL AND delivery_sha256 IS NOT NULL AND ( ( result_delivery_mode = 'artifact_callback' AND result_artifact_id IS NOT NULL ) OR ( result_delivery_mode = 'direct_mcp' AND result_artifact_id IS NULL ) ) ) ) ) OR (run_status IN ('rejected', 'failed') AND failure_code IS NOT NULL AND finished_at IS NOT NULL) OR (run_status = 'cancelled' AND finished_at IS NOT NULL) OR run_status IN ('received', 'queued', 'running', 'validating') ); COMMIT;