Merge: t-paliad-348 — port engine semantics to TS calc + manuscript regen (m/paliad#153)
This commit is contained in:
280
exports/gen-deadline-list.py
Executable file
280
exports/gen-deadline-list.py
Executable file
@@ -0,0 +1,280 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Generate a markdown deadline-list export for UPC PA training (work/head delegation #2572).
|
||||||
|
|
||||||
|
Sorts by proceeding-type display_order then sequence_order. Sections by proceeding.
|
||||||
|
|
||||||
|
t-paliad-348 / yoUPC#178 update: matches the engine's `IncludeOptional=false`
|
||||||
|
default (`pkg/litigationplanner/engine.go`). Optional rules (priority='optional')
|
||||||
|
are SUPPRESSED by default so the manuscript shows the same "naked proceeding
|
||||||
|
backbone" the UI now renders. Pass `--include-optional` to opt back in for an
|
||||||
|
exhaustive catalog dump.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
uv run exports/gen-deadline-list.py [--include-optional] [-o OUT]
|
||||||
|
"""
|
||||||
|
# /// script
|
||||||
|
# requires-python = ">=3.10"
|
||||||
|
# dependencies = ["psycopg2-binary"]
|
||||||
|
# ///
|
||||||
|
import argparse
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from datetime import date
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import psycopg2
|
||||||
|
import psycopg2.extras
|
||||||
|
|
||||||
|
DSN = os.environ.get(
|
||||||
|
"PALIAD_DEADLINE_EXPORT_DSN",
|
||||||
|
"postgres://postgres:rpsak3yf4lu1izgefx9p9xweg3qroojw@100.99.98.201:11833/postgres?sslmode=disable",
|
||||||
|
)
|
||||||
|
|
||||||
|
# `priority` filter is wired at the SQL level (not post-filter in Python) so
|
||||||
|
# the row counter in the markdown header reflects what's actually in the
|
||||||
|
# manuscript — matching what the lawyer sees on /tools/procedures.
|
||||||
|
SQL_TEMPLATE = """
|
||||||
|
SELECT
|
||||||
|
pt.code AS pt_code,
|
||||||
|
pt.display_order,
|
||||||
|
COALESCE(pt.name_en, pt.name) AS pt_label_en,
|
||||||
|
pt.name AS pt_label_de,
|
||||||
|
COALESCE(pe.name_en, pe.name) AS event_en,
|
||||||
|
pe.name AS event_de,
|
||||||
|
sr.duration_value,
|
||||||
|
sr.duration_unit,
|
||||||
|
sr.timing,
|
||||||
|
sr.alt_duration_value,
|
||||||
|
sr.alt_duration_unit,
|
||||||
|
sr.combine_op,
|
||||||
|
sr.rule_code,
|
||||||
|
COALESCE(te.name, te.name_de) AS trigger_label,
|
||||||
|
te.code AS trigger_code,
|
||||||
|
sr.primary_party,
|
||||||
|
sr.is_court_set,
|
||||||
|
sr.is_spawn,
|
||||||
|
sr.priority,
|
||||||
|
sr.deadline_notes_en,
|
||||||
|
sr.deadline_notes,
|
||||||
|
sr.condition_expr,
|
||||||
|
sr.sequence_order
|
||||||
|
FROM paliad.sequencing_rules sr
|
||||||
|
JOIN paliad.procedural_events pe ON pe.id = sr.procedural_event_id
|
||||||
|
LEFT JOIN paliad.proceeding_types pt ON pt.id = sr.proceeding_type_id
|
||||||
|
LEFT JOIN paliad.trigger_events te ON te.id = sr.trigger_event_id
|
||||||
|
WHERE sr.lifecycle_state = 'published'
|
||||||
|
AND sr.is_active = true
|
||||||
|
AND pt.id IS NOT NULL
|
||||||
|
{priority_filter}
|
||||||
|
ORDER BY pt.display_order NULLS LAST, pt.code, sr.sequence_order NULLS LAST, sr.rule_code, pe.name;
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def format_frist(duration_value, duration_unit, timing, alt_value, alt_unit, combine_op):
|
||||||
|
"""Format the deadline duration cleanly."""
|
||||||
|
if duration_value is None or duration_unit is None:
|
||||||
|
return ""
|
||||||
|
unit_map = {
|
||||||
|
"days": "d",
|
||||||
|
"weeks": "w",
|
||||||
|
"months": "M",
|
||||||
|
"years": "y",
|
||||||
|
"calendar_days": "CD",
|
||||||
|
"working_days": "WD",
|
||||||
|
}
|
||||||
|
unit = unit_map.get(duration_unit, duration_unit)
|
||||||
|
main = f"{duration_value} {unit}"
|
||||||
|
if alt_value is not None and alt_unit is not None:
|
||||||
|
alt_unit_short = unit_map.get(alt_unit, alt_unit)
|
||||||
|
op = combine_op or "or"
|
||||||
|
main = f"{main} {op} {alt_value} {alt_unit_short}"
|
||||||
|
if timing == "before":
|
||||||
|
main = f"{main} before"
|
||||||
|
elif timing == "after":
|
||||||
|
main = f"{main} after"
|
||||||
|
return main
|
||||||
|
|
||||||
|
|
||||||
|
def format_party(primary_party, is_court_set):
|
||||||
|
if is_court_set:
|
||||||
|
return "court-set"
|
||||||
|
if primary_party == "claimant":
|
||||||
|
return "claimant"
|
||||||
|
if primary_party == "defendant":
|
||||||
|
return "defendant"
|
||||||
|
if primary_party == "both":
|
||||||
|
return "either"
|
||||||
|
if primary_party == "court":
|
||||||
|
return "court"
|
||||||
|
return primary_party or "—"
|
||||||
|
|
||||||
|
|
||||||
|
def detect_r94(notes_en, notes_de):
|
||||||
|
"""Flag R.9.4 non-extendable from notes text (heuristic — no DB field)."""
|
||||||
|
blobs = " ".join(filter(None, [notes_en or "", notes_de or ""])).lower()
|
||||||
|
if "r.9.4" in blobs or "r 9.4" in blobs or "r9.4" in blobs:
|
||||||
|
return "✗"
|
||||||
|
if "non-extendable" in blobs or "nicht verlängerbar" in blobs or "nicht verlaengerbar" in blobs:
|
||||||
|
return "✗"
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
def conditional_marker(condition_expr):
|
||||||
|
if condition_expr in (None, "", {}):
|
||||||
|
return ""
|
||||||
|
# condition_expr is JSONB → returns dict
|
||||||
|
if isinstance(condition_expr, dict):
|
||||||
|
if "flag" in condition_expr:
|
||||||
|
return f"if `{condition_expr['flag']}`"
|
||||||
|
if condition_expr.get("op") == "and" and "args" in condition_expr:
|
||||||
|
flags = [a.get("flag", "?") for a in condition_expr["args"]]
|
||||||
|
return "if " + " & ".join(f"`{f}`" for f in flags)
|
||||||
|
if condition_expr.get("op") == "or" and "args" in condition_expr:
|
||||||
|
flags = [a.get("flag", "?") for a in condition_expr["args"]]
|
||||||
|
return "if " + " | ".join(f"`{f}`" for f in flags)
|
||||||
|
return "cond"
|
||||||
|
|
||||||
|
|
||||||
|
def md_escape(s):
|
||||||
|
if s is None:
|
||||||
|
return ""
|
||||||
|
return str(s).replace("|", "\\|").replace("\n", " ")
|
||||||
|
|
||||||
|
|
||||||
|
def render(rows, *, include_optional: bool, generated_for: str) -> str:
|
||||||
|
by_pt = {}
|
||||||
|
for r in rows:
|
||||||
|
key = (r["display_order"] or 9999, r["pt_code"], r["pt_label_de"], r["pt_label_en"])
|
||||||
|
by_pt.setdefault(key, []).append(r)
|
||||||
|
|
||||||
|
out = []
|
||||||
|
today = date.today().isoformat()
|
||||||
|
out.append(f"# UPC + DE/EP Deadline Catalog — Stand {today}")
|
||||||
|
out.append("")
|
||||||
|
out.append(f"Source: `paliad.sequencing_rules` (lifecycle_state=published, is_active=true).")
|
||||||
|
out.append(f"Generated for {generated_for}. {len(rows)} rules across {len(by_pt)} proceedings.")
|
||||||
|
if include_optional:
|
||||||
|
out.append("")
|
||||||
|
out.append(
|
||||||
|
"**Mode:** `--include-optional` — every published rule, including "
|
||||||
|
"`priority='optional'` rules suppressed by the engine's default "
|
||||||
|
"(`IncludeOptional=false`). This is the exhaustive catalog dump."
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
out.append("")
|
||||||
|
out.append(
|
||||||
|
"**Mode:** default — matches the engine's `IncludeOptional=false` "
|
||||||
|
"behaviour (pkg/litigationplanner/engine.go). `priority='optional'` "
|
||||||
|
"rules are suppressed; the manuscript shows only the mandatory "
|
||||||
|
"backbone the lawyer sees by default on /tools/procedures. "
|
||||||
|
"Re-run with `--include-optional` for the full catalog. "
|
||||||
|
"(t-paliad-348 / yoUPC#178)"
|
||||||
|
)
|
||||||
|
out.append("")
|
||||||
|
out.append("**Spalten:**")
|
||||||
|
out.append("- **Phase/Event** = procedural event (German primary)")
|
||||||
|
out.append("- **Frist** = duration + timing (`d` days, `w` weeks, `M` months, `CD` calendar days, `WD` working days; `before` = relative to anchor)")
|
||||||
|
out.append("- **Rule** = legal source (RoP / § ZPO / § PatG / Art. EPÜ)")
|
||||||
|
out.append("- **Anchor** = trigger event the deadline runs from")
|
||||||
|
out.append("- **Seite** = filing party (claimant / defendant / either / court-set)")
|
||||||
|
out.append("- **Priorität** = mandatory / recommended / optional / informational (only when `--include-optional`)")
|
||||||
|
out.append("- **R.9.4** = ✗ marked non-extendable in notes (heuristic — confirm against rule text)")
|
||||||
|
out.append("- **Bedingung** = scenario flag(s) that must be set for the rule to fire (blank = always)")
|
||||||
|
out.append("")
|
||||||
|
out.append("---")
|
||||||
|
out.append("")
|
||||||
|
|
||||||
|
for (order, pt_code, pt_de, pt_en) in sorted(by_pt.keys()):
|
||||||
|
prules = by_pt[(order, pt_code, pt_de, pt_en)]
|
||||||
|
out.append(f"## {pt_de} · `{pt_code}`")
|
||||||
|
out.append("")
|
||||||
|
if pt_en and pt_en != pt_de:
|
||||||
|
out.append(f"*{pt_en}*")
|
||||||
|
out.append("")
|
||||||
|
if include_optional:
|
||||||
|
out.append("| # | Phase / Event | Frist | Rule | Anchor | Seite | Priorität | R.9.4 | Bedingung |")
|
||||||
|
out.append("|---:|---|---|---|---|---|---|:---:|---|")
|
||||||
|
else:
|
||||||
|
out.append("| # | Phase / Event | Frist | Rule | Anchor | Seite | R.9.4 | Bedingung |")
|
||||||
|
out.append("|---:|---|---|---|---|---|:---:|---|")
|
||||||
|
for i, r in enumerate(prules, 1):
|
||||||
|
event = md_escape(r["event_de"] or r["event_en"] or "")
|
||||||
|
frist = md_escape(
|
||||||
|
format_frist(
|
||||||
|
r["duration_value"], r["duration_unit"], r["timing"],
|
||||||
|
r["alt_duration_value"], r["alt_duration_unit"], r["combine_op"],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
rule = md_escape(r["rule_code"] or "")
|
||||||
|
anchor = md_escape(r["trigger_label"] or "")
|
||||||
|
party = format_party(r["primary_party"], r["is_court_set"])
|
||||||
|
r94 = detect_r94(r["deadline_notes_en"], r["deadline_notes"])
|
||||||
|
cond = md_escape(conditional_marker(r["condition_expr"]))
|
||||||
|
spawn_marker = " ⤴" if r["is_spawn"] else ""
|
||||||
|
if include_optional:
|
||||||
|
priority = md_escape(r["priority"] or "")
|
||||||
|
out.append(
|
||||||
|
f"| {i} | {event}{spawn_marker} | {frist} | {rule} | {anchor} | {party} | {priority} | {r94} | {cond} |"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
out.append(
|
||||||
|
f"| {i} | {event}{spawn_marker} | {frist} | {rule} | {anchor} | {party} | {r94} | {cond} |"
|
||||||
|
)
|
||||||
|
out.append("")
|
||||||
|
|
||||||
|
out.append("---")
|
||||||
|
out.append("")
|
||||||
|
out.append("**Lesehilfe:**")
|
||||||
|
out.append("- ⤴ Spawn-Marker: event opens a sub-proceeding (e.g. CCR forks revocation track)")
|
||||||
|
out.append("- `with_ccr` = Widerklage auf Nichtigkeit gefilt | `with_amend` = Patentänderungsantrag | `with_cci` = Widerklage auf Verletzung (in rev.cfi)")
|
||||||
|
out.append("- Catalog ist work-in-progress: 7 compound-name rules + Patentänderung-Duplikation noch in m's split-review backlog (m/paliad#149).")
|
||||||
|
return "\n".join(out)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description=__doc__)
|
||||||
|
parser.add_argument(
|
||||||
|
"--include-optional",
|
||||||
|
action="store_true",
|
||||||
|
help="Include priority='optional' rules. Default false matches the engine's IncludeOptional=false default.",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-o",
|
||||||
|
"--out",
|
||||||
|
default="exports/upc-deadlines-2026-05-28.md",
|
||||||
|
help="Output path (relative to repo root).",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--generated-for",
|
||||||
|
default="PA-Schulung 2026-05-28",
|
||||||
|
help="Free-text label rendered in the markdown header.",
|
||||||
|
)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
priority_filter = "" if args.include_optional else "AND sr.priority != 'optional'"
|
||||||
|
sql = SQL_TEMPLATE.format(priority_filter=priority_filter)
|
||||||
|
|
||||||
|
conn = psycopg2.connect(DSN)
|
||||||
|
try:
|
||||||
|
cur = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
|
||||||
|
cur.execute(sql)
|
||||||
|
rows = cur.fetchall()
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
md = render(rows, include_optional=args.include_optional, generated_for=args.generated_for)
|
||||||
|
# Resolve out path relative to the repo root (= the script's grandparent).
|
||||||
|
out_path = Path(args.out)
|
||||||
|
if not out_path.is_absolute():
|
||||||
|
out_path = Path(__file__).resolve().parent.parent / out_path
|
||||||
|
out_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
out_path.write_text(md)
|
||||||
|
n_pt = len({(r["display_order"] or 9999, r["pt_code"]) for r in rows})
|
||||||
|
print(
|
||||||
|
f"WROTE {out_path} ({len(rows)} rules, {n_pt} proceedings, "
|
||||||
|
f"include_optional={args.include_optional})"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
BIN
exports/screenshots/paliad-348-after-upc-inf-cfi.png
Normal file
BIN
exports/screenshots/paliad-348-after-upc-inf-cfi.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 156 KiB |
BIN
exports/screenshots/paliad-348-before-upc-inf-cfi.png
Normal file
BIN
exports/screenshots/paliad-348-before-upc-inf-cfi.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 490 KiB |
378
exports/upc-deadlines-2026-05-28.md
Normal file
378
exports/upc-deadlines-2026-05-28.md
Normal file
@@ -0,0 +1,378 @@
|
|||||||
|
# UPC + DE/EP Deadline Catalog — Stand 2026-05-28
|
||||||
|
|
||||||
|
Source: `paliad.sequencing_rules` (lifecycle_state=published, is_active=true).
|
||||||
|
Generated for PA-Schulung 2026-05-28. 178 rules across 25 proceedings.
|
||||||
|
|
||||||
|
**Mode:** default — matches the engine's `IncludeOptional=false` behaviour (pkg/litigationplanner/engine.go). `priority='optional'` rules are suppressed; the manuscript shows only the mandatory backbone the lawyer sees by default on /tools/procedures. Re-run with `--include-optional` for the full catalog. (t-paliad-348 / yoUPC#178)
|
||||||
|
|
||||||
|
**Spalten:**
|
||||||
|
- **Phase/Event** = procedural event (German primary)
|
||||||
|
- **Frist** = duration + timing (`d` days, `w` weeks, `M` months, `CD` calendar days, `WD` working days; `before` = relative to anchor)
|
||||||
|
- **Rule** = legal source (RoP / § ZPO / § PatG / Art. EPÜ)
|
||||||
|
- **Anchor** = trigger event the deadline runs from
|
||||||
|
- **Seite** = filing party (claimant / defendant / either / court-set)
|
||||||
|
- **Priorität** = mandatory / recommended / optional / informational (only when `--include-optional`)
|
||||||
|
- **R.9.4** = ✗ marked non-extendable in notes (heuristic — confirm against rule text)
|
||||||
|
- **Bedingung** = scenario flag(s) that must be set for the rule to fire (blank = always)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Verletzungsverfahren · `upc.inf.cfi`
|
||||||
|
|
||||||
|
*Infringement Action*
|
||||||
|
|
||||||
|
| # | Phase / Event | Frist | Rule | Anchor | Seite | R.9.4 | Bedingung |
|
||||||
|
|---:|---|---|---|---|---|:---:|---|
|
||||||
|
| 1 | Klageerhebung | 0 M after | RoP.013.1 | | claimant | | |
|
||||||
|
| 2 | Klageerwiderung | 3 M after | RoP.023 | | defendant | | |
|
||||||
|
| 3 | Replik | 2 M or 2 M after | RoP.029.b | | claimant | | if `with_ccr` |
|
||||||
|
| 4 | Duplik | 1 M or 2 M after | RoP.029.c | | defendant | | if `with_ccr` |
|
||||||
|
| 5 | Erwiderung auf Nichtigkeitswiderklage | 2 M after | RoP.029.a | | claimant | | if `with_ccr` |
|
||||||
|
| 6 | Replik auf Erwiderung zur Nichtigkeitswiderklage | 2 M after | RoP.029.d | | defendant | | if `with_ccr` |
|
||||||
|
| 7 | Duplik auf Replik zur Erwiderung Nichtigkeitswiderklage | 1 M after | RoP.029.e | | claimant | | if `with_ccr` |
|
||||||
|
| 8 | Antrag auf Patentänderung | 2 M after | RoP.030.1 | | claimant | | if `with_ccr` & `with_amend` |
|
||||||
|
| 9 | Erwiderung auf Patentänderungsantrag | 2 M after | RoP.032.1 | | defendant | | if `with_ccr` & `with_amend` |
|
||||||
|
| 10 | Replik auf Erwiderung zum Patentänderungsantrag | 1 M after | RoP.032.3 | | claimant | | if `with_ccr` & `with_amend` |
|
||||||
|
| 11 | Duplik auf Replik zum Patentänderungsantrag | 1 M after | RoP.032.3 | | defendant | | if `with_ccr` & `with_amend` |
|
||||||
|
| 12 | Zwischenanhörung | 0 M after | RoP.105 | | court-set | | |
|
||||||
|
| 13 | Mitteilung Dolmetscherkosten | 2 w before | RoP.109.4 | Oral hearing | court | | |
|
||||||
|
| 14 | Übersetzungen einreichen | 2 w after | RoP.109.5 | | either | | |
|
||||||
|
| 15 | Mündliche Verhandlung | 0 M after | RoP.112 | | court-set | | |
|
||||||
|
| 16 | Entscheidung | 0 M after | RoP.118.1 | | court-set | | |
|
||||||
|
| 17 | Duplik zur Replik auf die Erwiderung zum Patentänderungsantrag | 1 M after | RoP.032.3 | Reply to the Defence to an Application to amend the patent | defendant | | if `with_ccr` & `with_amend` |
|
||||||
|
| 18 | Einreichung von Übersetzungen von Schriftstücken | 1 M after | RoP.007.4 | Order of the judge-rapporteur to lodge translations | either | | |
|
||||||
|
| 19 | Antrag auf Simultanübersetzung | 1 M before | RoP.109.5 | Oral hearing | either | | |
|
||||||
|
| 20 | Antrag auf Folgemaßnahmen aus einer rechtskräftigen Validitätsentscheidung | 2 M after | RoP.118.4 | Final decision of the central division, Court of Appeal or EPO on the validity of the patent | either | | if `with_ccr` |
|
||||||
|
| 21 | Antrag auf Überprüfung einer verfahrensleitenden Anordnung | 15 d after | RoP.333 | Case management order (Service) | either | | |
|
||||||
|
| 22 | Mängelbeseitigung / Einreichung schriftlicher Stellungnahme | 14 d after | RoP.019 | Preliminary Objection | either | | |
|
||||||
|
| 23 | Mängelbeseitigung / Zahlung | 14 d after | RoP.016 | Notification by the Registry to correct deficiencies | either | | |
|
||||||
|
| 24 | Antrag auf Verweisung an die Zentralkammer | 10 d after | RoP.323 | Information by the Court not to approve Application to use the patent's language as language of the proceedings | either | | |
|
||||||
|
| 25 | Mitteilung über Beauftragung eines Dolmetschers auf Kosten der Partei | 2 w before | RoP.109.5 | Oral hearing | either | | |
|
||||||
|
| 26 | Klärung von Übersetzungsfragen | 2 w after | RoP.109 | Summons to Oral Hearing | court | | |
|
||||||
|
| 27 | Antrag auf Vertraulichkeit gegenüber der Öffentlichkeit | 14 d after | RoP.262.2 | Opponent Submission | either | | |
|
||||||
|
| 28 | Wiedereinsetzungsantrag (UPC R.320) | 2 M after | RoP.320 | Removal of obstacle (UPC R.320) | either | | |
|
||||||
|
|
||||||
|
## Verletzungsverfahren (LG) · `de.inf.lg`
|
||||||
|
|
||||||
|
*Infringement (Regional Court)*
|
||||||
|
|
||||||
|
| # | Phase / Event | Frist | Rule | Anchor | Seite | R.9.4 | Bedingung |
|
||||||
|
|---:|---|---|---|---|---|:---:|---|
|
||||||
|
| 1 | Klageerhebung | 0 M after | § 253 ZPO | | claimant | | |
|
||||||
|
| 2 | Anzeige der Verteidigungsbereitschaft | 2 w after | § 276 ZPO | | defendant | | |
|
||||||
|
| 3 | Klageerwiderung | 6 w after | § 276 ZPO | | court-set | | |
|
||||||
|
| 4 | Replik | 4 w after | § 282 ZPO | | court-set | | |
|
||||||
|
| 5 | Duplik | 4 w after | § 282 ZPO | | court-set | | |
|
||||||
|
| 6 | Haupttermin | 0 M after | § 279 ZPO | | court-set | | |
|
||||||
|
| 7 | Urteil | 0 M after | § 300 ZPO | | court-set | | |
|
||||||
|
| 8 | Berufungsfrist | 1 M after | § 517 ZPO | | either | | |
|
||||||
|
| 9 | Berufungsbegründung | 2 M after | § 520 ZPO | | either | | |
|
||||||
|
| 10 | Wiedereinsetzungsantrag (§ 233 ZPO) | 2 w after | § 233 ZPO | Removal of obstacle (ZPO §233) | — | | |
|
||||||
|
| 11 | Einspruch gegen Versäumnisurteil (§ 339 ZPO) | 2 w after | § 339 ZPO | Service of default judgment | — | | |
|
||||||
|
| 12 | Schriftsatznachreichung (§ 296a ZPO) | 3 w after | § 296a ZPO | End of oral hearing | — | | |
|
||||||
|
|
||||||
|
## Nichtigkeitsverfahren · `upc.rev.cfi`
|
||||||
|
|
||||||
|
*Revocation Action*
|
||||||
|
|
||||||
|
| # | Phase / Event | Frist | Rule | Anchor | Seite | R.9.4 | Bedingung |
|
||||||
|
|---:|---|---|---|---|---|:---:|---|
|
||||||
|
| 1 | Nichtigkeitsklage | 0 M after | RoP.044 | | claimant | | |
|
||||||
|
| 2 | Klageerwiderung | 2 M after | RoP.049.1 | | defendant | | |
|
||||||
|
| 3 | Antrag auf Patentänderung | 0 M after | RoP.049.2.a | | defendant | | if `with_amend` |
|
||||||
|
| 4 | Verletzungswiderklage | 0 M after | RoP.049.2.b | | defendant | | if `with_cci` |
|
||||||
|
| 5 | Replik | 2 M after | RoP.051 | | claimant | | |
|
||||||
|
| 6 | Erwiderung auf Patentänderungsantrag | 2 M after | RoP.043.3 | | claimant | | if `with_amend` |
|
||||||
|
| 7 | Erwiderung auf Verletzungswiderklage | 2 M after | RoP.056.1 | | claimant | | if `with_cci` |
|
||||||
|
| 8 | Duplik | 1 M after | RoP.052 | | defendant | | |
|
||||||
|
| 9 | Replik auf Erwiderung zum Patentänderungsantrag | 1 M after | RoP.032.3 | | defendant | | if `with_amend` |
|
||||||
|
| 10 | Replik auf Erwiderung zur Verletzungswiderklage | 1 M after | RoP.056.3 | | defendant | | if `with_cci` |
|
||||||
|
| 11 | Duplik auf Replik zum Patentänderungsantrag | 1 M after | RoP.032.3 | | claimant | | if `with_amend` |
|
||||||
|
| 12 | Duplik auf Replik zur Erwiderung Verletzungswiderklage | 1 M after | RoP.056.4 | | claimant | | if `with_cci` |
|
||||||
|
| 13 | Zwischenanhörung | 0 M after | RoP.105 | | court-set | | |
|
||||||
|
| 14 | Mündliche Verhandlung | 0 M after | RoP.112 | | court-set | | |
|
||||||
|
| 15 | Entscheidung | 0 M after | RoP.118.3 | | court-set | | |
|
||||||
|
| 16 | Duplik zur Replik auf die Erwiderung zur Nichtigkeitsklage | 1 M after | RoP.052 | Reply to the Defence to revocation | — | | |
|
||||||
|
| 17 | Verletzungswiderklage | 2 M after | RoP.053 | Statement for Revocation | — | | |
|
||||||
|
| 18 | Antrag auf Patentänderung | 2 M after | RoP.050 | Statement for Revocation | — | | |
|
||||||
|
|
||||||
|
## Nichtigkeitsverfahren (BPatG) · `de.null.bpatg`
|
||||||
|
|
||||||
|
*Nullity (Federal Patent Court)*
|
||||||
|
|
||||||
|
| # | Phase / Event | Frist | Rule | Anchor | Seite | R.9.4 | Bedingung |
|
||||||
|
|---:|---|---|---|---|---|:---:|---|
|
||||||
|
| 1 | Nichtigkeitsklage | 0 M after | § 81 PatG | | claimant | | |
|
||||||
|
| 2 | Klageerwiderung | 2 M after | § 82 Abs. 3 PatG | | defendant | | |
|
||||||
|
| 3 | Replik | 2 M after | § 83 PatG | | claimant | | |
|
||||||
|
| 4 | Hinweisbeschluss | 0 M after | § 83 PatG | | court-set | | |
|
||||||
|
| 5 | Stellungnahme zum Hinweisbeschluss | 0 M after | § 83 PatG | | either | | |
|
||||||
|
| 6 | Duplik | 1 M after | § 83 PatG | | defendant | | |
|
||||||
|
| 7 | Mündliche Verhandlung | 0 M after | § 80 PatG | | court-set | | |
|
||||||
|
| 8 | Urteil | 0 M after | § 84 PatG | | court-set | | |
|
||||||
|
| 9 | Berufungsfrist | 1 M after | § 110 PatG | | either | | |
|
||||||
|
| 10 | Berufungsbegründung | 3 M after | § 111 PatG | | either | | |
|
||||||
|
| 11 | Wiedereinsetzungsantrag (§ 123 PatG) | 2 M after | § 123 PatG | Removal of obstacle (PatG §123) | — | | |
|
||||||
|
|
||||||
|
## Einspruchsverfahren · `epa.opp.opd`
|
||||||
|
|
||||||
|
*Opposition Proceedings*
|
||||||
|
|
||||||
|
| # | Phase / Event | Frist | Rule | Anchor | Seite | R.9.4 | Bedingung |
|
||||||
|
|---:|---|---|---|---|---|:---:|---|
|
||||||
|
| 1 | Veröffentlichung der Erteilung | 0 M after | Art. 97 EPÜ | | either | | |
|
||||||
|
| 2 | Einspruchsfrist | 9 M after | Art. 99 EPÜ | | either | | |
|
||||||
|
| 3 | Erwiderung des Patentinhabers | 4 M after | R. 79(1) EPÜ | | court-set | | |
|
||||||
|
| 4 | Entscheidung | 0 M after | Art. 102 EPÜ | | court-set | | |
|
||||||
|
| 5 | Beschwerdefrist | 2 M after | Art. 108 EPÜ | | either | | |
|
||||||
|
| 6 | Beschwerdebegründung | 4 M after | Art. 108 EPÜ | | either | | |
|
||||||
|
| 7 | Stellungnahme weiterer Beteiligter | 0 M after | R. 79 EPÜ | | either | | |
|
||||||
|
| 8 | Eingaben vor mündl. Verhandlung | 0 M after | R. 116 EPÜ | | either | | |
|
||||||
|
| 9 | Wiedereinsetzungsantrag (Art. 122 EPÜ) | 2 M after | Art. 122 EPÜ | Removal of obstacle (EPC Art.122) | — | | |
|
||||||
|
|
||||||
|
## Beschwerdeverfahren · `epa.opp.boa`
|
||||||
|
|
||||||
|
*Appeal Proceedings*
|
||||||
|
|
||||||
|
| # | Phase / Event | Frist | Rule | Anchor | Seite | R.9.4 | Bedingung |
|
||||||
|
|---:|---|---|---|---|---|:---:|---|
|
||||||
|
| 1 | Zustellung der Beschwerdeentscheidung | 0 M after | R. 124 EPÜ | | either | | |
|
||||||
|
| 2 | Beschwerdeeinlegung | 2 M after | Art. 108 EPÜ | | either | | |
|
||||||
|
| 3 | Beschwerdebegründung | 4 M after | Art. 108 EPÜ | | either | | |
|
||||||
|
| 4 | Beschwerdeerwiderung | 4 M after | RPBA Art. 12 | | either | | |
|
||||||
|
| 5 | Mündliche Verhandlung | 0 M after | Art. 116 EPÜ | | court-set | | |
|
||||||
|
| 6 | Entscheidung | 0 M after | Art. 111 EPÜ | | court-set | | |
|
||||||
|
| 7 | Eingaben vor mündl. Verhandlung | 0 M after | R. 116 EPÜ | | either | | |
|
||||||
|
| 8 | Antrag auf Überprüfung | 2 M after | Art. 112a EPÜ | | either | | |
|
||||||
|
|
||||||
|
## Einspruchsverfahren DPMA · `dpma.opp.dpma`
|
||||||
|
|
||||||
|
*Opposition DPMA*
|
||||||
|
|
||||||
|
| # | Phase / Event | Frist | Rule | Anchor | Seite | R.9.4 | Bedingung |
|
||||||
|
|---:|---|---|---|---|---|:---:|---|
|
||||||
|
| 1 | Veröffentlichung der Erteilung | 0 M after | § 58 PatG | | either | | |
|
||||||
|
| 2 | Einspruchsfrist | 9 M after | § 59 PatG | | either | | |
|
||||||
|
| 3 | Erwiderung des Patentinhabers | 4 M after | § 59(2) PatG | | court-set | | |
|
||||||
|
| 4 | DPMA-Entscheidung | 0 M after | § 61 PatG | | court-set | | |
|
||||||
|
| 5 | Wiedereinsetzungsantrag (DPMA) | 2 M after | § 123 PatG | Removal of obstacle (DPMA, PatG §123) | — | | |
|
||||||
|
|
||||||
|
## Berufungsverfahren · `upc.apl.merits`
|
||||||
|
|
||||||
|
*Appeal*
|
||||||
|
|
||||||
|
| # | Phase / Event | Frist | Rule | Anchor | Seite | R.9.4 | Bedingung |
|
||||||
|
|---:|---|---|---|---|---|:---:|---|
|
||||||
|
| 1 | Berufungseinlegung | 2 M after | RoP.224.1.a | | either | | |
|
||||||
|
| 2 | Berufungsbegründung | 4 M after | RoP.224.2.a | | either | | |
|
||||||
|
| 3 | Berufungserwiderung | 3 M after | RoP.235.1 | | either | | |
|
||||||
|
| 4 | Mündliche Verhandlung | 0 M after | RoP.240 | | court-set | | |
|
||||||
|
| 5 | Entscheidung | 0 M after | RoP.235.4 | | court-set | | |
|
||||||
|
| 6 | Anschlussberufung | 3 M after | RoP.237 | | either | | |
|
||||||
|
| 7 | Erwiderung Anschlussberufung | 2 M after | RoP.238.1 | | either | | |
|
||||||
|
| 8 | Berufungsschrift gegen eine in Regel 220.1(a) und (b) genannte Entscheidung | 2 M after | RoP.224.1(a) | Decision referred to in Rule 220.1(a) and (b) | — | | |
|
||||||
|
| 9 | Berufungsbegründung gegen eine in Regel 220.1(a) und (b) genannte Entscheidung | 4 M after | RoP.224.1(a) | Decision referred to in Rule 220.1(a) and (b) | — | | |
|
||||||
|
| 10 | Anfechtung einer Entscheidung über die Verwerfung der Berufung als unzulässig | 1 M after | RoP.245 | Decision to reject an appeal as inadmissible | — | | |
|
||||||
|
| 11 | Antrag auf Wiederaufnahme (schwerwiegender Verfahrensmangel) | 2 M after | RoP.247.2 | Final decision (Service) / Discovery of the fundamental defect (whichever is later) | — | | |
|
||||||
|
| 12 | Antrag auf Wiederaufnahme (Straftat) | 2 M after | RoP.247.1 | Final decision (Service) / Court decision on criminal offence (whichever is later) | — | | |
|
||||||
|
|
||||||
|
## Berufungsverfahren OLG (Verletzung) · `de.inf.olg`
|
||||||
|
|
||||||
|
*Appeal OLG (Infringement)*
|
||||||
|
|
||||||
|
| # | Phase / Event | Frist | Rule | Anchor | Seite | R.9.4 | Bedingung |
|
||||||
|
|---:|---|---|---|---|---|:---:|---|
|
||||||
|
| 1 | Zustellung LG-Urteil | 0 M after | § 540 ZPO | | either | | |
|
||||||
|
| 2 | Berufungsschrift | 1 M after | § 517 ZPO | | either | | |
|
||||||
|
| 3 | Berufungsbegründung | 2 M after | § 520 ZPO | | either | | |
|
||||||
|
| 4 | Berufungserwiderung | 1 M after | § 521 ZPO | | either | | |
|
||||||
|
| 5 | Anschlussberufung | 0 M after | § 524 ZPO | | either | | |
|
||||||
|
| 6 | Mündliche Verhandlung | 0 M after | § 540 ZPO | | court-set | | |
|
||||||
|
| 7 | OLG-Urteil | 0 M after | § 540 ZPO | | court-set | | |
|
||||||
|
|
||||||
|
## Revisions-/NZB-Verfahren BGH (Verletzung) · `de.inf.bgh`
|
||||||
|
|
||||||
|
*Revision / Non-admission Appeal BGH (Infringement)*
|
||||||
|
|
||||||
|
| # | Phase / Event | Frist | Rule | Anchor | Seite | R.9.4 | Bedingung |
|
||||||
|
|---:|---|---|---|---|---|:---:|---|
|
||||||
|
| 1 | Zustellung OLG-Urteil | 0 M after | § 555 ZPO | | either | | |
|
||||||
|
| 2 | Nichtzulassungsbeschwerde | 1 M after | § 544 ZPO | | either | | |
|
||||||
|
| 3 | Nichtzulassungsbeschwerde-Begründung | 2 M after | § 544 ZPO | | either | | |
|
||||||
|
| 4 | Revisionsfrist | 1 M after | § 548 ZPO | | either | | |
|
||||||
|
| 5 | Revisionsbegründung | 2 M after | § 551 ZPO | | either | | |
|
||||||
|
| 6 | Revisionserwiderung | 1 M after | § 554 ZPO | | either | | |
|
||||||
|
| 7 | Mündliche Verhandlung BGH | 0 M after | § 555 ZPO | | court-set | | |
|
||||||
|
| 8 | BGH-Urteil | 0 M after | § 555 ZPO | | court-set | | |
|
||||||
|
|
||||||
|
## Berufungsverfahren BGH (Nichtigkeit) · `de.null.bgh`
|
||||||
|
|
||||||
|
*Appeal BGH (Nullity)*
|
||||||
|
|
||||||
|
| # | Phase / Event | Frist | Rule | Anchor | Seite | R.9.4 | Bedingung |
|
||||||
|
|---:|---|---|---|---|---|:---:|---|
|
||||||
|
| 1 | Zustellung BPatG-Urteil | 0 M after | § 110 PatG | | either | | |
|
||||||
|
| 2 | Berufungsschrift | 1 M after | § 110 PatG | | either | | |
|
||||||
|
| 3 | Berufungsbegründung | 3 M after | § 520 Abs. 2 ZPO i.V.m. § 117 PatG | | either | | |
|
||||||
|
| 4 | Berufungserwiderung | 2 M after | § 521 Abs. 2 ZPO i.V.m. § 117 PatG | | court-set | | |
|
||||||
|
| 5 | Mündliche Verhandlung BGH | 0 M after | § 121 PatG | | court-set | | |
|
||||||
|
| 6 | BGH-Urteil | 0 M after | § 122 PatG | | court-set | | |
|
||||||
|
|
||||||
|
## EP-Erteilungsverfahren · `epa.grant.exa`
|
||||||
|
|
||||||
|
*EP Grant Procedure*
|
||||||
|
|
||||||
|
| # | Phase / Event | Frist | Rule | Anchor | Seite | R.9.4 | Bedingung |
|
||||||
|
|---:|---|---|---|---|---|:---:|---|
|
||||||
|
| 1 | Anmeldung | 0 M after | Art. 75 EPÜ | | claimant | | |
|
||||||
|
| 2 | Recherchenbericht | 6 M after | Art. 92 EPÜ | | court-set | | |
|
||||||
|
| 3 | Veröffentlichung (A1) | 18 M after | Art. 93 EPÜ | | court-set | | |
|
||||||
|
| 4 | Prüfungsantrag | 6 M after | R. 70(1) EPÜ | | claimant | | |
|
||||||
|
| 5 | Mitteilung nach R. 71(3) | 0 M after | R. 71(3) EPÜ | | court-set | | |
|
||||||
|
| 6 | Zustimmung + Übersetzung | 4 M after | R. 71(3) EPÜ | | claimant | | |
|
||||||
|
| 7 | Erteilung (B1) | 0 M after | Art. 97 EPÜ | | court-set | | |
|
||||||
|
|
||||||
|
## Beschwerdeverfahren BPatG (DPMA) · `dpma.appeal.bpatg`
|
||||||
|
|
||||||
|
*Appeal BPatG (against DPMA Decision)*
|
||||||
|
|
||||||
|
| # | Phase / Event | Frist | Rule | Anchor | Seite | R.9.4 | Bedingung |
|
||||||
|
|---:|---|---|---|---|---|:---:|---|
|
||||||
|
| 1 | Zustellung DPMA-Entscheidung | 0 M after | § 65 PatG | | either | | |
|
||||||
|
| 2 | Beschwerde | 1 M after | § 73 PatG | | either | | |
|
||||||
|
| 3 | Beschwerdebegründung | 1 M after | § 75 PatG | | court-set | | |
|
||||||
|
| 4 | Mündliche Verhandlung BPatG | 0 M after | § 78 PatG | | court-set | | |
|
||||||
|
| 5 | BPatG-Entscheidung | 0 M after | § 78 PatG | | court-set | | |
|
||||||
|
|
||||||
|
## Rechtsbeschwerdeverfahren BGH · `dpma.appeal.bgh`
|
||||||
|
|
||||||
|
*Legal Appeal BGH*
|
||||||
|
|
||||||
|
| # | Phase / Event | Frist | Rule | Anchor | Seite | R.9.4 | Bedingung |
|
||||||
|
|---:|---|---|---|---|---|:---:|---|
|
||||||
|
| 1 | Zustellung BPatG-Entscheidung | 0 M after | § 100 PatG | | either | | |
|
||||||
|
| 2 | Rechtsbeschwerde | 1 M after | § 100 PatG | | either | | |
|
||||||
|
| 3 | Rechtsbeschwerdebegründung | 1 M after | § 102 PatG | | either | | |
|
||||||
|
| 4 | BGH-Entscheidung | 0 M after | § 100 PatG | | court-set | | |
|
||||||
|
|
||||||
|
## Berufungsverfahren Anordnungen · `upc.apl.order`
|
||||||
|
|
||||||
|
*Order Appeal (15-day track)*
|
||||||
|
|
||||||
|
| # | Phase / Event | Frist | Rule | Anchor | Seite | R.9.4 | Bedingung |
|
||||||
|
|---:|---|---|---|---|---|:---:|---|
|
||||||
|
| 1 | Anordnung / angegriffene Entscheidung | 0 M after | RoP.220 | | court-set | | |
|
||||||
|
| 2 | Berufung mit Zulassung | 15 d after | RoP.220.2 | | either | | |
|
||||||
|
| 3 | Antrag auf Ermessensüberprüfung | 15 d after | RoP.220.3 | | either | | |
|
||||||
|
| 4 | Berufungsbegründung (Orders Track) | 15 d after | RoP.224.2.b | | either | | |
|
||||||
|
| 5 | Anschlussberufung | 15 d after | RoP.237 | | either | | |
|
||||||
|
| 6 | Erwiderung Anschlussberufung | 15 d after | RoP.238.2 | | either | | |
|
||||||
|
| 7 | Berufungsschrift gegen eine in Regel 220.1(c) genannte Anordnung oder eine in Regel 220.2 oder 221.3 genannte Entscheidung | 15 d after | RoP.224.1(b) | Order referred to in Rule 220.1(c) or a decision referred to in Rule 220.2 or 221.3 | — | | |
|
||||||
|
| 8 | Berufungsbegründung gegen eine in Regel 220.1(c) genannte Anordnung oder eine in Regel 220.2 oder 221.3 genannte Entscheidung | 15 d after | RoP.224.1(b) | Order referred to in Rule 220.1(c) or a decision referred to in Rule 220.2 or 221.3 | — | | |
|
||||||
|
|
||||||
|
## Schadensbemessungsverfahren · `upc.dmgs.cfi`
|
||||||
|
|
||||||
|
*Damages Determination*
|
||||||
|
|
||||||
|
| # | Phase / Event | Frist | Rule | Anchor | Seite | R.9.4 | Bedingung |
|
||||||
|
|---:|---|---|---|---|---|:---:|---|
|
||||||
|
| 1 | Antrag auf Schadensbemessung | 0 M after | RoP.125 | | claimant | | |
|
||||||
|
| 2 | Klageerwiderung | 2 M after | RoP.137.2 | | defendant | | |
|
||||||
|
| 3 | Replik | 1 M after | RoP.139 | | claimant | | |
|
||||||
|
| 4 | Duplik | 1 M after | RoP.139 | | defendant | | |
|
||||||
|
|
||||||
|
## Bucheinsichtsverfahren · `upc.disc.cfi`
|
||||||
|
|
||||||
|
*Lay-open Books / Discovery*
|
||||||
|
|
||||||
|
| # | Phase / Event | Frist | Rule | Anchor | Seite | R.9.4 | Bedingung |
|
||||||
|
|---:|---|---|---|---|---|:---:|---|
|
||||||
|
| 1 | Antrag auf Bucheinsicht | 0 M after | RoP.190 | | claimant | | |
|
||||||
|
| 2 | Klageerwiderung | 2 M after | RoP.142.2 | | defendant | | |
|
||||||
|
| 3 | Replik | 14 d after | RoP.142.3 | | claimant | | |
|
||||||
|
| 4 | Duplik | 14 d after | RoP.142.3 | | defendant | | |
|
||||||
|
|
||||||
|
## Einstweilige Maßnahmen · `upc.pi.cfi`
|
||||||
|
|
||||||
|
*Provisional Measures*
|
||||||
|
|
||||||
|
| # | Phase / Event | Frist | Rule | Anchor | Seite | R.9.4 | Bedingung |
|
||||||
|
|---:|---|---|---|---|---|:---:|---|
|
||||||
|
| 1 | Antrag | 0 M after | RoP.206 | | claimant | | |
|
||||||
|
| 2 | Erwiderung | 0 M after | RoP.211.2 | | court-set | | |
|
||||||
|
| 3 | Mündliche Verhandlung | 0 M after | RoP.195 | | court-set | | |
|
||||||
|
| 4 | Mängelbeseitigung Antrag | 14 d after | RoP.207.6.a | | claimant | | |
|
||||||
|
| 5 | Beschluss | 0 M after | RoP.211 | | court-set | | |
|
||||||
|
| 6 | Klage in der Hauptsache erheben | 31 d max 20 WD after | RoP.213 | | claimant | | |
|
||||||
|
|
||||||
|
## Schutzschrift · `upc.pl.cfi`
|
||||||
|
|
||||||
|
*Protective Letter*
|
||||||
|
|
||||||
|
| # | Phase / Event | Frist | Rule | Anchor | Seite | R.9.4 | Bedingung |
|
||||||
|
|---:|---|---|---|---|---|:---:|---|
|
||||||
|
| 1 | Einreichung der Schutzschrift | 0 M after | RoP.207 | | defendant | | |
|
||||||
|
| 2 | Erneuerung der Schutzschrift | 6 M after | RoP.207.9 | Protective Letter | — | | |
|
||||||
|
|
||||||
|
## Berufungsverfahren Kosten · `upc.apl.cost`
|
||||||
|
|
||||||
|
*Cost-Decision Appeal*
|
||||||
|
|
||||||
|
| # | Phase / Event | Frist | Rule | Anchor | Seite | R.9.4 | Bedingung |
|
||||||
|
|---:|---|---|---|---|---|:---:|---|
|
||||||
|
| 1 | Kostenfestsetzungsbeschluss | 0 M after | RoP.221.4 | | court-set | | |
|
||||||
|
| 2 | Antrag auf Berufungszulassung | 15 d after | RoP.221.1 | | either | | |
|
||||||
|
| 3 | Antrag auf Berufungszulassung gegen Kostenentscheidungen | 15 d after | RoP.220.2 | Decision on fixation of costs (Rule 157) | — | | |
|
||||||
|
|
||||||
|
## Negative Feststellungsklage · `upc.dni.cfi`
|
||||||
|
|
||||||
|
*Declaration of Non-Infringement*
|
||||||
|
|
||||||
|
| # | Phase / Event | Frist | Rule | Anchor | Seite | R.9.4 | Bedingung |
|
||||||
|
|---:|---|---|---|---|---|:---:|---|
|
||||||
|
| 1 | Klage auf negative Feststellung der Nichtverletzung | 0 M after | RoP.063 | | claimant | | |
|
||||||
|
| 2 | Erwiderung auf die negative Feststellungsklage | 2 M after | RoP.066 | Statement for a declaration of non-infringement | — | | |
|
||||||
|
| 3 | Replik auf die Erwiderung zur negativen Feststellungsklage | 1 M after | RoP.067 | Defence to the Statement for a declaration of non-infringement | — | | |
|
||||||
|
| 4 | Duplik zur Replik auf die Erwiderung zur negativen Feststellungsklage | 1 M after | RoP.068 | Reply to the Defence to the Statement for a declaration of non-infringement | — | | |
|
||||||
|
|
||||||
|
## Überprüfung von EPA-Entscheidungen · `upc.epo.review`
|
||||||
|
|
||||||
|
*Review of EPO decisions*
|
||||||
|
|
||||||
|
| # | Phase / Event | Frist | Rule | Anchor | Seite | R.9.4 | Bedingung |
|
||||||
|
|---:|---|---|---|---|---|:---:|---|
|
||||||
|
| 1 | Antrag auf Überprüfung der EPA-Entscheidung | 0 M after | RoP.088 | | — | | |
|
||||||
|
| 2 | Antrag auf Aufhebung einer Entscheidung des EPA, mit der ein Antrag auf einheitliche Wirkung zurückgewiesen wurde | 3 w after | RoP.097 | Decision of the EPO not to grant unitary effect | — | | |
|
||||||
|
|
||||||
|
## Separate Kostenentscheidung · `upc.costs.cfi`
|
||||||
|
|
||||||
|
*Separate Cost Decision*
|
||||||
|
|
||||||
|
| # | Phase / Event | Frist | Rule | Anchor | Seite | R.9.4 | Bedingung |
|
||||||
|
|---:|---|---|---|---|---|:---:|---|
|
||||||
|
| 1 | Antrag auf Kostenfestsetzung | 1 M after | RoP.151 | | claimant | | |
|
||||||
|
|
||||||
|
## Beweissicherung / saisie · `upc.bsv.cfi`
|
||||||
|
|
||||||
|
*Evidence Preservation*
|
||||||
|
|
||||||
|
| # | Phase / Event | Frist | Rule | Anchor | Seite | R.9.4 | Bedingung |
|
||||||
|
|---:|---|---|---|---|---|:---:|---|
|
||||||
|
| 1 | Antrag auf Beweissicherung | 0 M after | RoP.192 | | court-set | | |
|
||||||
|
| 2 | Antrag auf Überprüfung der Beweissicherungsanordnung | 30 d after | RoP.197.3 | Execution of measures to preserve evidence | — | | |
|
||||||
|
| 3 | Beginn des Hauptsacheverfahrens | 31 d max 20 WD after | RoP.198 | Date specified in the Court's order to preserve evidence | — | | |
|
||||||
|
|
||||||
|
## Widerklage auf Nichtigkeit · `upc.ccr.cfi`
|
||||||
|
|
||||||
|
*Counterclaim for Revocation*
|
||||||
|
|
||||||
|
| # | Phase / Event | Frist | Rule | Anchor | Seite | R.9.4 | Bedingung |
|
||||||
|
|---:|---|---|---|---|---|:---:|---|
|
||||||
|
| 1 | Widerklage auf Nichtigkeit | 3 M after | RoP.025 | | defendant | | |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Lesehilfe:**
|
||||||
|
- ⤴ Spawn-Marker: event opens a sub-proceeding (e.g. CCR forks revocation track)
|
||||||
|
- `with_ccr` = Widerklage auf Nichtigkeit gefilt | `with_amend` = Patentänderungsantrag | `with_cci` = Widerklage auf Verletzung (in rev.cfi)
|
||||||
|
- Catalog ist work-in-progress: 7 compound-name rules + Patentänderung-Duplikation noch in m's split-review backlog (m/paliad#149).
|
||||||
@@ -24,6 +24,7 @@ import {
|
|||||||
type DeadlineResponse,
|
type DeadlineResponse,
|
||||||
type Side,
|
type Side,
|
||||||
} from "./views/verfahrensablauf-core";
|
} from "./views/verfahrensablauf-core";
|
||||||
|
import { filterByDetailMode, type DetailMode } from "./verfahrensablauf-detail-mode";
|
||||||
import { mountAddProceedingPicker, type ProceedingTypeMeta } from "./builder-picker";
|
import { mountAddProceedingPicker, type ProceedingTypeMeta } from "./builder-picker";
|
||||||
import { overlayEventStates, renderTriplet, type ScenarioFlagCatalogEntry } from "./builder-triplet";
|
import { overlayEventStates, renderTriplet, type ScenarioFlagCatalogEntry } from "./builder-triplet";
|
||||||
import {
|
import {
|
||||||
@@ -550,15 +551,32 @@ async function hydrateTriplet(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const stichtag = proc.stichtag || state.active?.stichtag || todayISO();
|
const stichtag = proc.stichtag || state.active?.stichtag || todayISO();
|
||||||
|
// t-paliad-348 — port engine semantics to the Builder triplet calc:
|
||||||
|
// - `includeOptional` follows the proceeding's detailgrad. The
|
||||||
|
// "selected" default suppresses optional rules server-side
|
||||||
|
// (engine drops them); "all_options" opts in so the dimmed
|
||||||
|
// optional cards can be rendered for the lawyer to opt into.
|
||||||
|
// - `filterByDetailMode` then runs client-side over what the
|
||||||
|
// engine emitted, dropping isConditional rows (rules whose
|
||||||
|
// `trigger_event_id` anchor wasn't supplied) when the lawyer
|
||||||
|
// is on "selected"/"mandatory_only" — those rules belong to the
|
||||||
|
// "naked proceeding with options but not always displayed"
|
||||||
|
// mental model and shouldn't pollute the backbone view.
|
||||||
|
const detailgrad: DetailMode = (proc.detailgrad as DetailMode) || "selected";
|
||||||
const data: DeadlineResponse | null = await calculateDeadlines({
|
const data: DeadlineResponse | null = await calculateDeadlines({
|
||||||
proceedingType: meta.code,
|
proceedingType: meta.code,
|
||||||
triggerDate: stichtag,
|
triggerDate: stichtag,
|
||||||
flags: scenarioFlagsToArray(proc.scenario_flags),
|
flags: scenarioFlagsToArray(proc.scenario_flags),
|
||||||
|
includeOptional: detailgrad === "all_options",
|
||||||
});
|
});
|
||||||
const side: Side = (proc.primary_party as Side) || null;
|
const side: Side = (proc.primary_party as Side) || null;
|
||||||
const eventsByRule = buildEventsByRule(proc.id);
|
const eventsByRule = buildEventsByRule(proc.id);
|
||||||
const columnsHtml = data
|
const scenarioFlagsBool = scenarioFlagsToBoolMap(proc.scenario_flags);
|
||||||
? renderColumnsBody(data, { editable: false, side, showDurations: false })
|
const filteredData: DeadlineResponse | null = data
|
||||||
|
? { ...data, deadlines: filterByDetailMode(data.deadlines, detailgrad, scenarioFlagsBool) }
|
||||||
|
: null;
|
||||||
|
const columnsHtml = filteredData
|
||||||
|
? renderColumnsBody(filteredData, { editable: false, side, showDurations: false })
|
||||||
: "";
|
: "";
|
||||||
host.innerHTML = renderTriplet({
|
host.innerHTML = renderTriplet({
|
||||||
proceeding: proc,
|
proceeding: proc,
|
||||||
@@ -927,6 +945,19 @@ function scenarioFlagsToArray(flags: Record<string, unknown>): string[] {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// scenarioFlagsToBoolMap narrows the jsonb-shape scenario_flags blob
|
||||||
|
// (`{key: true|false|null|other}`) to the strict `Record<string, boolean>`
|
||||||
|
// shape filterByDetailMode consumes. The rule:<uuid>=true|false per-rule
|
||||||
|
// deviation keys flow through verbatim (their truthiness IS the override
|
||||||
|
// signal isRuleSelected reads).
|
||||||
|
function scenarioFlagsToBoolMap(flags: Record<string, unknown>): Record<string, boolean> {
|
||||||
|
const out: Record<string, boolean> = {};
|
||||||
|
for (const [k, v] of Object.entries(flags)) {
|
||||||
|
if (typeof v === "boolean") out[k] = v;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
// ────────────────────────────────────────────────────────────────────────────
|
// ────────────────────────────────────────────────────────────────────────────
|
||||||
// Actions
|
// Actions
|
||||||
// ────────────────────────────────────────────────────────────────────────────
|
// ────────────────────────────────────────────────────────────────────────────
|
||||||
|
|||||||
@@ -176,6 +176,20 @@ const APPEAL_TARGET_PROCEEDINGS = new Set([
|
|||||||
"upc.apl.unified",
|
"upc.apl.unified",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// hasOptionalOptIn — true when any `rule:<uuid>=true` override exists in
|
||||||
|
// the scenarioFlags map (the per-rule "Aufnehmen" deviation written by
|
||||||
|
// the detail-mode selection-chip in onRuleSelectionToggle). When set we
|
||||||
|
// flip the engine's IncludeOptional on so the chosen optional rules
|
||||||
|
// actually reach the response; the engine has no rule:<uuid> awareness
|
||||||
|
// of its own so without this layer the pick would silently no-op.
|
||||||
|
// (t-paliad-348)
|
||||||
|
function hasOptionalOptIn(flags: Record<string, boolean>): boolean {
|
||||||
|
for (const [k, v] of Object.entries(flags)) {
|
||||||
|
if (v === true && k.startsWith("rule:")) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
function hasAppealTarget(proceedingType: string): boolean {
|
function hasAppealTarget(proceedingType: string): boolean {
|
||||||
return APPEAL_TARGET_PROCEEDINGS.has(proceedingType);
|
return APPEAL_TARGET_PROCEEDINGS.has(proceedingType);
|
||||||
}
|
}
|
||||||
@@ -408,6 +422,16 @@ async function doCalc() {
|
|||||||
perCardChoices,
|
perCardChoices,
|
||||||
includeHidden: showHidden,
|
includeHidden: showHidden,
|
||||||
appealTarget,
|
appealTarget,
|
||||||
|
// t-paliad-348 — match the page-level detail mode to the engine's
|
||||||
|
// optional-rule suppression. The engine drops optional rules by
|
||||||
|
// default (IncludeOptional=false); "all_options" mode needs them
|
||||||
|
// back in the response so filterByDetailMode can dim them. We
|
||||||
|
// also opt-in whenever any per-rule `rule:<uuid>=true` deviation
|
||||||
|
// is set on scenarioFlags so an "Aufnehmen"-ed optional in
|
||||||
|
// "selected" mode still surfaces — the engine doesn't read
|
||||||
|
// rule:<uuid> overrides, so without this the user's pick would
|
||||||
|
// silently no-op server-side.
|
||||||
|
includeOptional: detailMode === "all_options" || hasOptionalOptIn(scenarioFlags),
|
||||||
});
|
});
|
||||||
if (seq !== calcSeq) return;
|
if (seq !== calcSeq) return;
|
||||||
if (!data) return;
|
if (!data) return;
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { describe, expect, test } from "bun:test";
|
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
||||||
import {
|
import {
|
||||||
type CalculatedDeadline,
|
type CalculatedDeadline,
|
||||||
type DeadlineResponse,
|
type DeadlineResponse,
|
||||||
bucketDeadlinesIntoColumns,
|
bucketDeadlinesIntoColumns,
|
||||||
|
calculateDeadlines,
|
||||||
deadlineCardHtml,
|
deadlineCardHtml,
|
||||||
formatDurationLabel,
|
formatDurationLabel,
|
||||||
renderColumnsBody,
|
renderColumnsBody,
|
||||||
@@ -773,3 +774,81 @@ describe("stripLeadingDurationFromNotes — render-side dedup (t-paliad-307)", (
|
|||||||
.toBe("Time limit set by the court");
|
.toBe("Time limit set by the court");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Pin the engine-options plumbing surface (t-paliad-348 / yoUPC#178).
|
||||||
|
// calculateDeadlines must forward `includeOptional` and
|
||||||
|
// `triggerEventAnchors` straight into the POST body so the Go handler
|
||||||
|
// (handleFristenrechnerAPI) can pass them into lp.CalcOptions. If a
|
||||||
|
// future refactor drops the fields, the Builder triplet silently
|
||||||
|
// reverts to "engine emits optional rules" and the unified
|
||||||
|
// /tools/procedures page loses its naked-proceeding default.
|
||||||
|
describe("calculateDeadlines — forwards engine options into request body", () => {
|
||||||
|
type CapturedRequest = { url: string; body: Record<string, unknown> };
|
||||||
|
let captured: CapturedRequest | null;
|
||||||
|
let originalFetch: typeof globalThis.fetch;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
captured = null;
|
||||||
|
originalFetch = globalThis.fetch;
|
||||||
|
globalThis.fetch = (async (input: RequestInfo | URL, init?: RequestInit) => {
|
||||||
|
const body = typeof init?.body === "string" ? JSON.parse(init.body) : {};
|
||||||
|
captured = { url: String(input), body };
|
||||||
|
return new Response(JSON.stringify({
|
||||||
|
proceedingType: "x", proceedingName: "x", triggerDate: "2026-01-01", deadlines: [],
|
||||||
|
}), { status: 200, headers: { "Content-Type": "application/json" } });
|
||||||
|
}) as typeof globalThis.fetch;
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
globalThis.fetch = originalFetch;
|
||||||
|
});
|
||||||
|
|
||||||
|
test("default call omits includeOptional and triggerEventAnchors", async () => {
|
||||||
|
await calculateDeadlines({ proceedingType: "upc.inf.cfi", triggerDate: "2026-05-26" });
|
||||||
|
expect(captured).not.toBeNull();
|
||||||
|
expect(captured!.body.includeOptional).toBeUndefined();
|
||||||
|
expect(captured!.body.triggerEventAnchors).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("includeOptional=true sends includeOptional: true", async () => {
|
||||||
|
await calculateDeadlines({
|
||||||
|
proceedingType: "upc.inf.cfi",
|
||||||
|
triggerDate: "2026-05-26",
|
||||||
|
includeOptional: true,
|
||||||
|
});
|
||||||
|
expect(captured!.body.includeOptional).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("includeOptional=false is omitted (matches engine default)", async () => {
|
||||||
|
await calculateDeadlines({
|
||||||
|
proceedingType: "upc.inf.cfi",
|
||||||
|
triggerDate: "2026-05-26",
|
||||||
|
includeOptional: false,
|
||||||
|
});
|
||||||
|
expect(captured!.body.includeOptional).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("triggerEventAnchors forwarded as object", async () => {
|
||||||
|
await calculateDeadlines({
|
||||||
|
proceedingType: "upc.inf.cfi",
|
||||||
|
triggerDate: "2026-05-26",
|
||||||
|
triggerEventAnchors: {
|
||||||
|
"upc.inf.cfi.oral": "2026-09-01",
|
||||||
|
"upc.inf.cfi.decision": "2026-12-15",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(captured!.body.triggerEventAnchors).toEqual({
|
||||||
|
"upc.inf.cfi.oral": "2026-09-01",
|
||||||
|
"upc.inf.cfi.decision": "2026-12-15",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("empty triggerEventAnchors is omitted", async () => {
|
||||||
|
await calculateDeadlines({
|
||||||
|
proceedingType: "upc.inf.cfi",
|
||||||
|
triggerDate: "2026-05-26",
|
||||||
|
triggerEventAnchors: {},
|
||||||
|
});
|
||||||
|
expect(captured!.body.triggerEventAnchors).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -271,6 +271,12 @@ export interface DeadlineResponse {
|
|||||||
// when the toggle is OFF — so users know there's something to
|
// when the toggle is OFF — so users know there's something to
|
||||||
// re-surface.
|
// re-surface.
|
||||||
hiddenCount?: number;
|
hiddenCount?: number;
|
||||||
|
// rulesAwaitingAnchor (t-paliad-348 / yoUPC#178): number of rules the
|
||||||
|
// engine suppressed because their `trigger_event_id` anchor wasn't
|
||||||
|
// supplied via CalcParams.triggerEventAnchors. Mirrors the Go
|
||||||
|
// Timeline.RulesAwaitingAnchor counter — a single integer surface for
|
||||||
|
// "N rules waiting on an anchor" UI affordances.
|
||||||
|
rulesAwaitingAnchor?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CourtRow {
|
export interface CourtRow {
|
||||||
@@ -311,6 +317,20 @@ export interface CalcParams {
|
|||||||
// endentscheidung | kostenentscheidung | anordnung |
|
// endentscheidung | kostenentscheidung | anordnung |
|
||||||
// schadensbemessung | bucheinsicht.
|
// schadensbemessung | bucheinsicht.
|
||||||
appealTarget?: string;
|
appealTarget?: string;
|
||||||
|
// t-paliad-348 / yoUPC#178 — surface the engine's two new CalcOptions
|
||||||
|
// axes to the HTTP boundary:
|
||||||
|
//
|
||||||
|
// includeOptional: when true, the engine returns priority='optional'
|
||||||
|
// rules in the timeline. Default false matches the engine default
|
||||||
|
// (mandatory backbone only). The /tools/procedures detailgrad
|
||||||
|
// toggle ("all_options" mode) drives this to true so the dimmed
|
||||||
|
// optional cards can be rendered for the lawyer to opt into.
|
||||||
|
// triggerEventAnchors: per-event-code anchor dates the engine
|
||||||
|
// consults for rules carrying trigger_event_id. Empty/omitted =
|
||||||
|
// no anchors → such rules render as IsConditional (the engine
|
||||||
|
// refuses to fabricate a date off the proceeding's trigger date).
|
||||||
|
includeOptional?: boolean;
|
||||||
|
triggerEventAnchors?: Record<string, string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PARTY_CLASS: Record<string, string> = {
|
const PARTY_CLASS: Record<string, string> = {
|
||||||
@@ -1118,6 +1138,10 @@ export async function calculateDeadlines(params: CalcParams): Promise<DeadlineRe
|
|||||||
: undefined,
|
: undefined,
|
||||||
includeHidden: params.includeHidden ? true : undefined,
|
includeHidden: params.includeHidden ? true : undefined,
|
||||||
appealTarget: params.appealTarget || undefined,
|
appealTarget: params.appealTarget || undefined,
|
||||||
|
includeOptional: params.includeOptional ? true : undefined,
|
||||||
|
triggerEventAnchors: params.triggerEventAnchors && Object.keys(params.triggerEventAnchors).length > 0
|
||||||
|
? params.triggerEventAnchors
|
||||||
|
: undefined,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
if (!resp.ok) {
|
if (!resp.ok) {
|
||||||
|
|||||||
@@ -91,6 +91,19 @@ func handleFristenrechnerAPI(w http.ResponseWriter, r *http.Request) {
|
|||||||
// slugs are silently dropped (no filter) so a stale frontend
|
// slugs are silently dropped (no filter) so a stale frontend
|
||||||
// chip doesn't 400 the request.
|
// chip doesn't 400 the request.
|
||||||
AppealTarget string `json:"appealTarget,omitempty"`
|
AppealTarget string `json:"appealTarget,omitempty"`
|
||||||
|
// t-paliad-348 / yoUPC#178 — surface the engine's two new
|
||||||
|
// CalcOptions axes to the HTTP boundary:
|
||||||
|
//
|
||||||
|
// IncludeOptional: when true, priority='optional' rules
|
||||||
|
// surface on the timeline. Default false matches the
|
||||||
|
// engine's default (mandatory backbone only).
|
||||||
|
// TriggerEventAnchors: per-event-code anchor dates the
|
||||||
|
// engine consults for rules carrying trigger_event_id.
|
||||||
|
// When a rule's anchor is absent the engine renders the
|
||||||
|
// rule as IsConditional rather than fabricating a date
|
||||||
|
// off the proceeding's trigger date.
|
||||||
|
IncludeOptional bool `json:"includeOptional,omitempty"`
|
||||||
|
TriggerEventAnchors map[string]string `json:"triggerEventAnchors,omitempty"`
|
||||||
}
|
}
|
||||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Ungültige Anfrage"})
|
writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Ungültige Anfrage"})
|
||||||
@@ -130,15 +143,17 @@ func handleFristenrechnerAPI(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
resp, err := dbSvc.fristenrechner.Calculate(r.Context(), req.ProceedingType, req.TriggerDate, services.CalcOptions{
|
resp, err := dbSvc.fristenrechner.Calculate(r.Context(), req.ProceedingType, req.TriggerDate, services.CalcOptions{
|
||||||
PriorityDateStr: req.PriorityDate,
|
PriorityDateStr: req.PriorityDate,
|
||||||
Flags: req.Flags,
|
Flags: req.Flags,
|
||||||
AnchorOverrides: req.AnchorOverrides,
|
AnchorOverrides: req.AnchorOverrides,
|
||||||
CourtID: req.CourtID,
|
CourtID: req.CourtID,
|
||||||
PerCardAppellant: addendum.PerCardAppellant,
|
PerCardAppellant: addendum.PerCardAppellant,
|
||||||
SkipRules: addendum.SkipRules,
|
SkipRules: addendum.SkipRules,
|
||||||
IncludeCCRFor: addendum.IncludeCCRFor,
|
IncludeCCRFor: addendum.IncludeCCRFor,
|
||||||
IncludeHidden: req.IncludeHidden,
|
IncludeHidden: req.IncludeHidden,
|
||||||
AppealTarget: req.AppealTarget,
|
AppealTarget: req.AppealTarget,
|
||||||
|
IncludeOptional: req.IncludeOptional,
|
||||||
|
TriggerEventAnchors: req.TriggerEventAnchors,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, services.ErrUnknownProceedingType) {
|
if errors.Is(err, services.ErrUnknownProceedingType) {
|
||||||
|
|||||||
Reference in New Issue
Block a user