# Proceeding-code taxonomy (t-paliad-204 ratified 2026-05-18)

> Source of truth for `paliad.proceeding_types.code`. Every active row's
> `code` MUST conform to the convention below. This document anchors
> migration 096 (`internal/db/migrations/096_proceeding_code_rename.up.sql`)
> and the post-migration determinator + fristenrechner mapping in
> `internal/services/proceeding_mapping.go`.

## 0. Why we renamed

The historical `code` strings (`UPC_INF`, `DE_INF`, `EPA_OPP`, …) were
UPPER_SNAKE jurisdiction-glued-to-acronym slugs. They were structurally
opaque and the taxonomy grew unevenly as more proceedings entered the
fristenrechner — `UPC_APP` covers all UPC appeals, `DE_INF_OLG` /
`DE_INF_BGH` carry the instance hint inline, `EP_GRANT` is the only EPA
row with no `EPA_` prefix at all. The mapping in
`internal/services/proceeding_mapping.go` had to special-case appeal
ambiguities (no instance hint on UPC_APP, none on the DE side either).
After mig 095 landed the t-paliad-205 fristen gap-fill, m and paliadin
ratified a uniform convention for the corpus, captured here.

## 0.1 Convention

Active proceeding codes are lowercase, dot-separated, three positions:

    <jurisdiction>.<X>.<Y>

* **`<jurisdiction>`** — one of `upc`, `de`, `epa`, `dpma`.
* **`<X>` / `<Y>`** — contextual; for first-instance proceedings they are
  `<substantive-type>.<forum>` (e.g. `de.inf.lg` for Verletzungsklage am
  Landgericht). For appeals they are `<appeal-type>.<scope>` (e.g.
  `upc.apl.merits`, `upc.apl.cost`, `upc.apl.order`).
* The CHECK constraint installed by mig 096 enforces
  `code ~ '^[a-z]+\.[a-z]+\.[a-z]+$'` on every active row, with a
  carve-out for the legacy `_archived_litigation` bucket
  (`code ~ '^_archived_'`).

The convention is forward-looking: any new fristenrechner row added
after mig 096 MUST conform — no further UPPER_SNAKE codes.

## 0.2 Ratified taxonomy

### UPC

| New code           | Old code         | id | Notes                                                                  |
|--------------------|------------------|----|------------------------------------------------------------------------|
| `upc.inf.cfi`      | `UPC_INF`        | 8  | Verletzungsverfahren, CFI                                              |
| `upc.rev.cfi`      | `UPC_REV`        | 9  | Nichtigkeitsverfahren, CFI                                             |
| `upc.ccr.cfi`      | _new_            | _new_ | Widerklage auf Nichtigkeit — illustrative peer of `upc.inf.cfi`. Rules live on `upc.inf.cfi` with `with_ccr=true`. See §1 sub-decision S1. |
| `upc.pi.cfi`       | `UPC_PI`         | 10 | Einstweilige Maßnahmen                                                 |
| `upc.dmgs.cfi`     | `UPC_DAMAGES`    | 17 | Schadensbemessung                                                      |
| `upc.disc.cfi`     | `UPC_DISCOVERY`  | 18 | Bucheinsicht                                                           |
| `upc.apl.merits`   | `UPC_APP`        | 11 | Hauptberufung — covers inf + rev + ccr + damages-merits appeals        |
| `upc.apl.order`    | `UPC_APP_ORDERS` | 20 | 15-Tage-Beschwerde gegen Anordnungen (R.220 (1)(c))                    |
| `upc.apl.cost`     | `UPC_COST_APPEAL`| 19 | Kostenbeschwerde                                                       |

### DE

| New code            | Old code               | id | Notes                                                       |
|---------------------|------------------------|----|-------------------------------------------------------------|
| `de.inf.lg`         | `DE_INF`               | 12 | Verletzungsklage am Landgericht                             |
| `de.inf.olg`        | `DE_INF_OLG`           | 25 | Berufung am OLG                                             |
| `de.inf.bgh`        | `DE_INF_BGH`           | 26 | Revision + NZB merged — `with_nzb` flag on NZB-detour rules |
| `de.null.bpatg`     | `DE_NULL`              | 13 | Nichtigkeitsverfahren am BPatG                              |
| `de.null.bgh`       | `DE_NULL_BGH`          | 27 | Nichtigkeitsberufung am BGH                                 |

### EPA

| New code            | Old code     | id | Notes                                          |
|---------------------|--------------|----|------------------------------------------------|
| `epa.grant.exa`     | `EP_GRANT`   | 16 | EP-Erteilungsverfahren                         |
| `epa.opp.opd`       | `EPA_OPP`    | 14 | Einspruchsverfahren                            |
| `epa.opp.boa`       | `EPA_APP`    | 15 | Einspruchsbeschwerde (Board of Appeal)         |

