proceeding_types taxonomy cleanup — separate primary proceedings from phases and cross-cutting admin #147

Open
opened 2026-05-26 19:52:07 +00:00 by mAi · 1 comment
Collaborator

m's bug (2026-05-26 21:49)

not all are first level / primary proceeding types. Some don't work — we should not have phases as proceeding types; how to implement them is a different story

Live audit (46 active rows in paliad.proceeding_types, 2026-05-26)

Grouping the rows by what they actually represent:

A. Primary proceedings (~13) — these belong in proceeding_types

Self-contained matters with their own filing, their own deadline cascade, their own ablauf.

code name jurisdiction
upc.inf.cfi Verletzungsverfahren UPC
upc.rev.cfi Nichtigkeitsverfahren UPC
upc.pi.cfi Einstweilige Maßnahmen UPC
upc.dni.cfi Negative Feststellungsklage UPC
upc.dmgs.cfi Schadensbemessung UPC
upc.disc.cfi Bucheinsicht UPC
upc.bsv.cfi Beweissicherung / saisie UPC
upc.apl.unified Berufungsverfahren UPC
upc.epo.review Überprüfung von EPA-Entscheidungen UPC
de.inf.lg / de.inf.olg / de.inf.bgh Verletzungsinstanzen DE
de.null.bpatg / de.null.bgh Nichtigkeitsinstanzen DE
epa.opp.opd / epa.opp.boa / epa.grant.exa EPA-Verfahren EPA
dpma.opp.dpma / dpma.appeal.bpatg / dpma.appeal.bgh DPMA-Verfahren DPMA

B. Phases of a primary proceeding (5) — should NOT be proceeding_types

These are stages WITHIN a CFI procedure, not standalone proceedings. A upc.inf.cfi matter always passes through interim → oral → decision phases; they're not optionally elected, they're the structure of the parent.

code name actually a phase of
upc.cfi.interim CFI - Zwischenverfahren every CFI proceeding (inf/rev/pi/dni/dmgs/disc/bsv)
upc.cfi.oral CFI - Mündliche Verhandlung every CFI proceeding
upc.cfi.decision CFI - Endentscheidung every CFI proceeding
upc.costs.cfi Separate Kostenentscheidung post-decision phase
upc.default.cfi Versäumnisentscheidung alternative decision-phase path

C. Side-actions within a proceeding (10) — could go either way

Applications and orders that arise inside a primary proceeding. Treated today as their own "types" but are sub-events of the parent matter.

code name
upc.evidence.cfi Beweisanordnungen (allgemein)
upc.experiments.cfi Gerichtlich angeordnete Versuche
upc.security.cfi Sicherheitsleistung
upc.intervention.rop Streitbeitritt
upc.parties.change Parteiwechsel / Patentübergang
upc.optout.cfi Antrag auf Opt-out
upc.inspection.cfi Besichtigungsantrag
upc.freezing.cfi Anordnung zur Vermögenssperre
upc.withdrawal.rop Klagerücknahme
upc.rehearing.coa Wiederaufnahmeantrag

D. Cross-cutting administrative / meta (8) — definitely not proceedings

These describe rules-of-procedure mechanics, not matters a lawyer takes on.

code name
upc.case.mgmt Verfahrensverwaltung
upc.general.rop Allgemeine Bestimmungen
upc.service.rop Zustellung von Schriftsätzen
upc.language.rop Verfahrenssprache
upc.representation.rop Vertretung / Anwaltsprivileg
upc.fees.court Gerichtsgebühren
upc.legalaid.cfi Prozesskostenhilfe
upc.special.cfi Besondere Verfahrenslagen
upc.reestablishment.rop Wiedereinsetzung in den vorigen Stand (cross-cutting)

E. Edge cases — call needed

  • upc.ccr.cfi (Widerklage auf Nichtigkeit) — technically a sub-procedure of an INF action, never standalone. Hint: handled today via [with_ccr] flag inside UPC_INF.
  • upc.pl.cfi (Schutzschrift) — pre-litigation defensive filing, not a proceeding yet. Could be standalone or a meta-event.

The implementation question (m: "a different story")

