-- 139_deadline_rules_unified_view — Slice B.3 read cutover (t-paliad-305 / m/paliad#93) -- -- Creates paliad.deadline_rules_unified — a Postgres VIEW that -- re-projects paliad.sequencing_rules + paliad.procedural_events + -- paliad.legal_sources back into the legacy paliad.deadline_rules -- column shape. -- -- Why a view instead of rewriting every SELECT in Go: -- -- - 19 read sites across 11 service files reference -- paliad.deadline_rules. Rewriting each by hand multiplies the -- opportunity for off-by-one bugs in the JOIN. -- - The view has the same column names + types as the legacy table, -- so the change in Go is a 1-token substitution per query -- (FROM paliad.deadline_rules → FROM paliad.deadline_rules_unified) -- with no struct or scanner changes. -- - When B.4 drops paliad.deadline_rules, this view stays — it -- becomes the canonical legacy-shape reader for any code that -- hasn't been migrated to direct sr/pe/ls reads. -- -- Column mapping (per design §4.2): -- - id, proceeding_type_id, parent_id, primary_party, duration_*, -- timing, sequence_order, is_spawn/court_set/bilateral, priority, -- rule_code, rule_codes, deadline_notes(_en), condition_expr, -- choices_offered, applies_to_target, trigger_event_id, -- spawn_proceeding_type_id, anchor_alt, alt_duration_*, -- alt_rule_code, combine_op, lifecycle_state, draft_of, -- published_at, is_active, created_at, updated_at, spawn_label -- → from paliad.sequencing_rules -- - submission_code → procedural_events.code -- - name, name_en, description→ procedural_events -- - event_type → procedural_events.event_kind (renamed) -- - concept_id → procedural_events -- - legal_source → legal_sources.citation (via legal_source_id FK) -- -- The view is READ-ONLY by default. Writes still go to the underlying -- tables — RuleEditorService is refactored in the same slice to write -- directly to sr/pe/ls. paliad.deadline_rules is FROZEN from B.3 onward -- (no new writes); the dual-write helper from B.2 is decommissioned. -- The CHECK constraint on sequencing_rules.primary_party doesn't exist -- yet (mig 135 only constrained deadline_rules.primary_party). The view -- inherits whatever value sr.primary_party carries; mig 136's backfill -- set sr.primary_party = dr.primary_party so the canonical four-value -- vocab is already in place. A later slice can add the same CHECK to -- sequencing_rules itself. CREATE OR REPLACE VIEW paliad.deadline_rules_unified AS SELECT sr.id, sr.proceeding_type_id, sr.parent_id, pe.code AS submission_code, pe.name, pe.name_en, pe.description, sr.primary_party, pe.event_kind AS event_type, sr.duration_value, sr.duration_unit, sr.timing, sr.alt_duration_value, sr.alt_duration_unit, sr.alt_rule_code, sr.anchor_alt, sr.combine_op, sr.rule_code, sr.deadline_notes, sr.deadline_notes_en, sr.sequence_order, sr.is_spawn, sr.spawn_label, sr.spawn_proceeding_type_id, sr.is_bilateral, sr.is_court_set, sr.priority, sr.condition_expr, pe.concept_id, ls.citation AS legal_source, sr.trigger_event_id, sr.rule_codes, sr.choices_offered, sr.applies_to_target, sr.lifecycle_state, sr.draft_of, sr.published_at, sr.is_active, sr.created_at, sr.updated_at FROM paliad.sequencing_rules sr JOIN paliad.procedural_events pe ON pe.id = sr.procedural_event_id LEFT JOIN paliad.legal_sources ls ON ls.id = pe.legal_source_id; COMMENT ON VIEW paliad.deadline_rules_unified IS 'Slice B.3 (mig 139, t-paliad-305): legacy-shape projection over ' 'sequencing_rules + procedural_events + legal_sources. Read-only — ' 'writes go directly to the three underlying tables via ' 'RuleEditorService. Survives B.4 destructive drop of ' 'paliad.deadline_rules; the view will then be the only ' 'legacy-shape reader.'; -- Post-apply integrity check: confirm the view's row count matches the -- live sequencing_rules row count. A mismatch would indicate either a -- mid-deploy race (rare) or a JOIN issue (the LEFT JOIN to legal_sources -- never drops rows, the INNER JOIN to procedural_events drops sr rows -- whose procedural_event_id is NULL — but that column is NOT NULL on -- the table so it can't happen). Belt-and-braces. DO $$ DECLARE v_view_count int; v_sr_count int; BEGIN SELECT COUNT(*) INTO v_view_count FROM paliad.deadline_rules_unified; SELECT COUNT(*) INTO v_sr_count FROM paliad.sequencing_rules; IF v_view_count <> v_sr_count THEN RAISE EXCEPTION '[mig 139] FAILED POST: view row count % does not match sequencing_rules row count %. ' 'Possible cause: a sequencing_rules row references a procedural_event_id that does not exist (NOT NULL FK should prevent this).', v_view_count, v_sr_count; END IF; RAISE NOTICE '[mig 139] view OK — deadline_rules_unified rows = % (= sequencing_rules)', v_view_count; END $$;