Compare commits

...

1 Commits

Author SHA1 Message Date
mAi
cb44b3b8cc mAi: #117 + #118 - t-paliad-285/-286 UPC dmgs+pi court followup (mig 133)
Adds the post-submission court phase to upc.dmgs.cfi and the appeal
route to upc.pi.cfi. The Verfahrensablauf timeline currently stops at
the last party submission (dmgs.rejoin / pi.order); without these rows
the interim conference / oral hearing / decision / appeal sub-tree
never renders, even though atlas's #96 spawn mechanism is in place.

Migration 133 (single slot, coordinated with knuth's #116 on 132):

Section A — UPC Damages tree end (#117):
- upc.dmgs.cfi.interim       court-set, R.105
- upc.dmgs.cfi.oral          court-set, R.118 / R.250
- upc.dmgs.cfi.decision      court-set, R.118 / R.144
- upc.dmgs.cfi.appeal_spawn  2mo, R.220.1(a) / R.224.1(a), spawn → upc.apl.merits

Section B — UPC PI appeal route (#118):
- upc.pi.cfi.appeal_spawn    2mo, R.220.1(a) / R.224.1(a), spawn → upc.apl.merits
  PI orders under R.211 dispose of the urgent question and ride the
  main 2-month track; the 15-day R.220.1(c) order track does not apply.

Same shape as mig 095 inf.appeal_spawn and the upc.inf.cfi
interim/oral/decision rows from mig 012. Court-set rows reuse the
shared interim-conference / oral-hearing / decision concepts.

Citations: docs/research-deadlines-completeness-2026-05-25.md §D + Tier 4 (R.144), docs/audit-upc-rop-deadlines-2026-05-08.md §D R.144 + §F R.220.1(a)/R.224.1(a). Per-row RoP citation in the migration header.

Idempotent INSERT NOT EXISTS guards per row + post-insert DO block that RAISEs EXCEPTION if any expected row is missing or the spawn shape (is_spawn / spawn_proceeding_type_id / parent_id) is wrong.

go build ./... clean, go test ./internal/... clean, bun run build clean.
2026-05-25 17:25:19 +02:00
2 changed files with 438 additions and 0 deletions

View File

@@ -0,0 +1,33 @@
-- Reverses mig 133. Removes the 5 new rules:
-- * upc.dmgs.cfi.interim
-- * upc.dmgs.cfi.oral
-- * upc.dmgs.cfi.decision
-- * upc.dmgs.cfi.appeal_spawn
-- * upc.pi.cfi.appeal_spawn
--
-- The audit_reason is required by the mig 079 trigger for DELETE;
-- set_config at top supplies it.
--
-- Idempotent — if a rule is already missing the DELETE matches zero
-- rows and the audit log records nothing extra.
SELECT set_config(
'paliad.audit_reason',
'mig 133 (down): revert UPC Damages tree-end rows and UPC PI appeal-spawn (t-paliad-285 / m/paliad#117 + t-paliad-286 / m/paliad#118)',
true);
-- Delete the spawn rows first so the parent_id reference goes away
-- before the parent decision row is removed.
DELETE FROM paliad.deadline_rules
WHERE submission_code IN (
'upc.dmgs.cfi.appeal_spawn',
'upc.pi.cfi.appeal_spawn')
AND lifecycle_state = 'published';
DELETE FROM paliad.deadline_rules
WHERE submission_code IN (
'upc.dmgs.cfi.interim',
'upc.dmgs.cfi.oral',
'upc.dmgs.cfi.decision')
AND proceeding_type_id = 17
AND lifecycle_state = 'published';

View File

@@ -0,0 +1,405 @@
-- t-paliad-285 (m/paliad#117) + t-paliad-286 (m/paliad#118) —
-- post-submission court followup for UPC Damages and appeal route
-- for UPC Provisional Measures.
--
-- m's 2026-05-25 report: the upc.dmgs.cfi proceeding stops at the
-- last party submission (rejoin) — no interim conference, no oral
-- hearing, no decision row, no appeal-spawn. The upc.pi.cfi
-- proceeding has its decision row (`pi.order`) but no spawn into
-- the appeal tree. Both gaps prevent the Verfahrensablauf timeline
-- from rendering the court phase plus any downstream appeal sub-
-- tree that atlas's #96 spawn-rendering mechanism is otherwise
-- ready to surface.
--
-- Two sections in one migration (slot 133 — knuth on 132, paliadin
-- coordinated):
--
-- A. UPC Damages tree-end rows (#117)
-- A1 upc.dmgs.cfi.interim UPC RoP R.105 court-set hearing
-- A2 upc.dmgs.cfi.oral UPC RoP R.118 / R.250 court-set hearing
-- A3 upc.dmgs.cfi.decision UPC RoP R.118 / R.144 court-set decision
-- A4 upc.dmgs.cfi.appeal_spawn UPC RoP R.220.1(a) / R.224.1(a) 2mo, spawn → upc.apl.merits (id=11)
--
-- B. UPC Provisional Measures appeal route (#118)
-- B1 upc.pi.cfi.appeal_spawn UPC RoP R.220.1(a) / R.224.1(a) 2mo, spawn → upc.apl.merits (id=11)
--
-- Source citations:
-- * docs/research-deadlines-completeness-2026-05-25.md
-- — §2.1 (upc.dmgs.cfi has only 4 rules: R.131.2 / R.137.2 / R.139)
-- — §D Damages table (R.144 tree-end row missing — listed
-- in Tier 4 as "cosmetic", upgraded to Tier-0 by m's
-- report once the wider follow-up gap was understood)
-- * docs/audit-upc-rop-deadlines-2026-05-08.md §D row R.144,
-- §F R.220.1(a) / R.224.1(a) (verified verbatim in youpc DB
-- under law_type=UPCRoP).
-- * UPC Rules of Procedure (consolidated):
-- R.105 — Interim conference (court fixes after written
-- procedure closes; same structural shape as the inf
-- interim conference, already modelled as `upc.inf.cfi.interim`).
-- R.118 — Decision after oral hearing; general rule for
-- deciding panels.
-- R.250 — Determination of damages decision; damages-
-- specific decision rule (chains R.144 indication →
-- damages award).
-- R.144 — Final decision on damages quantum (tree-end
-- anchor for §A3).
-- R.220.1(a) — Appeal lies from any final decision /
-- decision disposing of the case at first instance.
-- A PI order under R.211 disposes of the urgent question
-- and is therefore appealable on the main 2-month track
-- (not the 15-day order track of R.220.1(c), which covers
-- case-management and procedural orders requiring leave).
-- Curie's §F table confirms the main-track wiring for
-- decisions on merits / disposing orders.
-- R.224.1(a) — Statement of Appeal within 2 months of
-- service of the final decision; the deadline-notes text
-- mirrors mig 095's inf.appeal_spawn / rev.appeal_spawn.
-- R.224.2(a) — Statement of grounds within 4 months
-- (separate deadline in the spawned upc.apl.merits
-- proceeding; already present as upc.apl.merits.grounds).
--
-- Shape decisions (mirroring mig 012 / mig 095 conventions):
-- * Court-set rows (interim / oral / decision) carry
-- primary_party='court', event_type='hearing'|'decision',
-- duration_value=0, is_court_set=true, parent_id=NULL,
-- concept_id reuses the shared concepts already wired for
-- upc.inf.cfi (interim-conference / oral-hearing / decision).
-- * Spawn rows carry primary_party='both', is_spawn=true,
-- spawn_proceeding_type_id=11 (upc.apl.merits), spawn_label
-- identical to the merits spawn already in production. The
-- spawn row's parent_id is the spawning decision/order row
-- (so the audit log carries the trigger link).
-- * No condition_expr — m's F2.3 decision recorded in mig 095
-- §3: "the appeal deadline should always be triggered by a
-- decision … appeal is always a possibility." Visibility
-- filtering on the frontend hides appeals on projects where
-- no appeal is contemplated.
-- * sequence_order numbering follows the inf convention
-- (40=interim, 50=oral, 60=decision, 80=appeal_spawn) so the
-- Verfahrensablauf timeline orders consistently across
-- proceedings. For PI the existing pi.order sits at
-- sequence_order=3; the appeal_spawn lands at 10 (clear of
-- the writ phase, room for future court-phase rows).
--
-- Idempotency: every INSERT is gated by `WHERE NOT EXISTS (… same
-- submission_code, proceeding_type_id, lifecycle_state)`. Re-apply
-- against an already-migrated DB inserts zero rows and the audit
-- log carries no duplicate entries.
--
-- audit_reason set_config required at the top — the mig 079 trigger
-- on paliad.deadline_rules raises EXCEPTION 'audit reason required'
-- on INSERT/UPDATE/DELETE without it.
SELECT set_config(
'paliad.audit_reason',
'mig 133: t-paliad-285 / m/paliad#117 + t-paliad-286 / m/paliad#118 — UPC Damages tree-end rows (interim conference R.105, oral hearing R.118/R.250, decision R.118/R.144, appeal-spawn R.220.1(a)) and UPC Provisional Measures appeal-spawn R.220.1(a); see docs/research-deadlines-completeness-2026-05-25.md §D and docs/audit-upc-rop-deadlines-2026-05-08.md §D/§F',
true);
-- =============================================================================
-- A. UPC Damages — court-phase tree end (m/paliad#117)
-- =============================================================================
-- A1. upc.dmgs.cfi.interim — Interim conference (UPC RoP R.105).
-- Court-set hearing fixed by the judge-rapporteur once the
-- written procedure closes. Identical shape to
-- upc.inf.cfi.interim; reuses the shared interim-conference
-- concept node.
INSERT INTO paliad.deadline_rules
(proceeding_type_id, parent_id, submission_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,
concept_id)
SELECT
17,
NULL,
'upc.dmgs.cfi.interim',
'Zwischenverfahren',
'Interim Conference',
NULL,
'court',
'hearing',
0,
'months',
'after',
NULL,
'Termin vom Gericht bestimmt',
'Date set by the court',
40,
false,
NULL,
NULL,
true,
NULL,
false,
NULL,
'optional',
true,
'published',
'e5071152-d408-4455-b644-9e79d86fd538'
WHERE NOT EXISTS (
SELECT 1 FROM paliad.deadline_rules
WHERE submission_code = 'upc.dmgs.cfi.interim'
AND proceeding_type_id = 17
AND lifecycle_state = 'published');
-- A2. upc.dmgs.cfi.oral — Oral hearing (UPC RoP R.118 / R.250).
-- Court-set hearing after the interim conference / close of
-- written procedure. Same shape as upc.inf.cfi.oral; reuses
-- the shared oral-hearing concept node.
INSERT INTO paliad.deadline_rules
(proceeding_type_id, parent_id, submission_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,
concept_id)
SELECT
17,
NULL,
'upc.dmgs.cfi.oral',
'Mündliche Verhandlung',
'Oral Hearing',
NULL,
'court',
'hearing',
0,
'months',
'after',
NULL,
NULL,
NULL,
50,
false,
NULL,
NULL,
true,
NULL,
false,
NULL,
'optional',
true,
'published',
'd6e5b793-dcf1-4d83-81ff-34f42dbb3693'
WHERE NOT EXISTS (
SELECT 1 FROM paliad.deadline_rules
WHERE submission_code = 'upc.dmgs.cfi.oral'
AND proceeding_type_id = 17
AND lifecycle_state = 'published');
-- A3. upc.dmgs.cfi.decision — Damages decision (UPC RoP R.118 /
-- R.144 / R.250). Court-set decision delivered after oral
-- hearing; closes the §3.1 audit gap (R.144 tree-end). Same
-- shape as upc.inf.cfi.decision; reuses the shared decision
-- concept node.
INSERT INTO paliad.deadline_rules
(proceeding_type_id, parent_id, submission_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,
concept_id)
SELECT
17,
NULL,
'upc.dmgs.cfi.decision',
'Entscheidung',
'Decision',
NULL,
'court',
'decision',
0,
'months',
'after',
NULL,
NULL,
NULL,
60,
false,
NULL,
NULL,
true,
NULL,
false,
NULL,
'optional',
true,
'published',
'472fc32d-cc4f-4aa4-8ace-e422031812de'
WHERE NOT EXISTS (
SELECT 1 FROM paliad.deadline_rules
WHERE submission_code = 'upc.dmgs.cfi.decision'
AND proceeding_type_id = 17
AND lifecycle_state = 'published');
-- A4. upc.dmgs.cfi.appeal_spawn — Appeal against damages decision
-- (UPC RoP R.220.1(a), 2-month main track; grounds R.224.2(a)
-- run as a separate deadline in the spawned upc.apl.merits
-- proceeding). Parent points at the freshly-inserted
-- upc.dmgs.cfi.decision; the SELECT subquery resolves it
-- after A3 lands. Same shape as the mig 095 inf.appeal_spawn.
INSERT INTO paliad.deadline_rules
(proceeding_type_id, parent_id, submission_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
17,
(SELECT id FROM paliad.deadline_rules
WHERE submission_code = 'upc.dmgs.cfi.decision'
AND proceeding_type_id = 17
AND lifecycle_state = 'published'
AND is_active = true),
'upc.dmgs.cfi.appeal_spawn',
'Berufung gegen Schadensentscheidung',
'Appeal against damages decision',
'Berufung gegen die Entscheidung über die Schadensbemessung (R.118 / R.144). 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 Schadensentscheidung 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 damages 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 submission_code = 'upc.dmgs.cfi.appeal_spawn'
AND proceeding_type_id = 17
AND lifecycle_state = 'published');
-- =============================================================================
-- B. UPC Provisional Measures — appeal route (m/paliad#118)
-- =============================================================================
-- B1. upc.pi.cfi.appeal_spawn — Appeal against PI order (UPC RoP
-- R.220.1(a), 2-month main track). PI orders under R.211
-- dispose of the urgent question and are appealable on the
-- main 2-month track (R.220.1(a)/R.224.1(a)); the 15-day
-- order track of R.220.1(c) is for case-management /
-- procedural orders requiring leave and does not apply to
-- PI dispositions. Parent points at the existing
-- upc.pi.cfi.order (sequence_order=3) so the spawn fires
-- once the order is anchored on a project's timeline.
INSERT INTO paliad.deadline_rules
(proceeding_type_id, parent_id, submission_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
10,
(SELECT id FROM paliad.deadline_rules
WHERE submission_code = 'upc.pi.cfi.order'
AND proceeding_type_id = 10
AND lifecycle_state = 'published'
AND is_active = true),
'upc.pi.cfi.appeal_spawn',
'Berufung gegen Anordnung',
'Appeal against PI order',
'Berufung gegen die einstweilige Anordnung nach R.211. Eine PI-Anordnung erledigt die einstweilige Streitfrage und wird wie eine Endentscheidung im Hauptverfahren behandelt: statutarische Frist von 2 Monaten ab Zustellung (R.224.1(a)); die Berufungsbegründung folgt mit 4 Monaten ab Zustellung (R.224.2(a), eigenständige Frist im Berufungsverfahren). Die 15-Tage-Spur nach R.220.1(c) / R.220.2 gilt für Verfahrensanordnungen mit Zulassung und ist hier nicht einschlägig.',
'both',
'filing',
2,
'months',
'after',
'RoP.220.1.a',
'Innerhalb von 2 Monaten ab Zustellung der PI-Anordnung 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 PI order 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.',
10,
true,
11,
'Berufungsverfahren öffnen',
true,
'UPC.RoP.220.1',
false,
NULL,
'optional',
false,
'published'
WHERE NOT EXISTS (
SELECT 1 FROM paliad.deadline_rules
WHERE submission_code = 'upc.pi.cfi.appeal_spawn'
AND proceeding_type_id = 10
AND lifecycle_state = 'published');
-- =============================================================================
-- C. Post-insert verification — raise if any expected row is missing
-- (matches the mig 095 / 127 convention; protects against a future
-- re-shape of the table that silently drops one of the WHERE NOT
-- EXISTS predicates).
-- =============================================================================
DO $$
DECLARE
v_missing text;
BEGIN
SELECT string_agg(expected, ', ' ORDER BY expected)
INTO v_missing
FROM (VALUES
('upc.dmgs.cfi.interim'),
('upc.dmgs.cfi.oral'),
('upc.dmgs.cfi.decision'),
('upc.dmgs.cfi.appeal_spawn'),
('upc.pi.cfi.appeal_spawn')
) AS t(expected)
WHERE NOT EXISTS (
SELECT 1 FROM paliad.deadline_rules dr
WHERE dr.submission_code = t.expected
AND dr.lifecycle_state = 'published'
AND dr.is_active = true);
IF v_missing IS NOT NULL THEN
RAISE EXCEPTION
'mig 133: expected published rules missing after insert: %', v_missing;
END IF;
IF NOT EXISTS (
SELECT 1 FROM paliad.deadline_rules dr
WHERE dr.submission_code = 'upc.dmgs.cfi.appeal_spawn'
AND dr.proceeding_type_id = 17
AND dr.spawn_proceeding_type_id = 11
AND dr.is_spawn = true
AND dr.parent_id IS NOT NULL
AND dr.lifecycle_state = 'published'
) THEN
RAISE EXCEPTION
'mig 133: upc.dmgs.cfi.appeal_spawn shape check failed (expected is_spawn=true, spawn_proceeding_type_id=11, parent_id set)';
END IF;
IF NOT EXISTS (
SELECT 1 FROM paliad.deadline_rules dr
WHERE dr.submission_code = 'upc.pi.cfi.appeal_spawn'
AND dr.proceeding_type_id = 10
AND dr.spawn_proceeding_type_id = 11
AND dr.is_spawn = true
AND dr.parent_id IS NOT NULL
AND dr.lifecycle_state = 'published'
) THEN
RAISE EXCEPTION
'mig 133: upc.pi.cfi.appeal_spawn shape check failed (expected is_spawn=true, spawn_proceeding_type_id=11, parent_id set)';
END IF;
END $$;