feat: t-paliad-284 Wave 1 Tier 1 deadline-rule additions (mig 132)

Add 12 Tier 1 procedural deadline rules from curie's audit §10
(docs/research-deadlines-completeness-2026-05-25.md), backfill the
UPC R.104/R.105 Interim Conference citation on upc.inf.cfi.interim
(m/paliad#116 / m's 2026-05-25 report), and fold in the audit Q6
cleanup of the 40 _archived_litigation.* rows.

New rules:
  T1.1  upc.inf.cfi.cmo_review           15d / R.333.2
  T1.2  upc.inf.cfi.confidentiality_response 14d / R.262.2 (trigger 25)
  T1.3  upc.apl.order.grounds_orders     15d / R.224.2(b)
  T1.4  upc.apl.order.response_orders    15d / R.235.2
  T1.5  upc.inf.cfi.cons_orders          2mo / R.118.4
  T1.6  upc.inf.cfi.rectification        1mo / R.353
  T1.7  upc.pi.cfi.deficiency            14d / R.207.6(a)
  T1.8  upc.pi.cfi.merits_start          31d OR 20wd (max) / R.213 + R.198.1
  T1.9  upc.inf.cfi.translation_request  1mo BEFORE oral / R.109.1
  T1.10 upc.inf.cfi.interpreter_cost     2wk BEFORE oral / R.109.4
  T1.11 upc.inf.cfi.translations_lodge   2wk / R.109.5 (trigger 113)
  T1.12 upc.pi.cfi.response              UPDATE: re-anchor on .app, court-set

T1.8 uses Wave 2 Slice A primitives (mig 128: working_days unit +
combine_op='max'). T1.9/T1.10 use timing='before' with the
backward-snap path in deadline_calculator.go.

Also drops the deadline_rule_audit.rule_id FK constraint. The mig 079
audit trigger had a latent bug — it could not log DELETEs because the
FK rejected the post-delete INSERT (count(*) WHERE action='delete'
was 0 across the entire history). Audit tables are append-only
history and should not FK-constrain on live entity tables; before_json
preserves the full row state. Unblocking this also unblocks the §13b
Q6 cleanup.

Verified on Supabase: 13 rows present in post-fix shape, all
assertions in the DO-block pass, audit log now records 11 creates +
2 updates + 40 deletes for this migration.
This commit is contained in:
mAi
2026-05-25 17:29:13 +02:00
parent c4e9875ff4
commit a6cf6ff4c9
2 changed files with 735 additions and 0 deletions

View File

@@ -0,0 +1,76 @@
-- Rollback of mig 132 (t-paliad-284 Wave 1 + m/paliad#116).
--
-- Reverses §0 (R.104/R.105 citation backfill) + §1..§11 (11 Tier 1
-- INSERTs) + §12 (T1.12 re-anchor of upc.pi.cfi.response).
--
-- Does NOT reverse §13b (Q6 archived-litigation cleanup) — those rows
-- were already in lifecycle_state='archived' before deletion and are not
-- surfaced by any product code path. Restoring them would require the
-- pre-mig-132 backup. Leaving them gone is the correct rollback choice;
-- emergency restore goes via mig 123 backup snapshot.
--
-- DOES restore §13a (re-add the deadline_rule_audit.rule_id FK) so the
-- audit-table schema returns to its pre-mig-132 shape on rollback. Any
-- orphan audit rows accumulated under mig 132 (rule_id pointing at
-- now-deleted rules) would block the FK re-add; the rollback DELETE
-- below removes them first.
SELECT set_config(
'paliad.audit_reason',
'mig 132 down: rollback Wave 1 Tier 1 rule additions + R.105 citation backfill + T1.12 re-anchor (t-paliad-284 / m/paliad#116)',
true);
-- §12 down — un-re-anchor upc.pi.cfi.response back to its broken root state.
UPDATE paliad.deadline_rules
SET parent_id = NULL,
is_court_set = false,
rule_code = NULL,
legal_source = NULL,
updated_at = now()
WHERE submission_code = 'upc.pi.cfi.response'
AND is_active = true
AND lifecycle_state = 'published'
AND is_court_set = true
AND rule_code = 'RoP.211.2';
-- §1..§11 down — delete the 11 Tier 1 INSERTs by submission_code.
DELETE FROM paliad.deadline_rules
WHERE submission_code IN (
'upc.inf.cfi.cmo_review',
'upc.inf.cfi.confidentiality_response',
'upc.apl.order.response_orders', -- delete child first (FK to grounds_orders)
'upc.apl.order.grounds_orders',
'upc.inf.cfi.cons_orders',
'upc.inf.cfi.rectification',
'upc.pi.cfi.deficiency',
'upc.pi.cfi.merits_start',
'upc.inf.cfi.translation_request',
'upc.inf.cfi.interpreter_cost',
'upc.inf.cfi.translations_lodge'
)
AND lifecycle_state = 'published';
-- §0 down — clear the R.104/R.105 citation on upc.inf.cfi.interim.
UPDATE paliad.deadline_rules
SET rule_code = NULL,
legal_source = NULL,
rule_codes = NULL,
updated_at = now()
WHERE submission_code = 'upc.inf.cfi.interim'
AND is_active = true
AND lifecycle_state = 'published'
AND rule_code = 'RoP.104'
AND legal_source = 'UPC.RoP.104';
-- §13a down — re-add the deadline_rule_audit.rule_id FK with the
-- original ON DELETE CASCADE shape. Purge any orphan audit rows first
-- (audit entries pointing at rule_ids that no longer exist in
-- deadline_rules) so the FK re-add doesn't fail validation.
DELETE FROM paliad.deadline_rule_audit a
WHERE NOT EXISTS (
SELECT 1 FROM paliad.deadline_rules dr WHERE dr.id = a.rule_id
);
ALTER TABLE paliad.deadline_rule_audit
ADD CONSTRAINT deadline_rule_audit_rule_id_fkey
FOREIGN KEY (rule_id) REFERENCES paliad.deadline_rules(id) ON DELETE CASCADE;

View File

@@ -0,0 +1,659 @@
-- t-paliad-284 Wave 1 + m/paliad#116 — Tier 1 deadline-rule additions
-- (12 high-frequency procedural events) + UPC RoP R.104/R.105 Interim
-- Conference citation backfill + Q6 archived-litigation cleanup.
--
-- Source: docs/research-deadlines-completeness-2026-05-25.md
-- • §10 Tier 1 table (T1.1 .. T1.12)
-- • §3.1 missing-rules catalogue (per-rule statutory citations)
-- • §9.7 / Q6 (drop the _archived_litigation.* rows — m's design ack
-- locked in 2026-05-25)
--
-- m's report (2026-05-25 17:12) also explicitly named "Zwischenverfahren /
-- Interim Conference 105" as missing a rule citation. The audit does not
-- list R.105 as a Tier 1 item (the row upc.inf.cfi.interim already exists
-- as a court-set anchor), so the fix is to BACKFILL rule_code/legal_source
-- on that row rather than to insert a new rule. Done here as a separate
-- §0 section, with both RoP.104 (Aims of the interim conference) and
-- RoP.105 (Holding of the interim conference) cited via rule_codes[].
--
-- Wave 2 Slice A primitives (mig 128: working_days unit + combine_op +
-- timing='before' backward snap in deadline_calculator.go) are used by:
-- • T1.8 upc.pi.cfi.merits_start — 31d OR 20wd, combine_op=max
-- • T1.9 upc.inf.cfi.translation_request — 1 month BEFORE oral hearing
-- • T1.10 upc.inf.cfi.interpreter_cost — 2 weeks BEFORE oral hearing
-- Wave 2 Slice A landed mig 128 (`deadline_rules_unit_check`) — these
-- rules are no longer blocked.
--
-- Slot 132 reserved: 127 brunel Wave 0, 128 knuth W2-A, 129 demeter,
-- 130 atlas, 131 artemis → 132 this migration.
--
-- Idempotency:
-- • INSERTs guarded with `WHERE NOT EXISTS (... submission_code = ...)`
-- so re-applying matches zero rows on the second run.
-- • UPDATEs guarded with `WHERE` clauses that match the pre-fix row
-- state only (mig 095 convention).
-- • DELETE guarded by lifecycle_state='archived' AND prefix — repeats
-- match zero rows after first run.
--
-- audit_reason set_config is required at the top (mig 079 trigger on
-- paliad.deadline_rules raises EXCEPTION 'audit reason required' for
-- any INSERT / UPDATE / DELETE without it).
SELECT set_config(
'paliad.audit_reason',
'mig 132: t-paliad-284 Wave 1 + m/paliad#116 — Tier 1 deadline-rule additions (12 rules) from curie''s audit §10 + UPC RoP R.104/105 Interim Conference citation backfill (m''s 2026-05-25 17:12 report) + Q6 archived-litigation cleanup (audit §9.7)',
true);
-- =============================================================================
-- §0 R.104/R.105 — Backfill citation on the existing Interim Conference row.
-- m's report flagged that `upc.inf.cfi.interim` (Zwischenverfahren) renders
-- with no rule reference at /admin/rules. The row exists as a court-set
-- anchor (duration=0, parent_id=NULL, primary_party='court'). The
-- governing UPC Rules of Procedure are:
-- • R.104 — Aims of the interim conference (the substantive rule)
-- • R.105 — Holding of the interim conference (procedural)
-- Both cited via the rule_codes[] array; rule_code/legal_source carry
-- the primary citation (R.104 — Aims).
-- =============================================================================
UPDATE paliad.deadline_rules
SET rule_code = 'RoP.104',
legal_source = 'UPC.RoP.104',
rule_codes = ARRAY['RoP.104', 'RoP.105'],
updated_at = now()
WHERE submission_code = 'upc.inf.cfi.interim'
AND is_active = true
AND lifecycle_state = 'published'
AND rule_code IS NULL
AND legal_source IS NULL;
-- =============================================================================
-- §1 T1.1 upc.inf.cfi.cmo_review — Review of case-management order.
-- 15 days from CMO service. UPC RoP R.333.2: "Any party adversely
-- affected by a case management order may within 15 days of service
-- of the order apply to the panel for a review." Routine in busy LDs
-- (Munich CMO traffic ~weekly). Anchor: the Interim Conference row,
-- which is where CMOs are typically issued.
-- =============================================================================
INSERT INTO paliad.deadline_rules
(proceeding_type_id, parent_id, submission_code, name, name_en,
primary_party, duration_value, duration_unit, timing, rule_code,
legal_source, priority, is_court_set, lifecycle_state, is_active,
sequence_order, deadline_notes, deadline_notes_en)
SELECT 8, -- upc.inf.cfi
(SELECT id FROM paliad.deadline_rules
WHERE submission_code = 'upc.inf.cfi.interim'
AND lifecycle_state = 'published' AND is_active = true
LIMIT 1),
'upc.inf.cfi.cmo_review',
'Überprüfung Verfahrensanordnung',
'Review of Case-Management Order',
'both', 15, 'days', 'after', 'RoP.333.2', 'UPC.RoP.333.2',
'optional', false, 'published', true, 42,
'Frist 15 Tage ab Zustellung der Verfahrensanordnung (R.333.2). Jede beschwerte Partei kann beim Spruchkörper Überprüfung beantragen.',
'15-day period from service of the case-management order (R.333.2). Any adversely-affected party may apply to the panel for a review.'
WHERE NOT EXISTS (
SELECT 1 FROM paliad.deadline_rules
WHERE submission_code = 'upc.inf.cfi.cmo_review'
AND lifecycle_state = 'published'
);
-- =============================================================================
-- §2 T1.2 upc.inf.cfi.confidentiality_response — Response to opposing
-- party's confidentiality application. 14 days from receipt of the
-- opposing party's R.262.2 application: "Within 14 days of service
-- … the other party may lodge an Application to the contrary."
-- Trigger event 25 (paliad.trigger_events) maps 1:1 to this rule.
-- Daily occurrence in HLC infringement work. Anchor: Statement of
-- Claim row as proceeding root — actual trigger date supplied via
-- 'Datum setzen' when the opp party files, since the confidentiality
-- app is not itself modelled as a deadline_rules row.
-- =============================================================================
INSERT INTO paliad.deadline_rules
(proceeding_type_id, parent_id, submission_code, name, name_en,
primary_party, duration_value, duration_unit, timing, rule_code,
legal_source, priority, is_court_set, lifecycle_state, is_active,
sequence_order, trigger_event_id, deadline_notes, deadline_notes_en)
SELECT 8,
(SELECT id FROM paliad.deadline_rules
WHERE submission_code = 'upc.inf.cfi.soc'
AND lifecycle_state = 'published' AND is_active = true
LIMIT 1),
'upc.inf.cfi.confidentiality_response',
'Erwiderung auf Vertraulichkeitsantrag',
'Response to Confidentiality Application',
'both', 14, 'days', 'after', 'RoP.262.2', 'UPC.RoP.262.2',
'optional', false, 'published', true, 8,
25,
'Frist 14 Tage ab Zustellung des Vertraulichkeitsantrags der Gegenseite (R.262.2). Datum bei Eingang des Antrags manuell setzen.',
'14-day period from service of the opposing party''s confidentiality application (R.262.2). Set trigger date manually on receipt of the application.'
WHERE NOT EXISTS (
SELECT 1 FROM paliad.deadline_rules
WHERE submission_code = 'upc.inf.cfi.confidentiality_response'
AND lifecycle_state = 'published'
);
-- =============================================================================
-- §3 T1.3 upc.apl.order.grounds_orders — Statement of Grounds on the
-- orders-track appeal. 15 days from service of the appealed
-- order/decision. UPC RoP R.224.2(b): "A Statement of grounds of
-- appeal shall be lodged … within 15 days of service of the
-- decision/order in cases referred to in Rule 220.1(c), Rule 220.2
-- and Rule 221.3." Existing upc.apl.order tree has the with_leave
-- notice but no separate grounds row — adding it.
-- =============================================================================
INSERT INTO paliad.deadline_rules
(proceeding_type_id, parent_id, submission_code, name, name_en,
primary_party, duration_value, duration_unit, timing, rule_code,
legal_source, priority, is_court_set, lifecycle_state, is_active,
sequence_order, deadline_notes, deadline_notes_en)
SELECT 20, -- upc.apl.order
(SELECT id FROM paliad.deadline_rules
WHERE submission_code = 'upc.apl.order.order'
AND lifecycle_state = 'published' AND is_active = true
LIMIT 1),
'upc.apl.order.grounds_orders',
'Berufungsbegründung (Orders Track)',
'Statement of Grounds (Orders Track)',
'both', 15, 'days', 'after', 'RoP.224.2.b', 'UPC.RoP.224.2.b',
'mandatory', false, 'published', true, 2,
'Frist 15 Tage ab Zustellung der angegriffenen Anordnung/Entscheidung (R.224.2(b)).',
'15-day period from service of the appealed order/decision (R.224.2(b)).'
WHERE NOT EXISTS (
SELECT 1 FROM paliad.deadline_rules
WHERE submission_code = 'upc.apl.order.grounds_orders'
AND lifecycle_state = 'published'
);
-- =============================================================================
-- §4 T1.4 upc.apl.order.response_orders — Statement of Response on the
-- orders-track appeal. 15 days from service of the grounds. UPC RoP
-- R.235.2: "Within 15 days of service of grounds of appeal pursuant
-- to Rule 224.2(b), any other party … may lodge a Statement of
-- response." Parent: the grounds_orders row inserted in §3, looked
-- up by submission_code so this INSERT works either against a fresh
-- DB or a partially-applied state.
-- =============================================================================
INSERT INTO paliad.deadline_rules
(proceeding_type_id, parent_id, submission_code, name, name_en,
primary_party, duration_value, duration_unit, timing, rule_code,
legal_source, priority, is_court_set, lifecycle_state, is_active,
sequence_order, deadline_notes, deadline_notes_en)
SELECT 20,
(SELECT id FROM paliad.deadline_rules
WHERE submission_code = 'upc.apl.order.grounds_orders'
AND lifecycle_state = 'published' AND is_active = true
LIMIT 1),
'upc.apl.order.response_orders',
'Berufungserwiderung (Orders Track)',
'Statement of Response (Orders Track)',
'both', 15, 'days', 'after', 'RoP.235.2', 'UPC.RoP.235.2',
'optional', false, 'published', true, 3,
'Frist 15 Tage ab Zustellung der Berufungsbegründung (R.235.2).',
'15-day period from service of the Statement of grounds of appeal (R.235.2).'
WHERE NOT EXISTS (
SELECT 1 FROM paliad.deadline_rules
WHERE submission_code = 'upc.apl.order.response_orders'
AND lifecycle_state = 'published'
);
-- =============================================================================
-- §5 T1.5 upc.inf.cfi.cons_orders — Application for orders consequential
-- on validity. 2 months from service of the validity decision. UPC
-- RoP R.118.4: "The Court may, upon a reasoned request by one of
-- the parties, … give a decision granting consequential orders.
-- The application … shall be made within two months of service of
-- the decision …". Common after central-division revocation in
-- bifurcated UPC matters.
-- =============================================================================
INSERT INTO paliad.deadline_rules
(proceeding_type_id, parent_id, submission_code, name, name_en,
primary_party, duration_value, duration_unit, timing, rule_code,
legal_source, priority, is_court_set, lifecycle_state, is_active,
sequence_order, deadline_notes, deadline_notes_en)
SELECT 8,
(SELECT id FROM paliad.deadline_rules
WHERE submission_code = 'upc.inf.cfi.decision'
AND lifecycle_state = 'published' AND is_active = true
LIMIT 1),
'upc.inf.cfi.cons_orders',
'Antrag auf Folgeentscheidungen',
'Application for Consequential Orders',
'both', 2, 'months', 'after', 'RoP.118.4', 'UPC.RoP.118.4',
'optional', false, 'published', true, 60,
'Frist 2 Monate ab Zustellung der Validitätsentscheidung (R.118.4). Antrag auf Folgeentscheidungen (z.B. nach Zentralkammer-Nichtigerklärung).',
'2-month period from service of the validity decision (R.118.4). Application for orders consequential on validity (e.g. after central-division revocation).'
WHERE NOT EXISTS (
SELECT 1 FROM paliad.deadline_rules
WHERE submission_code = 'upc.inf.cfi.cons_orders'
AND lifecycle_state = 'published'
);
-- =============================================================================
-- §6 T1.6 upc.inf.cfi.rectification — Application for rectification of a
-- decision/order. 1 month from delivery of the decision. UPC RoP
-- R.353: "Clerical mistakes, errors arising from any accidental
-- slip or omission and obvious errors in a decision or order of
-- the Court may be corrected by the Court of its own motion or on
-- the application of a party. The application shall be made within
-- one month of the decision or order being notified."
-- =============================================================================
INSERT INTO paliad.deadline_rules
(proceeding_type_id, parent_id, submission_code, name, name_en,
primary_party, duration_value, duration_unit, timing, rule_code,
legal_source, priority, is_court_set, lifecycle_state, is_active,
sequence_order, deadline_notes, deadline_notes_en)
SELECT 8,
(SELECT id FROM paliad.deadline_rules
WHERE submission_code = 'upc.inf.cfi.decision'
AND lifecycle_state = 'published' AND is_active = true
LIMIT 1),
'upc.inf.cfi.rectification',
'Antrag auf Berichtigung',
'Application for Rectification',
'both', 1, 'months', 'after', 'RoP.353', 'UPC.RoP.353',
'optional', false, 'published', true, 70,
'Frist 1 Monat ab Zustellung der Entscheidung/Anordnung (R.353). Berichtigung von Schreib-, Rechen- oder ähnlichen Versehen.',
'1-month period from notification of the decision/order (R.353). Rectification of clerical mistakes, accidental slips or obvious errors.'
WHERE NOT EXISTS (
SELECT 1 FROM paliad.deadline_rules
WHERE submission_code = 'upc.inf.cfi.rectification'
AND lifecycle_state = 'published'
);
-- =============================================================================
-- §7 T1.7 upc.pi.cfi.deficiency — Cure of PI-application deficiency.
-- 14 days from notification of the deficiency. UPC RoP R.207.6(a):
-- "The Registry shall as soon as practicable examine the
-- Application … and notify any deficiencies to the applicant. The
-- applicant shall be invited to correct the deficiencies … within
-- 14 days." Failure to cure leads to deemed-withdrawal.
-- =============================================================================
INSERT INTO paliad.deadline_rules
(proceeding_type_id, parent_id, submission_code, name, name_en,
primary_party, duration_value, duration_unit, timing, rule_code,
legal_source, priority, is_court_set, lifecycle_state, is_active,
sequence_order, deadline_notes, deadline_notes_en)
SELECT 10, -- upc.pi.cfi
(SELECT id FROM paliad.deadline_rules
WHERE submission_code = 'upc.pi.cfi.app'
AND lifecycle_state = 'published' AND is_active = true
LIMIT 1),
'upc.pi.cfi.deficiency',
'Mängelbeseitigung Antrag',
'Cure of Application Deficiency',
'claimant', 14, 'days', 'after', 'RoP.207.6.a', 'UPC.RoP.207.6.a',
'mandatory', false, 'published', true, 2,
'Frist 14 Tage ab Mängelmitteilung durch die Geschäftsstelle (R.207.6(a)). Bei Nichtbehebung gilt der Antrag als zurückgenommen.',
'14-day period from notification of deficiency by the Registry (R.207.6(a)). Failure to cure leads to deemed withdrawal of the application.'
WHERE NOT EXISTS (
SELECT 1 FROM paliad.deadline_rules
WHERE submission_code = 'upc.pi.cfi.deficiency'
AND lifecycle_state = 'published'
);
-- =============================================================================
-- §8 T1.8 upc.pi.cfi.merits_start — Start proceedings on the merits.
-- 31 calendar days OR 20 working days, whichever is the longer,
-- from grant of the PI. UPC RoP R.213.1 → R.198.1: "the applicant
-- shall start proceedings leading to a decision on the merits of
-- the case … within a period not exceeding 31 calendar days or
-- 20 working days, whichever is the longer." Combine-max wiring
-- via Wave 2 Slice A primitives (mig 128: working_days unit +
-- combine_op). Failure to commence on time → PI lapses (R.213.2).
-- =============================================================================
INSERT INTO paliad.deadline_rules
(proceeding_type_id, parent_id, submission_code, name, name_en,
primary_party, duration_value, duration_unit,
alt_duration_value, alt_duration_unit, alt_rule_code,
combine_op, timing, rule_code, legal_source, priority,
is_court_set, lifecycle_state, is_active, sequence_order,
deadline_notes, deadline_notes_en)
SELECT 10,
(SELECT id FROM paliad.deadline_rules
WHERE submission_code = 'upc.pi.cfi.order'
AND lifecycle_state = 'published' AND is_active = true
LIMIT 1),
'upc.pi.cfi.merits_start',
'Klage in der Hauptsache erheben',
'Start Proceedings on the Merits',
'claimant', 31, 'days',
20, 'working_days', 'RoP.198.1',
'max', 'after', 'RoP.213', 'UPC.RoP.213',
'mandatory', false, 'published', true, 3,
'Frist 31 Kalendertage ODER 20 Arbeitstage (jeweils das längere) ab Anordnung der einstweiligen Maßnahme (R.213 i.V.m. R.198.1). Bei Versäumnis erlischt die einstweilige Maßnahme.',
'31 calendar days OR 20 working days, whichever is the longer, from grant of the provisional measure (R.213 referring to R.198.1). Failure to commence within the period causes the provisional measure to lapse.'
WHERE NOT EXISTS (
SELECT 1 FROM paliad.deadline_rules
WHERE submission_code = 'upc.pi.cfi.merits_start'
AND lifecycle_state = 'published'
);
-- =============================================================================
-- §9 T1.9 upc.inf.cfi.translation_request — Request for simultaneous
-- translation at the oral hearing. 1 month BEFORE the oral hearing.
-- UPC RoP R.109.1: "A party requiring simultaneous interpretation
-- of the oral hearing into a language other than the language of
-- proceedings shall, no later than one month before the date of
-- the oral hearing, lodge a request with the Court." timing='before'
-- uses the backward-snap path in deadline_calculator.go (mig 128).
-- =============================================================================
INSERT INTO paliad.deadline_rules
(proceeding_type_id, parent_id, submission_code, name, name_en,
primary_party, duration_value, duration_unit, timing, rule_code,
legal_source, priority, is_court_set, lifecycle_state, is_active,
sequence_order, deadline_notes, deadline_notes_en)
SELECT 8,
(SELECT id FROM paliad.deadline_rules
WHERE submission_code = 'upc.inf.cfi.oral'
AND lifecycle_state = 'published' AND is_active = true
LIMIT 1),
'upc.inf.cfi.translation_request',
'Antrag auf Simultanübersetzung',
'Request for Simultaneous Translation',
'both', 1, 'months', 'before', 'RoP.109.1', 'UPC.RoP.109.1',
'optional', false, 'published', true, 45,
'Frist 1 Monat VOR der mündlichen Verhandlung (R.109.1). Antrag auf Simultanübersetzung in eine andere Sprache als die Verfahrenssprache.',
'1 month BEFORE the oral hearing (R.109.1). Request for simultaneous interpretation into a language other than the language of proceedings.'
WHERE NOT EXISTS (
SELECT 1 FROM paliad.deadline_rules
WHERE submission_code = 'upc.inf.cfi.translation_request'
AND lifecycle_state = 'published'
);
-- =============================================================================
-- §10 T1.10 upc.inf.cfi.interpreter_cost — Notification of interpreter
-- cost-bearing. 2 weeks BEFORE the oral hearing. UPC RoP R.109.4:
-- "Where … the party which made the request for interpretation is
-- not the party who has chosen the language of the proceedings,
-- the costs of the interpretation … shall be borne by the
-- requesting party, unless the Court orders otherwise. The party
-- shall be notified at least two weeks before the oral hearing."
-- timing='before' as in §9.
-- =============================================================================
INSERT INTO paliad.deadline_rules
(proceeding_type_id, parent_id, submission_code, name, name_en,
primary_party, duration_value, duration_unit, timing, rule_code,
legal_source, priority, is_court_set, lifecycle_state, is_active,
sequence_order, deadline_notes, deadline_notes_en)
SELECT 8,
(SELECT id FROM paliad.deadline_rules
WHERE submission_code = 'upc.inf.cfi.oral'
AND lifecycle_state = 'published' AND is_active = true
LIMIT 1),
'upc.inf.cfi.interpreter_cost',
'Mitteilung Dolmetscherkosten',
'Notification of Interpreter Costs',
'court', 2, 'weeks', 'before', 'RoP.109.4', 'UPC.RoP.109.4',
'mandatory', false, 'published', true, 46,
'Frist 2 Wochen VOR der mündlichen Verhandlung (R.109.4). Mitteilung, dass die antragstellende Partei die Dolmetscherkosten zu tragen hat.',
'2 weeks BEFORE the oral hearing (R.109.4). Notification to the requesting party that it shall bear the interpreter costs.'
WHERE NOT EXISTS (
SELECT 1 FROM paliad.deadline_rules
WHERE submission_code = 'upc.inf.cfi.interpreter_cost'
AND lifecycle_state = 'published'
);
-- =============================================================================
-- §11 T1.11 upc.inf.cfi.translations_lodge — Lodging of translations on
-- judge-rapporteur order. 2 weeks AFTER the JR's order. UPC RoP
-- R.109.5: "If the judge-rapporteur orders, the parties shall lodge
-- a translation of any pleading or other document into the language
-- of the proceedings within two weeks." trigger_event_id=113 maps
-- to the JR translation order. Anchor: Interim Conference row, where
-- such JR orders are typically issued.
-- =============================================================================
INSERT INTO paliad.deadline_rules
(proceeding_type_id, parent_id, submission_code, name, name_en,
primary_party, duration_value, duration_unit, timing, rule_code,
legal_source, priority, is_court_set, lifecycle_state, is_active,
sequence_order, trigger_event_id, deadline_notes, deadline_notes_en)
SELECT 8,
(SELECT id FROM paliad.deadline_rules
WHERE submission_code = 'upc.inf.cfi.interim'
AND lifecycle_state = 'published' AND is_active = true
LIMIT 1),
'upc.inf.cfi.translations_lodge',
'Übersetzungen einreichen',
'Lodging of Translations',
'both', 2, 'weeks', 'after', 'RoP.109.5', 'UPC.RoP.109.5',
'mandatory', false, 'published', true, 47,
113,
'Frist 2 Wochen ab Anordnung des Berichterstatters, Übersetzungen einzureichen (R.109.5).',
'2-week period from the judge-rapporteur''s order to lodge translations (R.109.5).'
WHERE NOT EXISTS (
SELECT 1 FROM paliad.deadline_rules
WHERE submission_code = 'upc.inf.cfi.translations_lodge'
AND lifecycle_state = 'published'
);
-- =============================================================================
-- §12 T1.12 upc.pi.cfi.response — RE-ANCHOR of the existing PI Response
-- row. Currently broken: parent_id=NULL with is_court_set=false and
-- duration=0 makes the calculator treat this as a root anchor. UPC
-- RoP R.211.2 — judge sets the inter-partes hearing date and the
-- deadline for the response. Fix: set is_court_set=true and chain
-- parent_id on upc.pi.cfi.app (the proceeding root). Duration
-- remains 0 (court-set placeholder); the lawyer fills in the actual
-- date via 'Datum setzen'.
-- =============================================================================
UPDATE paliad.deadline_rules
SET parent_id = (SELECT id FROM paliad.deadline_rules
WHERE submission_code = 'upc.pi.cfi.app'
AND lifecycle_state = 'published'
AND is_active = true
LIMIT 1),
is_court_set = true,
rule_code = 'RoP.211.2',
legal_source = 'UPC.RoP.211.2',
updated_at = now()
WHERE submission_code = 'upc.pi.cfi.response'
AND is_active = true
AND lifecycle_state = 'published'
AND parent_id IS NULL
AND is_court_set = false;
-- =============================================================================
-- §13a Pre-requisite for §13b — drop the deadline_rule_audit.rule_id FK.
-- The audit trigger (mig 079) tries to INSERT an audit row on AFTER
-- DELETE pointing at OLD.id, but the existing FK constraint
-- `deadline_rule_audit_rule_id_fkey` (FOREIGN KEY rule_id REFERENCES
-- paliad.deadline_rules(id) ON DELETE CASCADE) makes that INSERT fail
-- because by the time the trigger fires the parent row is gone. As a
-- result no DELETE on paliad.deadline_rules has ever succeeded in
-- production (`SELECT count(*) FROM paliad.deadline_rule_audit
-- WHERE action='delete'` returns 0). The trigger's DELETE branch was
-- dead code.
--
-- Standard audit-table design: the audit log is append-only history
-- and should NOT FK-constrain on the live entity table — before_json
-- captures the full row state at the time of the change, which is
-- all the audit trail needs. Dropping the FK fixes the latent bug
-- and unblocks legitimate cleanup work (here: §13b, plus any future
-- hard-delete migrations against deadline_rules).
--
-- Idempotent: DROP CONSTRAINT IF EXISTS no-ops on re-run.
-- =============================================================================
ALTER TABLE paliad.deadline_rule_audit
DROP CONSTRAINT IF EXISTS deadline_rule_audit_rule_id_fkey;
-- =============================================================================
-- §13b Q6 cleanup — drop the _archived_litigation.* deadline rules.
-- 40 rows at audit §9.7 flagged as obsolete Pipeline-A residue
-- (proceeding_type id=32 '_archived_litigation' — kept for FK
-- parity but the rules are no longer surfaced anywhere in the
-- product). m's Q6 design ack 2026-05-25 locked in their removal.
-- Idempotent: prefix + lifecycle_state='archived' match zero rows
-- after first run. The proceeding_type row itself is left in place
-- (referenced by historical deadline_rule_audit before_json blobs).
-- =============================================================================
DELETE FROM paliad.deadline_rules
WHERE submission_code LIKE '_archived_litigation.%' ESCAPE '\'
AND lifecycle_state = 'archived';
-- =============================================================================
-- Hard assertions. Each new/changed row must end up in its post-fix
-- shape. Re-running the migration is a no-op for the data but the
-- assertions still pass because they check the post-fix state.
-- =============================================================================
DO $$
DECLARE
v_count integer;
BEGIN
-- §0 R.105 interim conference backfilled
SELECT count(*) INTO v_count
FROM paliad.deadline_rules
WHERE submission_code = 'upc.inf.cfi.interim'
AND is_active = true
AND lifecycle_state = 'published'
AND rule_code = 'RoP.104'
AND legal_source = 'UPC.RoP.104'
AND 'RoP.105' = ANY(rule_codes);
IF v_count <> 1 THEN
RAISE EXCEPTION 'mig 132 §0: upc.inf.cfi.interim citation backfill not in post-fix shape (got % matches)', v_count;
END IF;
-- §1 T1.1 cmo_review present
SELECT count(*) INTO v_count
FROM paliad.deadline_rules
WHERE submission_code = 'upc.inf.cfi.cmo_review'
AND is_active = true AND lifecycle_state = 'published'
AND rule_code = 'RoP.333.2' AND duration_value = 15
AND duration_unit = 'days' AND timing = 'after';
IF v_count <> 1 THEN
RAISE EXCEPTION 'mig 132 T1.1: upc.inf.cfi.cmo_review missing or wrong shape (got % matches)', v_count;
END IF;
-- §2 T1.2 confidentiality_response
SELECT count(*) INTO v_count
FROM paliad.deadline_rules
WHERE submission_code = 'upc.inf.cfi.confidentiality_response'
AND is_active = true AND lifecycle_state = 'published'
AND rule_code = 'RoP.262.2' AND duration_value = 14
AND duration_unit = 'days' AND trigger_event_id = 25;
IF v_count <> 1 THEN
RAISE EXCEPTION 'mig 132 T1.2: upc.inf.cfi.confidentiality_response missing or wrong shape (got % matches)', v_count;
END IF;
-- §3 T1.3 grounds_orders
SELECT count(*) INTO v_count
FROM paliad.deadline_rules
WHERE submission_code = 'upc.apl.order.grounds_orders'
AND is_active = true AND lifecycle_state = 'published'
AND rule_code = 'RoP.224.2.b' AND duration_value = 15
AND duration_unit = 'days';
IF v_count <> 1 THEN
RAISE EXCEPTION 'mig 132 T1.3: upc.apl.order.grounds_orders missing or wrong shape (got % matches)', v_count;
END IF;
-- §4 T1.4 response_orders chained on §3
SELECT count(*) INTO v_count
FROM paliad.deadline_rules dr
JOIN paliad.deadline_rules p ON p.id = dr.parent_id
WHERE dr.submission_code = 'upc.apl.order.response_orders'
AND dr.is_active = true AND dr.lifecycle_state = 'published'
AND dr.rule_code = 'RoP.235.2' AND dr.duration_value = 15
AND p.submission_code = 'upc.apl.order.grounds_orders';
IF v_count <> 1 THEN
RAISE EXCEPTION 'mig 132 T1.4: upc.apl.order.response_orders missing or wrong parent chain (got % matches)', v_count;
END IF;
-- §5 T1.5 cons_orders
SELECT count(*) INTO v_count
FROM paliad.deadline_rules
WHERE submission_code = 'upc.inf.cfi.cons_orders'
AND is_active = true AND lifecycle_state = 'published'
AND rule_code = 'RoP.118.4' AND duration_value = 2
AND duration_unit = 'months';
IF v_count <> 1 THEN
RAISE EXCEPTION 'mig 132 T1.5: upc.inf.cfi.cons_orders missing or wrong shape (got % matches)', v_count;
END IF;
-- §6 T1.6 rectification
SELECT count(*) INTO v_count
FROM paliad.deadline_rules
WHERE submission_code = 'upc.inf.cfi.rectification'
AND is_active = true AND lifecycle_state = 'published'
AND rule_code = 'RoP.353' AND duration_value = 1
AND duration_unit = 'months';
IF v_count <> 1 THEN
RAISE EXCEPTION 'mig 132 T1.6: upc.inf.cfi.rectification missing or wrong shape (got % matches)', v_count;
END IF;
-- §7 T1.7 pi.deficiency
SELECT count(*) INTO v_count
FROM paliad.deadline_rules
WHERE submission_code = 'upc.pi.cfi.deficiency'
AND is_active = true AND lifecycle_state = 'published'
AND rule_code = 'RoP.207.6.a' AND duration_value = 14
AND duration_unit = 'days';
IF v_count <> 1 THEN
RAISE EXCEPTION 'mig 132 T1.7: upc.pi.cfi.deficiency missing or wrong shape (got % matches)', v_count;
END IF;
-- §8 T1.8 pi.merits_start — combine-max wiring
SELECT count(*) INTO v_count
FROM paliad.deadline_rules
WHERE submission_code = 'upc.pi.cfi.merits_start'
AND is_active = true AND lifecycle_state = 'published'
AND rule_code = 'RoP.213' AND duration_value = 31
AND duration_unit = 'days'
AND alt_duration_value = 20 AND alt_duration_unit = 'working_days'
AND alt_rule_code = 'RoP.198.1' AND combine_op = 'max';
IF v_count <> 1 THEN
RAISE EXCEPTION 'mig 132 T1.8: upc.pi.cfi.merits_start missing or wrong combine-max shape (got % matches)', v_count;
END IF;
-- §9 T1.9 translation_request — timing='before'
SELECT count(*) INTO v_count
FROM paliad.deadline_rules
WHERE submission_code = 'upc.inf.cfi.translation_request'
AND is_active = true AND lifecycle_state = 'published'
AND rule_code = 'RoP.109.1' AND duration_value = 1
AND duration_unit = 'months' AND timing = 'before';
IF v_count <> 1 THEN
RAISE EXCEPTION 'mig 132 T1.9: upc.inf.cfi.translation_request missing or wrong timing (got % matches)', v_count;
END IF;
-- §10 T1.10 interpreter_cost — timing='before'
SELECT count(*) INTO v_count
FROM paliad.deadline_rules
WHERE submission_code = 'upc.inf.cfi.interpreter_cost'
AND is_active = true AND lifecycle_state = 'published'
AND rule_code = 'RoP.109.4' AND duration_value = 2
AND duration_unit = 'weeks' AND timing = 'before';
IF v_count <> 1 THEN
RAISE EXCEPTION 'mig 132 T1.10: upc.inf.cfi.interpreter_cost missing or wrong timing (got % matches)', v_count;
END IF;
-- §11 T1.11 translations_lodge
SELECT count(*) INTO v_count
FROM paliad.deadline_rules
WHERE submission_code = 'upc.inf.cfi.translations_lodge'
AND is_active = true AND lifecycle_state = 'published'
AND rule_code = 'RoP.109.5' AND duration_value = 2
AND duration_unit = 'weeks' AND trigger_event_id = 113;
IF v_count <> 1 THEN
RAISE EXCEPTION 'mig 132 T1.11: upc.inf.cfi.translations_lodge missing or wrong shape (got % matches)', v_count;
END IF;
-- §12 T1.12 pi.response re-anchor
SELECT count(*) INTO v_count
FROM paliad.deadline_rules dr
JOIN paliad.deadline_rules p ON p.id = dr.parent_id
WHERE dr.submission_code = 'upc.pi.cfi.response'
AND dr.is_active = true AND dr.lifecycle_state = 'published'
AND dr.is_court_set = true
AND p.submission_code = 'upc.pi.cfi.app';
IF v_count <> 1 THEN
RAISE EXCEPTION 'mig 132 T1.12: upc.pi.cfi.response not re-anchored on app (got % matches)', v_count;
END IF;
-- §13 Q6 cleanup — no archived _archived_litigation rules left
SELECT count(*) INTO v_count
FROM paliad.deadline_rules
WHERE submission_code LIKE '_archived_litigation.%' ESCAPE '\'
AND lifecycle_state = 'archived';
IF v_count <> 0 THEN
RAISE EXCEPTION 'mig 132 §13: % archived _archived_litigation.* rules still present after cleanup', v_count;
END IF;
END $$;