Four candidate models for phases / side-actions / meta:

  1. kind discriminator on proceeding_typeskind text CHECK ('proceeding','phase','side_action','meta'). Minimal schema change; pickers filter by kind. Cheapest. Doesn't model parent-relationship for phases.
  2. Self-referencing parent_idproceeding_types.parent_proceeding_id for phases / side-actions. Phase rows have a kind='phase' and a parent FK; meta rows have NULL parent + kind='meta'. Models the structural relationship cleanly.
  3. Separate tablesproceeding_phases + proceeding_side_actions + proceeding_rop_general. Most expressive, most schema churn, queries get more joins.
  4. Move phases into procedural_events — phases like "Zwischenanhörung" are arguably just events anchored to a primary proceeding's proceeding_type_id. Side-actions like "Besichtigungsantrag" become events with their own follow-up rules. This is the most aggressive: shrink proceeding_types to category A (13 rows) and represent everything else as events under those proceedings.

Each has different implications for the Fristenrechner overhaul (m/paliad#146) which uses proceeding_type as a qualifier in the R3 wizard row — restructuring proceeding_types changes R3's pick list.

Data preserved

Whichever model wins, every existing sequencing_rule.proceeding_type_id must remain resolvable (no orphaned rules). The mig will reparent before any DROP.

Open design questions for the inventor

  1. Pick a model from 1-4 (or propose 5). What's the right shape?
  2. For phases (interim/oral/decision): are they always linear sub-phases of every CFI proceeding (i.e. implicit), or do some proceedings skip phases (e.g. summary judgment)?
  3. For side-actions: are they triggered by an event in the parent proceeding, or initiated by the user out-of-band?
  4. Should de.inf.lg / de.inf.olg / de.inf.bgh collapse into one de.inf with an instance_level qualifier? They share most rules and are distinguished by instance_level (mig 084 added that column).
  5. Same question for de.null.bpatg / de.null.bgh.
  6. upc.apl.unified (id=160) — already collapsed all UPC appeal types into one. Should DE follow that pattern (de.inf.unified with instance_level)?
  7. upc.ccr.cfi — should it stay as a discrete proceeding_type or move to [with_ccr] flag on upc.inf.cfi?
  8. UI implication for the Fristenrechner Mode B R3 — does the pick list show only primary proceedings (category A), or all 'proceeding'+'phase'+'side_action' kinds with visual grouping?
  9. UI implication for the project model — projects.proceeding_type_id (today FK to proceeding_types) should reference only primary proceedings, or also phases/side-actions?
  10. Migration sequence — given m/paliad#146 (Fristenrechner) is in flight on the S1-S6 train (knuth, t-paliad-323), do we (a) pause m/paliad#146 until taxonomy is cleaned, (b) land m/paliad#146 against current shape and migrate after, or (c) land the categorization in parallel and let knuth re-target if the qualifier set changes?
  11. Rule-side editorial impact — moving rules off phase/side-action proceeding_type_ids onto their real parent may force condition_expr / trigger_event_id additions to disambiguate. How many rules need a new condition vs. how many are already trigger-event-anchored?

Acceptance for the design pass

Deliverable: docs/design-proceeding-types-taxonomy-2026-05-NN.md covering:

  • Ratified categorization of all 46 active rows into (proceeding / phase / side-action / meta) with edge-case calls
  • Chosen model (1-4 or alternative) with schema sketch + migration plan
  • For each row that moves out of proceeding_types, the new home and the FK reparent
  • Mig sketch (DDL only; no implementation)
  • One worked example: trace a upc.inf.cfi.interim (now: phase) through the new model end-to-end
  • Impact on projects.proceeding_type_id, sequencing_rules.proceeding_type_id, sequencing_rules.spawn_proceeding_type_id, Fristenrechner Mode B R3 picker, Litigation Planner suite
  • Migration sequencing decision against m/paliad#146 (pause / parallel / re-target)
  • Out-of-scope notes

No code yet — design only. Coder shift comes after m ratifies.

Out of scope

  • Renaming/relabelling primary proceedings (category A) — that's editorial, not structural
  • Adding new proceedings beyond what's in the corpus today
  • The Fristenrechner UI overhaul (m/paliad#146) — separate track; this design only tells the wizard what set of proceeding_types to query
## m's bug (2026-05-26 21:49) > not all are first level / primary proceeding types. Some don't work — we should not have phases as proceeding types; how to implement them is a different story ## Live audit (46 active rows in `paliad.proceeding_types`, 2026-05-26) Grouping the rows by what they actually represent: ### A. Primary proceedings (~13) — these belong in `proceeding_types` Self-contained matters with their own filing, their own deadline cascade, their own ablauf. | code | name | jurisdiction | |---|---|---| | `upc.inf.cfi` | Verletzungsverfahren | UPC | | `upc.rev.cfi` | Nichtigkeitsverfahren | UPC | | `upc.pi.cfi` | Einstweilige Maßnahmen | UPC | | `upc.dni.cfi` | Negative Feststellungsklage | UPC | | `upc.dmgs.cfi` | Schadensbemessung | UPC | | `upc.disc.cfi` | Bucheinsicht | UPC | | `upc.bsv.cfi` | Beweissicherung / saisie | UPC | | `upc.apl.unified` | Berufungsverfahren | UPC | | `upc.epo.review` | Überprüfung von EPA-Entscheidungen | UPC | | `de.inf.lg` / `de.inf.olg` / `de.inf.bgh` | Verletzungsinstanzen | DE | | `de.null.bpatg` / `de.null.bgh` | Nichtigkeitsinstanzen | DE | | `epa.opp.opd` / `epa.opp.boa` / `epa.grant.exa` | EPA-Verfahren | EPA | | `dpma.opp.dpma` / `dpma.appeal.bpatg` / `dpma.appeal.bgh` | DPMA-Verfahren | DPMA | ### B. Phases of a primary proceeding (5) — should NOT be proceeding_types These are stages WITHIN a CFI procedure, not standalone proceedings. A `upc.inf.cfi` matter always passes through interim → oral → decision phases; they're not optionally elected, they're the structure of the parent. | code | name | actually a phase of | |---|---|---| | `upc.cfi.interim` | CFI - Zwischenverfahren | every CFI proceeding (inf/rev/pi/dni/dmgs/disc/bsv) | | `upc.cfi.oral` | CFI - Mündliche Verhandlung | every CFI proceeding | | `upc.cfi.decision` | CFI - Endentscheidung | every CFI proceeding | | `upc.costs.cfi` | Separate Kostenentscheidung | post-decision phase | | `upc.default.cfi` | Versäumnisentscheidung | alternative decision-phase path | ### C. Side-actions within a proceeding (10) — could go either way Applications and orders that arise inside a primary proceeding. Treated today as their own "types" but are sub-events of the parent matter. | code | name | |---|---| | `upc.evidence.cfi` | Beweisanordnungen (allgemein) | | `upc.experiments.cfi` | Gerichtlich angeordnete Versuche | | `upc.security.cfi` | Sicherheitsleistung | | `upc.intervention.rop` | Streitbeitritt | | `upc.parties.change` | Parteiwechsel / Patentübergang | | `upc.optout.cfi` | Antrag auf Opt-out | | `upc.inspection.cfi` | Besichtigungsantrag | | `upc.freezing.cfi` | Anordnung zur Vermögenssperre | | `upc.withdrawal.rop` | Klagerücknahme | | `upc.rehearing.coa` | Wiederaufnahmeantrag | ### D. Cross-cutting administrative / meta (8) — definitely not proceedings These describe rules-of-procedure mechanics, not matters a lawyer takes on. | code | name | |---|---| | `upc.case.mgmt` | Verfahrensverwaltung | | `upc.general.rop` | Allgemeine Bestimmungen | | `upc.service.rop` | Zustellung von Schriftsätzen | | `upc.language.rop` | Verfahrenssprache | | `upc.representation.rop` | Vertretung / Anwaltsprivileg | | `upc.fees.court` | Gerichtsgebühren | | `upc.legalaid.cfi` | Prozesskostenhilfe | | `upc.special.cfi` | Besondere Verfahrenslagen | | `upc.reestablishment.rop` | Wiedereinsetzung in den vorigen Stand (cross-cutting) | ### E. Edge cases — call needed - `upc.ccr.cfi` (Widerklage auf Nichtigkeit) — technically a sub-procedure of an INF action, never standalone. Hint: handled today via `[with_ccr]` flag inside UPC_INF. - `upc.pl.cfi` (Schutzschrift) — pre-litigation defensive filing, not a proceeding yet. Could be standalone or a meta-event. ## The implementation question (m: "a different story") Four candidate models for phases / side-actions / meta: 1. **`kind` discriminator on `proceeding_types`** — `kind text CHECK ('proceeding','phase','side_action','meta')`. Minimal schema change; pickers filter by kind. Cheapest. Doesn't model parent-relationship for phases. 2. **Self-referencing `parent_id`** — `proceeding_types.parent_proceeding_id` for phases / side-actions. Phase rows have a `kind='phase'` and a parent FK; meta rows have NULL parent + `kind='meta'`. Models the structural relationship cleanly. 3. **Separate tables** — `proceeding_phases` + `proceeding_side_actions` + `proceeding_rop_general`. Most expressive, most schema churn, queries get more joins. 4. **Move phases into `procedural_events`** — phases like "Zwischenanhörung" are arguably just events anchored to a primary proceeding's `proceeding_type_id`. Side-actions like "Besichtigungsantrag" become events with their own follow-up rules. This is the most aggressive: shrink `proceeding_types` to category A (13 rows) and represent everything else as events under those proceedings. Each has different implications for the Fristenrechner overhaul (m/paliad#146) which uses `proceeding_type` as a qualifier in the R3 wizard row — restructuring proceeding_types changes R3's pick list. ## Data preserved Whichever model wins, every existing `sequencing_rule.proceeding_type_id` must remain resolvable (no orphaned rules). The mig will reparent before any DROP. ## Open design questions for the inventor 1. Pick a model from 1-4 (or propose 5). What's the right shape? 2. For phases (interim/oral/decision): are they always linear sub-phases of every CFI proceeding (i.e. implicit), or do some proceedings skip phases (e.g. summary judgment)? 3. For side-actions: are they triggered by an event in the parent proceeding, or initiated by the user out-of-band? 4. Should `de.inf.lg` / `de.inf.olg` / `de.inf.bgh` collapse into one `de.inf` with an `instance_level` qualifier? They share most rules and are distinguished by `instance_level` (mig 084 added that column). 5. Same question for `de.null.bpatg` / `de.null.bgh`. 6. `upc.apl.unified` (id=160) — already collapsed all UPC appeal types into one. Should DE follow that pattern (`de.inf.unified` with instance_level)? 7. `upc.ccr.cfi` — should it stay as a discrete proceeding_type or move to `[with_ccr]` flag on `upc.inf.cfi`? 8. UI implication for the Fristenrechner Mode B R3 — does the pick list show only primary proceedings (category A), or all 'proceeding'+'phase'+'side_action' kinds with visual grouping? 9. UI implication for the project model — `projects.proceeding_type_id` (today FK to proceeding_types) should reference only primary proceedings, or also phases/side-actions? 10. Migration sequence — given m/paliad#146 (Fristenrechner) is in flight on the S1-S6 train (knuth, t-paliad-323), do we (a) pause m/paliad#146 until taxonomy is cleaned, (b) land m/paliad#146 against current shape and migrate after, or (c) land the categorization in parallel and let knuth re-target if the qualifier set changes? 11. Rule-side editorial impact — moving rules off phase/side-action proceeding_type_ids onto their real parent may force `condition_expr` / `trigger_event_id` additions to disambiguate. How many rules need a new condition vs. how many are already trigger-event-anchored? ## Acceptance for the design pass Deliverable: `docs/design-proceeding-types-taxonomy-2026-05-NN.md` covering: - Ratified categorization of all 46 active rows into (proceeding / phase / side-action / meta) with edge-case calls - Chosen model (1-4 or alternative) with schema sketch + migration plan - For each row that moves out of `proceeding_types`, the new home and the FK reparent - Mig sketch (DDL only; no implementation) - One worked example: trace a `upc.inf.cfi.interim` (now: phase) through the new model end-to-end - Impact on `projects.proceeding_type_id`, `sequencing_rules.proceeding_type_id`, `sequencing_rules.spawn_proceeding_type_id`, Fristenrechner Mode B R3 picker, Litigation Planner suite - Migration sequencing decision against m/paliad#146 (pause / parallel / re-target) - Out-of-scope notes No code yet — design only. Coder shift comes after m ratifies. ## Out of scope - Renaming/relabelling primary proceedings (category A) — that's editorial, not structural - Adding new proceedings beyond what's in the corpus today - The Fristenrechner UI overhaul (m/paliad#146) — separate track; this design only tells the wizard what set of proceeding_types to query
mAi self-assigned this 2026-05-26 19:52:07 +00:00
Author
Collaborator

TAXONOMY KIND DISCRIMINATOR COMPLETE — 23 rows reclassified

Commit: 9d68845 on mai/ritchie/coder-mig-153-proceeding (t-paliad-325).

What landed

  • Mig 153 (internal/db/migrations/153_proceeding_types_kind.{up,down}.sql) — additive: ADD COLUMN kind text NOT NULL DEFAULT 'proceeding' CHECK (kind IN ('proceeding','phase','side_action','meta')), partial index on (kind, is_active), snapshot to paliad.proceeding_types_pre_153 in same TX, set_config defensive audit_reason, DO-block invariant check (expects exactly 23 reclassified rows), new BEFORE INSERT/UPDATE trigger projects_proceeding_type_kind_check.
  • internal/services/project_service.govalidateProceedingTypeCategory now picks up category + kind + is_active in one SELECT and surfaces a new ErrInvalidProceedingTypeKind typed error.
  • internal/services/project_service_test.go — new TestProjectService_ProceedingTypeKindGuard (4 angles: service-layer kind reject; active-phase-row still rejects on kind; mig 153 trigger backstop on raw INSERT; happy-path kind='proceeding' accept). Skips without TEST_DATABASE_URL, matches the Slice 5 guard test pattern.
  • cmd/gen-upc-snapshot/main.go — proceeding_types query now filters AND kind = 'proceeding' for forward-compat.

Acceptance verification

Pre-mig audit (Supabase MCP, 2026-05-27):

Check Result
23 row IDs match live data (173, 174, 175, 185, 178, 182, 177, 184, 165, 170, 180, 181, 187, 183, 162, 161, 163, 168, 164, 166, 167, 186, 169) all present
upc.costs.cfi (176) carve-out → stays primary defaults to kind='proceeding'
upc.pl.cfi (188) carve-out → stays primary defaults to kind='proceeding'
Active sequencing_rules.proceeding_type_id pointing at any reclassified row 0
Active sequencing_rules.spawn_proceeding_type_id pointing at any reclassified row 0
projects.proceeding_type_id pointing at any reclassified row 0
event_category_concepts.proceeding_type_code pointing at any reclassified row's code 0
Post-mig row counts per kind (verified via CTE simulation) proceeding: 23 active + 4 inactive = 27 / phase: 4 / side_action: 10 / meta: 9 — = 50 total ✓
Full mig 153 SQL dry-run in DO-block (forced rollback) NOTICE "mig 153 dry-run OK: 23 rows reclassified"
go test ./internal/services/ ./pkg/litigationplanner/... short all green

Snapshot regen status

The embedded pkg/litigationplanner/embedded/upc/ snapshot is a placeholder today (meta.json source_db_label: "placeholder — operator must run make snapshot-upc against prod once mig 134/135 are applied"). It contains only upc.inf.cfi and upc.rev.cfi — none of the 23 non-primary rows are in it, so mig 153 doesn't change the placeholder JSON.

The generator query is updated to filter AND kind = 'proceeding'. A proper regen needs DATABASE_URL access to the live paliad DB with mig 153 applied — that's an operator step post-merge:

DATABASE_URL=postgres://... make snapshot-upc

Filing this as a separate snapshot-refresh follow-up rather than blocking this commit on prod-DSN access (ritchie's mAi role has read-only access to the paliad schema).

Migration sequencing reminder

Per design §7 + m's Q10: this mig lands in parallel with knuth's m/paliad#146 (Fristenrechner overhaul). Mig 153 must merge before knuth's S3 ships so the R3 chip query can add the kind='proceeding' filter on day one. No data drift between mig 152 and mig 153.

**TAXONOMY KIND DISCRIMINATOR COMPLETE — 23 rows reclassified** Commit: [`9d68845`](https://mgit.msbls.de/m/paliad/commit/9d688459e32b4621bf4e3fa7fc9c0fdd0e35901d) on `mai/ritchie/coder-mig-153-proceeding` (t-paliad-325). ## What landed - **Mig 153** (`internal/db/migrations/153_proceeding_types_kind.{up,down}.sql`) — additive: ADD COLUMN `kind text NOT NULL DEFAULT 'proceeding' CHECK (kind IN ('proceeding','phase','side_action','meta'))`, partial index on `(kind, is_active)`, snapshot to `paliad.proceeding_types_pre_153` in same TX, set_config defensive audit_reason, DO-block invariant check (expects exactly 23 reclassified rows), new BEFORE INSERT/UPDATE trigger `projects_proceeding_type_kind_check`. - **`internal/services/project_service.go`** — `validateProceedingTypeCategory` now picks up `category + kind + is_active` in one SELECT and surfaces a new `ErrInvalidProceedingTypeKind` typed error. - **`internal/services/project_service_test.go`** — new `TestProjectService_ProceedingTypeKindGuard` (4 angles: service-layer kind reject; active-phase-row still rejects on kind; mig 153 trigger backstop on raw INSERT; happy-path kind='proceeding' accept). Skips without `TEST_DATABASE_URL`, matches the Slice 5 guard test pattern. - **`cmd/gen-upc-snapshot/main.go`** — proceeding_types query now filters `AND kind = 'proceeding'` for forward-compat. ## Acceptance verification Pre-mig audit (Supabase MCP, 2026-05-27): | Check | Result | |---|---| | 23 row IDs match live data (173, 174, 175, 185, 178, 182, 177, 184, 165, 170, 180, 181, 187, 183, 162, 161, 163, 168, 164, 166, 167, 186, 169) | ✅ all present | | `upc.costs.cfi` (176) carve-out → stays primary | ✅ defaults to kind='proceeding' | | `upc.pl.cfi` (188) carve-out → stays primary | ✅ defaults to kind='proceeding' | | Active `sequencing_rules.proceeding_type_id` pointing at any reclassified row | **0** | | Active `sequencing_rules.spawn_proceeding_type_id` pointing at any reclassified row | **0** | | `projects.proceeding_type_id` pointing at any reclassified row | **0** | | `event_category_concepts.proceeding_type_code` pointing at any reclassified row's code | **0** | | Post-mig row counts per kind (verified via CTE simulation) | proceeding: 23 active + 4 inactive = 27 / phase: 4 / side_action: 10 / meta: 9 — **= 50 total ✓** | | Full mig 153 SQL dry-run in DO-block (forced rollback) | ✅ NOTICE "mig 153 dry-run OK: 23 rows reclassified" | | `go test ./internal/services/ ./pkg/litigationplanner/...` short | ✅ all green | ## Snapshot regen status The embedded `pkg/litigationplanner/embedded/upc/` snapshot is a **placeholder** today (`meta.json` source_db_label: "placeholder — operator must run `make snapshot-upc` against prod once mig 134/135 are applied"). It contains only `upc.inf.cfi` and `upc.rev.cfi` — none of the 23 non-primary rows are in it, so mig 153 doesn't change the placeholder JSON. The generator query is updated to filter `AND kind = 'proceeding'`. A proper regen needs DATABASE_URL access to the live paliad DB with mig 153 applied — that's an operator step post-merge: ```bash DATABASE_URL=postgres://... make snapshot-upc ``` Filing this as a separate snapshot-refresh follow-up rather than blocking this commit on prod-DSN access (ritchie's mAi role has read-only access to the paliad schema). ## Migration sequencing reminder Per design §7 + m's Q10: this mig lands in **parallel** with knuth's m/paliad#146 (Fristenrechner overhaul). Mig 153 must merge **before** knuth's S3 ships so the R3 chip query can add the `kind='proceeding'` filter on day one. No data drift between mig 152 and mig 153.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: m/paliad#147
No description provided.