Compare commits
3 Commits
mai/fermi/
...
mai/ampere
| Author | SHA1 | Date | |
|---|---|---|---|
| fe421d917c | |||
| 4c85515e50 | |||
| eac39456be |
@@ -1,52 +0,0 @@
|
||||
# t-paliad-207 follow-up scope — close-out assessment
|
||||
|
||||
**Author:** fermi (inventor)
|
||||
**Date:** 2026-05-20
|
||||
**Verdict:** **(A) DONE** — interactive session scope is shipped; remaining tail is filed-or-fileable as discrete issues, not a fresh fermi slice.
|
||||
|
||||
---
|
||||
|
||||
## 0. What shipped under t-paliad-207
|
||||
|
||||
Six substantive deliveries on `mai/fermi/interactive-session`, all merged to main as of 2026-05-20 morning:
|
||||
|
||||
1. **Verfahrensablauf + Fristenrechner polish** — jurisdiction prefix on the picked proceeding, trigger-event label derived from the root rule, flag rows lifted to `/tools/verfahrensablauf`, rule references rendered as `youpc.org/laws#…` links via new `BuildLegalSourceURL`, `Vorab-Einrede → Einspruch` rename (DE i18n).
|
||||
2. **DE proceeding picker — sub-group headers** (`Verletzungsverfahren` / `Nichtigkeitsverfahren`) + parallel labels (`LG (1. Instanz)` / `OLG (Berufung)` / …).
|
||||
3. **mig 099** — drop the `with_po` flag from the two RoP 19 rules (Einspruch is always-available, not flag-gated).
|
||||
4. **mig 100** — `upc.inf.cfi.ccr` visible rule (`Nichtigkeitswiderklage`) so the CCR filing event surfaces when `with_ccr` is set; later corrected to `priority='optional'` via mig 101.
|
||||
5. **mig 101** — strip rule-cite brackets from the two Einspruch names + flip the CCR priority `informational → optional`.
|
||||
6. **mig 102** — track-aware sequence reshuffle on `upc.inf.cfi` so at any tied date the order is infringement (Replik) → revocation (Erwiderung Nichtigkeitswiderklage) → amendment.
|
||||
7. **Notes toggle** — `Hinweise anzeigen` checkbox in the view-toggle bar; compact ⓘ hover hint when off (default), inline `timeline-notes` block when on. `localStorage` shared across both tool pages.
|
||||
|
||||
Filed two follow-up issues during the session:
|
||||
|
||||
- **m/paliad#39** — link DE + EPA + EU rule references to `youpc.org/laws` (depends on youpc.org ingesting the corpus).
|
||||
- **m/paliad#41** — DE proceedings as one combined timeline per type (LG→OLG→BGH, BPatG→BGH) — corpus + spawn + de-duplication + multi-instance UI.
|
||||
|
||||
## 1. Why (A) DONE
|
||||
|
||||
Every concrete thing m surfaced in the session was addressed and merged. The two larger unaddressed asks — combined-timeline behaviour for DE proceedings, and DE/EPA rule-link coverage — are already captured in #39 and #41 with concrete scope notes. Neither belongs as a fermi "next slice" because:
|
||||
|
||||
- **#41** is a corpus + UI design pass of its own (3 new spawn rules, de-duplication of the existing `de.inf.lg.berufung ↔ de.inf.olg.berufung` pair, multi-court picker shape, instance markers in the timeline body). That's its own design ticket, not a fermi follow-up.
|
||||
- **#39** is primarily a youpc.org-side ingest task; the paliad-side change is a 5-line `switch` extension once youpc serves the URLs. Wait for the dependency, then small.
|
||||
|
||||
Everything else I surfaced in the read-only audit is either pre-existing (not introduced by this session) or speculative (no user complaint behind it).
|
||||
|
||||
## 2. Optional tail — would file as discrete issues, not a fermi slice
|
||||
|
||||
Surfacing these for completeness; none are blocking, and most would be small enough to either roll into the existing tickets or land as one-off polish:
|
||||
|
||||
| # | Candidate | Size | Already covered? |
|
||||
|---|---|---|---|
|
||||
| 1 | **`legal_source` backfill on 47 unsourced active rules** — query: 4 of `upc.inf.cfi`, 4 of `upc.pi.cfi` (100% gap), 6 of `upc.rev.cfi`, others. Pre-condition for #39's links to bite. | Medium — corpus research per rule | Partially: huygens did the broader citation backfill in t-paliad-208 / mig 097. This is the remaining tail. |
|
||||
| 2 | **`upc.pi.cfi` corpus completeness audit** — all 4 of its rules lack `legal_source`; likely also missing the analogous track-of-decision spawn rules to `upc.apl.merits`. | Small audit, medium fix | No — would be a fresh task. |
|
||||
| 3 | **Touch-device fallback for the ⓘ hover hint** — `title=` attribute degrades poorly on phones (no hover, no tap-to-show). Either a click-to-popover variant, or accept the gap. | Tiny | No, but no user complaint yet. |
|
||||
| 4 | **R.46 mutatis-mutandis distinction in `upc.rev.cfi.prelim` description** — when mig 101 stripped the `(R. 19 i.V.m. R. 46)` cite, the legal nuance dropped from the user-visible name. Could be surfaced in the description text where it doesn't crowd the timeline cell. | Tiny (one row update) | No. |
|
||||
| 5 | **Save-modal warning on SoD + CCR double-check** — with mig 100's new `upc.inf.cfi.ccr` rule, a user can save both `sod` and `ccr` from the same modal and get two `paliad.deadlines` rows on the same date. Today's pre-uncheck behaviour for optional priority mitigates accidental double-write but doesn't surface the duplication actively. | Small | No. |
|
||||
| 6 | **Deferred slices from earlier design docs that touch this surface**: t-paliad-179 Slice 2-4 (variant chips, lane view, side-by-side compare on `/tools/verfahrensablauf`); t-paliad-169 "+ Eintrag" CTA on the SmartTimeline (project-bound) path. | Each a separate slice. | Yes — parked from their original tasks; would be revisited when m prioritises. |
|
||||
|
||||
None of these warrant a "next fermi slice" right now. They're polish + corpus tail, and best handled as individual issues that m can pick from.
|
||||
|
||||
## 3. Recommendation
|
||||
|
||||
Close t-paliad-207. Fire fermi. The remaining tail (items 1–6 above) is appropriate as a small "polish backlog" m can dip into when relevant, but not a coherent unit of work that needs a parked inventor.
|
||||
@@ -57,19 +57,6 @@ type ProcedureView = "timeline" | "columns";
|
||||
// HLC team than the single vertical line.
|
||||
let procedureView: ProcedureView = "columns";
|
||||
|
||||
// Notes toggle — off by default; per-rule notes render as a compact
|
||||
// ⓘ hover icon. Flipped on, they expand under each card. Choice is
|
||||
// localStorage-persisted (paliad.fristen.notes-show key shared with
|
||||
// /tools/verfahrensablauf so the preference carries across both).
|
||||
const NOTES_PREF_KEY = "paliad.fristen.notes-show";
|
||||
function readNotesPref(): boolean {
|
||||
try { return localStorage.getItem(NOTES_PREF_KEY) === "1"; } catch { return false; }
|
||||
}
|
||||
function writeNotesPref(on: boolean): void {
|
||||
try { localStorage.setItem(NOTES_PREF_KEY, on ? "1" : "0"); } catch { /* no-op */ }
|
||||
}
|
||||
let showNotes = readNotesPref();
|
||||
|
||||
onLangChange(() => {
|
||||
if (lastResponse) renderProcedureResults(lastResponse);
|
||||
// Update trigger event name if a proceeding is selected
|
||||
@@ -127,24 +114,27 @@ async function calculate() {
|
||||
|
||||
// Flags — proceeding-specific checkboxes:
|
||||
// upc.inf.cfi: with_ccr (always available); with_amend (nested under
|
||||
// with_ccr — R.30 application is only available with a CCR).
|
||||
// upc.rev.cfi: with_amend (R.49.2.a) and with_cci (R.49.2.b) as two
|
||||
// independent gates; both can be on simultaneously.
|
||||
// R.19 Einspruch is NOT flag-gated (mig 098, m's 2026-05-18 call): it's
|
||||
// an always-available optional submission, surfaced as priority='optional'
|
||||
// without a separate checkbox.
|
||||
// with_ccr — R.30 application is only available with a CCR);
|
||||
// with_po (mig 095, R.19.1 preliminary objection).
|
||||
// upc.rev.cfi: with_amend (R.49.2.a), with_cci (R.49.2.b),
|
||||
// with_po (R.19.1 via R.46) as three independent gates;
|
||||
// all combinations are valid.
|
||||
const ccrFlag = document.getElementById("ccr-flag") as HTMLInputElement | null;
|
||||
const infAmendFlag = document.getElementById("inf-amend-flag") as HTMLInputElement | null;
|
||||
const infPoFlag = document.getElementById("inf-po-flag") as HTMLInputElement | null;
|
||||
const revAmendFlag = document.getElementById("rev-amend-flag") as HTMLInputElement | null;
|
||||
const revCciFlag = document.getElementById("rev-cci-flag") as HTMLInputElement | null;
|
||||
const revPoFlag = document.getElementById("rev-po-flag") as HTMLInputElement | null;
|
||||
const flags: string[] = [];
|
||||
if (selectedType === "upc.inf.cfi") {
|
||||
if (ccrFlag?.checked) flags.push("with_ccr");
|
||||
if (ccrFlag?.checked && infAmendFlag?.checked) flags.push("with_amend");
|
||||
if (infPoFlag?.checked) flags.push("with_po");
|
||||
}
|
||||
if (selectedType === "upc.rev.cfi") {
|
||||
if (revAmendFlag?.checked) flags.push("with_amend");
|
||||
if (revCciFlag?.checked) flags.push("with_cci");
|
||||
if (revPoFlag?.checked) flags.push("with_po");
|
||||
}
|
||||
|
||||
// Forward any user-set per-rule date overrides so downstream rules
|
||||
@@ -404,8 +394,8 @@ function renderProcedureResults(data: DeadlineResponse) {
|
||||
</div>`;
|
||||
|
||||
const bodyHtml = procedureView === "columns"
|
||||
? renderColumnsBody(data, { editable: true, showNotes })
|
||||
: renderTimelineBody(data, { showParty: true, editable: true, showNotes });
|
||||
? renderColumnsBody(data, { editable: true })
|
||||
: renderTimelineBody(data, { showParty: true, editable: true });
|
||||
|
||||
container.innerHTML = headerHtml + bodyHtml;
|
||||
printBtn.style.display = "block";
|
||||
@@ -524,18 +514,24 @@ function selectProceeding(btn: HTMLButtonElement) {
|
||||
// ccr-flag → upc.inf.cfi only
|
||||
// inf-amend-flag → upc.inf.cfi only, but disabled until ccr-flag is on
|
||||
// (R.30 amend only available with a CCR)
|
||||
// inf-po-flag → upc.inf.cfi only (R.19.1 preliminary objection, mig 095)
|
||||
// rev-amend-flag → upc.rev.cfi only
|
||||
// rev-cci-flag → upc.rev.cfi only
|
||||
// rev-po-flag → upc.rev.cfi only (R.19.1 via R.46, mig 095)
|
||||
const priorityRow = document.getElementById("priority-date-row");
|
||||
if (priorityRow) priorityRow.style.display = selectedType === "epa.grant.exa" ? "" : "none";
|
||||
const ccrRow = document.getElementById("ccr-flag-row");
|
||||
if (ccrRow) ccrRow.style.display = selectedType === "upc.inf.cfi" ? "" : "none";
|
||||
const infAmendRow = document.getElementById("inf-amend-flag-row");
|
||||
if (infAmendRow) infAmendRow.style.display = selectedType === "upc.inf.cfi" ? "" : "none";
|
||||
const infPoRow = document.getElementById("inf-po-flag-row");
|
||||
if (infPoRow) infPoRow.style.display = selectedType === "upc.inf.cfi" ? "" : "none";
|
||||
const revAmendRow = document.getElementById("rev-amend-flag-row");
|
||||
if (revAmendRow) revAmendRow.style.display = selectedType === "upc.rev.cfi" ? "" : "none";
|
||||
const revCciRow = document.getElementById("rev-cci-flag-row");
|
||||
if (revCciRow) revCciRow.style.display = selectedType === "upc.rev.cfi" ? "" : "none";
|
||||
const revPoRow = document.getElementById("rev-po-flag-row");
|
||||
if (revPoRow) revPoRow.style.display = selectedType === "upc.rev.cfi" ? "" : "none";
|
||||
|
||||
syncInfAmendEnabled();
|
||||
populateCourtPickerCore("court-picker-row", "court-picker", selectedType);
|
||||
@@ -636,10 +632,14 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
|
||||
const infAmendFlag = document.getElementById("inf-amend-flag") as HTMLInputElement | null;
|
||||
if (infAmendFlag) infAmendFlag.addEventListener("change", () => scheduleProcCalc(0));
|
||||
const infPoFlag = document.getElementById("inf-po-flag") as HTMLInputElement | null;
|
||||
if (infPoFlag) infPoFlag.addEventListener("change", () => scheduleProcCalc(0));
|
||||
const revAmendFlag = document.getElementById("rev-amend-flag") as HTMLInputElement | null;
|
||||
if (revAmendFlag) revAmendFlag.addEventListener("change", () => scheduleProcCalc(0));
|
||||
const revCciFlag = document.getElementById("rev-cci-flag") as HTMLInputElement | null;
|
||||
if (revCciFlag) revCciFlag.addEventListener("change", () => scheduleProcCalc(0));
|
||||
const revPoFlag = document.getElementById("rev-po-flag") as HTMLInputElement | null;
|
||||
if (revPoFlag) revPoFlag.addEventListener("change", () => scheduleProcCalc(0));
|
||||
const courtPicker = document.getElementById("court-picker") as HTMLSelectElement | null;
|
||||
if (courtPicker) courtPicker.addEventListener("change", () => scheduleProcCalc(0));
|
||||
|
||||
@@ -674,18 +674,6 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
const saveBtn = document.getElementById("fristen-save-cta");
|
||||
if (saveBtn) saveBtn.addEventListener("click", openSaveModal);
|
||||
|
||||
// Notes toggle — restores last preference on load + re-renders when
|
||||
// the user flips it. Lives in the same toggle bar as the view picker.
|
||||
const notesShowCb = document.getElementById("fristen-notes-show") as HTMLInputElement | null;
|
||||
if (notesShowCb) {
|
||||
notesShowCb.checked = showNotes;
|
||||
notesShowCb.addEventListener("change", () => {
|
||||
showNotes = notesShowCb.checked;
|
||||
writeNotesPref(showNotes);
|
||||
if (lastResponse) renderProcedureResults(lastResponse);
|
||||
});
|
||||
}
|
||||
|
||||
// View toggle (timeline vs. columns layout) for procedure mode.
|
||||
initViewToggle();
|
||||
|
||||
|
||||
@@ -221,8 +221,10 @@ const translations: Record<Lang, Record<string, string>> = {
|
||||
"deadlines.court.label": "Gericht:",
|
||||
"deadlines.flag.ccr": "Mit Widerklage auf Nichtigkeit",
|
||||
"deadlines.flag.inf_amend": "Mit Antrag auf Patentänderung (R.30)",
|
||||
"deadlines.flag.inf_po": "Mit Einspruch (R.19)",
|
||||
"deadlines.flag.rev_amend": "Mit Antrag auf Patentänderung (R.49.2.a)",
|
||||
"deadlines.flag.rev_cci": "Mit Verletzungswiderklage (R.49.2.b)",
|
||||
"deadlines.flag.rev_po": "Mit Einspruch (R.19 i.V.m. R.46)",
|
||||
"deadlines.calculate": "Fristen berechnen",
|
||||
"deadlines.print": "Drucken",
|
||||
"deadlines.reset": "\u2190 Neu berechnen",
|
||||
@@ -235,13 +237,11 @@ const translations: Record<Lang, Record<string, string>> = {
|
||||
"deadlines.upc.disc.cfi": "Bucheinsicht",
|
||||
"deadlines.upc.apl.cost": "Berufung Kosten",
|
||||
"deadlines.upc.apl.order": "Berufung Anordnungen",
|
||||
"deadlines.de.group.inf": "Verletzungsverfahren",
|
||||
"deadlines.de.group.null": "Nichtigkeitsverfahren",
|
||||
"deadlines.de.inf.lg": "LG (1. Instanz)",
|
||||
"deadlines.de.inf.olg": "OLG (Berufung)",
|
||||
"deadlines.de.inf.bgh": "BGH (Revision / NZB)",
|
||||
"deadlines.de.null.bpatg": "BPatG (1. Instanz)",
|
||||
"deadlines.de.null.bgh": "BGH (Berufung)",
|
||||
"deadlines.de.inf.lg": "Verletzungsklage (LG)",
|
||||
"deadlines.de.inf.olg": "Berufung OLG",
|
||||
"deadlines.de.inf.bgh": "Revision/NZB BGH",
|
||||
"deadlines.de.null.bpatg": "Nichtigkeitsverfahren",
|
||||
"deadlines.de.null.bgh": "Berufung BGH (Nichtigk.)",
|
||||
"deadlines.epa.opp.opd": "Einspruchsverfahren",
|
||||
"deadlines.epa.opp.boa": "Beschwerdeverfahren",
|
||||
"deadlines.epa.grant.exa": "EP-Erteilungsverfahren",
|
||||
@@ -300,7 +300,6 @@ const translations: Record<Lang, Record<string, string>> = {
|
||||
"deadlines.view.label": "Ansicht:",
|
||||
"deadlines.view.timeline": "Zeitstrahl",
|
||||
"deadlines.view.columns": "Spalten",
|
||||
"deadlines.notes.show": "Hinweise anzeigen",
|
||||
"deadlines.col.proactive": "Proaktiv",
|
||||
"deadlines.col.court": "Gericht",
|
||||
"deadlines.col.reactive": "Reaktiv",
|
||||
@@ -2809,8 +2808,10 @@ const translations: Record<Lang, Record<string, string>> = {
|
||||
"deadlines.court.label": "Court:",
|
||||
"deadlines.flag.ccr": "Counterclaim for revocation filed",
|
||||
"deadlines.flag.inf_amend": "Application to amend the patent filed (R.30)",
|
||||
"deadlines.flag.inf_po": "Preliminary objection filed (R.19)",
|
||||
"deadlines.flag.rev_amend": "Application to amend the patent filed (R.49.2.a)",
|
||||
"deadlines.flag.rev_cci": "Counterclaim for infringement filed (R.49.2.b)",
|
||||
"deadlines.flag.rev_po": "Preliminary objection filed (R.19 via R.46)",
|
||||
"deadlines.calculate": "Calculate Deadlines",
|
||||
"deadlines.print": "Print",
|
||||
"deadlines.reset": "\u2190 Start Over",
|
||||
@@ -2823,13 +2824,11 @@ const translations: Record<Lang, Record<string, string>> = {
|
||||
"deadlines.upc.disc.cfi": "Lay-open Books",
|
||||
"deadlines.upc.apl.cost": "Cost-Decision Appeal",
|
||||
"deadlines.upc.apl.order": "Order Appeal (15-day)",
|
||||
"deadlines.de.group.inf": "Infringement proceedings",
|
||||
"deadlines.de.group.null": "Nullity proceedings",
|
||||
"deadlines.de.inf.lg": "LG (1st instance)",
|
||||
"deadlines.de.inf.olg": "OLG (Appeal)",
|
||||
"deadlines.de.inf.bgh": "BGH (Revision / NZB)",
|
||||
"deadlines.de.null.bpatg": "BPatG (1st instance)",
|
||||
"deadlines.de.null.bgh": "BGH (Appeal)",
|
||||
"deadlines.de.inf.lg": "Infringement (Regional Court)",
|
||||
"deadlines.de.inf.olg": "Appeal OLG",
|
||||
"deadlines.de.inf.bgh": "Revision / NZB BGH",
|
||||
"deadlines.de.null.bpatg": "Nullity",
|
||||
"deadlines.de.null.bgh": "Appeal BGH (Nullity)",
|
||||
"deadlines.epa.opp.opd": "Opposition",
|
||||
"deadlines.epa.opp.boa": "Appeal",
|
||||
"deadlines.epa.grant.exa": "Grant Procedure",
|
||||
@@ -2888,7 +2887,6 @@ const translations: Record<Lang, Record<string, string>> = {
|
||||
"deadlines.view.label": "View:",
|
||||
"deadlines.view.timeline": "Timeline",
|
||||
"deadlines.view.columns": "Columns",
|
||||
"deadlines.notes.show": "Show details",
|
||||
"deadlines.col.proactive": "Proactive",
|
||||
"deadlines.col.court": "Court",
|
||||
"deadlines.col.reactive": "Reactive",
|
||||
|
||||
@@ -25,19 +25,6 @@ let lastResponse: DeadlineResponse | null = null;
|
||||
type ProcedureView = "timeline" | "columns";
|
||||
let procedureView: ProcedureView = "columns";
|
||||
|
||||
// Notes toggle — when off (default), per-rule descriptive notes render
|
||||
// as a compact ⓘ icon next to the meta line (hover for full text). When
|
||||
// on, the full notes block expands under each card. Choice persists in
|
||||
// localStorage so a reload or recalc keeps the user's preference.
|
||||
const NOTES_PREF_KEY = "paliad.fristen.notes-show";
|
||||
function readNotesPref(): boolean {
|
||||
try { return localStorage.getItem(NOTES_PREF_KEY) === "1"; } catch { return false; }
|
||||
}
|
||||
function writeNotesPref(on: boolean): void {
|
||||
try { localStorage.setItem(NOTES_PREF_KEY, on ? "1" : "0"); } catch { /* no-op */ }
|
||||
}
|
||||
let showNotes = readNotesPref();
|
||||
|
||||
// Jurisdiction display prefix for the proceeding-summary chip + the
|
||||
// trigger-event placeholder. Same forum slugs the .proceeding-group
|
||||
// `data-forum` attribute carries in verfahrensablauf.tsx /
|
||||
@@ -93,22 +80,25 @@ function showStep(n: number) {
|
||||
// gating semantics stay identical: with_amend on upc.inf.cfi is
|
||||
// nested under with_ccr (R.30 is only available with a CCR);
|
||||
// upc.rev.cfi exposes with_amend + with_cci as two independent
|
||||
// gates. R.19 Einspruch is NOT flag-gated (mig 098, m's 2026-05-18
|
||||
// call): it's just an always-available optional submission, so it
|
||||
// has no checkbox.
|
||||
// gates; with_po (RoP 19.1, mig 095) gates the optional preliminary
|
||||
// objection rule on both inf and rev.
|
||||
function readFlags(): string[] {
|
||||
const ccr = document.getElementById("ccr-flag") as HTMLInputElement | null;
|
||||
const infAmend = document.getElementById("inf-amend-flag") as HTMLInputElement | null;
|
||||
const infPo = document.getElementById("inf-po-flag") as HTMLInputElement | null;
|
||||
const revAmend = document.getElementById("rev-amend-flag") as HTMLInputElement | null;
|
||||
const revCci = document.getElementById("rev-cci-flag") as HTMLInputElement | null;
|
||||
const revPo = document.getElementById("rev-po-flag") as HTMLInputElement | null;
|
||||
const flags: string[] = [];
|
||||
if (selectedType === "upc.inf.cfi") {
|
||||
if (ccr?.checked) flags.push("with_ccr");
|
||||
if (ccr?.checked && infAmend?.checked) flags.push("with_amend");
|
||||
if (infPo?.checked) flags.push("with_po");
|
||||
}
|
||||
if (selectedType === "upc.rev.cfi") {
|
||||
if (revAmend?.checked) flags.push("with_amend");
|
||||
if (revCci?.checked) flags.push("with_cci");
|
||||
if (revPo?.checked) flags.push("with_po");
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
@@ -180,8 +170,8 @@ function renderResults(data: DeadlineResponse) {
|
||||
</div>`;
|
||||
|
||||
const bodyHtml = procedureView === "columns"
|
||||
? renderColumnsBody(data, { showNotes })
|
||||
: renderTimelineBody(data, { showParty: true, showNotes });
|
||||
? renderColumnsBody(data)
|
||||
: renderTimelineBody(data);
|
||||
|
||||
container.innerHTML = headerHtml + bodyHtml;
|
||||
if (printBtn) printBtn.style.display = "block";
|
||||
@@ -210,8 +200,10 @@ function syncFlagRows() {
|
||||
};
|
||||
show("ccr-flag-row", selectedType === "upc.inf.cfi");
|
||||
show("inf-amend-flag-row", selectedType === "upc.inf.cfi");
|
||||
show("inf-po-flag-row", selectedType === "upc.inf.cfi");
|
||||
show("rev-amend-flag-row", selectedType === "upc.rev.cfi");
|
||||
show("rev-cci-flag-row", selectedType === "upc.rev.cfi");
|
||||
show("rev-po-flag-row", selectedType === "upc.rev.cfi");
|
||||
syncInfAmendEnabled();
|
||||
}
|
||||
|
||||
@@ -305,25 +297,13 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
syncInfAmendEnabled();
|
||||
scheduleCalc(0);
|
||||
});
|
||||
(["inf-amend-flag", "rev-amend-flag", "rev-cci-flag"]).forEach((id) => {
|
||||
(["inf-amend-flag", "inf-po-flag", "rev-amend-flag", "rev-cci-flag", "rev-po-flag"]).forEach((id) => {
|
||||
const cb = document.getElementById(id) as HTMLInputElement | null;
|
||||
if (cb) cb.addEventListener("change", () => scheduleCalc(0));
|
||||
});
|
||||
|
||||
document.getElementById("fristen-print-btn")?.addEventListener("click", () => window.print());
|
||||
|
||||
// Notes toggle — restores last preference on load + re-renders when
|
||||
// the user flips it. Lives in the same toggle bar as the view picker.
|
||||
const notesShowCb = document.getElementById("fristen-notes-show") as HTMLInputElement | null;
|
||||
if (notesShowCb) {
|
||||
notesShowCb.checked = showNotes;
|
||||
notesShowCb.addEventListener("change", () => {
|
||||
showNotes = notesShowCb.checked;
|
||||
writeNotesPref(showNotes);
|
||||
if (lastResponse) renderResults(lastResponse);
|
||||
});
|
||||
}
|
||||
|
||||
initViewToggle();
|
||||
|
||||
onLangChange(() => {
|
||||
|
||||
@@ -219,13 +219,6 @@ export interface CardOpts {
|
||||
// verfahrensablauf abstract-browse surface keeps editable=false because
|
||||
// there's no anchor-override state on that page in Slice 1.
|
||||
editable?: boolean;
|
||||
// showNotes controls how the per-rule descriptive notes render:
|
||||
// true → expanded `<div class="timeline-notes">…</div>` below the card
|
||||
// false → compact ⓘ icon next to the meta line, full text on hover
|
||||
// (browser-native `title` attribute) and screen-reader-readable
|
||||
// Page shells expose a toggle ("Hinweise anzeigen") that flips this and
|
||||
// re-renders. Default false — notes are noisy on long timelines.
|
||||
showNotes?: boolean;
|
||||
}
|
||||
|
||||
export function deadlineCardHtml(dl: CalculatedDeadline, opts: CardOpts): string {
|
||||
@@ -271,19 +264,14 @@ export function deadlineCardHtml(dl: CalculatedDeadline, opts: CardOpts): string
|
||||
}
|
||||
|
||||
const noteText = getLang() === "en" ? (dl.notesEN || dl.notes) : dl.notes;
|
||||
const showNotes = opts.showNotes === true;
|
||||
const notesBlock = noteText && showNotes
|
||||
const notes = noteText
|
||||
? `<div class="timeline-notes">${noteText}</div>`
|
||||
: "";
|
||||
const noteHint = noteText && !showNotes
|
||||
? `<span class="timeline-note-hint" tabindex="0" role="note" aria-label="${escAttr(noteText)}" title="${escAttr(noteText)}">ⓘ</span>`
|
||||
: "";
|
||||
|
||||
const meta = (opts.showParty || ruleRef || noteHint)
|
||||
const meta = (opts.showParty || ruleRef)
|
||||
? `<div class="timeline-meta">
|
||||
${opts.showParty ? partyBadge(dl.party) : ""}
|
||||
${ruleRef}
|
||||
${noteHint}
|
||||
</div>`
|
||||
: "";
|
||||
|
||||
@@ -296,7 +284,7 @@ export function deadlineCardHtml(dl: CalculatedDeadline, opts: CardOpts): string
|
||||
</div>
|
||||
${meta}
|
||||
${adjustedNote}
|
||||
${notesBlock}`;
|
||||
${notes}`;
|
||||
}
|
||||
|
||||
export function renderTimelineBody(data: DeadlineResponse, opts: CardOpts = { showParty: true }): string {
|
||||
@@ -370,7 +358,7 @@ export function renderColumnsBody(data: DeadlineResponse, opts: Omit<CardOpts, "
|
||||
unscheduledKeys.sort();
|
||||
const keys = [...datedKeys, ...unscheduledKeys];
|
||||
|
||||
const cardOpts: CardOpts = { showParty: false, editable: opts.editable, showNotes: opts.showNotes };
|
||||
const cardOpts: CardOpts = { showParty: false, editable: opts.editable };
|
||||
|
||||
const renderCell = (items: CalculatedDeadline[]): string => {
|
||||
if (items.length === 0) {
|
||||
|
||||
@@ -65,21 +65,12 @@ const UPC_TYPES: ProceedingDef[] = [
|
||||
{ code: "upc.apl.order", i18nKey: "deadlines.upc.apl.order", name: "Berufung Anordnungen" },
|
||||
];
|
||||
|
||||
// DE proceedings split by type (Verletzung / Nichtigkeit) per m's
|
||||
// 2026-05-18 ask. Labels are parallel: <court> (<procedural role>),
|
||||
// so a user scanning the picker sees the instance-and-role at a glance
|
||||
// without one tile reading "Berufung OLG" and another "Nichtigkeits-
|
||||
// verfahren". Sub-group headers convey the type grouping. Combined-
|
||||
// timeline behaviour (LG→OLG→BGH as one calc) is filed as m/paliad#41.
|
||||
const DE_INF_TYPES: ProceedingDef[] = [
|
||||
{ code: "de.inf.lg", i18nKey: "deadlines.de.inf.lg", name: "LG (1. Instanz)" },
|
||||
{ code: "de.inf.olg", i18nKey: "deadlines.de.inf.olg", name: "OLG (Berufung)" },
|
||||
{ code: "de.inf.bgh", i18nKey: "deadlines.de.inf.bgh", name: "BGH (Revision / NZB)" },
|
||||
];
|
||||
|
||||
const DE_NULL_TYPES: ProceedingDef[] = [
|
||||
{ code: "de.null.bpatg", i18nKey: "deadlines.de.null.bpatg", name: "BPatG (1. Instanz)" },
|
||||
{ code: "de.null.bgh", i18nKey: "deadlines.de.null.bgh", name: "BGH (Berufung)" },
|
||||
const DE_TYPES: ProceedingDef[] = [
|
||||
{ code: "de.inf.lg", i18nKey: "deadlines.de.inf.lg", name: "Verletzungsklage (LG)" },
|
||||
{ code: "de.inf.olg", i18nKey: "deadlines.de.inf.olg", name: "Berufung OLG" },
|
||||
{ code: "de.inf.bgh", i18nKey: "deadlines.de.inf.bgh", name: "Revision/NZB BGH" },
|
||||
{ code: "de.null.bpatg", i18nKey: "deadlines.de.null.bpatg", name: "Nichtigkeitsverfahren" },
|
||||
{ code: "de.null.bgh", i18nKey: "deadlines.de.null.bgh", name: "Berufung BGH (Nichtigk.)" },
|
||||
];
|
||||
|
||||
const EPA_TYPES: ProceedingDef[] = [
|
||||
@@ -434,17 +425,8 @@ export function renderFristenrechner(): string {
|
||||
|
||||
<div className="proceeding-group" data-forum="de">
|
||||
<h4 data-i18n="deadlines.de">Deutsche Gerichte</h4>
|
||||
<div className="proceeding-subgroup">
|
||||
<h5 className="proceeding-subgroup-heading" data-i18n="deadlines.de.group.inf">Verletzungsverfahren</h5>
|
||||
<div className="proceeding-btns">
|
||||
{DE_INF_TYPES.map((p) => proceedingBtn(p))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="proceeding-subgroup">
|
||||
<h5 className="proceeding-subgroup-heading" data-i18n="deadlines.de.group.null">Nichtigkeitsverfahren</h5>
|
||||
<div className="proceeding-btns">
|
||||
{DE_NULL_TYPES.map((p) => proceedingBtn(p))}
|
||||
</div>
|
||||
<div className="proceeding-btns">
|
||||
{DE_TYPES.map((p) => proceedingBtn(p))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -512,6 +494,12 @@ export function renderFristenrechner(): string {
|
||||
<span data-i18n="deadlines.flag.inf_amend">Mit Antrag auf Patentänderung (R.30)</span>
|
||||
</label>
|
||||
</div>
|
||||
<div className="date-field-row" id="inf-po-flag-row" style="display:none">
|
||||
<label className="date-label">
|
||||
<input type="checkbox" id="inf-po-flag" />
|
||||
<span data-i18n="deadlines.flag.inf_po">Mit Einspruch (R.19)</span>
|
||||
</label>
|
||||
</div>
|
||||
<div className="date-field-row" id="rev-amend-flag-row" style="display:none">
|
||||
<label className="date-label">
|
||||
<input type="checkbox" id="rev-amend-flag" />
|
||||
@@ -524,6 +512,12 @@ export function renderFristenrechner(): string {
|
||||
<span data-i18n="deadlines.flag.rev_cci">Mit Verletzungswiderklage (R.49.2.b)</span>
|
||||
</label>
|
||||
</div>
|
||||
<div className="date-field-row" id="rev-po-flag-row" style="display:none">
|
||||
<label className="date-label">
|
||||
<input type="checkbox" id="rev-po-flag" />
|
||||
<span data-i18n="deadlines.flag.rev_po">Mit Einspruch (R.19 i.V.m. R.46)</span>
|
||||
</label>
|
||||
</div>
|
||||
<button type="button" id="calculate-btn" className="calculate-btn" data-i18n="deadlines.calculate">
|
||||
Fristen berechnen
|
||||
</button>
|
||||
@@ -546,10 +540,6 @@ export function renderFristenrechner(): string {
|
||||
<input type="radio" name="fristen-view" value="timeline" />
|
||||
<span data-i18n="deadlines.view.timeline">Zeitstrahl</span>
|
||||
</label>
|
||||
<label className="fristen-notes-option">
|
||||
<input type="checkbox" id="fristen-notes-show" />
|
||||
<span data-i18n="deadlines.notes.show">Hinweise anzeigen</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div id="timeline-container">
|
||||
|
||||
@@ -931,8 +931,6 @@ export type I18nKey =
|
||||
| "deadlines.court.set"
|
||||
| "deadlines.date.edit.hint"
|
||||
| "deadlines.de"
|
||||
| "deadlines.de.group.inf"
|
||||
| "deadlines.de.group.null"
|
||||
| "deadlines.de.inf.bgh"
|
||||
| "deadlines.de.inf.lg"
|
||||
| "deadlines.de.inf.olg"
|
||||
@@ -1040,8 +1038,10 @@ export type I18nKey =
|
||||
| "deadlines.filter.today"
|
||||
| "deadlines.flag.ccr"
|
||||
| "deadlines.flag.inf_amend"
|
||||
| "deadlines.flag.inf_po"
|
||||
| "deadlines.flag.rev_amend"
|
||||
| "deadlines.flag.rev_cci"
|
||||
| "deadlines.flag.rev_po"
|
||||
| "deadlines.form.approval_hint"
|
||||
| "deadlines.heading"
|
||||
| "deadlines.inbox.all"
|
||||
@@ -1069,7 +1069,6 @@ export type I18nKey =
|
||||
| "deadlines.neu.submit"
|
||||
| "deadlines.neu.subtitle"
|
||||
| "deadlines.neu.title"
|
||||
| "deadlines.notes.show"
|
||||
| "deadlines.optional.badge"
|
||||
| "deadlines.party.both"
|
||||
| "deadlines.party.both.label"
|
||||
|
||||
@@ -3075,25 +3075,6 @@ input[type="range"]::-moz-range-thumb {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
/* Sub-group inside a .proceeding-group — used today by the DE block
|
||||
to split Verletzungsverfahren tiles from Nichtigkeitsverfahren tiles
|
||||
under one "Deutsche Gerichte" h4. Heading is one tier below the h4
|
||||
(mixed-case, no upper-tracking) so the two-level hierarchy reads at
|
||||
a glance. */
|
||||
.proceeding-subgroup {
|
||||
margin-top: 0.6rem;
|
||||
}
|
||||
|
||||
.proceeding-subgroup:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.proceeding-subgroup-heading {
|
||||
font-size: 0.78rem;
|
||||
font-weight: 600;
|
||||
color: var(--color-text);
|
||||
margin: 0 0 0.35rem 0;
|
||||
}
|
||||
|
||||
.proceeding-btns {
|
||||
display: flex;
|
||||
@@ -3441,49 +3422,6 @@ input[type="range"]::-moz-range-thumb {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Notes toggle — checkbox affordance in the view-toggle bar that flips
|
||||
per-card descriptive notes between compact (ⓘ tooltip icon) and
|
||||
expanded (timeline-notes block). Sits with a leading separator so it
|
||||
reads as a distinct control from the radio view picker. */
|
||||
.fristen-notes-option {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.35rem;
|
||||
cursor: pointer;
|
||||
color: var(--color-text);
|
||||
margin-left: auto;
|
||||
padding-left: 0.75rem;
|
||||
border-left: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
.fristen-notes-option input[type=checkbox] {
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Compact note hint — sits in the timeline-meta line when the notes
|
||||
toggle is off. Native browser tooltip via title= attribute carries
|
||||
the full text on hover; tabindex=0 + aria-label make it
|
||||
keyboard / screen-reader accessible. */
|
||||
.timeline-note-hint {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 1.1rem;
|
||||
height: 1.1rem;
|
||||
border-radius: 50%;
|
||||
font-size: 0.85rem;
|
||||
color: var(--color-text-muted);
|
||||
cursor: help;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.timeline-note-hint:hover,
|
||||
.timeline-note-hint:focus-visible {
|
||||
color: var(--color-text);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* Fristenrechner — three-column lane view (Proactive | Court | Reactive).
|
||||
Each lane is independently date-ordered; party=both rows render below
|
||||
as full-width spans because they apply to all sides. */
|
||||
|
||||
@@ -40,21 +40,12 @@ const UPC_TYPES: ProceedingDef[] = [
|
||||
{ code: "upc.apl.order", i18nKey: "deadlines.upc.apl.order", name: "Berufung Anordnungen" },
|
||||
];
|
||||
|
||||
// DE proceedings split by type (Verletzung / Nichtigkeit) per m's
|
||||
// 2026-05-18 ask. Labels are parallel: <court> (<procedural role>),
|
||||
// so a user scanning the picker sees the instance-and-role at a glance
|
||||
// without one tile reading "Berufung OLG" and another "Nichtigkeits-
|
||||
// verfahren". Sub-group headers convey the type grouping. Combined-
|
||||
// timeline behaviour (LG→OLG→BGH as one calc) is filed as m/paliad#41.
|
||||
const DE_INF_TYPES: ProceedingDef[] = [
|
||||
{ code: "de.inf.lg", i18nKey: "deadlines.de.inf.lg", name: "LG (1. Instanz)" },
|
||||
{ code: "de.inf.olg", i18nKey: "deadlines.de.inf.olg", name: "OLG (Berufung)" },
|
||||
{ code: "de.inf.bgh", i18nKey: "deadlines.de.inf.bgh", name: "BGH (Revision / NZB)" },
|
||||
];
|
||||
|
||||
const DE_NULL_TYPES: ProceedingDef[] = [
|
||||
{ code: "de.null.bpatg", i18nKey: "deadlines.de.null.bpatg", name: "BPatG (1. Instanz)" },
|
||||
{ code: "de.null.bgh", i18nKey: "deadlines.de.null.bgh", name: "BGH (Berufung)" },
|
||||
const DE_TYPES: ProceedingDef[] = [
|
||||
{ code: "de.inf.lg", i18nKey: "deadlines.de.inf.lg", name: "Verletzungsklage (LG)" },
|
||||
{ code: "de.inf.olg", i18nKey: "deadlines.de.inf.olg", name: "Berufung OLG" },
|
||||
{ code: "de.inf.bgh", i18nKey: "deadlines.de.inf.bgh", name: "Revision/NZB BGH" },
|
||||
{ code: "de.null.bpatg", i18nKey: "deadlines.de.null.bpatg", name: "Nichtigkeitsverfahren" },
|
||||
{ code: "de.null.bgh", i18nKey: "deadlines.de.null.bgh", name: "Berufung BGH (Nichtigk.)" },
|
||||
];
|
||||
|
||||
const EPA_TYPES: ProceedingDef[] = [
|
||||
@@ -117,17 +108,8 @@ export function renderVerfahrensablauf(): string {
|
||||
|
||||
<div className="proceeding-group" data-forum="de">
|
||||
<h4 data-i18n="deadlines.de">Deutsche Gerichte</h4>
|
||||
<div className="proceeding-subgroup">
|
||||
<h5 className="proceeding-subgroup-heading" data-i18n="deadlines.de.group.inf">Verletzungsverfahren</h5>
|
||||
<div className="proceeding-btns">
|
||||
{DE_INF_TYPES.map((p) => proceedingBtn(p))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="proceeding-subgroup">
|
||||
<h5 className="proceeding-subgroup-heading" data-i18n="deadlines.de.group.null">Nichtigkeitsverfahren</h5>
|
||||
<div className="proceeding-btns">
|
||||
{DE_NULL_TYPES.map((p) => proceedingBtn(p))}
|
||||
</div>
|
||||
<div className="proceeding-btns">
|
||||
{DE_TYPES.map((p) => proceedingBtn(p))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -191,6 +173,12 @@ export function renderVerfahrensablauf(): string {
|
||||
<span data-i18n="deadlines.flag.inf_amend">Mit Antrag auf Patentänderung (R.30)</span>
|
||||
</label>
|
||||
</div>
|
||||
<div className="date-field-row" id="inf-po-flag-row" style="display:none">
|
||||
<label className="date-label">
|
||||
<input type="checkbox" id="inf-po-flag" />
|
||||
<span data-i18n="deadlines.flag.inf_po">Mit Einspruch (R.19)</span>
|
||||
</label>
|
||||
</div>
|
||||
<div className="date-field-row" id="rev-amend-flag-row" style="display:none">
|
||||
<label className="date-label">
|
||||
<input type="checkbox" id="rev-amend-flag" />
|
||||
@@ -203,6 +191,12 @@ export function renderVerfahrensablauf(): string {
|
||||
<span data-i18n="deadlines.flag.rev_cci">Mit Verletzungswiderklage (R.49.2.b)</span>
|
||||
</label>
|
||||
</div>
|
||||
<div className="date-field-row" id="rev-po-flag-row" style="display:none">
|
||||
<label className="date-label">
|
||||
<input type="checkbox" id="rev-po-flag" />
|
||||
<span data-i18n="deadlines.flag.rev_po">Mit Einspruch (R.19 i.V.m. R.46)</span>
|
||||
</label>
|
||||
</div>
|
||||
<button type="button" id="calculate-btn" className="calculate-btn" data-i18n="deadlines.calculate">
|
||||
Fristen berechnen
|
||||
</button>
|
||||
@@ -225,10 +219,6 @@ export function renderVerfahrensablauf(): string {
|
||||
<input type="radio" name="fristen-view" value="timeline" />
|
||||
<span data-i18n="deadlines.view.timeline">Zeitstrahl</span>
|
||||
</label>
|
||||
<label className="fristen-notes-option">
|
||||
<input type="checkbox" id="fristen-notes-show" />
|
||||
<span data-i18n="deadlines.notes.show">Hinweise anzeigen</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div id="timeline-container">
|
||||
|
||||
@@ -240,17 +240,13 @@ BEGIN
|
||||
v_bad_shape;
|
||||
END IF;
|
||||
|
||||
-- 6.2 No NULL submission_code on active+published rows that BELONG
|
||||
-- to a proceeding. Orphan rows (`proceeding_type_id IS NULL`)
|
||||
-- are cross-cutting rules without a fixed proceeding home
|
||||
-- (Wiedereinsetzung, Schriftsatznachreichung, etc.) — they
|
||||
-- legitimately carry NULL submission_code because there's no
|
||||
-- proceeding to prefix with. Exempt them.
|
||||
-- 6.2 No NULL submission_code on active+published rows. The column
|
||||
-- is nullable for legacy reasons, but every live row should
|
||||
-- carry a code after the prefix step.
|
||||
SELECT count(*) INTO v_null_codes
|
||||
FROM paliad.deadline_rules
|
||||
WHERE is_active = true
|
||||
AND lifecycle_state = 'published'
|
||||
AND proceeding_type_id IS NOT NULL
|
||||
AND submission_code IS NULL;
|
||||
IF v_null_codes <> 0 THEN
|
||||
RAISE EXCEPTION
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
-- Revert mig 098 — restore the with_po condition_expr (mig 095 shape).
|
||||
-- audit_reason required: set via SET LOCAL paliad.audit_reason in tooling.
|
||||
|
||||
UPDATE paliad.deadline_rules dr
|
||||
SET condition_expr = '{"flag":"with_po"}'::jsonb
|
||||
FROM paliad.proceeding_types pt
|
||||
WHERE dr.proceeding_type_id = pt.id
|
||||
AND pt.code IN ('upc.inf.cfi', 'upc.rev.cfi')
|
||||
AND dr.rule_code = 'RoP.019.1'
|
||||
AND dr.condition_expr IS NULL;
|
||||
@@ -1,34 +0,0 @@
|
||||
-- t-paliad-207 — drop the `with_po` flag from the two RoP 19 rules.
|
||||
-- m's call 2026-05-18 (interactive session): the Einspruch (R. 19) is
|
||||
-- not flag-gated — it's just an optional submission the defendant can
|
||||
-- always make, triggered by the SoC. Same reasoning that drove the
|
||||
-- always-fire decision for the appeal-spawn rules in t-paliad-203 F2.3
|
||||
-- ("appeal is always a possibility").
|
||||
--
|
||||
-- Net effect: the calculator will surface the R.19 row on every UPC_INF
|
||||
-- / UPC_REV calc as an optional row (priority='optional' already set
|
||||
-- by mig 095, unchanged here). The save-modal pre-uncheck behaviour
|
||||
-- for optional priority handles the "user opts in" gesture without a
|
||||
-- separate flag.
|
||||
--
|
||||
-- Two rows updated; pinned by proceeding code so this stays correct
|
||||
-- after any rule-id reshuffle. Idempotent: the WHERE clause matches
|
||||
-- the live shape, so re-apply is a no-op.
|
||||
--
|
||||
-- audit_reason set_config required at the top — the mig 079 trigger
|
||||
-- on paliad.deadline_rules raises EXCEPTION 'audit reason required'
|
||||
-- on any UPDATE without it. Original mig 099 author missed this and
|
||||
-- crash-looped paliad prod; this is the recovery patch.
|
||||
|
||||
SELECT set_config(
|
||||
'paliad.audit_reason',
|
||||
'mig 099: drop with_po condition_expr on the two RoP.019.1 rows — m''s call 2026-05-18 (t-paliad-207 interactive session), R.19 Einspruch is always-available not flag-gated',
|
||||
true);
|
||||
|
||||
UPDATE paliad.deadline_rules dr
|
||||
SET condition_expr = NULL
|
||||
FROM paliad.proceeding_types pt
|
||||
WHERE dr.proceeding_type_id = pt.id
|
||||
AND pt.code IN ('upc.inf.cfi', 'upc.rev.cfi')
|
||||
AND dr.rule_code = 'RoP.019.1'
|
||||
AND dr.condition_expr::text LIKE '%with_po%';
|
||||
@@ -1,26 +0,0 @@
|
||||
-- Revert mig 100 — remove the upc.inf.cfi.ccr informational rule and
|
||||
-- restore the sequence_order values of def_to_ccr / app_to_amend.
|
||||
|
||||
SELECT set_config(
|
||||
'paliad.audit_reason',
|
||||
'mig 100 down: revert upc.inf.cfi.ccr informational rule + sequence reshuffle',
|
||||
true);
|
||||
|
||||
UPDATE paliad.deadline_rules
|
||||
SET sequence_order = 12
|
||||
WHERE submission_code = 'upc.inf.cfi.app_to_amend'
|
||||
AND proceeding_type_id = 8
|
||||
AND lifecycle_state = 'published'
|
||||
AND sequence_order = 13;
|
||||
|
||||
UPDATE paliad.deadline_rules
|
||||
SET sequence_order = 11
|
||||
WHERE submission_code = 'upc.inf.cfi.def_to_ccr'
|
||||
AND proceeding_type_id = 8
|
||||
AND lifecycle_state = 'published'
|
||||
AND sequence_order = 12;
|
||||
|
||||
DELETE FROM paliad.deadline_rules
|
||||
WHERE submission_code = 'upc.inf.cfi.ccr'
|
||||
AND proceeding_type_id = 8
|
||||
AND lifecycle_state = 'published';
|
||||
@@ -1,97 +0,0 @@
|
||||
-- t-paliad-207 — make the Nichtigkeitswiderklage (CCR) visible in the
|
||||
-- calculator output when the `with_ccr` flag is set. m's observation
|
||||
-- 2026-05-18 (interactive session): toggling "Mit Nichtigkeitswider-
|
||||
-- klage" surfaces the response rules (def_to_ccr, reply, rejoin, …)
|
||||
-- but the triggering event itself — the act of filing the CCR — is
|
||||
-- invisible. Per R.25 VerfO the CCR is filed AS PART OF the Statement
|
||||
-- of Defence with the same 3-month deadline, so the corpus author
|
||||
-- (mig 028) skipped it. UX is the problem: users see consequences
|
||||
-- without the cause.
|
||||
--
|
||||
-- Net effect: a new `upc.inf.cfi.ccr` row with priority='informational'
|
||||
-- renders the CCR as a notice card on the timeline (no save action,
|
||||
-- no extra deadline-to-track; the SoD's deadline already covers it).
|
||||
-- Date is identical to the SoD (3 months from SoC, same anchor +
|
||||
-- duration). condition_expr={"flag":"with_ccr"} so the row only appears
|
||||
-- when the user has flagged that a CCR is being filed.
|
||||
--
|
||||
-- Sequence reshuffle: inserting at sequence_order=11 pushes
|
||||
-- def_to_ccr 11→12 and app_to_amend 12→13 so the timeline reads
|
||||
-- SoD → CCR → def_to_ccr → app_to_amend (cause before effect). The
|
||||
-- two UPDATEs are guarded by the SOURCE values so re-apply is a no-op.
|
||||
--
|
||||
-- audit_reason set_config required at the top — the deadline_rules
|
||||
-- audit trigger raises EXCEPTION 'audit reason required' on any
|
||||
-- mutation without it (cf. mig 099 hotfix history).
|
||||
--
|
||||
-- Idempotency:
|
||||
-- * INSERT uses NOT EXISTS keyed on (proceeding_type_id,
|
||||
-- submission_code, lifecycle_state='published').
|
||||
-- * UPDATEs are guarded by current sequence_order value.
|
||||
|
||||
SELECT set_config(
|
||||
'paliad.audit_reason',
|
||||
'mig 100: add upc.inf.cfi.ccr informational rule so CCR filing event is visible when with_ccr flag is set (m''s 2026-05-18 ask, t-paliad-207 interactive session)',
|
||||
true);
|
||||
|
||||
INSERT INTO paliad.deadline_rules
|
||||
(proceeding_type_id, parent_id, submission_code, name, name_en,
|
||||
description, primary_party, event_type,
|
||||
duration_value, duration_unit, timing,
|
||||
rule_code, deadline_notes, deadline_notes_en, sequence_order,
|
||||
is_spawn, spawn_proceeding_type_id, spawn_label,
|
||||
is_active, legal_source, is_bilateral,
|
||||
condition_expr, priority, is_court_set, lifecycle_state)
|
||||
SELECT
|
||||
8,
|
||||
(SELECT id FROM paliad.deadline_rules
|
||||
WHERE submission_code = 'upc.inf.cfi.soc'
|
||||
AND proceeding_type_id = 8
|
||||
AND lifecycle_state = 'published'
|
||||
AND is_active = true),
|
||||
'upc.inf.cfi.ccr',
|
||||
'Nichtigkeitswiderklage',
|
||||
'Counterclaim for Revocation',
|
||||
'Widerklage des Beklagten auf Nichtigkeit des Klagepatents. Wird gemeinsam mit der Klageerwiderung (Statement of Defence) eingereicht (R.25 VerfO); selbe Frist von 3 Monaten ab Zustellung der Klage. Eigener adversarialer Schriftsatz, der die Folge-Schriftsätze (Erwiderung auf Nichtigkeitswiderklage, Replik, Duplik) auslöst.',
|
||||
'defendant',
|
||||
'filing',
|
||||
3,
|
||||
'months',
|
||||
'after',
|
||||
'RoP.025',
|
||||
'Wird mit der Klageerwiderung eingereicht (R.25 VerfO); kein separater Fristtermin — selbes Datum wie die Klageerwiderung. Wird informativ angezeigt, damit der auslösende Schriftsatz für die Folgefristen sichtbar bleibt.',
|
||||
'Filed together with the Statement of Defence (RoP 25); no separate deadline — same date as the SoD. Surfaced informationally so the triggering submission for the downstream deadlines is visible.',
|
||||
11,
|
||||
false,
|
||||
NULL,
|
||||
NULL,
|
||||
true,
|
||||
'UPC.RoP.25.1',
|
||||
false,
|
||||
'{"flag":"with_ccr"}'::jsonb,
|
||||
'informational',
|
||||
false,
|
||||
'published'
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM paliad.deadline_rules
|
||||
WHERE submission_code = 'upc.inf.cfi.ccr'
|
||||
AND proceeding_type_id = 8
|
||||
AND lifecycle_state = 'published');
|
||||
|
||||
-- Sequence reshuffle: bump def_to_ccr and app_to_amend by 1 so the
|
||||
-- new ccr row at 11 sits between SoD (10) and def_to_ccr. Guarded by
|
||||
-- the source values to keep idempotency.
|
||||
|
||||
UPDATE paliad.deadline_rules
|
||||
SET sequence_order = 12
|
||||
WHERE submission_code = 'upc.inf.cfi.def_to_ccr'
|
||||
AND proceeding_type_id = 8
|
||||
AND lifecycle_state = 'published'
|
||||
AND sequence_order = 11;
|
||||
|
||||
UPDATE paliad.deadline_rules
|
||||
SET sequence_order = 13
|
||||
WHERE submission_code = 'upc.inf.cfi.app_to_amend'
|
||||
AND proceeding_type_id = 8
|
||||
AND lifecycle_state = 'published'
|
||||
AND sequence_order = 12;
|
||||
@@ -1,52 +0,0 @@
|
||||
-- Revert mig 101 — restore the bracket-bearing Einspruch names and
|
||||
-- flip the CCR priority back to 'informational'.
|
||||
|
||||
SELECT set_config(
|
||||
'paliad.audit_reason',
|
||||
'mig 101 down: restore "Einspruch (R. 19 VerfO)" and "Einspruch (R. 19 i.V.m. R. 46 VerfO)" names + flip upc.inf.cfi.ccr priority back to informational',
|
||||
true);
|
||||
|
||||
UPDATE paliad.deadline_rules dr
|
||||
SET name_en = 'Preliminary Objection (RoP 19 in conjunction with RoP 46)'
|
||||
FROM paliad.proceeding_types pt
|
||||
WHERE dr.proceeding_type_id = pt.id
|
||||
AND pt.code = 'upc.rev.cfi'
|
||||
AND dr.submission_code = 'upc.rev.cfi.prelim'
|
||||
AND dr.lifecycle_state = 'published'
|
||||
AND dr.name_en = 'Preliminary Objection';
|
||||
|
||||
UPDATE paliad.deadline_rules dr
|
||||
SET name = 'Einspruch (R. 19 i.V.m. R. 46 VerfO)'
|
||||
FROM paliad.proceeding_types pt
|
||||
WHERE dr.proceeding_type_id = pt.id
|
||||
AND pt.code = 'upc.rev.cfi'
|
||||
AND dr.submission_code = 'upc.rev.cfi.prelim'
|
||||
AND dr.lifecycle_state = 'published'
|
||||
AND dr.name = 'Einspruch';
|
||||
|
||||
UPDATE paliad.deadline_rules dr
|
||||
SET name_en = 'Preliminary Objection (RoP 19)'
|
||||
FROM paliad.proceeding_types pt
|
||||
WHERE dr.proceeding_type_id = pt.id
|
||||
AND pt.code = 'upc.inf.cfi'
|
||||
AND dr.submission_code = 'upc.inf.cfi.prelim'
|
||||
AND dr.lifecycle_state = 'published'
|
||||
AND dr.name_en = 'Preliminary Objection';
|
||||
|
||||
UPDATE paliad.deadline_rules dr
|
||||
SET name = 'Einspruch (R. 19 VerfO)'
|
||||
FROM paliad.proceeding_types pt
|
||||
WHERE dr.proceeding_type_id = pt.id
|
||||
AND pt.code = 'upc.inf.cfi'
|
||||
AND dr.submission_code = 'upc.inf.cfi.prelim'
|
||||
AND dr.lifecycle_state = 'published'
|
||||
AND dr.name = 'Einspruch';
|
||||
|
||||
UPDATE paliad.deadline_rules dr
|
||||
SET priority = 'informational'
|
||||
FROM paliad.proceeding_types pt
|
||||
WHERE dr.proceeding_type_id = pt.id
|
||||
AND pt.code = 'upc.inf.cfi'
|
||||
AND dr.submission_code = 'upc.inf.cfi.ccr'
|
||||
AND dr.lifecycle_state = 'published'
|
||||
AND dr.priority = 'optional';
|
||||
@@ -1,89 +0,0 @@
|
||||
-- t-paliad-207 (m's interactive session) — two label/priority polish
|
||||
-- fixes on upc.inf.cfi / upc.rev.cfi:
|
||||
--
|
||||
-- 1. **CCR priority informational → optional.** m's correction
|
||||
-- 2026-05-18 18:01: the Nichtigkeitswiderklage is a substantive
|
||||
-- defensive choice the defendant makes — not just an informational
|
||||
-- notice. priority='optional' renders it as an unchecked save row
|
||||
-- the user can opt into. The fermi amend (commit e8d658a) flipping
|
||||
-- this didn't land in main — paliadin's merge of mig 100 (commit
|
||||
-- c10f8cf, merge 4ddcd28) picked up the pre-amend 'informational'
|
||||
-- version. This is the recovery.
|
||||
--
|
||||
-- 2. **Strip rule citation from Einspruch names.** m's correction
|
||||
-- 2026-05-18 18:08: every other rule name in the corpus carries
|
||||
-- the act-name without a parenthetical rule cite (Klageerwiderung,
|
||||
-- Antrag auf Patentänderung, Replik, etc.). The Einspruch rule
|
||||
-- names are the outliers:
|
||||
-- upc.inf.cfi.prelim "Einspruch (R. 19 VerfO)" → "Einspruch"
|
||||
-- upc.rev.cfi.prelim "Einspruch (R. 19 i.V.m. R. 46 VerfO)" → "Einspruch"
|
||||
-- and EN equivalents:
|
||||
-- "Preliminary Objection (RoP 19)" → "Preliminary Objection"
|
||||
-- "Preliminary Objection (RoP 19 in conjunction with RoP 46)"
|
||||
-- → "Preliminary Objection"
|
||||
-- The legal_source / rule_code columns already carry the citation
|
||||
-- and render in the deadline card's meta line, so the name stays
|
||||
-- clean. The R.46-i.V.m. distinction is preserved in the legal
|
||||
-- source field (RoP.019.1 for both — m may want to further
|
||||
-- differentiate; flagged in description text instead).
|
||||
--
|
||||
-- audit_reason set_config required at the top — the deadline_rules
|
||||
-- audit trigger raises EXCEPTION 'audit reason required' on any
|
||||
-- mutation without it (cf. mig 099 hotfix history).
|
||||
--
|
||||
-- Idempotency:
|
||||
-- * Priority UPDATE guarded on the current 'informational' value.
|
||||
-- * Name UPDATEs guarded on the current parenthetical-bearing names.
|
||||
|
||||
SELECT set_config(
|
||||
'paliad.audit_reason',
|
||||
'mig 101: flip upc.inf.cfi.ccr priority informational→optional + strip rule-cite brackets from R.19 Einspruch names on both upc.inf.cfi.prelim and upc.rev.cfi.prelim (m''s corrections 2026-05-18, t-paliad-207 interactive session)',
|
||||
true);
|
||||
|
||||
-- 1) Flip CCR priority
|
||||
UPDATE paliad.deadline_rules dr
|
||||
SET priority = 'optional'
|
||||
FROM paliad.proceeding_types pt
|
||||
WHERE dr.proceeding_type_id = pt.id
|
||||
AND pt.code = 'upc.inf.cfi'
|
||||
AND dr.submission_code = 'upc.inf.cfi.ccr'
|
||||
AND dr.lifecycle_state = 'published'
|
||||
AND dr.priority = 'informational';
|
||||
|
||||
-- 2a) Strip "(R. 19 VerfO)" from upc.inf.cfi.prelim DE/EN names
|
||||
UPDATE paliad.deadline_rules dr
|
||||
SET name = 'Einspruch'
|
||||
FROM paliad.proceeding_types pt
|
||||
WHERE dr.proceeding_type_id = pt.id
|
||||
AND pt.code = 'upc.inf.cfi'
|
||||
AND dr.submission_code = 'upc.inf.cfi.prelim'
|
||||
AND dr.lifecycle_state = 'published'
|
||||
AND dr.name = 'Einspruch (R. 19 VerfO)';
|
||||
|
||||
UPDATE paliad.deadline_rules dr
|
||||
SET name_en = 'Preliminary Objection'
|
||||
FROM paliad.proceeding_types pt
|
||||
WHERE dr.proceeding_type_id = pt.id
|
||||
AND pt.code = 'upc.inf.cfi'
|
||||
AND dr.submission_code = 'upc.inf.cfi.prelim'
|
||||
AND dr.lifecycle_state = 'published'
|
||||
AND dr.name_en = 'Preliminary Objection (RoP 19)';
|
||||
|
||||
-- 2b) Strip "(R. 19 i.V.m. R. 46 VerfO)" from upc.rev.cfi.prelim DE/EN names
|
||||
UPDATE paliad.deadline_rules dr
|
||||
SET name = 'Einspruch'
|
||||
FROM paliad.proceeding_types pt
|
||||
WHERE dr.proceeding_type_id = pt.id
|
||||
AND pt.code = 'upc.rev.cfi'
|
||||
AND dr.submission_code = 'upc.rev.cfi.prelim'
|
||||
AND dr.lifecycle_state = 'published'
|
||||
AND dr.name = 'Einspruch (R. 19 i.V.m. R. 46 VerfO)';
|
||||
|
||||
UPDATE paliad.deadline_rules dr
|
||||
SET name_en = 'Preliminary Objection'
|
||||
FROM paliad.proceeding_types pt
|
||||
WHERE dr.proceeding_type_id = pt.id
|
||||
AND pt.code = 'upc.rev.cfi'
|
||||
AND dr.submission_code = 'upc.rev.cfi.prelim'
|
||||
AND dr.lifecycle_state = 'published'
|
||||
AND dr.name_en = 'Preliminary Objection (RoP 19 in conjunction with RoP 46)';
|
||||
@@ -1,31 +0,0 @@
|
||||
-- Revert mig 102 — restore the pre-mig-102 sequence_order values
|
||||
-- (post-mig-100 state). Same two-phase swap pattern.
|
||||
|
||||
SELECT set_config(
|
||||
'paliad.audit_reason',
|
||||
'mig 102 down: restore pre-track-aware sequence_order on upc.inf.cfi rules',
|
||||
true);
|
||||
|
||||
-- Phase 1: park
|
||||
UPDATE paliad.deadline_rules SET sequence_order = 1011 WHERE submission_code = 'upc.inf.cfi.ccr' AND proceeding_type_id = 8 AND lifecycle_state = 'published' AND sequence_order = 20;
|
||||
UPDATE paliad.deadline_rules SET sequence_order = 1012 WHERE submission_code = 'upc.inf.cfi.def_to_ccr' AND proceeding_type_id = 8 AND lifecycle_state = 'published' AND sequence_order = 22;
|
||||
UPDATE paliad.deadline_rules SET sequence_order = 1013 WHERE submission_code = 'upc.inf.cfi.app_to_amend' AND proceeding_type_id = 8 AND lifecycle_state = 'published' AND sequence_order = 30;
|
||||
UPDATE paliad.deadline_rules SET sequence_order = 1020 WHERE submission_code = 'upc.inf.cfi.reply' AND proceeding_type_id = 8 AND lifecycle_state = 'published' AND sequence_order = 12;
|
||||
UPDATE paliad.deadline_rules SET sequence_order = 1021 WHERE submission_code = 'upc.inf.cfi.def_to_amend' AND proceeding_type_id = 8 AND lifecycle_state = 'published' AND sequence_order = 32;
|
||||
UPDATE paliad.deadline_rules SET sequence_order = 1022 WHERE submission_code = 'upc.inf.cfi.reply_def_ccr' AND proceeding_type_id = 8 AND lifecycle_state = 'published' AND sequence_order = 24;
|
||||
UPDATE paliad.deadline_rules SET sequence_order = 1030 WHERE submission_code = 'upc.inf.cfi.rejoin' AND proceeding_type_id = 8 AND lifecycle_state = 'published' AND sequence_order = 14;
|
||||
UPDATE paliad.deadline_rules SET sequence_order = 1031 WHERE submission_code = 'upc.inf.cfi.reply_def_amd' AND proceeding_type_id = 8 AND lifecycle_state = 'published' AND sequence_order = 34;
|
||||
UPDATE paliad.deadline_rules SET sequence_order = 1032 WHERE submission_code = 'upc.inf.cfi.rejoin_reply_ccr' AND proceeding_type_id = 8 AND lifecycle_state = 'published' AND sequence_order = 26;
|
||||
UPDATE paliad.deadline_rules SET sequence_order = 1033 WHERE submission_code = 'upc.inf.cfi.rejoin_amd' AND proceeding_type_id = 8 AND lifecycle_state = 'published' AND sequence_order = 36;
|
||||
|
||||
-- Phase 2: assign originals
|
||||
UPDATE paliad.deadline_rules SET sequence_order = 11 WHERE submission_code = 'upc.inf.cfi.ccr' AND proceeding_type_id = 8 AND lifecycle_state = 'published' AND sequence_order = 1011;
|
||||
UPDATE paliad.deadline_rules SET sequence_order = 12 WHERE submission_code = 'upc.inf.cfi.def_to_ccr' AND proceeding_type_id = 8 AND lifecycle_state = 'published' AND sequence_order = 1012;
|
||||
UPDATE paliad.deadline_rules SET sequence_order = 13 WHERE submission_code = 'upc.inf.cfi.app_to_amend' AND proceeding_type_id = 8 AND lifecycle_state = 'published' AND sequence_order = 1013;
|
||||
UPDATE paliad.deadline_rules SET sequence_order = 20 WHERE submission_code = 'upc.inf.cfi.reply' AND proceeding_type_id = 8 AND lifecycle_state = 'published' AND sequence_order = 1020;
|
||||
UPDATE paliad.deadline_rules SET sequence_order = 21 WHERE submission_code = 'upc.inf.cfi.def_to_amend' AND proceeding_type_id = 8 AND lifecycle_state = 'published' AND sequence_order = 1021;
|
||||
UPDATE paliad.deadline_rules SET sequence_order = 22 WHERE submission_code = 'upc.inf.cfi.reply_def_ccr' AND proceeding_type_id = 8 AND lifecycle_state = 'published' AND sequence_order = 1022;
|
||||
UPDATE paliad.deadline_rules SET sequence_order = 30 WHERE submission_code = 'upc.inf.cfi.rejoin' AND proceeding_type_id = 8 AND lifecycle_state = 'published' AND sequence_order = 1030;
|
||||
UPDATE paliad.deadline_rules SET sequence_order = 31 WHERE submission_code = 'upc.inf.cfi.reply_def_amd' AND proceeding_type_id = 8 AND lifecycle_state = 'published' AND sequence_order = 1031;
|
||||
UPDATE paliad.deadline_rules SET sequence_order = 32 WHERE submission_code = 'upc.inf.cfi.rejoin_reply_ccr' AND proceeding_type_id = 8 AND lifecycle_state = 'published' AND sequence_order = 1032;
|
||||
UPDATE paliad.deadline_rules SET sequence_order = 33 WHERE submission_code = 'upc.inf.cfi.rejoin_amd' AND proceeding_type_id = 8 AND lifecycle_state = 'published' AND sequence_order = 1033;
|
||||
@@ -1,211 +0,0 @@
|
||||
-- t-paliad-207 — re-sequence upc.inf.cfi rules so within any tied-date
|
||||
-- group the infringement-track responses sit ABOVE the revocation-
|
||||
-- track responses ABOVE the amendment-track responses. m's ask
|
||||
-- 2026-05-18 18:08: "the infringement parts (like Replik) should show
|
||||
-- above the part for the revocation (Erwiderung Nichtigkeitswider-
|
||||
-- klage)".
|
||||
--
|
||||
-- Three tracks coexist on upc.inf.cfi once the with_ccr / with_amend
|
||||
-- flags are set. They share calendar dates because R.29 / R.30 / R.32
|
||||
-- all key off the SoD or its descendants. The current sequence_orders
|
||||
-- (post-mig 100) interleave them; the user sees Erwiderung-zur-CCR
|
||||
-- before Replik even though Replik is the infringement-side response
|
||||
-- to the same triggering event.
|
||||
--
|
||||
-- New sequence_order assignment (preserves the soc=0, prelim=5,
|
||||
-- sod=10, ccr=11 anchors at the head; phase markers interim/oral/
|
||||
-- decision/cost_app/appeal_spawn keep their existing 40/50/60/70/80
|
||||
-- slots at the tail):
|
||||
--
|
||||
-- Old → New submission_code track date
|
||||
-- --- --- --------------- ----- ----
|
||||
-- 0 0 upc.inf.cfi.soc — D+0
|
||||
-- 5 5 upc.inf.cfi.prelim — D+1mo
|
||||
-- 10 10 upc.inf.cfi.sod infringement D+3mo
|
||||
-- 11 20 upc.inf.cfi.ccr revocation D+3mo
|
||||
-- 20 12 upc.inf.cfi.reply infringement D+5mo ← MOVED UP
|
||||
-- 12 22 upc.inf.cfi.def_to_ccr revocation D+5mo
|
||||
-- 13 30 upc.inf.cfi.app_to_amend amendment D+5mo
|
||||
-- 30 14 upc.inf.cfi.rejoin infringement D+6mo ← MOVED UP
|
||||
-- 22 24 upc.inf.cfi.reply_def_ccr revocation D+7mo
|
||||
-- 21 32 upc.inf.cfi.def_to_amend amendment D+7mo
|
||||
-- 32 26 upc.inf.cfi.rejoin_reply_ccr revocation D+8mo
|
||||
-- 31 34 upc.inf.cfi.reply_def_amd amendment D+8mo
|
||||
-- 33 36 upc.inf.cfi.rejoin_amd amendment D+9mo
|
||||
-- 40 40 upc.inf.cfi.interim phase later
|
||||
-- 50 50 upc.inf.cfi.oral phase later
|
||||
-- 60 60 upc.inf.cfi.decision phase later
|
||||
-- 70 70 upc.inf.cfi.cost_app phase later
|
||||
-- 80 80 upc.inf.cfi.appeal_spawn phase later
|
||||
--
|
||||
-- Order within each tied-date group after the reshuffle:
|
||||
-- D+3mo: sod(10), ccr(20) — SoD then its CCR
|
||||
-- D+5mo: reply(12), def_to_ccr(22), app_to_amend(30) — inf → rev → amd
|
||||
-- D+7mo: reply_def_ccr(24), def_to_amend(32) — rev → amd
|
||||
-- D+8mo: rejoin_reply_ccr(26), reply_def_amd(34) — rev → amd
|
||||
--
|
||||
-- (no infringement-track rule at +7mo or +8mo so revocation leads
|
||||
-- those dates; rejoin sits alone at +6mo so it has no peers to order
|
||||
-- against.)
|
||||
--
|
||||
-- audit_reason set_config required at the top — the deadline_rules
|
||||
-- audit trigger raises EXCEPTION 'audit reason required' on any
|
||||
-- mutation without it (cf. mig 099 hotfix history).
|
||||
--
|
||||
-- Idempotency: every UPDATE is guarded by both the submission_code
|
||||
-- AND the SOURCE sequence_order, so re-apply is a no-op once the new
|
||||
-- numbers are in place.
|
||||
|
||||
SELECT set_config(
|
||||
'paliad.audit_reason',
|
||||
'mig 102: re-sequence upc.inf.cfi rules track-aware (infringement → revocation → amendment within tied-date groups; m''s 2026-05-18 ask, t-paliad-207 interactive session)',
|
||||
true);
|
||||
|
||||
-- Two-phase swap to avoid sequence collisions during the UPDATE
|
||||
-- (otherwise two rules can briefly share a sequence_order if Postgres
|
||||
-- evaluates them in parallel). Phase 1: move every reshuffled rule to
|
||||
-- a high temporary number (1000+). Phase 2: assign final numbers.
|
||||
|
||||
-- ─── Phase 1: park reshuffled rules at 1000+ ────────────────────────
|
||||
|
||||
UPDATE paliad.deadline_rules
|
||||
SET sequence_order = 1011
|
||||
WHERE submission_code = 'upc.inf.cfi.ccr'
|
||||
AND proceeding_type_id = 8
|
||||
AND lifecycle_state = 'published'
|
||||
AND sequence_order = 11;
|
||||
|
||||
UPDATE paliad.deadline_rules
|
||||
SET sequence_order = 1012
|
||||
WHERE submission_code = 'upc.inf.cfi.def_to_ccr'
|
||||
AND proceeding_type_id = 8
|
||||
AND lifecycle_state = 'published'
|
||||
AND sequence_order = 12;
|
||||
|
||||
UPDATE paliad.deadline_rules
|
||||
SET sequence_order = 1013
|
||||
WHERE submission_code = 'upc.inf.cfi.app_to_amend'
|
||||
AND proceeding_type_id = 8
|
||||
AND lifecycle_state = 'published'
|
||||
AND sequence_order = 13;
|
||||
|
||||
UPDATE paliad.deadline_rules
|
||||
SET sequence_order = 1020
|
||||
WHERE submission_code = 'upc.inf.cfi.reply'
|
||||
AND proceeding_type_id = 8
|
||||
AND lifecycle_state = 'published'
|
||||
AND sequence_order = 20;
|
||||
|
||||
UPDATE paliad.deadline_rules
|
||||
SET sequence_order = 1021
|
||||
WHERE submission_code = 'upc.inf.cfi.def_to_amend'
|
||||
AND proceeding_type_id = 8
|
||||
AND lifecycle_state = 'published'
|
||||
AND sequence_order = 21;
|
||||
|
||||
UPDATE paliad.deadline_rules
|
||||
SET sequence_order = 1022
|
||||
WHERE submission_code = 'upc.inf.cfi.reply_def_ccr'
|
||||
AND proceeding_type_id = 8
|
||||
AND lifecycle_state = 'published'
|
||||
AND sequence_order = 22;
|
||||
|
||||
UPDATE paliad.deadline_rules
|
||||
SET sequence_order = 1030
|
||||
WHERE submission_code = 'upc.inf.cfi.rejoin'
|
||||
AND proceeding_type_id = 8
|
||||
AND lifecycle_state = 'published'
|
||||
AND sequence_order = 30;
|
||||
|
||||
UPDATE paliad.deadline_rules
|
||||
SET sequence_order = 1031
|
||||
WHERE submission_code = 'upc.inf.cfi.reply_def_amd'
|
||||
AND proceeding_type_id = 8
|
||||
AND lifecycle_state = 'published'
|
||||
AND sequence_order = 31;
|
||||
|
||||
UPDATE paliad.deadline_rules
|
||||
SET sequence_order = 1032
|
||||
WHERE submission_code = 'upc.inf.cfi.rejoin_reply_ccr'
|
||||
AND proceeding_type_id = 8
|
||||
AND lifecycle_state = 'published'
|
||||
AND sequence_order = 32;
|
||||
|
||||
UPDATE paliad.deadline_rules
|
||||
SET sequence_order = 1033
|
||||
WHERE submission_code = 'upc.inf.cfi.rejoin_amd'
|
||||
AND proceeding_type_id = 8
|
||||
AND lifecycle_state = 'published'
|
||||
AND sequence_order = 33;
|
||||
|
||||
-- ─── Phase 2: assign final track-aware numbers ──────────────────────
|
||||
|
||||
UPDATE paliad.deadline_rules
|
||||
SET sequence_order = 12
|
||||
WHERE submission_code = 'upc.inf.cfi.reply'
|
||||
AND proceeding_type_id = 8
|
||||
AND lifecycle_state = 'published'
|
||||
AND sequence_order = 1020;
|
||||
|
||||
UPDATE paliad.deadline_rules
|
||||
SET sequence_order = 14
|
||||
WHERE submission_code = 'upc.inf.cfi.rejoin'
|
||||
AND proceeding_type_id = 8
|
||||
AND lifecycle_state = 'published'
|
||||
AND sequence_order = 1030;
|
||||
|
||||
UPDATE paliad.deadline_rules
|
||||
SET sequence_order = 20
|
||||
WHERE submission_code = 'upc.inf.cfi.ccr'
|
||||
AND proceeding_type_id = 8
|
||||
AND lifecycle_state = 'published'
|
||||
AND sequence_order = 1011;
|
||||
|
||||
UPDATE paliad.deadline_rules
|
||||
SET sequence_order = 22
|
||||
WHERE submission_code = 'upc.inf.cfi.def_to_ccr'
|
||||
AND proceeding_type_id = 8
|
||||
AND lifecycle_state = 'published'
|
||||
AND sequence_order = 1012;
|
||||
|
||||
UPDATE paliad.deadline_rules
|
||||
SET sequence_order = 24
|
||||
WHERE submission_code = 'upc.inf.cfi.reply_def_ccr'
|
||||
AND proceeding_type_id = 8
|
||||
AND lifecycle_state = 'published'
|
||||
AND sequence_order = 1022;
|
||||
|
||||
UPDATE paliad.deadline_rules
|
||||
SET sequence_order = 26
|
||||
WHERE submission_code = 'upc.inf.cfi.rejoin_reply_ccr'
|
||||
AND proceeding_type_id = 8
|
||||
AND lifecycle_state = 'published'
|
||||
AND sequence_order = 1032;
|
||||
|
||||
UPDATE paliad.deadline_rules
|
||||
SET sequence_order = 30
|
||||
WHERE submission_code = 'upc.inf.cfi.app_to_amend'
|
||||
AND proceeding_type_id = 8
|
||||
AND lifecycle_state = 'published'
|
||||
AND sequence_order = 1013;
|
||||
|
||||
UPDATE paliad.deadline_rules
|
||||
SET sequence_order = 32
|
||||
WHERE submission_code = 'upc.inf.cfi.def_to_amend'
|
||||
AND proceeding_type_id = 8
|
||||
AND lifecycle_state = 'published'
|
||||
AND sequence_order = 1021;
|
||||
|
||||
UPDATE paliad.deadline_rules
|
||||
SET sequence_order = 34
|
||||
WHERE submission_code = 'upc.inf.cfi.reply_def_amd'
|
||||
AND proceeding_type_id = 8
|
||||
AND lifecycle_state = 'published'
|
||||
AND sequence_order = 1031;
|
||||
|
||||
UPDATE paliad.deadline_rules
|
||||
SET sequence_order = 36
|
||||
WHERE submission_code = 'upc.inf.cfi.rejoin_amd'
|
||||
AND proceeding_type_id = 8
|
||||
AND lifecycle_state = 'published'
|
||||
AND sequence_order = 1033;
|
||||
@@ -878,23 +878,14 @@ func FormatLegalSourceDisplay(src string) string {
|
||||
// caller renders the display string as plain text.
|
||||
//
|
||||
// Inputs mirror FormatLegalSourceDisplay — structured dot-separated
|
||||
// codes like UPC.RoP.23.1, UPC.UPCA.83. Sub-paragraph segments beyond
|
||||
// the law-number position are dropped; youpc resolves the page at
|
||||
// <type>.<number> granularity. The law-number is zero-padded to 3
|
||||
// digits to match how youpc stores law_number (laws-data.json carries
|
||||
// "001" / "023" / "220" forms).
|
||||
// codes like UPC.RoP.220.1, UPC.UPCA.83. Sub-paragraph segments
|
||||
// beyond the law-number position are dropped; youpc resolves the page
|
||||
// at <type>/<number> granularity.
|
||||
//
|
||||
// URL shape uses the hash-fragment form that youpc itself emits from
|
||||
// its laws-page redirect (handlers/laws.go:215+229) — the canonical
|
||||
// in-app deep link target. The `/laws/:type/:number` pretty route also
|
||||
// resolves the same page but redirects to the hash form anyway.
|
||||
//
|
||||
// UPC.RoP.23.1 → https://youpc.org/laws#UPCRoP.023
|
||||
// UPC.RoP.139 → https://youpc.org/laws#UPCRoP.139
|
||||
// UPC.RoP.220.1 → https://youpc.org/laws#UPCRoP.220
|
||||
// UPC.RoP.29.a → https://youpc.org/laws#UPCRoP.029
|
||||
// UPC.UPCA.83 → https://youpc.org/laws#UPCA.083
|
||||
// DE.ZPO.276.1 → "" (no youpc home — render display text plain)
|
||||
// UPC.RoP.220.1 → https://youpc.org/laws/UPCRoP/220
|
||||
// UPC.RoP.29.a → https://youpc.org/laws/UPCRoP/29
|
||||
// UPC.UPCA.83 → https://youpc.org/laws/UPCA/83
|
||||
// DE.ZPO.276.1 → "" (no youpc home — render display text plain)
|
||||
func BuildLegalSourceURL(src string) string {
|
||||
src = strings.TrimSpace(src)
|
||||
if src == "" {
|
||||
@@ -915,30 +906,11 @@ func BuildLegalSourceURL(src string) string {
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
number := padLawNumber(parts[2])
|
||||
number := parts[2]
|
||||
if number == "" {
|
||||
return ""
|
||||
}
|
||||
return "https://youpc.org/laws#" + lawType + "." + number
|
||||
}
|
||||
|
||||
// padLawNumber zero-pads a pure-digit law-number segment to 3 digits.
|
||||
// Non-digit-only inputs (e.g. "112a" if youpc ever ingests EPÜ Art.
|
||||
// 112a) pass through unchanged so the URL still resolves. Empty input
|
||||
// returns the empty string.
|
||||
func padLawNumber(s string) string {
|
||||
if s == "" {
|
||||
return ""
|
||||
}
|
||||
for _, c := range s {
|
||||
if c < '0' || c > '9' {
|
||||
return s
|
||||
}
|
||||
}
|
||||
if len(s) >= 3 {
|
||||
return s
|
||||
}
|
||||
return strings.Repeat("0", 3-len(s)) + s
|
||||
return "https://youpc.org/laws/" + lawType + "/" + number
|
||||
}
|
||||
|
||||
// RefreshSearchView re-populates the materialised view. Safe to call on
|
||||
|
||||
@@ -48,14 +48,13 @@ func TestBuildLegalSourceURL(t *testing.T) {
|
||||
cases := []struct {
|
||||
in, want string
|
||||
}{
|
||||
{"UPC.RoP.23.1", "https://youpc.org/laws#UPCRoP.023"},
|
||||
{"UPC.RoP.139", "https://youpc.org/laws#UPCRoP.139"},
|
||||
{"UPC.RoP.220.1", "https://youpc.org/laws#UPCRoP.220"},
|
||||
{"UPC.RoP.29.a", "https://youpc.org/laws#UPCRoP.029"},
|
||||
{"UPC.RoP.49.2.a", "https://youpc.org/laws#UPCRoP.049"},
|
||||
{"UPC.RoP.19.1", "https://youpc.org/laws#UPCRoP.019"},
|
||||
{"UPC.UPCA.83", "https://youpc.org/laws#UPCA.083"},
|
||||
{"UPC.UPCS.40.1", "https://youpc.org/laws#UPCS.040"},
|
||||
{"UPC.RoP.23.1", "https://youpc.org/laws/UPCRoP/23"},
|
||||
{"UPC.RoP.139", "https://youpc.org/laws/UPCRoP/139"},
|
||||
{"UPC.RoP.220.1", "https://youpc.org/laws/UPCRoP/220"},
|
||||
{"UPC.RoP.29.a", "https://youpc.org/laws/UPCRoP/29"},
|
||||
{"UPC.RoP.49.2.a", "https://youpc.org/laws/UPCRoP/49"},
|
||||
{"UPC.UPCA.83", "https://youpc.org/laws/UPCA/83"},
|
||||
{"UPC.UPCS.40.1", "https://youpc.org/laws/UPCS/40"},
|
||||
{"DE.PatG.82.1", ""},
|
||||
{"DE.ZPO.276.1", ""},
|
||||
{"EU.EPÜ.108", ""},
|
||||
|
||||
Reference in New Issue
Block a user