-- DB-CONTRACT-001: model-operation tables required by the approved handlers. -- Source: existing 0008/0010 contracts; append-only closure for the canonical -- db/migrations catalog. Outbox/Inbox remain building_blocks-owned. create schema if not exists model_operations; create table if not exists model_operations.shadow_run ( run_id uuid primary key, model_id uuid not null, window_start date not null, window_end date not null, status varchar(50) not null default 'Pending', metrics_json jsonb, phase_analysis_json jsonb, cost_analysis_json jsonb, false_exit_analysis_json jsonb, validation_gates_json jsonb, error_message text, created_at timestamp not null default current_timestamp, published_at timestamp, constraint check_window_order check (window_start <= window_end), constraint check_status check (status in ('Pending', 'DataBackfill', 'Replay', 'EvaluationComplete', 'Failed')) ); create index if not exists idx_shadow_run_model_created on model_operations.shadow_run (model_id, created_at desc); create index if not exists idx_shadow_run_status on model_operations.shadow_run (status); create index if not exists idx_shadow_run_published_at on model_operations.shadow_run (published_at); create table if not exists model_operations.approval_queue ( id uuid primary key default gen_random_uuid(), run_id uuid not null unique, model_id uuid not null, status varchar(32) not null default 'Pending', requested_by uuid, approved_by uuid, approval_reason text, rejection_reason text, requested_at timestamp not null default current_timestamp, approved_at timestamp, rejected_at timestamp, constraint approval_queue_run_fk foreign key (run_id) references model_operations.shadow_run(run_id) on delete restrict, constraint approval_queue_status_valid check (status in ('Pending', 'Approved', 'Rejected')) ); create index if not exists approval_queue_status_idx on model_operations.approval_queue(status); create index if not exists approval_queue_model_idx on model_operations.approval_queue(model_id, requested_at desc); create index if not exists approval_queue_requested_idx on model_operations.approval_queue(requested_at desc); create or replace function model_operations.approval_queue_check() returns trigger as $$ begin if new.status = 'Approved' then if new.approved_at is null then new.approved_at := current_timestamp; end if; if new.approved_by is null then raise exception 'approved_by must be set when status = Approved'; end if; elsif new.status = 'Rejected' then if new.rejected_at is null then new.rejected_at := current_timestamp; end if; if new.rejection_reason is null then raise exception 'rejection_reason must be set when status = Rejected'; end if; end if; return new; end; $$ language plpgsql; drop trigger if exists approval_queue_check_trigger on model_operations.approval_queue; create trigger approval_queue_check_trigger before insert or update on model_operations.approval_queue for each row execute function model_operations.approval_queue_check();