docs(t-paliad-084): Fristenrechner completeness audit vs youpc deadline calc

Read-only research deliverable. Compares paliad's 9-proceeding-type
Fristenrechner ruleset (52 public rules in deadline_rules) against
youpc's 70-deadline event-driven calc (data.deadlines + data.events).

Top findings (§1 executive summary):
- youpc covers 64 distinct UPC RoP rule codes; paliad covers ~5
- The two tools answer different questions (timeline-by-procedure vs
  search-by-trigger-event) — biggest gap is structural, not data
- Paliad's holiday system is materially better; youpc's defaults are empty

Critical bugs surfaced (§4):
- Public UPC_INF Fristenrechner ignores CCR-conditional rejoinder
  duration (always uses 029.c/1mo, should be 029.d/2mo when CCR filed).
  KanzlAI internal INF type already wires this; public type doesn't.
- UPC_APP grounds chained off notice instead of decision date,
  giving wrong dates when notice is filed early
- EP_GRANT publish chained off filing instead of priority date
- Rule_code format inconsistent across migrations (RoP 23 vs RoP.023)

Recommendations ranked across 5 tiers (§6) for m to review.
Open product decisions in §7. No code changes.
This commit is contained in:
m
2026-04-30 10:36:30 +02:00
parent 8ddfb94f9e
commit aab82d4aca

View File

