-- v13.0 continuous model feedback loop. All schedules are inserted disabled and are evidence/proposal only.
create table if not exists evaluation.prediction_freeze (
    prediction_freeze_id uuid primary key,
    portfolio_scope text not null,
    market_session date not null,
    as_of timestamptz not null,
    dataset_id text not null,
    model_version text not null,
    config_version text not null,
    code_sha text not null,
    contract_version text not null,
    content_hash text not null unique,
    frozen_at timestamptz not null default now(),
    unique (portfolio_scope, market_session, model_version, content_hash)
);
create table if not exists evaluation.evaluation_window_maturity (
    maturity_id uuid primary key,
    decision_id uuid not null,
    window_sessions integer not null check (window_sessions in (1,5,20,63,126,252)),
    due_session date not null,
    maturity_revision integer not null check (maturity_revision > 0),
    status text not null check (status in ('PENDING','MATURED','HELD_DATA','EVALUATED','SUPERSEDED')),
    dataset_id text not null,
    supersedes_maturity_id uuid null references evaluation.evaluation_window_maturity(maturity_id),
    content_hash text not null unique,
    created_at timestamptz not null default now(),
    check (supersedes_maturity_id is null or supersedes_maturity_id <> maturity_id),
    unique (decision_id, window_sessions, dataset_id, maturity_revision)
);
create table if not exists governance.model_improvement_hypothesis (
    hypothesis_id uuid primary key,
    model_version text not null,
    hypothesis_version integer not null check (hypothesis_version > 0),
    problem_statement text not null,
    evidence_json jsonb not null,
    proposed_change text not null,
    expected_effect text not null,
    falsification_test text not null,
    non_goals text not null,
    status text not null check (status in ('DRAFT','REVIEW_REQUIRED','APPROVED_FOR_EXPERIMENT','REJECTED','SUPERSEDED','EXPIRED')),
    maker_id text not null,
    checker_id text null,
    supersedes_hypothesis_id uuid null references governance.model_improvement_hypothesis(hypothesis_id),
    expires_at timestamptz not null,
    content_hash text not null unique,
    created_at timestamptz not null default now(),
    decided_at timestamptz null,
    check (supersedes_hypothesis_id is null or supersedes_hypothesis_id <> hypothesis_id),
    check (status not in ('APPROVED_FOR_EXPERIMENT','REJECTED') or (checker_id is not null and checker_id <> maker_id and decided_at is not null)),
    unique (model_version, hypothesis_version)
);

drop trigger if exists prediction_freeze_append_only on evaluation.prediction_freeze;
create trigger prediction_freeze_append_only before update or delete on evaluation.prediction_freeze for each row execute function building_blocks.prevent_append_only_change();
drop trigger if exists evaluation_window_maturity_append_only on evaluation.evaluation_window_maturity;
create trigger evaluation_window_maturity_append_only before update or delete on evaluation.evaluation_window_maturity for each row execute function building_blocks.prevent_append_only_change();
drop trigger if exists model_improvement_hypothesis_append_only on governance.model_improvement_hypothesis;
create trigger model_improvement_hypothesis_append_only before update or delete on governance.model_improvement_hypothesis for each row execute function building_blocks.prevent_append_only_change();

insert into evaluation.model_operation_schedule
(schedule_id, operation_code, operation_name, scope_key, cadence, automation_mode, queue_name,
 schedule_version, enabled, next_due_at, max_lag, primary_owner, secondary_owner,
 calendar_id, due_policy, dependency_json, catch_up_policy, max_catch_up)
values
('e4100000-0000-4000-8000-000000000031','J31','PredictionFreezeRun','GLOBAL','DAILY','EVALUATION_ONLY','q-evaluation',2,false,now()+interval '1 day',interval '1 day','Quant/Data','QA/Risk','APPROVED_MARKET_CALENDAR','TRADING_SESSION','["PIT_CONTEXT_APPROVED","MODEL_CONTEXT_APPROVED"]','LATEST_ONLY',1),
('e4100000-0000-4000-8000-000000000032','J32','OutcomeMaturitySweep','GLOBAL','DAILY','EVALUATION_ONLY','q-evaluation',2,false,now()+interval '1 day',interval '1 day','Quant/Ops','Data/QA','APPROVED_MARKET_CALENDAR','TRADING_SESSION','["TOTAL_RETURN_COMPLETE","CALENDAR_APPROVED"]','BOUNDED',7),
('e4100000-0000-4000-8000-000000000033','J33','SellReentryAttributionReview','GLOBAL','WEEKLY','EVALUATION_ONLY','q-evaluation',2,false,now()+interval '7 days',interval '7 days','Quant/Risk','Advisor/QA','GLOBAL_UTC','FIXED_CADENCE','["OUTCOME_MATURED","METRIC_CONTRACT_APPROVED"]','LATEST_ONLY',1),
('e4100000-0000-4000-8000-000000000034','J34','CalibrationRegimeReview','GLOBAL','WEEKLY','EVALUATION_ONLY','q-evaluation',2,false,now()+interval '7 days',interval '7 days','Quant/Risk','Data/IndependentValidation','GLOBAL_UTC','FIXED_CADENCE','["COHORT_VERSION_APPROVED","REGIME_DEFINITION_APPROVED"]','LATEST_ONLY',1),
('e4100000-0000-4000-8000-000000000035','J35','ImprovementHypothesisBuild','GLOBAL','MONTHLY','PROPOSAL_ONLY','q-research',2,false,now()+interval '30 days',interval '30 days','Quant Lead','Risk/Architect','GLOBAL_UTC','FIXED_CADENCE','["SCORECARD_COMPLETE","ATTRIBUTION_COMPLETE","DEBT_REGISTER_CURRENT"]','LATEST_ONLY',1),
('e4100000-0000-4000-8000-000000000036','J36','ChallengerExperimentPlan','GLOBAL','MONTHLY','PROPOSAL_ONLY','q-research',2,false,now()+interval '30 days',interval '30 days','Quant Lead','IndependentValidation/QA','GLOBAL_UTC','FIXED_CADENCE','["HYPOTHESIS_APPROVED_FOR_EXPERIMENT","EXPERIMENT_REGISTRY_READY"]','LATEST_ONLY',1),
('e4100000-0000-4000-8000-000000000037','J37','IndependentValidationPack','GLOBAL','QUARTERLY','PROPOSAL_ONLY','q-control',2,false,now()+interval '90 days',interval '90 days','IndependentValidation','Risk/Compliance','GLOBAL_UTC','FIXED_CADENCE','["OOS_COMPLETE","PBO_DSR_COMPLETE","REPRODUCIBILITY_COMPLETE"]','LATEST_ONLY',1),
('e4100000-0000-4000-8000-000000000038','J38','ModelPolicyDebtReview','GLOBAL','MONTHLY','PROPOSAL_ONLY','q-control',2,false,now()+interval '30 days',interval '30 days','Risk/Architect','Quant/PM','GLOBAL_UTC','FIXED_CADENCE','["DEBT_REGISTER_CURRENT","INCIDENT_REVIEW_COMPLETE"]','LATEST_ONLY',1)
on conflict (operation_code, scope_key, schedule_version) do nothing;