### DPMA

| New code              | Old code                | id | Notes                                                          |
|-----------------------|-------------------------|----|----------------------------------------------------------------|
| `dpma.opp.dpma`       | `DPMA_OPP`              | 28 | Einspruch beim DPMA                                            |
| `dpma.appeal.bpatg`   | `DPMA_BPATG_BESCHWERDE` | 29 | Beschwerde am BPatG (generic — source differentiated at rule level) |
| `dpma.appeal.bgh`     | `DPMA_BGH_RB`           | 30 | Rechtsbeschwerde am BGH (generic — source differentiated at rule level) |

### Archived

| Code                    | id | Notes                                  |
|-------------------------|----|----------------------------------------|
| `_archived_litigation`  | 32 | Unchanged — Pipeline-A retired corpus  |

IDs are stable. Only the `code` STRING changes. The FKs
`deadline_rules.proceeding_type_id`, `projects.proceeding_type_id`, and
`deadline_rules.spawn_proceeding_type_id` reference IDs, so the existing
rule corpus and spawn wiring (incl. mig 095's `spawn_proceeding_type_id=11`)
continue to work unchanged.

## 0.3 Sub-decisions (m's calls, 2026-05-18)

### S1 — `upc.ccr.cfi` visibility

`is_active=true`, visible in the determinator + dropdowns. **No rules
attached.** When the determinator surfaces it, the UI shows the hint:

> "Regeln liegen auf upc.inf.cfi (with_ccr=true); wir leiten Sie dorthin
> weiter."

Routing logic lands in `internal/services/proceeding_mapping.go` — when
the cascade resolves to `upc.ccr.cfi`, the mapping returns the
`upc.inf.cfi` id (=8) with `with_ccr=true` as a default flag. The peer
exists for taxonomic completeness so users searching for
"Widerklage" find an entry; it is not a separate rule namespace.

### S2 — Abbreviations

`dmgs` for damages, `disc` for discovery. m's call: short form keeps the
codes terse and the dot-separated shape readable.

### S3 — Damages appeal

**NO separate code.** `upc.apl.merits` covers damages appeals — the
spawn rules from `upc.dmgs.cfi` (none seeded today) would carry their
own `spawn_label`. Avoids a code like `upc.apl.dmgs` whose rules would
be empty for the foreseeable future.

### S4 — NZB at BGH

Single bucket `de.inf.bgh`. Rules diverging in the NZB-detour-path
(Nichtzulassungsbeschwerde when the OLG didn't grant Revision) use a
`with_nzb` flag instead of a separate proceeding type. Keeps the dropdown
list shorter and matches how m practitioners think about the BGH
instance — same destination, two ways to arrive.

### S5 — DPMA appeals

Generic `dpma.appeal.bpatg` / `dpma.appeal.bgh` — source-of-decision
differentiation (was it a DPMA decision being appealed? a BPatG
decision being further appealed to BGH?) lives at the rule level, not
the proceeding-type level. Keeps the code namespace flat.

## 0.4 Spawn-FK invariant

After mig 096, the spawn FK invariant from mig 095 still holds:

    deadline_rules.spawn_proceeding_type_id = 11
       ↔ paliad.proceeding_types[id=11].code = 'upc.apl.merits'

Spawn rules from `upc.inf.cfi` / `upc.rev.cfi` chain to the appeal-merits
proceeding without code-string awareness. Same for any future spawn FK.

## 0.5 Not in scope

* `paliad.event_categories.slug` segments (`upc-inf`, `de-bgh-null`, …)
  are NOT renamed. They are stable identifiers in a separate taxonomy and
  their kebab form is presentation-layer (it appears in URL fragments).
  Mig 096 only updates the `proceeding_type_code` text column on
  `paliad.event_category_concepts` rows so the soft join through
  `event_category_concepts → proceeding_types.code` keeps resolving.
* Fee-table keys (`EPA_OPPOSITION`, `UPC_APPEAL`, …) in
  `internal/calc/fees.go` are NOT proceeding codes — they are fee-table
  bucket keys with their own naming. Untouched.
* Forum bucket slugs (`upc_cfi`, `de_lg`, …) in
  `ForumToProceedingCodes` are presentation buckets, not codes. The
  values inside (`UPC_INF`, …) are the codes being renamed.

## 0.6 References

* `internal/db/migrations/096_proceeding_code_rename.up.sql` — the
  migration that lands this rename.
* `internal/services/proceeding_mapping.go` — post-mig 096 mapping with
  the ccr-routing helper (S1).
* `internal/services/proceeding_codes_shape_test.go` — Go test asserting
  every active fristenrechner-category code matches the new shape regex.
* mig 095 (`internal/db/migrations/095_fristen_gap_fill.up.sql`) — the
  immediate predecessor; spawn_proceeding_type_id=11 carries through.