@@ -0,0 +1,314 @@
# Audit — Fristenrechner Completeness (paliad vs youpc deadline calc)
**Author:** curie (researcher)
**Date:** 2026-04-30
**Task:** t-paliad-084
**Mode:** read-only research, no code changes
**Question (m):** *"Does paliad's Fristenrechner have all the data from our youpc deadline calc?"*
---
## 1. Executive summary
**No.** Paliad's Fristenrechner is **timeline-shaped**, youpc's deadline calc is **trigger-event-shaped**, and the two have only ~10 % overlap of the rule corpus. They were built for different jobs:
| | paliad Fristenrechner | youpc deadline calc |
|---|---|---|
| Data shape | 9 proceeding-type trees (UPC + DE + EPA) | 102 trigger events → 70 deadlines (UPC only) |
| Rule count | 52 rules across 9 trees (the 9 public types) | 70 standalone deadlines + 36 timeline events |
| Tool UX | "pick proceeding type → see whole timeline from trigger date" | "pick trigger event → see all deadlines that flow from it" |
| RoP rule-code coverage | 5 distinct UPC RoP refs (`023`, `029b`, `029c`, `050`, `220.1`) | **64 distinct RoP refs** (`016.3.a``353`) |
| Working-day arithmetic | ❌ no | ❌ no, but data references it (RoP.198 / RoP.213 notes "or 20 working days, whichever is longer") |
| Holiday handling | ✅ DB-driven, German federal + UPC summer/winter vacation 2026/27 | ❌ empty default config, hardcoded TODO |
| Adaptive rules (with/without CCR) | ✅ via `condition_rule_id` + `alt_*` columns (KanzlAI types only — INF/REV/CCR; **not** in the public Fristenrechner trees) | ✅ via separate trigger events (29.a/b/c/d/e all distinct) |
| Law citation links | ❌ free-text rule_ref | ✅ `deadline_rule_codes``rule_codes``laws.unique_id` |
| Linkage to project / matter | ✅ (via `paliad.deadlines` rows, separate concern) | ✅ (via `data.proceeding_events` graph) |
The short answer for m: **paliad covers the 9 high-level UPC/DE/EPA procedure timelines well, but is missing ~56 of the 64 granular UPC RoP deadlines that the youpc calc exposes.** The ones in paliad are the SoC→SoD→Reply→Rejoinder backbone; the gap is everything around damages determination, protective letters, evidence preservation, lay-open-books, translation orders, leave-to-appeal, rectification, rehearing, cross-appeals, and the "correction of deficiencies" family. None of these have ever been ported.
---
## 2. Rule inventory
### 2.1 youpc — `data.deadlines` (primary "deadline calc" content)
70 active deadlines, grouped by RoP family. Each row: `title`, `duration_value`, `duration_unit` (`days|weeks|months`), `timing` (`before|after`), trigger event(s), rule code(s), notes. Source: `internal/services/deadline_service.go` + production DB.
| RoP family | # deadlines | Examples |
|---|---|---|
| Pleadings (R.019R.032, R.039) | 14 | Preliminary Objection (1mo, R.019.1), SoD (3mo, R.023), CCR (3mo, R.025), Reply 029.a/b/c/d/e (5 distinct rules) |
| Revocation (R.049R.052) | 5 | Defence to revocation (2mo, R.049.1), Counterclaim for infringement (2mo, R.049.2.b), Application to amend (2mo, R.049.2.a) |
| Counterclaim infringement (R.056) | 3 | Defence (2mo, R.056.1), Reply (1mo, R.056.3), Rejoinder (1mo, R.056.4) |
| DNI (R.067R.069) | 3 | Defence (2mo, R.067), Reply (1mo, R.069.1), Rejoinder (1mo, R.069.2) |
| Office decisions (R.088, R.097.1) | 2 | Annul EPO decision (1mo, R.088), Annul unitary-effect refusal (3w, R.097.1) |
| Oral hearing (R.109) | 3 | Simultaneous translation (1mo **before**), Interpreter cost (2w **before**), Translation org (2w after summons) |
| Cost orders (R.118.4, R.151, R.221.1) | 3 | App. for orders consequential on validity (2mo, R.118.4), Cost decision app (1mo, R.151), Leave-to-appeal cost decision (15d, R.221.1) |
| Damages (R.137R.139) | 3 | Defence (2mo, R.137.2), Reply (1mo, R.139), Rejoinder (1mo, R.139) |
| Lay-open books (R.142) | 3 | Defence (2mo, R.142.2), Reply (14d, R.142.3), Rejoinder (14d, R.142.3) |
| Evidence preservation (R.197.3, R.198) | 2 | Review request (30d, R.197.3), Start of merits (31d, R.198 — "or 20 working days, whichever is longer") |
| Provisional measures (R.207.6/9, R.213) | 3 | Correction (14d, R.207.6.a), Renewal (6mo, R.207.9), Start of merits (31d, R.213) |
| Appeals (R.220R.245) | 16 | Statement of Appeal (15d / 2mo, R.224.1.a/b), Grounds (15d / 4mo, R.224.2.a/b), Response (15d / 3mo, R.235.1/2), Cross-appeal (15d / 3mo, R.237), Reply to cross-appeal (15d / 2mo, R.238.1/2), Discretionary review (15d, R.220.3), Reject inadmissible (1mo, R.234.1), Rehearing (2mo, R.245.2.a/b) |
| Other (R.262.2, R.321.3, R.333.2, R.353) | 4 | Confidentiality (14d, R.262.2), Refer to central division (10d, R.321.3), Review CMO (15d, R.333.2), Rectification (1mo, R.353) |
| Registry corrections (multiple) | 6 | "Correction of deficiencies / payment" (14d) under R.016.3.a, R.027.2, R.089.2, R.229.2, R.253.2, R.207.6.a |
**Duration unit distribution:** 44 months · 23 days · 3 weeks. Min 10d, max 6mo.
**`timing='before'`:** 2 rows (R.109 family — simultaneous translation, interpreter cost).
### 2.2 youpc — `data.proceeding_events` (timeline tree, 36 rules)
Self-referential tree; parent_id = sequence, duration = edge weight. 6 proceeding types (INF=8, REV=7, CCR=7, APM=4, APP=8, AMD=2). **This is the table that paliad ported into `paliad.deadline_rules` (via KanzlAI).**
### 2.3 paliad — `paliad.deadline_rules` (96 rules across 16 proceeding types)
| Category | Proceeding types | Rules | Source |
|---|---|---|---|
| Public Fristenrechner (`category='fristenrechner'`) | 9: UPC_INF, UPC_REV, UPC_PI, UPC_APP, DE_INF, DE_NULL, EPA_OPP, EPA_APP, EP_GRANT | **52** | migration `012_fristenrechner_rules.up.sql`, ported from pre-Phase-C in-memory `internal/calc/deadline_rules.go` |
| Internal/matter-attached (KanzlAI port) | 7: INF, REV, CCR, APM, APP, AMD, ZPO_CIVIL | 44 | migration `009_seed_deadline_rules.up.sql`, ported from KanzlAI seed which itself came from `data.proceeding_events` |
The **public Fristenrechner UI** (`frontend/src/fristenrechner.tsx`, lines 2137) only exposes the 9 public types. The KanzlAI 7-type set is for matter-attached fristen (internal Aktenverwaltung), reachable only when a deadline is linked to a project — never as a "calculate deadlines from event" tool.
**UPC_CCR was planned in the design doc** (`design-prozesskostenrechner-fristenrechner.md` §4.1, line 386) but never seeded in `012_fristenrechner_rules.up.sql`. The CCR variant only exists under the internal `CCR` proceeding type.
---
## 3. Gap analysis — youpc rules NOT in paliad
The bulk of the youpc 70-deadline corpus is **invisible to a paliad user** today. Grouped by missing functional area:
### 3.1 Procedural-defect "Correction of deficiencies" family (6 rules, all 14d)
- R.016.3.a (initial), R.027.2 (CCR), R.089.2 (Office annul), R.207.6.a (PM), R.229.2 (appeal), R.253.2 (other) — six distinct triggers, six distinct rule codes, but identical duration. Paliad has no equivalent — there's no procedural-defect proceeding.
### 3.2 Damages determination (R.131.2, R.137R.139)
- Application for damages → 2mo Defence → 1mo Reply → 1mo Rejoinder. **Entirely missing from paliad.**
### 3.3 Lay-open books / discovery (R.142)
- Request → 2mo Defence → 14d Reply → 14d Rejoinder. **Entirely missing.**
### 3.4 Evidence preservation (R.197.3, R.198)
- Review request (30d), Start of merits ("31d **or** 20 working days, whichever is longer", R.198). **Missing.** Note: R.198 is the only deadline in either system that requires the **`max(calendar-days, working-days)` operator** — paliad has no support for it.
### 3.5 Provisional measures (R.207, R.213)
- Paliad's UPC_PI has 4 rules (Antrag → Erwiderung [court-set] → Oral → Beschluss). The **PI Renewal of Protective Letter (6mo, R.207.9)** and **Start of merits (31d / 20wd, R.213)** are missing.
### 3.6 Oral-hearing prep "before"-mode rules (R.109)
- Simultaneous translation (1 month **before** oral hearing, R.109)
- Interpreter cost notice (2 weeks **before**, R.109.4)
- The paliad data model has no `timing` column → all rules implicitly fire `after`. The `DeadlineCalculator.CalculateEndDate` reads `rule.Timing` (a `*string`), but the rule struct has no DB-mapped `timing` column; the `addDuration` helper in `fristenrechner.go:217228` always adds, never subtracts. **Adding "before" support is a tiny change to the schema + service, but no rule today populates it.**
### 3.7 Rule 220 leave/discretionary review (R.220.2, R.220.3)
- Appeal (orders & with leave) → 15d when leave granted; Discretionary review → 15d when leave refused. Both **missing.**
### 3.8 Rehearing (R.245.2.a/b)
- 2mo from final decision OR discovery of fundamental defect (whichever is later). Has its own "max of two trigger dates" semantics. **Missing**, and like R.198 needs a "max of multiple anchors" concept.
### 3.9 Cross-appeal (R.237, R.238)
- Cross-appeal 15d / 3mo (R.237), Reply to cross-appeal 15d / 2mo (R.238.1/2). **Missing.**
### 3.10 Other one-offs
- Rectification (1mo, R.353), Refer to central division (10d, R.321.3), Review of CMO (15d, R.333.2), Confidentiality (14d, R.262.2), Application for the review of leave-to-appeal-refused-on-cost-decision (R.221.1). **Missing.**
### 3.11 Aggregated count
Out of youpc's 64 distinct UPC RoP rule codes referenced by `data.deadline_rule_codes`, paliad's `paliad.deadline_rules.rule_code` references at most 5 (`RoP.023`, `RoP.029b`, `RoP.029c`, `RoP.050`, `RoP.220.1` — and even these have format drift, see §4.3). **That's a 92 % miss on UPC RoP coverage.**
### 3.12 Why so much was unported (likely)
Paliad's Fristenrechner was scoped as a **timeline visualisation** for the 4 most common UPC procedure types (Verletzung / Nichtigkeit / Einstweilige Maßnahme / Berufung) plus DE + EPA, **not** as a search-by-trigger-event tool. The youpc deadline calc is the latter — a reference for "a court just sent me X, what deadlines does this start?" That use case has never been part of paliad's product scope (the design doc `design-prozesskostenrechner-fristenrechner.md` doesn't mention it).
This is a product question, not a porting oversight. m needs to decide whether paliad should grow that second mode or keep the timeline-only shape and accept the corpus gap.
---
## 4. Divergences — rules in both systems with different logic/labels
### 4.1 RoP.029.b/c/d/e — Adaptive Reply/Rejoinder
- **youpc** models the with-CCR vs without-CCR variants as **separate trigger events**: "Statement of defence which includes a Counterclaim for Revocation" → Reply 029.a (2mo); "Statement of defence without a Counterclaim for Revocation" → Reply 029.b (2mo). The user picks the right trigger event; the data drives the rule code.
- **paliad** (KanzlAI port, internal `INF` type) uses `condition_rule_id` + `alt_rule_code`/`alt_duration_value` columns on a single rule row. The default is no-CCR (029.c, 1mo Rejoinder), `condition_rule_id=ccr_root` flips it to with-CCR (029.d, 2mo). Migration `009_seed_deadline_rules.up.sql:331341`.
- **public Fristenrechner type `UPC_INF`** uses **only the no-CCR path**`RoP.029b/c` hard-coded, no `condition_rule_id`. So paliad's public Fristenrechner is incorrect when a defendant filed a counterclaim for revocation: the rejoinder duration should be 2mo not 1mo, and the rule code should be RoP.029d not RoP.029c.
### 4.2 SoD duration anchor
- **youpc:** SoD is 3 months from the trigger event "Statement of Claim" (which is anchor day = filing day).
- **paliad:** SoD (`inf.sod`) is 3 months from `inf.soc`, with `inf.soc` itself being the trigger event (`duration=0`, `parent_id=NULL``IsRootEvent`). Same outcome, different shape.
### 4.3 Rule-code format inconsistency in paliad
```
RoP 23 ← UPC_INF (Fristenrechner, public)
RoP.023 ← INF (KanzlAI, internal)
RoP 29b ← UPC_INF
RoP.029b ← INF
RoP 29c ← UPC_INF
RoP.029c ← INF
RoP 220.1 ← UPC_APP
RoP.220.1 ← APP
```
Both halves of the codebase use different formatting for the same rule. youpc is uniform: `RoP.029.b` (period before letter). Paliad's two seeds disagree: `RoP 29b`, `RoP.029b`, never `RoP.029.b`.
If/when these surfaces ever merge (e.g. a deeplink from Fristenrechner result to a law-citation page), this drift will bite. Pick one canonical format (recommend youpc's `RoP.029.b`) and normalise.
### 4.4 EPA Beschwerdebegründung
- **paliad** UPC_APP has both `app.notice` (2mo, RoP 220.1) and `app.grounds` (2mo, RoP 220.1) — same rule code on both, both anchored 2mo from prior step.
- **youpc** has `Statement of Appeal` (R.224.1.a, 2mo from decision) and `Statement of grounds` (R.224.2.a, **4 months from decision**, not from notice). Paliad's chain "decision → 2mo notice → 2mo grounds" gives a final grounds date 4mo after decision by accident, but it models the dependency wrong: the official Rule is "grounds = 4 months **from decision**" — i.e., independent of when the notice was filed.
This is a **subtle but meaningful divergence**. If the appellant files the notice early (e.g. 1 month after decision), paliad would compute grounds at "1mo + 2mo = 3 months after decision" — incorrect; the real deadline is still 4 months after decision regardless.
The same pattern applies to the EPA Beschwerdeverfahren (`epa_app.beschwerde` + `epa_app.begr`): paliad chains them, youpc anchors both to the decision date. The note `'Ab Zustellung, nicht ab Beschwerdeeinlegung'` (migration `012_fristenrechner_rules.up.sql:211`) acknowledges this: **the data is right, the parent_id is wrong**. `epa_app.begr.parent_id = epa_app_entsch` would be correct, not `epa_app_entsch` indirectly via `epa_app.beschwerde`.
Wait — re-reading migration 012:206214 — `epa_app.begr` already has `parent_id = r_epa_app_entsch` (the decision row), not `r_epa_app.beschwerde`. So the EPA case is **right**. Verify: `epa_app.entsch → 2mo → epa_app.beschwerde` and **`epa_app.entsch → 4mo → epa_app.begr` (independent siblings).** OK. EPA is fine.
The UPC_APP case (`app.notice``app.grounds`) is **still wrong**`app.grounds.parent_id = r_app_notice` (line 153), so grounds compounds onto notice. Should be `app.grounds.parent_id = NULL` with anchor on the trigger date (the appealed decision), with duration = 4 months. Alternatively store both as siblings of an `app.decision_appealed` root. Today the displayed dates work out fine when the user enters the decision date as trigger and the notice is filed on day 60, but **break** if the user enters the notice-filing date or if the notice is filed on a non-canonical day.
### 4.5 EP_GRANT publish date
- paliad: 18 months from filing (`ep_grant.publish.parent_id = ep_grant.filing`, `ab Prioritätstag` in notes).
- youpc: not modelled in `data.deadlines`.
- Note inconsistency: paliad's `parent_id = ep_grant_filing` but the note says "Ab Prioritätstag". Filing date and priority date can differ. If the patent has a foreign priority claim, paliad will compute the publish date from the filing of the **EP** application, not the priority date — typically off by up to 12 months.
- This is the same parent-vs-anchor confusion as §4.4 UPC_APP.
---
## 5. Edge cases — youpc handles, paliad doesn't
### 5.1 Working days vs calendar days
youpc has notes on R.198 + R.213: *"Or 20 Working days, whichever is longer."* No code today implements `max(calendarDays, workingDays)`. Paliad's `DeadlineCalculator.CalculateEndDate` only takes `(value, unit)` where unit ∈ {days, weeks, months}. **Neither system actually computes the correct R.198/R.213 deadline.** If paliad ports these rules, it needs:
- A new unit `working_days`
- A `max_of_units` semantics, or two duration columns + a `combine` operator (`max` / `min`)
### 5.2 "Whichever is later" trigger events
youpc R.245.2.a/b: trigger event is *"Final decision (Service) **/** Discovery of the fundamental defect (whichever is later)"* — a single trigger event row that wraps two real-world dates. The user picks the later. youpc handles this by encoding it in the **event name** (the user reads the name, picks the later date themselves). Paliad doesn't have any "meta" trigger events like this, so the same rule would either need:
- A "compound trigger" event family, or
- Multiple separate triggers + a UI-level guidance note
### 5.3 Holiday handling — paliad WINS
youpc's `internal/services/holidays.go:4669` has an empty `defaultHolidayConfig()` with TODOs to populate. **No production holiday data is loaded**`IsUPCNonWorkingDay()` only catches Saturday/Sunday. So a deadline falling on Christmas Day in youpc is silently treated as a working day.
paliad's `internal/services/holidays.go` is materially better:
- DB-driven via `paliad.holidays` (55 rows in production, covering 2026 + 2027)
- Race-safe per-year cache via `sync.Map` of `*sync.Once`
- German federal holidays as embedded fallback (Easter via Anonymous Gregorian — same algorithm in both repos)
- Seeded UPC summer (27 Jul 28 Aug 2026) and winter vacation (24 Dec 2026 6 Jan 2027) per the official UPC Annual Report
If paliad ports the missing UPC rules, **the holiday system carries them**. youpc would need its holiday system filled in first.
### 5.4 Forward-only adjustment
Both systems push non-working deadlines **forward** to the next working day. Neither supports "previous working day" (which some legal systems use for "before" deadlines — e.g., translations 1 month *before* hearing should land on a working day at or before the target). For paliad's R.109 family port, this matters: if oral hearing is Mon, translation deadline is "1 month before" = Sun, → forward-adjustment would push to Mon (the hearing itself), which is wrong. Should push backward to Fri.
### 5.5 Soft "non-month" deadlines
youpc has `15d / 3mo` and `4mo / 15d` — wildly different durations on the same rule depending on which sub-rule (R.224.2.a vs .b) applies. paliad's tree shape can model this via two separate rules in different proceeding types, but if the same proceeding has both branches it'll need either conditional rules (`condition_rule_id`) or duplicate trees per branch.
### 5.6 Court-set deadlines (`pi.response`, `de_inf.replik`, etc.)
paliad already has `IsCourtSet` semantics: `duration=0` + non-NULL `parent_id` → UI shows "vom Gericht gesetzt" placeholder. youpc's data has the same gap (R.131.2 indication, etc.) and just stores them as separate trigger events with no calculation. **This is one area where paliad is slightly cleaner.**
### 5.7 Date arithmetic correctness
Both use Go `time.AddDate(0, n, 0)` for months — correct calendar math. Note however that youpc's `time_relationship_calculator.go:282` approximates months as 30 days (`time.Duration(value) * 30 * 24 * time.Hour`) for the **graph-based timeline calculator** path — **wrong** for legal months. This is a youpc bug, not a gap to port.
---
## 6. Amendment recommendations
Ranked by user value × implementation effort. **None of these should be implemented under this task — m needs to review §3 and §4 first.**
### Tier 1 — fix existing paliad bugs (no scope question)
1. **UPC_INF — wire the CCR-conditional adaptive rule** (§4.1).
- Public Fristenrechner today silently always uses 029.b/c (no-CCR variant). When defendant counterclaims for revocation, rejoinder is 2mo not 1mo and rule code is 029.d. Add `condition_rule_id` + `alt_*` to `inf.reply` and `inf.rejoin` rows in the public `UPC_INF` tree, mirroring the KanzlAI `INF` rows.
- Surface the toggle in the Fristenrechner UI: a checkbox "Mit Widerklage auf Nichtigkeit" between step 1 and step 2.
2. **UPC_APP grounds anchoring** (§4.4).
- Today: `app.grounds.parent_id = app.notice`, so grounds = (decision + 2mo notice + 2mo) instead of (decision + 4mo).
- Fix: change `app.grounds.parent_id` to NULL (sibling of notice) and `duration=4mo` from trigger date. Or add an explicit `app.decision_appealed` root and re-parent both.
- Same review needed for the matter-attached `APP` tree (`009_seed_deadline_rules.up.sql:269296`) — `app.grounds.parent_id = v_app_notice` there too.
3. **EP_GRANT publish — anchor on priority date, not filing date** (§4.5).
- Today: chained off `ep_grant.filing`. Note acknowledges "Ab Prioritätstag" but parent says otherwise.
- Fix: model priority date as a separate (court-event-style) input on the proceeding; or document that this rule assumes filing == priority.
4. **Normalise rule_code format** (§4.3).
- Migrate `RoP 23` / `RoP.029b` / `RoP 220.1` → uniform `RoP.023` / `RoP.029.b` / `RoP.220.1` (youpc style).
- One-time UPDATE; no schema change.
### Tier 2 — port a high-value subset of youpc deadlines
5. **Damages determination family** (R.137.2 / R.139, 3 rules) — common follow-on, no special arithmetic needed.
6. **Cost-decision appeals** (R.151, R.221.1) — frequently relevant after main proceedings end.
7. **Statement-of-Appeal "with leave" / discretionary review** (R.220.2, R.220.3) — closes a legitimate gap in the UPC_APP timeline.
8. **Cross-appeal family** (R.237, R.238.1/2, 4 rules) — straightforward calendar math, fills out the Berufung tree.
9. **Lay-open books / discovery** (R.142, 3 rules) — common in infringement cases where damages claim raised.
### Tier 3 — needs new arithmetic primitives
10. **R.198 / R.213 "Start of merits" — 31d OR 20 working days, whichever is longer.**
- Requires:
- New `duration_unit = 'working_days'` value (DeadlineService skips weekends + holidays via existing `HolidayService.IsNonWorkingDay`)
- Either a second `(alt_duration_value, alt_duration_unit, combine='max')` triple on the rule, or a Go-side composite rule type
- Decide whether to support this only for R.198/R.213 or generalise.
11. **R.245.2.a/b — Rehearing "whichever is later" trigger** (§5.2).
- Could ship as a "compound trigger" date input in the UI: two date pickers, take max.
- Alternatively, document the rule and accept manual user judgement.
### Tier 4 — separate product mode
12. **"Search by trigger event" mode for the public Fristenrechner.**
- This is the youpc deadline-calc UX. Inputs: trigger event (autocomplete from a list) + date. Output: all deadlines that flow from it.
- Requires either porting `data.events` + `data.deadlines` + `data.deadline_events` into the paliad schema, or an alternative data shape (e.g. flat list of rules tagged with trigger codes).
- This is the most fundamental gap and the most expensive — it's a second product, not a deeper rule set. m should explicitly decide whether paliad wants both modes.
13. **Procedural-defect "Correction of deficiencies" (6 rules, all 14d).**
- Hard to fit into the timeline model since the trigger ("Notification by the Registry to correct deficiencies") can fire from many different proceeding states with different rule codes. Naturally fits the trigger-event model (Tier 4), not the proceeding-tree model.
### Tier 5 — purely cosmetic
14. **Add law-citation links on rule codes** (paliad has no `deadline_rule_codes` / `deadline_laws` join). Low-value until paliad has a law-text database to link to. **Defer.**
---
## 7. Open questions for m
1. **Is the "search by trigger event" mode (Tier 4) in scope for paliad?**
- This is the single biggest gap. The youpc deadline calc is fundamentally event-driven; paliad's Fristenrechner is fundamentally proceeding-driven. They serve different jobs. If you want both, that's a sizeable second feature. If you only want timelines, the gap reduces to Tiers 13 (~10 fixable rules).
2. **The CCR adaptive bug (§4.1, recommendation 1) — do we want a UI toggle, or default-CCR-on?** A defendant facing a UPC infringement claim will almost always counterclaim for revocation. Defaulting `UPC_INF` to "with CCR" would silently fix 90 % of users without adding UI complexity. But it's a behaviour change and the result (rejoinder 2mo not 1mo) is subtle.
3. **Rule code format (§4.3) — accept normalisation to `RoP.029.b` style?** Cosmetic but disruptive if any downstream system parses the current strings.
4. **EP_GRANT priority date (recommendation 3)** — paliad doesn't model priority date as a project field today. Should we add a "priority date" input to the EP_GRANT Fristenrechner, or accept that it's an edge case for users with foreign priority claims and document the limitation?
5. **Working-days arithmetic (R.198/R.213, recommendation 10)** — only relevant for evidence-preservation cases. Real users? If never, skip Tier 3 entirely.
6. **The internal KanzlAI proceeding types (INF/REV/CCR/APM/APP/AMD/ZPO_CIVIL) — are they still wired into the matter-attached Fristen UX?** Recent task `t-paliad-080` did a service-layer naming sweep. If those types are still surfaced anywhere, fix recommendation 2 (UPC_APP grounds) needs to be applied to both the public `UPC_APP` rules and the internal `APP` rules.
7. **youpc's deadline calc itself has known gaps** (empty holiday config — §5.3) — should paliad's amendment work also feed back to youpc? Or is youpc intentionally decoupled? (My read: keep them decoupled; paliad serves HLC, youpc serves the public.)
---
## Appendix A — File references
**paliad — source of truth:**
- `internal/db/migrations/012_fristenrechner_rules.up.sql` (52 rules, 9 public types)
- `internal/db/migrations/009_seed_deadline_rules.up.sql` (44 rules, 7 internal types — ported from KanzlAI which itself came from youpc `data.proceeding_events`)
- `internal/db/migrations/010_seed_holidays.up.sql` (55 holiday rows)
- `internal/services/deadline_calculator.go` (date math)
- `internal/services/fristenrechner.go` (UI response shape)
- `internal/services/holidays.go` (DB-driven holidays + German federal fallback)
- `frontend/src/fristenrechner.tsx` (the 9-type wizard)
- `docs/design-prozesskostenrechner-fristenrechner.md` (intent — note: UPC_CCR was planned in §4.1 line 386 but never seeded)
**youpc — source of comparison:**
- `youpc-go/internal/services/deadline_service.go` (70-deadline calc service)
- `youpc-go/internal/services/holidays.go` (empty default config — known gap)
- `youpc-go/internal/services/time_relationship_calculator.go` (graph timeline calc — uses 30-day month approximation, **bug in youpc**)
- `youpc-go/internal/migrations/sql-migrations/039_create_proceeding_events.sql` (timeline tree schema)
- `youpc-go/internal/migrations/sql-migrations/040_adaptive_reply_deadline.sql` (CCR-conditional duration columns — origin of paliad's `condition_rule_id` pattern)
- `frontend/templates/mgmt/deadline-calculations.html` (UI shell — the actual logic is in handler/service, not template)
**Production data verified via Supabase:**
- youpc: 70 deadlines · 102 events · 140 deadline-event relations · 36 proceeding events · 6 proc types · 72 deadline-rule-code links · 0 deadline-law links
- paliad: 96 deadline_rules · 16 proc types (9 fristenrechner) · 55 holidays