Codifies curie's 4 new rules + 4 patches from docs/proposals/fristen-gap-fill-2026-05-18.md § 0.3 (m's decisions). NEW (4): inf.prelim UPC_INF parent=inf.soc 1mo RoP.019.1 flag=with_po rev.prelim UPC_REV parent=rev.app 1mo RoP.019.1 flag=with_po inf.appeal_spawn UPC_INF parent=inf.decision 2mo RoP.220.1.a always-fire → UPC_APP rev.appeal_spawn UPC_REV parent=rev.decision 2mo RoP.220.1.a always-fire → UPC_APP PATCH (4): de_inf.klage legal_source NULL → 'DE.ZPO.253' de_inf.anzeige no change (already correct — explicit in audit log) de_inf.erwidg is_court_set false → true + §276 Abs.1 S.2 description de_inf.berufung defensive verify legal_source = 'DE.ZPO.517' Idempotent via WHERE NOT EXISTS (no unique index on (proceeding_type_id, code) — mig 093 left archived rows sharing codes with their published successors, so ON CONFLICT isn't available). UPDATEs guarded by clauses that only fire when the row still has the old value. Backup snapshot in paliad.deadline_rules_pre_095 (CREATE TABLE IF NOT EXISTS); down migration restores from it. Hard assertions verify all 4 new rules landed active+published, de_inf.erwidg flipped to court-set, both spawn rules chain to a valid proceeding_type id=11. Dry-run verified end-to-end against the live Supabase corpus inside BEGIN/ROLLBACK; idempotency confirmed by running INSERT+UPDATE twice in the same transaction.
404 lines
17 KiB
SQL
404 lines
17 KiB
SQL
-- t-paliad-205 / Fristen gap-fill — ingest curie's t-paliad-203 deltas
|
|
-- as code. Source of truth for the deltas is
|
|
-- docs/proposals/fristen-gap-fill-2026-05-18.md § 0.3 (m's decisions
|
|
-- captured 2026-05-18, commit 0123d11).
|
|
--
|
|
-- Mig 093 (commit 40e49e8) retired the Pipeline-A litigation rule
|
|
-- corpus and surfaced four open coverage questions for legal review.
|
|
-- curie's proposal verified those questions and m signed off on:
|
|
--
|
|
-- * 4 new rules — preliminary-objection (RoP 19.1) on UPC_INF and
|
|
-- UPC_REV, and merits-appeal spawn (RoP 220.1(a)) on the same two
|
|
-- proceedings.
|
|
-- * 4 polish PATCHes on the German civil-procedure rules — backfill
|
|
-- legal_source on de_inf.klage, flip de_inf.erwidg to court-set
|
|
-- with a §276 Abs.1 S.2 note, plus a defensive verify on
|
|
-- de_inf.berufung.legal_source.
|
|
--
|
|
-- Final shape per the proposal § 0.3:
|
|
--
|
|
-- NEW
|
|
-- inf.prelim UPC_INF parent=inf.soc 1mo RoP.019.1 flag=with_po optional
|
|
-- rev.prelim UPC_REV parent=rev.app 1mo RoP.019.1 flag=with_po optional
|
|
-- inf.appeal_spawn UPC_INF parent=inf.decision 2mo RoP.220.1.a (no flag, always) optional spawn → UPC_APP (id=11)
|
|
-- rev.appeal_spawn UPC_REV parent=rev.decision 2mo RoP.220.1.a (no flag, always) optional spawn → UPC_APP (id=11)
|
|
--
|
|
-- PATCH
|
|
-- de_inf.klage legal_source NULL → 'DE.ZPO.253'
|
|
-- de_inf.anzeige no change (already 'DE.ZPO.276.1')
|
|
-- de_inf.erwidg is_court_set false → true; set description with §276 Abs.1 S.2 note
|
|
-- duration_value=6 weeks stays as the default-display value when no
|
|
-- court order is yet attached.
|
|
-- de_inf.berufung legal_source set to 'DE.ZPO.517' if still NULL (defensive verify)
|
|
--
|
|
-- The merits-appeal spawn rules unconditionally produce the 2-month
|
|
-- appeal-window row once inf.decision / rev.decision is anchored
|
|
-- (m's F2.3 decision: "appeal is always a possibility"). Visibility
|
|
-- filtering for non-appealing projects is a frontend concern, not a
|
|
-- rule-level flag (see proposal § 0.3 follow-up note).
|
|
--
|
|
-- The spawn_proceeding_type_id FK points at UPC_APP (id=11). t-paliad-204
|
|
-- may rename the `code` string for that row but the integer id is stable;
|
|
-- if id=11 ever moves, this migration's spawn rules still chain to the
|
|
-- correct row.
|
|
--
|
|
-- Idempotency:
|
|
-- * Backup snapshot `deadline_rules_pre_095` is CREATE TABLE IF NOT
|
|
-- EXISTS, capturing the 4 patched rows at first run.
|
|
-- * INSERTs use `WHERE NOT EXISTS` keyed on (proceeding_type_id, code,
|
|
-- lifecycle_state='published') — there is no unique index on
|
|
-- (proceeding_type_id, code) in paliad.deadline_rules (mig 093 left
|
|
-- archived and published rows co-existing with identical codes), so
|
|
-- ON CONFLICT is not available; WHERE NOT EXISTS is the equivalent
|
|
-- idempotency guard.
|
|
-- * UPDATEs are guarded by clauses that only fire when the row still
|
|
-- has the old value (legal_source IS NULL, is_court_set = false).
|
|
--
|
|
-- audit_reason wrapper required by the mig 079 trigger for both UPDATE
|
|
-- and INSERT (INSERT defaults to 'create' but we surface the t-paliad-205
|
|
-- context anyway so deadline_rule_audit reads cleanly).
|
|
|
|
SELECT set_config(
|
|
'paliad.audit_reason',
|
|
'mig 095: t-paliad-205 fristen gap-fill — 4 new rules (inf.prelim, rev.prelim, inf.appeal_spawn, rev.appeal_spawn) + 4 patches on de_inf.* rules per docs/proposals/fristen-gap-fill-2026-05-18.md § 0.3',
|
|
true);
|
|
|
|
-- =============================================================================
|
|
-- 1. Backup snapshot of the 4 rows the PATCHes touch. CREATE TABLE IF
|
|
-- NOT EXISTS keeps this idempotent across reapplications. Snapshot
|
|
-- persists post-patch as the audit anchor; the down migration
|
|
-- restores from it.
|
|
-- =============================================================================
|
|
|
|
CREATE TABLE IF NOT EXISTS paliad.deadline_rules_pre_095 AS
|
|
SELECT *, now() AS snapshotted_at
|
|
FROM paliad.deadline_rules
|
|
WHERE code IN ('de_inf.klage', 'de_inf.anzeige',
|
|
'de_inf.erwidg', 'de_inf.berufung')
|
|
AND lifecycle_state = 'published'
|
|
AND is_active = true;
|
|
|
|
COMMENT ON TABLE paliad.deadline_rules_pre_095 IS
|
|
'Snapshot of the 4 de_inf.* deadline_rules rows that mig 095 '
|
|
'PATCHed (t-paliad-205). Source-of-truth for the down migration; '
|
|
'persists post-patch as the permanent audit record. Drop with a '
|
|
'focused follow-up after the gap-fill is verified in prod.';
|
|
|
|
-- =============================================================================
|
|
-- 2. New rules — preliminary objection on UPC_INF and UPC_REV
|
|
-- (RoP 19.1, flag-gated `with_po`, 1 month from service of the
|
|
-- Statement of Claim / Application for Revocation).
|
|
--
|
|
-- Anchor: parent_id on the existing root rule (inf.soc / rev.app),
|
|
-- matching the chaining pattern used by inf.sod, inf.def_to_ccr,
|
|
-- rev.defence, rev.app_to_amend. Idempotent via WHERE NOT EXISTS.
|
|
--
|
|
-- sequence_order=5 places the PO row before the SoD (sequence_order=10)
|
|
-- in the per-proceeding timeline ordering, reflecting the 1-month
|
|
-- statutory window beating the 3-month defence in calendar terms.
|
|
-- =============================================================================
|
|
|
|
INSERT INTO paliad.deadline_rules
|
|
(proceeding_type_id, parent_id, code, name, name_en,
|
|
description, primary_party, event_type,
|
|
duration_value, duration_unit, timing,
|
|
rule_code, deadline_notes, deadline_notes_en, sequence_order,
|
|
is_spawn, spawn_proceeding_type_id, spawn_label,
|
|
is_active, legal_source, is_bilateral,
|
|
condition_expr, priority, is_court_set, lifecycle_state)
|
|
SELECT
|
|
8,
|
|
(SELECT id FROM paliad.deadline_rules
|
|
WHERE code = 'inf.soc'
|
|
AND proceeding_type_id = 8
|
|
AND lifecycle_state = 'published'
|
|
AND is_active = true),
|
|
'inf.prelim',
|
|
'Vorab-Einrede (R. 19 VerfO)',
|
|
'Preliminary Objection (RoP 19)',
|
|
'Vorab-Einrede des Beklagten gegen Zuständigkeit, Verfahrenssprache (R.14) oder Spruchkörper-Zusammensetzung. Statutarische Frist von 1 Monat ab Zustellung der Klage; der UPC entscheidet typischerweise durch Beschluss vor der Zwischenverhandlung (R.19.7).',
|
|
'defendant',
|
|
'filing',
|
|
1,
|
|
'months',
|
|
'after',
|
|
'RoP.019.1',
|
|
'Innerhalb von 1 Monat ab Zustellung der Klage. Drei mögliche Gründe: (a) Zuständigkeit/Kompetenz, (b) Verfahrenssprache (R.14), (c) Spruchkörper.',
|
|
'Within 1 month of service of the Statement of claim. Three available grounds: (a) jurisdiction/competence, (b) language (R.14), (c) panel composition.',
|
|
5,
|
|
false,
|
|
NULL,
|
|
NULL,
|
|
true,
|
|
'UPC.RoP.19.1',
|
|
false,
|
|
'{"flag":"with_po"}'::jsonb,
|
|
'optional',
|
|
false,
|
|
'published'
|
|
WHERE NOT EXISTS (
|
|
SELECT 1 FROM paliad.deadline_rules
|
|
WHERE code = 'inf.prelim'
|
|
AND proceeding_type_id = 8
|
|
AND lifecycle_state = 'published');
|
|
|
|
INSERT INTO paliad.deadline_rules
|
|
(proceeding_type_id, parent_id, code, name, name_en,
|
|
description, primary_party, event_type,
|
|
duration_value, duration_unit, timing,
|
|
rule_code, deadline_notes, deadline_notes_en, sequence_order,
|
|
is_spawn, spawn_proceeding_type_id, spawn_label,
|
|
is_active, legal_source, is_bilateral,
|
|
condition_expr, priority, is_court_set, lifecycle_state)
|
|
SELECT
|
|
9,
|
|
(SELECT id FROM paliad.deadline_rules
|
|
WHERE code = 'rev.app'
|
|
AND proceeding_type_id = 9
|
|
AND lifecycle_state = 'published'
|
|
AND is_active = true),
|
|
'rev.prelim',
|
|
'Vorab-Einrede (R. 19 i.V.m. R. 46 VerfO)',
|
|
'Preliminary Objection (RoP 19 in conjunction with RoP 46)',
|
|
'Vorab-Einrede des Beklagten (Patentinhaber) im Nichtigkeitsverfahren. R.46 erklärt R.19 für Nichtigkeitsverfahren mutatis mutandis anwendbar; statutarische Frist von 1 Monat ab Zustellung der Nichtigkeitsklage.',
|
|
'defendant',
|
|
'filing',
|
|
1,
|
|
'months',
|
|
'after',
|
|
'RoP.019.1',
|
|
'Innerhalb von 1 Monat ab Zustellung der Nichtigkeitsklage. R.46 macht R.19 mutatis mutandis für Nichtigkeitsverfahren anwendbar; in der Praxis vor allem Verfahrenssprache und Spruchkörper-Zusammensetzung als Gründe.',
|
|
'Within 1 month of service of the Application for Revocation. R.46 makes R.19 apply mutatis mutandis to revocation actions; in practice the main grounds are language and panel composition.',
|
|
5,
|
|
false,
|
|
NULL,
|
|
NULL,
|
|
true,
|
|
'UPC.RoP.19.1',
|
|
false,
|
|
'{"flag":"with_po"}'::jsonb,
|
|
'optional',
|
|
false,
|
|
'published'
|
|
WHERE NOT EXISTS (
|
|
SELECT 1 FROM paliad.deadline_rules
|
|
WHERE code = 'rev.prelim'
|
|
AND proceeding_type_id = 9
|
|
AND lifecycle_state = 'published');
|
|
|
|
-- =============================================================================
|
|
-- 3. New rules — merits-appeal spawn on UPC_INF and UPC_REV
|
|
-- (RoP 220.1(a), 2 months from service of the final decision, always
|
|
-- fires once the decision is anchored). spawn_proceeding_type_id=11
|
|
-- is UPC_APP; the spawn renders as an entry point into the appeal
|
|
-- proceeding which already has app.notice / app.grounds as root
|
|
-- rules.
|
|
--
|
|
-- No condition_expr — m's F2.3 decision: "the appeal deadline should
|
|
-- always be triggered by a decision … appeal is always a possibility".
|
|
-- Visibility filtering on the frontend is the right place to hide
|
|
-- appeals on projects where no appeal is contemplated.
|
|
--
|
|
-- sequence_order=80 places the spawn row after inf.cost_app (70)
|
|
-- and rev.decision's tail in the per-proceeding ordering.
|
|
-- =============================================================================
|
|
|
|
INSERT INTO paliad.deadline_rules
|
|
(proceeding_type_id, parent_id, code, name, name_en,
|
|
description, primary_party, event_type,
|
|
duration_value, duration_unit, timing,
|
|
rule_code, deadline_notes, deadline_notes_en, sequence_order,
|
|
is_spawn, spawn_proceeding_type_id, spawn_label,
|
|
is_active, legal_source, is_bilateral,
|
|
condition_expr, priority, is_court_set, lifecycle_state)
|
|
SELECT
|
|
8,
|
|
(SELECT id FROM paliad.deadline_rules
|
|
WHERE code = 'inf.decision'
|
|
AND proceeding_type_id = 8
|
|
AND lifecycle_state = 'published'
|
|
AND is_active = true),
|
|
'inf.appeal_spawn',
|
|
'Berufung gegen Endentscheidung',
|
|
'Appeal against final decision',
|
|
'Berufung gegen die Endentscheidung nach R.118. Statutarische Frist von 2 Monaten ab Zustellung der Entscheidung (R.224.1(a)); die Berufungsbegründung folgt mit 4 Monaten ab Zustellung (R.224.2(a), eigenständige Frist im Berufungsverfahren).',
|
|
'both',
|
|
'filing',
|
|
2,
|
|
'months',
|
|
'after',
|
|
'RoP.220.1.a',
|
|
'Innerhalb von 2 Monaten ab Zustellung der Endentscheidung Berufungsschrift einreichen (R.224.1(a)). Die Berufungsbegründung (R.224.2(a), 4 Monate) läuft als separate Frist im Berufungsverfahren.',
|
|
'Within 2 months of service of the final decision lodge the Statement of appeal (R.224.1(a)). The Statement of grounds (R.224.2(a), 4 months) runs as an independent deadline in the appeal proceeding.',
|
|
80,
|
|
true,
|
|
11,
|
|
'Berufungsverfahren öffnen',
|
|
true,
|
|
'UPC.RoP.220.1',
|
|
false,
|
|
NULL,
|
|
'optional',
|
|
false,
|
|
'published'
|
|
WHERE NOT EXISTS (
|
|
SELECT 1 FROM paliad.deadline_rules
|
|
WHERE code = 'inf.appeal_spawn'
|
|
AND proceeding_type_id = 8
|
|
AND lifecycle_state = 'published');
|
|
|
|
INSERT INTO paliad.deadline_rules
|
|
(proceeding_type_id, parent_id, code, name, name_en,
|
|
description, primary_party, event_type,
|
|
duration_value, duration_unit, timing,
|
|
rule_code, deadline_notes, deadline_notes_en, sequence_order,
|
|
is_spawn, spawn_proceeding_type_id, spawn_label,
|
|
is_active, legal_source, is_bilateral,
|
|
condition_expr, priority, is_court_set, lifecycle_state)
|
|
SELECT
|
|
9,
|
|
(SELECT id FROM paliad.deadline_rules
|
|
WHERE code = 'rev.decision'
|
|
AND proceeding_type_id = 9
|
|
AND lifecycle_state = 'published'
|
|
AND is_active = true),
|
|
'rev.appeal_spawn',
|
|
'Berufung gegen Endentscheidung (Nichtigkeit)',
|
|
'Appeal against final decision (revocation)',
|
|
'Berufung gegen die Endentscheidung im Nichtigkeitsverfahren nach R.118. Statutarische Frist von 2 Monaten ab Zustellung der Entscheidung (R.224.1(a)). Bei with_cci-Konstellationen (Verletzungswiderklage) deckt eine R.118-Entscheidung beide Streitgegenstände ab und erzeugt ein gemeinsames Berufungsfenster.',
|
|
'both',
|
|
'filing',
|
|
2,
|
|
'months',
|
|
'after',
|
|
'RoP.220.1.a',
|
|
'Innerhalb von 2 Monaten ab Zustellung der Endentscheidung Berufungsschrift einreichen (R.224.1(a)). Bei Verletzungswiderklage (with_cci) ein gemeinsames Fenster.',
|
|
'Within 2 months of service of the final decision lodge the Statement of appeal (R.224.1(a)). Where a counterclaim for infringement was raised (with_cci) the appeal window covers both parts.',
|
|
80,
|
|
true,
|
|
11,
|
|
'Berufungsverfahren öffnen',
|
|
true,
|
|
'UPC.RoP.220.1',
|
|
false,
|
|
NULL,
|
|
'optional',
|
|
false,
|
|
'published'
|
|
WHERE NOT EXISTS (
|
|
SELECT 1 FROM paliad.deadline_rules
|
|
WHERE code = 'rev.appeal_spawn'
|
|
AND proceeding_type_id = 9
|
|
AND lifecycle_state = 'published');
|
|
|
|
-- =============================================================================
|
|
-- 4. PATCHes on existing rows. Each UPDATE is guarded by a WHERE clause
|
|
-- that only fires when the row still has the old value — re-running
|
|
-- the migration is a no-op once the first run has applied.
|
|
-- =============================================================================
|
|
|
|
-- 4.1 de_inf.klage: legal_source NULL → 'DE.ZPO.253'
|
|
UPDATE paliad.deadline_rules
|
|
SET legal_source = 'DE.ZPO.253',
|
|
updated_at = now()
|
|
WHERE code = 'de_inf.klage'
|
|
AND lifecycle_state = 'published'
|
|
AND is_active = true
|
|
AND legal_source IS NULL;
|
|
|
|
-- 4.2 de_inf.anzeige: no change — verified DE.ZPO.276.1 already correct
|
|
-- (proposal § 4.2; intentional no-op to make the audit log complete).
|
|
|
|
-- 4.3 de_inf.erwidg: flip is_court_set true; set description with §276
|
|
-- Abs.1 S.2 note. Keep duration_value=6, duration_unit='weeks' as
|
|
-- the default-display value when no court order is yet attached
|
|
-- (per § 0.3 — fristenrechner renders the 6-week heuristic until
|
|
-- the user enters the actual court-set date).
|
|
UPDATE paliad.deadline_rules
|
|
SET is_court_set = true,
|
|
description = 'Gericht setzt eine Frist von mindestens zwei Wochen ab Verteidigungsanzeige (§276 Abs. 1 S. 2 ZPO).',
|
|
updated_at = now()
|
|
WHERE code = 'de_inf.erwidg'
|
|
AND lifecycle_state = 'published'
|
|
AND is_active = true
|
|
AND is_court_set = false;
|
|
|
|
-- 4.4 de_inf.berufung: defensive verify — set legal_source to
|
|
-- 'DE.ZPO.517' only if currently NULL. Production value is already
|
|
-- 'DE.ZPO.517' per the proposal § 4.4 verification, so this is a
|
|
-- no-op in prod; preserved here as a belt-and-braces guard against
|
|
-- a staging snapshot where the field was never backfilled.
|
|
UPDATE paliad.deadline_rules
|
|
SET legal_source = 'DE.ZPO.517',
|
|
updated_at = now()
|
|
WHERE code = 'de_inf.berufung'
|
|
AND lifecycle_state = 'published'
|
|
AND is_active = true
|
|
AND legal_source IS NULL;
|
|
|
|
-- =============================================================================
|
|
-- 5. Hard assertions. The migration is not safe to leave half-applied —
|
|
-- if any of the new rules failed to insert, or the de_inf.erwidg
|
|
-- flip didn't land, the fristenrechner corpus is inconsistent.
|
|
-- =============================================================================
|
|
|
|
DO $$
|
|
DECLARE
|
|
v_new_rules integer;
|
|
v_court_set integer;
|
|
v_appeal_ids integer;
|
|
v_klage_src text;
|
|
BEGIN
|
|
-- 5.1 All four new rules exist and are active+published
|
|
SELECT count(*) INTO v_new_rules
|
|
FROM paliad.deadline_rules
|
|
WHERE code IN ('inf.prelim', 'rev.prelim',
|
|
'inf.appeal_spawn', 'rev.appeal_spawn')
|
|
AND is_active = true
|
|
AND lifecycle_state = 'published';
|
|
IF v_new_rules <> 4 THEN
|
|
RAISE EXCEPTION
|
|
'mig 095: expected 4 new active+published rules, got %',
|
|
v_new_rules;
|
|
END IF;
|
|
|
|
-- 5.2 de_inf.erwidg is now court-set
|
|
SELECT count(*) INTO v_court_set
|
|
FROM paliad.deadline_rules
|
|
WHERE code = 'de_inf.erwidg'
|
|
AND lifecycle_state = 'published'
|
|
AND is_active = true
|
|
AND is_court_set = true;
|
|
IF v_court_set <> 1 THEN
|
|
RAISE EXCEPTION
|
|
'mig 095: expected de_inf.erwidg to be court-set after patch, got % matching rows',
|
|
v_court_set;
|
|
END IF;
|
|
|
|
-- 5.3 Both spawn rules reference an existing proceeding_type id=11
|
|
SELECT count(*) INTO v_appeal_ids
|
|
FROM paliad.deadline_rules dr
|
|
JOIN paliad.proceeding_types pt ON pt.id = dr.spawn_proceeding_type_id
|
|
WHERE dr.code IN ('inf.appeal_spawn', 'rev.appeal_spawn')
|
|
AND dr.lifecycle_state = 'published'
|
|
AND dr.is_active = true
|
|
AND pt.id = 11;
|
|
IF v_appeal_ids <> 2 THEN
|
|
RAISE EXCEPTION
|
|
'mig 095: expected both appeal_spawn rules to chain to proceeding_type id=11, got % matching rows',
|
|
v_appeal_ids;
|
|
END IF;
|
|
|
|
-- 5.4 de_inf.klage now has a legal_source (we just set it, or it was
|
|
-- already set — either way it must not be NULL after this mig)
|
|
SELECT legal_source INTO v_klage_src
|
|
FROM paliad.deadline_rules
|
|
WHERE code = 'de_inf.klage'
|
|
AND lifecycle_state = 'published'
|
|
AND is_active = true;
|
|
IF v_klage_src IS NULL THEN
|
|
RAISE EXCEPTION
|
|
'mig 095: de_inf.klage.legal_source is still NULL after patch';
|
|
END IF;
|
|
END $$;
|