-- t-paliad-263 Wave 0 + m/paliad#99 — Tier 0 deadline-rule corrections.
--
-- Source: docs/research-deadlines-completeness-2026-05-25.md §10 Tier 0
-- (curie's bulletproof completeness audit, merged 2026-05-25 as commit
-- 94a9e7e). 16 distinct single-row UPDATEs across UPC + DE-LG + DPMA +
-- EPA proceedings; T0.5 + T0.6 were shipped separately as mig 124
-- (m/paliad#95, de.inf.lg Replik/Duplik sequencing) and are not
-- repeated here. T0.8 (covered by T0.2) and T0.11 (covered by T0.1)
-- are dedup'd out per the audit's own note.
--
-- Also folds in m/paliad#99 (UPC Statement of Claim missing legal
-- citation): upc.inf.cfi.soc.rule_code / legal_source backfilled to
-- UPC RoP R.13(1). Same migration file, separate UPDATE block with
-- its own guard.
--
-- All fixes within the existing schema (no new columns). Each UPDATE
-- is guarded by a WHERE clause that matches only the pre-fix row
-- state (per mig 095 convention) — re-applying against a DB that
-- already carries the fix matches zero rows and no-ops, so there are
-- no duplicate deadline_rule_audit entries on idempotent re-runs.
--
-- Verification DO block at the end RAISEs EXCEPTION if any of the
-- patched rows is left in an inconsistent shape (mixing pre-fix and
-- post-fix state).
--
-- audit_reason set_config required at the top — the mig 079 trigger
-- on paliad.deadline_rules raises EXCEPTION 'audit reason required'
-- on any UPDATE without it.
--
-- Slot 127 reserved per paliadin: sequence is 124 brunel #95 (done),
-- 125 hermes #97, 126 icarus #80, 127 brunel Wave 0 + #99, 128+ next.

SELECT set_config(
    'paliad.audit_reason',
    'mig 127: t-paliad-263 Wave 0 + m/paliad#99 — Tier 0 deadline-rule corrections from curie''s audit (docs/research-deadlines-completeness-2026-05-25.md §10) plus UPC SoC R.13 citation',
    true);

-- =============================================================================
-- T0.1  upc.rev.cfi.defence — duration 3mo → 2mo per RoP.049.1.
--       Zero-pads the rule_code citation to canonical form. Audit §5
--       (wrong period — every UPC_REV tracked in paliad today computes
--       Defence at +3 months, statute says +2). Verbatim from
--       UPCRoP.049.1: "The defendant shall lodge a Defence to revocation
--       within two months of service of the Statement for revocation."
-- =============================================================================
UPDATE paliad.deadline_rules
   SET duration_value = 2,
       rule_code      = 'RoP.049.1',
       updated_at     = now()
 WHERE submission_code = 'upc.rev.cfi.defence'
   AND is_active = true
   AND lifecycle_state = 'published'
   AND duration_value = 3
   AND rule_code = 'RoP.49.1';

-- =============================================================================
-- T0.2  upc.rev.cfi.rejoin — duration 2mo → 1mo per RoP.052; add citation.
--       Audit §5 (wrong period). Verbatim from UPCRoP.052: "Within one
--       month of the service of the Reply the defendant may lodge a
--       Rejoinder to the Reply to the Defence to revocation."
-- =============================================================================
UPDATE paliad.deadline_rules
   SET duration_value = 1,
       rule_code      = 'RoP.052',
       legal_source   = 'UPC.RoP.52',
       updated_at     = now()
 WHERE submission_code = 'upc.rev.cfi.rejoin'
   AND is_active = true
   AND lifecycle_state = 'published'
   AND duration_value = 2
   AND rule_code IS NULL;

-- =============================================================================
-- T0.3  upc.apl.merits.response — duration 2mo → 3mo per RoP.235.1.
--       Audit §5 (wrong period — every main-track appellate respondent).
--       Verbatim from UPCRoP.235.1: "Within three months of service of
--       the Statement of grounds of appeal pursuant to Rule 224.2(a),
--       any other party … may lodge a Statement of response."
-- =============================================================================
UPDATE paliad.deadline_rules
   SET duration_value = 3,
       rule_code      = 'RoP.235.1',
       legal_source   = 'UPC.RoP.235.1',
       updated_at     = now()
 WHERE submission_code = 'upc.apl.merits.response'
   AND is_active = true
   AND lifecycle_state = 'published'
   AND duration_value = 2
   AND rule_code IS NULL;

-- =============================================================================
-- T0.4  de.inf.lg.beruf_begr — parent_id = NULL (was de.inf.lg.berufung).
--       Audit §7.1 — every DE-LG-Verletzung appeal renders the
--       Berufungsbegründung at trigger + 1mo (Berufung) + 2mo = 3 months
--       from Urteil-service. Per ZPO §520(2) "die Frist für die
--       Berufungsbegründung beträgt zwei Monate. Sie beginnt mit der
--       Zustellung des in vollständiger Form abgefassten Urteils" → 2
--       months from Urteil-service (parallel to, not chained off, the
--       Berufungsfrist itself). NULL parent_id makes the rule anchor
--       on the proceeding's trigger date — matches how the symmetric
--       de.inf.olg.begruendung is modelled.
-- =============================================================================
UPDATE paliad.deadline_rules
   SET parent_id  = NULL,
       updated_at = now()
 WHERE submission_code = 'de.inf.lg.beruf_begr'
   AND is_active = true
   AND lifecycle_state = 'published'
   AND parent_id = (
       SELECT id FROM paliad.deadline_rules
        WHERE submission_code = 'de.inf.lg.berufung'
          AND is_active = true
          AND lifecycle_state = 'published'
        LIMIT 1
   );

-- =============================================================================
-- T0.5 / T0.6  de.inf.lg.replik + de.inf.lg.duplik — already shipped
-- as mig 124 (m/paliad#95). Not repeated here. Idempotency of the
-- audit's Tier 0 sweep against a fresh DB is preserved because mig
-- 124 runs before this one and is itself guarded.
-- =============================================================================

-- =============================================================================
-- T0.7  upc.rev.cfi.reply — backfill rule_code + legal_source per RoP.051.
--       Audit §4.1 — duration (2mo) unchanged. Verbatim from UPCRoP.051:
--       "Reply to Defence to revocation and Application to amend the
--       patent. The claimant in the revocation action may, within two
--       months of service of the Defence to revocation and the
--       Application to amend the patent, if any, lodge a Reply…"
-- =============================================================================
UPDATE paliad.deadline_rules
   SET rule_code    = 'RoP.051',
       legal_source = 'UPC.RoP.51',
       updated_at   = now()
 WHERE submission_code = 'upc.rev.cfi.reply'
   AND is_active = true
   AND lifecycle_state = 'published'
   AND rule_code IS NULL
   AND legal_source IS NULL;

-- =============================================================================
-- T0.9  upc.apl.merits.notice — citation drift RoP.220.1 → RoP.224.1.a.
--       Audit §4.1 — duration unchanged. R.220.1 is the umbrella ("an
--       appeal may be brought"); R.224.1(a) carries the Notice-of-appeal
--       2-month period explicitly.
-- =============================================================================
UPDATE paliad.deadline_rules
   SET rule_code    = 'RoP.224.1.a',
       legal_source = 'UPC.RoP.224.1.a',
       updated_at   = now()
 WHERE submission_code = 'upc.apl.merits.notice'
   AND is_active = true
   AND lifecycle_state = 'published'
   AND rule_code = 'RoP.220.1'
   AND legal_source = 'UPC.RoP.220.1';

-- =============================================================================
-- T0.10 upc.apl.merits.grounds — citation drift RoP.220.1 → RoP.224.2.a.
--       Audit §4.1 — duration unchanged. R.224.2(a) sets the Grounds
--       4-month period for decisions referred to in R.220.1(a) and (b).
-- =============================================================================
UPDATE paliad.deadline_rules
   SET rule_code    = 'RoP.224.2.a',
       legal_source = 'UPC.RoP.224.2.a',
       updated_at   = now()
 WHERE submission_code = 'upc.apl.merits.grounds'
   AND is_active = true
   AND lifecycle_state = 'published'
   AND rule_code = 'RoP.220.1'
   AND legal_source = 'UPC.RoP.220.1';

-- =============================================================================
-- T0.12 dpma.opp.dpma.erwiderung — flip is_court_set = true; drop the
--       § 59(3) PatG citation. Audit §4.3 + §9.1: §59(3) addresses
--       Anhörung, not a 4-month response period. No statutory
--       Erwiderungsfrist exists in §59 — the 4-month figure is DPMA
--       practice (DPMA-Richtlinien D-IV 5.2). Modelled court-set, the
--       4-month value remains the default-display heuristic the
--       lawyer overrides via "Datum setzen".
-- =============================================================================
UPDATE paliad.deadline_rules
   SET is_court_set = true,
       rule_code    = NULL,
       legal_source = NULL,
       updated_at   = now()
 WHERE submission_code = 'dpma.opp.dpma.erwiderung'
   AND is_active = true
   AND lifecycle_state = 'published'
   AND is_court_set = false
   AND legal_source = 'DE.PatG.59.3';

-- =============================================================================
-- T0.13 dpma.appeal.bpatg.begruendung — flip is_court_set = true; drop
--       the § 75 PatG citation. Audit §4.3 + §9.1: §75 PatG addresses
--       aufschiebende Wirkung only, not a Begründungsfrist. No fixed
--       Begründungsfrist for BPatG-Beschwerde exists in PatG §§73-80 —
--       the BPatG sets it in the individual case. 1-month default
--       retained as display heuristic.
-- =============================================================================
UPDATE paliad.deadline_rules
   SET is_court_set = true,
       rule_code    = NULL,
       legal_source = NULL,
       updated_at   = now()
 WHERE submission_code = 'dpma.appeal.bpatg.begruendung'
   AND is_active = true
   AND lifecycle_state = 'published'
   AND is_court_set = false
   AND legal_source = 'DE.PatG.75.1';

-- =============================================================================
-- T0.14 de.null.bpatg.erwidg — citation DE.PatG.82.1 → DE.PatG.82.3.
--       Audit §4.4 — duration (2 months) is correct. §82(1) carries the
--       1-month Erklärungsfrist ("sich darüber zu erklären"); the full
--       Klageerwiderung 2-month period lives in §82(3).
-- =============================================================================
UPDATE paliad.deadline_rules
   SET rule_code    = '§ 82 Abs. 3 PatG',
       legal_source = 'DE.PatG.82.3',
       updated_at   = now()
 WHERE submission_code = 'de.null.bpatg.erwidg'
   AND is_active = true
   AND lifecycle_state = 'published'
   AND legal_source = 'DE.PatG.82.1';

-- =============================================================================
-- T0.15 de.null.bgh.begruendung — citation DE.PatG.111.1 →
--       DE.ZPO.520.2 (via PatG §117). Audit §4.4 — duration (3 months)
--       is correct. §111 PatG defines the Grounds of Berufung
--       (Verletzung des Bundesrechts), not a Begründungsfrist; the
--       3-month figure is supplied by §117 PatG → ZPO §520(2).
-- =============================================================================
UPDATE paliad.deadline_rules
   SET rule_code    = '§ 520 Abs. 2 ZPO i.V.m. § 117 PatG',
       legal_source = 'DE.ZPO.520.2',
       updated_at   = now()
 WHERE submission_code = 'de.null.bgh.begruendung'
   AND is_active = true
   AND lifecycle_state = 'published'
   AND legal_source = 'DE.PatG.111.1';

-- =============================================================================
-- T0.16 de.null.bgh.erwiderung — flip is_court_set = true; recite as
--       DE.ZPO.521.2 (via PatG §117). Audit §4.4 + §9.1 — §111 PatG
--       has no Erwiderungsfrist clause. The actual Erwiderungsfrist
--       for BGH-Nichtigkeitsberufung is set by the court per §117
--       PatG → ZPO §521(2). 2-month default retained as display
--       heuristic.
-- =============================================================================
UPDATE paliad.deadline_rules
   SET is_court_set = true,
       rule_code    = '§ 521 Abs. 2 ZPO i.V.m. § 117 PatG',
       legal_source = 'DE.ZPO.521.2',
       updated_at   = now()
 WHERE submission_code = 'de.null.bgh.erwiderung'
   AND is_active = true
   AND lifecycle_state = 'published'
   AND is_court_set = false
   AND legal_source = 'DE.PatG.111.3';

-- =============================================================================
-- T0.17 epa.opp.opd.erwidg — flip is_court_set = true. Audit §4.5 +
--       §9.1: R.79(1) EPÜ authorises the Opposition Division to set
--       the period, but does not specify a fixed 4 months. The 4-month
--       figure is administrative practice (EPO Guidelines D-IV 5.2).
--       Citation retained as the rule-of-authority for the OD's
--       discretion. 4-month default retained as display heuristic.
-- =============================================================================
UPDATE paliad.deadline_rules
   SET is_court_set = true,
       updated_at   = now()
 WHERE submission_code = 'epa.opp.opd.erwidg'
   AND is_active = true
   AND lifecycle_state = 'published'
   AND is_court_set = false
   AND legal_source = 'EU.EPC-R.79.1';

-- =============================================================================
-- m/paliad#99  upc.inf.cfi.soc — backfill UPC RoP R.13(1) citation.
--       The Statement of Claim is defined in UPC RoP R.13 (R.13.1
--       lists the required contents). The row carries no statutory
--       deadline (duration_value = 0, parent_id IS NULL — the SoC is
--       the originating filing that anchors the proceeding's trigger
--       date), but the catalog UI surfaces the rule citation in
--       result cards and the Type=Statement-of-Claim / Rule=Auto
--       resolution; both render blank today because rule_code +
--       legal_source are NULL. Backfill leaves duration / anchor /
--       party untouched.
-- =============================================================================
UPDATE paliad.deadline_rules
   SET rule_code    = 'RoP.013.1',
       legal_source = 'UPC.RoP.13.1',
       updated_at   = now()
 WHERE submission_code = 'upc.inf.cfi.soc'
   AND is_active = true
   AND lifecycle_state = 'published'
   AND rule_code IS NULL
   AND legal_source IS NULL;

-- =============================================================================
-- Hard assertions. Each touched row must end up in its post-fix
-- shape. Re-running the migration after a successful first run 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
    -- T0.1 defence: dur=2 + canonical zero-padded rule_code
    SELECT count(*) INTO v_count
      FROM paliad.deadline_rules
     WHERE submission_code = 'upc.rev.cfi.defence'
       AND is_active = true
       AND lifecycle_state = 'published'
       AND duration_value = 2
       AND rule_code = 'RoP.049.1';
    IF v_count <> 1 THEN
        RAISE EXCEPTION 'mig 127 T0.1: upc.rev.cfi.defence not in post-fix shape (got % matches)', v_count;
    END IF;

    -- T0.2 rejoin: dur=1
    SELECT count(*) INTO v_count
      FROM paliad.deadline_rules
     WHERE submission_code = 'upc.rev.cfi.rejoin'
       AND is_active = true
       AND lifecycle_state = 'published'
       AND duration_value = 1
       AND rule_code = 'RoP.052';
    IF v_count <> 1 THEN
        RAISE EXCEPTION 'mig 127 T0.2: upc.rev.cfi.rejoin not in post-fix shape (got % matches)', v_count;
    END IF;

    -- T0.3 response: dur=3
    SELECT count(*) INTO v_count
      FROM paliad.deadline_rules
     WHERE submission_code = 'upc.apl.merits.response'
       AND is_active = true
       AND lifecycle_state = 'published'
       AND duration_value = 3
       AND rule_code = 'RoP.235.1';
    IF v_count <> 1 THEN
        RAISE EXCEPTION 'mig 127 T0.3: upc.apl.merits.response not in post-fix shape (got % matches)', v_count;
    END IF;

    -- T0.4 beruf_begr: parent_id IS NULL
    SELECT count(*) INTO v_count
      FROM paliad.deadline_rules
     WHERE submission_code = 'de.inf.lg.beruf_begr'
       AND is_active = true
       AND lifecycle_state = 'published'
       AND parent_id IS NULL;
    IF v_count <> 1 THEN
        RAISE EXCEPTION 'mig 127 T0.4: de.inf.lg.beruf_begr not in post-fix shape (got % matches)', v_count;
    END IF;

    -- T0.7 reply: citation backfilled
    SELECT count(*) INTO v_count
      FROM paliad.deadline_rules
     WHERE submission_code = 'upc.rev.cfi.reply'
       AND is_active = true
       AND lifecycle_state = 'published'
       AND rule_code = 'RoP.051'
       AND legal_source = 'UPC.RoP.51';
    IF v_count <> 1 THEN
        RAISE EXCEPTION 'mig 127 T0.7: upc.rev.cfi.reply not in post-fix shape (got % matches)', v_count;
    END IF;

    -- T0.9 notice: citation RoP.224.1.a
    SELECT count(*) INTO v_count
      FROM paliad.deadline_rules
     WHERE submission_code = 'upc.apl.merits.notice'
       AND is_active = true
       AND lifecycle_state = 'published'
       AND rule_code = 'RoP.224.1.a'
       AND legal_source = 'UPC.RoP.224.1.a';
    IF v_count <> 1 THEN
        RAISE EXCEPTION 'mig 127 T0.9: upc.apl.merits.notice not in post-fix shape (got % matches)', v_count;
    END IF;

    -- T0.10 grounds: citation RoP.224.2.a
    SELECT count(*) INTO v_count
      FROM paliad.deadline_rules
     WHERE submission_code = 'upc.apl.merits.grounds'
       AND is_active = true
       AND lifecycle_state = 'published'
       AND rule_code = 'RoP.224.2.a'
       AND legal_source = 'UPC.RoP.224.2.a';
    IF v_count <> 1 THEN
        RAISE EXCEPTION 'mig 127 T0.10: upc.apl.merits.grounds not in post-fix shape (got % matches)', v_count;
    END IF;

    -- T0.12 dpma.opp erwiderung: court-set, no citation
    SELECT count(*) INTO v_count
      FROM paliad.deadline_rules
     WHERE submission_code = 'dpma.opp.dpma.erwiderung'
       AND is_active = true
       AND lifecycle_state = 'published'
       AND is_court_set = true
       AND legal_source IS NULL
       AND rule_code IS NULL;
    IF v_count <> 1 THEN
        RAISE EXCEPTION 'mig 127 T0.12: dpma.opp.dpma.erwiderung not in post-fix shape (got % matches)', v_count;
    END IF;

    -- T0.13 dpma.appeal.bpatg begründung: court-set, no citation
    SELECT count(*) INTO v_count
      FROM paliad.deadline_rules
     WHERE submission_code = 'dpma.appeal.bpatg.begruendung'
       AND is_active = true
       AND lifecycle_state = 'published'
       AND is_court_set = true
       AND legal_source IS NULL
       AND rule_code IS NULL;
    IF v_count <> 1 THEN
        RAISE EXCEPTION 'mig 127 T0.13: dpma.appeal.bpatg.begruendung not in post-fix shape (got % matches)', v_count;
    END IF;

    -- T0.14 bpatg erwidg: §82.3
    SELECT count(*) INTO v_count
      FROM paliad.deadline_rules
     WHERE submission_code = 'de.null.bpatg.erwidg'
       AND is_active = true
       AND lifecycle_state = 'published'
       AND legal_source = 'DE.PatG.82.3';
    IF v_count <> 1 THEN
        RAISE EXCEPTION 'mig 127 T0.14: de.null.bpatg.erwidg not in post-fix shape (got % matches)', v_count;
    END IF;

    -- T0.15 bgh begründung: ZPO §520.2
    SELECT count(*) INTO v_count
      FROM paliad.deadline_rules
     WHERE submission_code = 'de.null.bgh.begruendung'
       AND is_active = true
       AND lifecycle_state = 'published'
       AND legal_source = 'DE.ZPO.520.2';
    IF v_count <> 1 THEN
        RAISE EXCEPTION 'mig 127 T0.15: de.null.bgh.begruendung not in post-fix shape (got % matches)', v_count;
    END IF;

    -- T0.16 bgh erwiderung: court-set, ZPO §521.2
    SELECT count(*) INTO v_count
      FROM paliad.deadline_rules
     WHERE submission_code = 'de.null.bgh.erwiderung'
       AND is_active = true
       AND lifecycle_state = 'published'
       AND is_court_set = true
       AND legal_source = 'DE.ZPO.521.2';
    IF v_count <> 1 THEN
        RAISE EXCEPTION 'mig 127 T0.16: de.null.bgh.erwiderung not in post-fix shape (got % matches)', v_count;
    END IF;

    -- T0.17 epa.opp opd erwidg: court-set
    SELECT count(*) INTO v_count
      FROM paliad.deadline_rules
     WHERE submission_code = 'epa.opp.opd.erwidg'
       AND is_active = true
       AND lifecycle_state = 'published'
       AND is_court_set = true;
    IF v_count <> 1 THEN
        RAISE EXCEPTION 'mig 127 T0.17: epa.opp.opd.erwidg not in post-fix shape (got % matches)', v_count;
    END IF;

    -- #99 upc.inf.cfi.soc: citation backfilled
    SELECT count(*) INTO v_count
      FROM paliad.deadline_rules
     WHERE submission_code = 'upc.inf.cfi.soc'
       AND is_active = true
       AND lifecycle_state = 'published'
       AND rule_code = 'RoP.013.1'
       AND legal_source = 'UPC.RoP.13.1';
    IF v_count <> 1 THEN
        RAISE EXCEPTION 'mig 127 #99: upc.inf.cfi.soc not in post-fix shape (got % matches)', v_count;
    END IF;
END $$;
