diff --git a/docs/design-procedures-workflow-tracker-2026-05-27.md b/docs/design-procedures-workflow-tracker-2026-05-27.md new file mode 100644 index 0000000..864208e --- /dev/null +++ b/docs/design-procedures-workflow-tracker-2026-05-27.md @@ -0,0 +1,510 @@ +# Design — `/tools/procedures` workflow tracker (m/paliad#152) + +**Task:** t-paliad-337 +**Gitea:** m/paliad#152 +**Inventor:** atlas (shift-1, fresh — name-recycle, not the atlas from earlier today) +**Date:** 2026-05-27 +**Branch:** `mai/atlas/inventor-extend-tools` +**Status:** Draft — coder gate held; m to ratify the remaining open questions via `AskUserQuestion` before any coder shift. + +**Builds on:** +- `docs/design-unified-procedural-events-tool-2026-05-27.md` (cronus's U0-U4 design, shipped today as `/tools/procedures`) +- `docs/design-deadline-system-revision-2026-05-27.md` §3.3 + §3.3a (atlas Phase 2 model layer + view-mode toggle) +- `docs/design-fristenrechner-overhaul-2026-05-26.md` (cronus 2026-05-26 Mode A+B+result, shipped via t-paliad-322) + +**Reframe note (2026-05-27 21:01):** the first draft of this doc overengineered the surface — three-view toggle, separate compound drawer, separate Konstellationen drawer. m re-anchored: "clean display of timelines that have potential forks the user can select. UX should be key. It should be easy to find your thing." This rewrite collapses to a single canonical shape and folds the zoom / constellation / cross-cut concepts into it. The pre-grilling §13 + the 11-Q batch in §14 of the first draft are gone — superseded by m's 4 answers in §0.2 and the smaller open-question set in §10. + +--- + +## §0 Premises + +### §0.1 What shipped today and what m hit + +`/tools/procedures` (U0-U4, knuth, m/paliad#151) is a **catalog browser**: +- 4 always-visible tabs (Verfahren wählen / Direkt suchen / Geführt / Aus Akte). +- Shared filter strip + search box at the top (markup-only in U0). +- Two output shapes — TREE (Verfahrensablauf) and LINEAR (Mode A/B result view) — bound to specific entry tabs. + +m's bugs (2026-05-27 20:43 / 20:46): + +1. 4 tabs visible → pre-form leaks across them, page feels like 4 disjoint workflows. +2. Result view fires too many rules incl. conditional-flag-off + curie's 7 compound rules. +3. Proaktiv/Gericht/Reaktiv columns are a stance grouping, not a sequence anchor. +4. No "you are here" marker. +5. Sequence isn't visualised as a sequence — flat priority groups, not chained. + +m's reframe (verbatim, 20:43): "view proceedings with all possible constellations and the sequences and determine **where we are** in that sequence and **what steps are coming next** for any given procedural event." + +Tightened by m on 21:01: + +> "clean display of timelines that have potential forks the user can select. procedural_events that act as triggers for mandatory or optional events. And there is a limited type of proceedings — a sequence of the events builds the proceeding. Some aux proceedings, some main… but a lot is connected. UX should be key. It should be easy to find your thing." + +### §0.2 The four m-answers that lock the architecture + +Asked back during the grilling round at 20:57, answered 21:01: + +| | inventor's grilling question | m's answer | what it locks | +|---|---|---|---| +| 1 | One canonical shape or still 3 views? | "I still want zoomability for one event and all events it triggers. But that can be from within the full timeline/tree as well." | **One canonical view** (full timeline/tree); zoom is an *interaction* on it, not a separate view. The Anchor / Verfahren / Konstellationen toggle is dropped. | +| 2 | What's a "fork" — scenario flags only / +optionals / everything? | "c" (everything: flags + optionals + appeal-target + court-set picks) | **Every choice point in the data is a fork.** Optionals (priority='optional') + conditional flags + appeal-target + perspective + court-set scheduling. Inline pickers. | +| 3 | "Easy to find" — timeline-as-index / search box / proceeding picker first? | "all of these — text search, filter pills, a display of the resulting proceedings timelines" | **Find = combined affordance.** Text search + filter pills + the displayed result *is* the matched proceeding timelines. The page never has chrome that isn't either the find affordance or the timelines themselves. | +| 4 | Aux proceedings inline or drillable? | "inline" | **Aux proceedings draw inline as expandable child timelines** hanging off the spawn point in the parent timeline. The full connected graph is one visible thing. | + +### §0.3 Live data the tracker has to work against + +Verified 2026-05-27 against `paliad.sequencing_rules` (231 published / 242 total): +- 110 chained (parent_id not null) — most rules in a chain. +- 78 trigger-rooted, 4 spawns (cross-PT), 47 court-set, 18 conditional (6 `with_ccr` / 4 `with_amend` / 4 `with_cci` / 4 compound `with_ccr AND with_amend`). +- Biggest single proceeding: `upc.inf.cfi` (50 rules). +- ~46 proceeding types total (UPC 35 / DE 5 / EPA 3 / DPMA 3). +- `paliad.deadlines` carries both `procedural_event_id` and `sequencing_rule_id` → Akte actuals overlay is a direct join. + +### §0.4 Scope + +**In:** redesign the `/tools/procedures` surface as a single timeline-tree view with inline forks + a combined find affordance. + +**Out:** +- Calculator changes. +- Editorial backfill (curie's t-paliad-333 owns the 7 compound rules + R.109 chain). This design is *independent* of curie's column-shape work; compound rules surface inline via parent_id like any other rule, with whatever annotation curie ships. +- `/admin/procedural-events` write surface. +- `/projects/{id}` Verlauf / SmartTimeline — cross-link only. +- youpc.org cross-repo / Outlook sync / PDF export. + +--- + +## §1 The single canonical shape + +One page. One view. Top section = find affordance. Below = matched proceeding timelines, each as an inline-forked tree, vertically stacked. + +``` +┌────────────────────────────────────────────────────────────────────┐ +│ [🔍 Suche: Klageerwiderung_____________________] │ +│ Forum: [● UPC] [DE] [EPA] [DPMA] │ +│ Verfahren: [● Verletzung] [● Widerklage] [Berufung] [Nichtigkeit] … │ +│ Partei: [Klägerseite] [● Beklagtenseite] │ +│ Akte: HL-2024-001 ▼ Stichtag: 2026-04-01 │ +│ │ +│ 2 Verfahren passen — Anker: Klageerwiderung (HL-2024-001) │ +└────────────────────────────────────────────────────────────────────┘ + +┌─ upc.inf.cfi · Verletzungsverfahren UPC ─────────────────────────┐ +│ │ +│ ● Klageerhebung (R.13) 2026-01-15 · Klg · M │ +│ │ │ +│ ▼ ● Klageerwiderung (R.23.1) 2026-04-01 · Bekl · M │ +│ │ ━━━━ DU BIST HIER ━━━━ │ +│ │ Optionen für dieses Ereignis: │ +│ │ ☑ Widerklage auf Nichtigkeit │ +│ │ ☐ Antrag Patentänderung (R.30) │ +│ │ ☐ Vorläufige Einwendungen │ +│ │ │ +│ ├─● Replik (R.29.a/b) 2026-06-01 · Klg · M │ +│ │ ├─● Duplik (R.29.c) 2026-07-01 · Bekl · M │ +│ │ └─● Replik auf Defence to CCR (R.29.d) 2026-08-01 · Klg · M │ +│ │ └─● Rejoinder (R.29.e) 2026-09-01 · Bekl · M │ +│ │ │ +│ ├─● Widerklage auf Nichtigkeit ✓ │ +│ │ └─▼ Tochterverfahren upc.rev.cfi ▾ │ +│ │ │ │ +│ │ ├─● Antrag Patentänderung (R.50) optional ☐ │ +│ │ ├─● Hauptverhandlung [Gericht] │ +│ │ └─● Entscheidung [Gericht] │ +│ │ │ +│ └─● Vorläufige Einwendungen ☐ (optional, ausgewählt: nein) │ +│ │ +│ ● Mündliche Verhandlung [Gericht bestimmt] │ +│ │ │ +│ └─● Urteil [Gericht] │ +│ └─▼ Berufungsverfahren upc.apl ▸ (auf Endentscheidung) │ +│ │ +└────────────────────────────────────────────────────────────────────┘ + +┌─ upc.ccr.cfi · Widerklage auf Nichtigkeit (Tochter, oben verlinkt) ┐ +│ … │ +└────────────────────────────────────────────────────────────────────┘ +``` + +No tabs. No view toggle. The output reacts to the find affordance, the anchor pin, and per-node fork selections. + +### §1.1 The shape's components + +1. **Find header** (sticky at top): search input + filter pills + Akte/date row + a one-line result summary. §2. +2. **Timeline-trees** (the page body): one block per matched proceeding, full chain + inline forks + inline aux branches. §3-§5. +3. **Anchor pin** (when set): the "DU BIST HIER" band on a specific node, optionally with zoom mode collapsing everything else. §6. + +That's the entire UI surface. No drawers, no separate drillable panes, no constellation viewer. Forks are inline checkboxes; aux proceedings are inline expandable subtrees; zoom is an interaction on the existing rendering. + +--- + +## §2 The find affordance + +m's #3 answer makes this load-bearing: text + pills + result-timelines are all the same affordance. As the user narrows, the timelines below filter; as the timelines change, the result-count summary updates; clicking a node in a timeline auto-narrows the filter pills to that proceeding (optional sugar). + +### §2.1 Composition + +| Control | Source | Composes via | Persists in | +|---|---|---|---| +| Free-text search | input box, debounced 200ms | OR-against (procedural_event.name DE/EN, rule_code, aliases) | `?q=` | +| Forum pill row | static enum (UPC/DE/EPA/DPMA), single-select | AND | `?forum=` | +| Verfahren pill row | proceeding_type chips, multi-select (deduped from active forum) | AND (any-of) | `?procs=` | +| Partei pill row | claimant / defendant / both / — (or auto from Akte) | AND | `?party=` | +| Akte picker | dropdown of user's projects | seeds Verfahren + Partei + scenario_flags + anchor | `?project=` | +| Stichtag (date) | date input, defaults today | feeds computed dates throughout the timelines | `?trigger_date=` | + +All controls live in one sticky header. The header keeps its height stable so the timelines below don't reflow on every keystroke. + +### §2.2 Cold open behaviour + +No URL params, no Akte: +- Search box empty, all forums neutral, all proceeding pills neutral. Show a curated default of the most-common proceedings: `upc.inf.cfi`, `upc.rev.cfi`, `upc.apl.merits`, `de.inf.lg`, `epa.opp.opd`, `dpma.opp.dpma`. (See Q4 below.) +- A hint above the timelines: "Suche oder filtere, um andere Verfahren einzublenden." + +With a `?project=` param: filters pre-fill from the Akte, anchor pins to the latest completed deadline. + +With a `?q=` or `?event=` param: filters pre-fill to match, single matched proceeding renders pinned. + +### §2.3 What the search matches + +Free-text search hits the same corpus the existing `/api/tools/fristenrechner/search?kind=events` endpoint covers — procedural_events by name + code + aliases. Spawn-only events stay filtered out (per atlas P0 §2.2). Hits surface in two ways simultaneously: + +- The matched proceeding(s) render expanded with the hit event(s) anchor-pinned. +- A small "Treffer: 3 Ereignisse in 2 Verfahren" summary above the timelines. + +If the user types something narrow enough to match a single event, the page auto-pins that event (auto-anchor). If multiple events match, the user picks via a small dropdown under the search input — picking sets the anchor. + +### §2.4 Why pills, not chips-with-sub-modes + +The shipped 4-tab UI tried to express "what kind of question are you asking" via tabs. m's answer #3 collapses that — the find affordance doesn't care which "kind" of question; it cares about the active filter set. A user with a search + a forum + an Akte set gets the right timelines regardless of which tab they "came from". The mental model is: narrow the set; the timelines arrive. + +--- + +## §3 Timelines and forks + +Each matched proceeding renders as one card. Inside the card: the proceeding's name + jurisdiction badge in a thin header strip, then the chain. + +### §3.1 The chain + +Vertical, top-to-bottom = chronological. Each node = one procedural_event (the rule that fires it lives inside). Edges = parent_id. Per node: + +- **Bullet style** by priority: solid filled (mandatory), solid outline (recommended), dotted (optional), dashed (conditional-flag-off and hidden). +- **Bullet colour**: priority band — black/grey/blue/light depending on the scale we end up picking. Lime accent (`#c6f41c`) reserved for the anchor pin. +- **Inline metadata**: name, rule code, computed date, party badge, priority badge. Stripped to one line. +- **Court-set events**: render with `[Gericht bestimmt]` in date column. +- **Spawn nodes**: terminate the bullet with `▼ Tochterverfahren ▾` — expandable inline; collapsed by default unless the spawn flag is on. §5. + +### §3.2 Forks — every choice point is one + +A "fork" is anywhere the user can flip the proceeding's shape: + +1. **Scenario flags** (`with_ccr`, `with_amend`, `with_cci`) — currently 3, extensible via curie's `scenario_flag_catalog`. +2. **Optional rules** (`priority='optional'`) — each is a "do I do this?" pick. +3. **Appeal-target picks** — `applies_to_target` array on appeal proceedings (endentscheidung / kostenentscheidung / anordnung / schadensbemessung / bucheinsicht). Per-card chip group at the appeal root. +4. **Perspective** — claimant / defendant per proceeding (mostly comes from Akte's `our_side`, picker overrides). +5. **Court-set timing choices** — `choices_offered` JSON on `sequencing_rules` (`appellant` / `include_ccr` / `skip` shapes from einstein). Per-card chip set. + +**Where forks render.** Inline, *on the node where the fork's effect begins.* Not in a top-of-page flag strip (m's bug #5 — sequences should be visualised as sequences; flags above the tree decouple cause from effect). + +Concretely: the `with_ccr` fork renders as a checkbox **on the Klageerwiderung node**, because that's where the user decides "we are filing a Widerklage with our KEW". Toggling it lights up the CCR child branches below. Similarly: + +- `with_amend` renders on the KEW node *and* on the Antrag-Patentänderung node it gates. +- `with_cci` renders on the Defence-to-Revocation node. +- Optional rules render as a checkbox on their own card. +- Appeal-target picks render on the appeal root. + +If multiple forks share a node, they cluster as a small "Optionen für dieses Ereignis" mini-strip *below* the node header: + +``` +▼ ● Klageerwiderung (R.23.1) 2026-04-01 · Bekl · M + │ Optionen: + │ ☑ Widerklage auf Nichtigkeit + │ ☐ Antrag Patentänderung (R.30) + │ ☐ Vorläufige Einwendungen einlegen +``` + +### §3.3 Default rendering ("Gewählt" semantics) + +Each node renders iff: +- It's mandatory (priority='mandatory'), OR +- It's selected per current scenario state (priority='recommended' unless explicitly deselected; priority='optional' iff explicitly selected; conditional iff flag is on). +- Same as atlas P3's "Gewählt" view-mode. + +Conditional rules whose flag is off **do not render at all** by default. The fork checkbox to *turn the flag on* still appears on the gating node — turning it on causes the dependent branch to render. + +This is m's bug #2 fix: no more dump of every-rule including flag-off conditional. The forks themselves are the affordance that brings hidden branches into view. + +### §3.4 Optional reveal — "Alle Optionen" + +A single toggle at the top of each proceeding card (NOT page-wide): + +``` +[· Gewählt ·] [ Alle Optionen ] +``` + +"Alle Optionen" renders every rule including flag-off conditionals (greyed with their flag hint) and unselected optionals (dotted with `[Aufnehmen]` chip). Useful when the user wants to see the whole shape. Per-proceeding so a page with 3 proceedings can have one in "Alle Optionen" mode without affecting the others. State persists in `localStorage` per proceeding code. + +### §3.5 Why dropping "Nur Pflicht" + +Atlas P3's three-way toggle had Nur Pflicht / Gewählt / Alle Optionen. With forks made inline + per-node, "Nur Pflicht" loses load-bearing — it was useful when the page had no fork interactivity (you wanted to dial down clutter). Now the user can just leave all forks off and see the mandatory-only chain in Gewählt mode. The two-way Gewählt ↔ Alle Optionen is enough. + +### §3.6 Cross-party rows + +Per atlas §2.4 / m's lock: every rule for the proceeding renders, with rows where the user is *not* the primary_party muted + carrying a "Gegenseitig" badge. Same treatment in this tracker. Not hidden by perspective; just visually deemphasised. + +--- + +## §4 Court-set events & date rendering + +`is_court_set=true` rules don't compute a date — the court picks it on the day. Two display options that interact: + +- Render with `[Gericht bestimmt]` in the date column, no date. Standard. +- When the user has scheduled the actual date (an `appointments` row on the project or a manual override), the actual date replaces the badge. Akte-only. + +If the date is "vom Gericht" and matters as a trigger for downstream events, downstream events render `[abhängig von Verhandlung]` instead of a date, and recompute live once the court date is known. + +`choices_offered` per-rule (the 3 known shapes today: `appellant`, `include_ccr`, `skip`) — also inline per-node, treated as forks (§3.2 #5). + +--- + +## §5 Aux proceedings inline + +Per m's #4 answer: spawned proceedings draw inline as expandable subtrees, not as drillable separate pages. + +### §5.1 Render + +A spawn node renders as a leaf chip terminating the parent's chain segment: + +``` +●─● Widerklage auf Nichtigkeit ✓ + └─▼ Tochterverfahren upc.rev.cfi ▾ + │ + ├─● Antrag Patentänderung (R.50) optional ☐ + ├─● Hauptverhandlung [Gericht] + └─● Entscheidung [Gericht] + └─▼ Berufungsverfahren upc.apl ▸ +``` + +- Collapsed by default unless the gating fork is on (e.g. `with_ccr` ticked → CCR's spawn into upc.rev.cfi auto-expands). +- Expanding writes nothing — pure UI state in `sessionStorage["procedures:expanded_spawns"]`. +- The aux subtree renders with the same node vocabulary as the parent; forks inside the aux are independently editable. +- Aux subtrees can themselves have aux subtrees (e.g. CCR → Berufung). Depth is bounded by the data — today 2 levels deep at most. + +### §5.2 Cross-references + +When two paths converge on the same aux proceeding (e.g. CCR triggers from a couple of places), the aux renders inline at the first path's spawn point and renders as a back-reference at subsequent spawn points: `▸ (siehe oben: Tochterverfahren upc.rev.cfi)`. Single source of truth in the rendered tree, even when the graph has multiple edges. + +### §5.3 Akte mode + +In Akte mode, if the spawn was actualised (a child project exists linked via `parent_project_id`), the aux subtree shows the child project's badge: `📁 HL-2024-001-CCR · Tochterakte`. Clicking the badge navigates to that child project. The subtree itself still renders inline. + +--- + +## §6 Anchor pin & zoom + +m's #1 answer: "zoomability for one event and all events it triggers, from within the full timeline". + +### §6.1 The anchor pin + +Any node can be pinned as the anchor. Pinning sources: +- URL `?event=` (deep link). +- Search box auto-pin when the search narrows to a single hit. +- Click-to-pin on any node (small pin icon in the node's metadata row). +- Akte landing: auto-pin to latest completed deadline. + +The pinned node renders with a 4px lime-coloured left band + a `━━ DU BIST HIER ━━` divider above its successors. The pin is also reflected in the find-header's result summary: "Anker: Klageerwiderung (HL-2024-001)". + +### §6.2 Zoom mode + +A small `[ 🔍 Fokus ]` chip on the anchored node toggles zoom mode for that anchor. When zoom is on: + +- The anchored node's ancestors collapse to a single breadcrumb at the top of the proceeding card: + ``` + upc.inf.cfi ▸ Klageerhebung ▸ ━ Klageerwiderung ━ + ``` +- The anchored node renders full. +- Successors render fully (the forward subtree under the anchor). +- Sibling branches at every ancestor depth collapse to a single-line summary card: `… 4 weitere Schritte verborgen — [zeigen]`. + +This is what m means by "zoom into one event from within the timeline" — the *same view*, just with non-relevant siblings collapsed. Toggle off → full timeline restored, anchor still pinned. + +Zoom is page-scoped (one anchor per page, one zoom state). State in URL: `?event=&zoom=1`. + +### §6.5 Multi-proceeding anchor scope (m's Q3 divergence) + +When the page shows >1 matched proceeding *and* an anchor is pinned, the non-anchored proceedings auto-collapse to a header-only one-line card: + +``` +┌─ upc.inf.cfi · Verletzungsverfahren UPC ─────┐ +│ … full timeline … │ +│ ━━ DU BIST HIER: Klageerwiderung ━━ │ +└──────────────────────────────────────────────┘ + +┌─ upc.rev.cfi ▸ ausblenden — [zeigen] ────────┐ +└──────────────────────────────────────────────┘ + +┌─ upc.apl.merits ▸ — [zeigen] ────────────────┐ +└──────────────────────────────────────────────┘ +``` + +Clicking a header card's `[zeigen]` link restores that proceeding's full timeline (the header stays as a per-card affordance for re-collapse). The collapsed state persists in `sessionStorage["procedures:collapsed_proceedings"]`. Un-pinning the anchor restores all visible proceedings to full-render automatically. + +The rule applies regardless of how the anchor was pinned (URL, search-auto, click-to-pin, Akte landing). The find-header result count still shows N proceedings matched — header cards are present, just collapsed. + +### §6.3 The "where I came from" question + +m's brief asked for backward-walk visualisation. Without zoom: the chain above the anchor is the backward walk — it's the same tree. With zoom: the breadcrumb at the top of the proceeding card is the backward walk in compact form. No separate concept; backward walk = upward in the tree. + +### §6.4 Akte mode: actuals overlay + +When `?project=` is set, each node in the chain queries `paliad.deadlines WHERE project_id = $p AND sequencing_rule_id = $r` and overlays: + +- `status='done'` → ✓ in the node bullet area + actual completed date in the date column. Greyed slightly to read as "past". +- `status='open'` and `due_date < today` → ⚠ overdue. +- `status='open'` and `due_date >= today` → 📅 actual due date if differs from computed; ◇ marker. +- No deadline row → render as template (current behaviour). + +The anchor auto-pins to the latest `status='done'` deadline by default — the natural reading is "we just finished this". + +--- + +## §7 What lives where: the find header vs the timelines + +A short table to make the responsibility boundary explicit: + +| Concern | Find header | Timeline body | +|---|---|---| +| Pick proceeding(s) | Filter pill row | (auto-rendered after) | +| Pick anchor | Search-narrow → auto-pin / URL `?event=` | Click pin icon on any node | +| Pick perspective | Pill (or auto from Akte) | (read-only — feeds rendering) | +| Pick scenario flags | (no) | Inline fork checkboxes on gating nodes | +| Pick optional rules | (no) | Inline fork checkboxes on each optional node | +| Pick appeal target | (no) | Inline chip group on appeal root | +| Pick date | Stichtag input | (read-only — feeds computed dates) | +| Toggle Alle Optionen / Gewählt | (no) | Per-proceeding 2-way toggle | +| Zoom on anchor | (no) | `[Fokus]` chip on anchored node | +| Akte select | Akte picker | (read-only — feeds actuals overlay) | + +Find header = "narrow the set + global context". Timelines = "everything per-event". No drawers, no overlays. + +--- + +## §8 Cold open + empty state + +Cold open with no Akte, no URL params (Q4 below): show a curated default of 6 most-common proceedings (`upc.inf.cfi`, `upc.rev.cfi`, `upc.apl.merits`, `de.inf.lg`, `epa.opp.opd`, `dpma.opp.dpma`), each rendered with default Gewählt + no forks selected + no anchor. Hint text above: "Suche oder filtere, um andere Verfahren zu sehen." + +Empty filter result (e.g. user types nonsense): zero timelines render, with a helper card: "Keine Treffer. Filter zurücksetzen ▸" + +--- + +## §9 Migration (direct replace per m's Q7) + +4 slices + 1 cleanup, all surface, no DB mig, no `?tracker=1` flag. Each slice ships visibly to users at `/tools/procedures`. T1 must be at least as functional as today's catalog browser — so the find header + multi-proceeding render + inline forks + aux inline all front-load there. T2-T4 layer the remaining behaviour. + +All independent of curie's editorial work — compound rules render inline via parent_id like any other rule; if curie ships a `compound_predecessors uuid[]` column later, those rules can render at multiple positions (one inline per predecessor) without tracker code changes beyond the join. + +| Slice | What ships | Notes | +|---|---|---| +| **T1 — Tracker shell replaces the catalog page** | `/tools/procedures` now renders: sticky find header (search + Forum/Verfahren/Partei pills + Akte picker + global Stichtag), N-proceeding render (one card per matched proceeding), inline forks (scenario flags + optionals visible as checkboxes on the gating node), aux proceedings inline-expandable at spawn points, cold-open with 6 curated defaults (Q4), default = Gewählt. The 4 entry-mode tabs are deleted in the same PR; URL params `?mode=proceeding\|search\|wizard\|akte` 301-redirect or drop. URL anchor `?event=` scroll-highlights the matching node (no zoom yet). | Replaces catalog UI; users see the new tracker immediately. | +| **T2 — Anchor pin + zoom + multi-proceeding scope** | Anchor pin (lime band + DU BIST HIER divider), `[Fokus]` chip on anchored node toggles zoom (§6.2), URL state `?event=…&zoom=1`. Multi-proceeding auto-collapse rule (§6.5) kicks in when an anchor is set. Click-to-pin on any node. | Layered on T1's existing render. | +| **T3 — Akte landing + actuals overlay** | `?project=` derives anchor from latest `status='done'` deadline (Q5), backward walk overlays `paliad.deadlines` actuals as status badges (§6.4), scenario_flags load from project, fork write-back via existing `PATCH /api/projects/{id}/scenario-flags` + `POST /api/projects/{id}/deadlines/bulk`. | The first slice that exercises the project hookup end-to-end. | +| **T4 — Appeal-target + court-set choices + polish** | Wire `applies_to_target` array forks on appeal proceedings, `choices_offered` shapes (`appellant`, `include_ccr`, `skip`), court-set date override from `appointments` table, cross-party muted treatment per §3.6. Per-proceeding "Alle Optionen" toggle (§3.4). | Polish + the edge-case fork shapes. | +| **T5 — Cleanup** | Dead-code removal: legacy `procedures.ts` tab toggling, `fristenrechner-mode-a.ts` / `fristenrechner-wizard.ts` / `fristenrechner-result.ts` / `verfahrensablauf.ts` if no longer referenced (verify with grep before deletion). Sidebar/cmd-K unchanged (URL same). | No user-visible change. | + +### §9.1 Constraint: T1 is the new floor + +Because there's no flag, **T1 must not regress** from today's catalog UI in any non-trivial way. The catalog today serves four user workflows: + +1. **Pick a proceeding, see its full Verfahrensablauf** → T1 covers via "Verfahren" pill click → that proceeding renders alone. +2. **Search for an event** → T1 covers via search input + auto-pin. +3. **Wizard from R1-R5** → T1 covers via Forum/Verfahren/Partei pills + search (the wizard's narrowing is just a sequence of filter applications). +4. **Enter via Akte** → T1 covers via the Akte picker; full actuals overlay arrives in T3 (open/done badges may render partial in T1, but the Akte's scenario_flags + proceeding pre-load works). + +If T1 reviewing exposes a regression, T1 holds (the issue blocks merge) — m's PR review gates the slice landing. + +### §9.2 What stays unchanged + +- URL: `/tools/procedures` keeps it. +- Sidebar entry "Verfahren & Fristen" keeps it. +- cmd-K palette keeps it. +- All other tools, calendar, projects, deadlines surfaces — untouched. +- Calculator (`pkg/litigationplanner.CalculateRule`) — untouched. + +### §9.3 Out-of-band dependencies + +- The compound-predecessors editorial column is owned by curie's t-paliad-333. Tracker reads whatever lands. If it slips past T4, compound rules render via their primary parent_id only (today's shape) — degraded but still correct on that path. No tracker re-render needed when curie ships. +- The Akte actuals overlay (T3) reads `paliad.deadlines.sequencing_rule_id` — column exists, nothing new. + +### §9.4 Test surface per slice + +- **T1**: cold-open 6 curated defaults render; search narrows to single proceeding; pill toggles change render; `?project=` loads Akte filters (no actuals yet); URL deep-link `?event=` highlights matching node; legacy `?mode=` redirects. +- **T2**: click-to-pin sets anchor with lime band; `[Fokus]` zoom collapses siblings; un-zoom restores; multi-proceeding auto-collapse when anchor active; URL state survives reload. +- **T3**: Akte landing auto-pins latest done deadline; status badges render on each node from `paliad.deadlines`; fork tick writes to `scenario_flags`; "In Akte speichern" persists. +- **T4**: appeal-target chips switch the rule set rendered on appeal proceedings; `choices_offered` per-node chip groups visible + functional; "Alle Optionen" reveals hidden conditional rules with greyed state. +- **T5**: production deploy unchanged surface; no live regression; deleted files don't break build. + +--- + +## §10 Open questions for m + +Seven questions in 2 batches (4 + 3) for `AskUserQuestion`. Tier 1 = how the per-node fork UI feels + how zoom interacts with multi-proceeding pages. Tier 2 = cold-open content + Akte default + Stichtag scope + migration cadence. + +m's picks fold back into §11 below before the "TRACKER DESIGN READY FOR REVIEW" signal. + +### Batch 1 — fork UI + zoom + cross-party +- **Q1 (Fork-cluster shape on a node)** — when a node has 2-4 forks (e.g. Klageerwiderung: `with_ccr` + `with_amend` + Vorl. Einwend.) — (a) inline checkbox list below the node header (current sketch), (b) collapsed "Optionen (3) ▾" affordance that expands on hover/click, (c) chip strip on the same line as the node header. +- **Q2 (Zoom interaction)** — `[Fokus]` chip on the anchored node — (a) collapses siblings to one-line summaries (current sketch), (b) outright hides siblings, breadcrumb-only, (c) split-view (zoomed pane below original full tree). +- **Q3 (Anchor scope on a multi-proceeding page)** — when 3 timelines are visible and the user pins an anchor in one — (a) the other 2 timelines stay expanded normally (no zoom effect on them), (b) the other 2 timelines auto-collapse to header-only ("upc.rev.cfi ▸ ausblenden — [zeigen]"), (c) the other 2 timelines reorder to bottom of page (anchored proceeding floats to top). +- **Q4 (Cold-open default content)** — opening `/tools/procedures` with no URL params and no Akte — (a) the 6-curated-default-proceedings sketch (Verletzung UPC + DE LG, Nichtigkeit UPC, Berufung UPC, EPA-Einspruch, DPMA-Einspruch), (b) all ~46 proceedings rendered with all forks off (lots of scrolling), (c) empty state with a "Filter wählen, um Verfahren einzublenden" prompt. + +### Batch 2 — Akte semantics + Stichtag + migration +- **Q5 (Akte landing — default anchor)** — `?project=` — (a) auto-pin to latest `status='done'` deadline (current sketch), (b) auto-pin to next-open deadline (forward-looking), (c) no auto-pin, just pre-fill filters + actuals overlay, user picks anchor. +- **Q6 (Stichtag scope)** — date input in the find header — (a) global, feeds all visible proceedings' computed dates (current sketch — useful for browsing "if today were the trigger"), (b) per-proceeding (each timeline carries its own date input), (c) only valid in single-proceeding mode (hidden when the page shows >1 proceeding). +- **Q7 (Migration cadence)** — (a) flag-gated dev under `?tracker=1`, T1-T4 ship, T5 hard-cut (current sketch, cronus precedent), (b) direct replace at T1 (no flag — every slice ships visibly to users), (c) parallel URL `/tools/procedures-v2` until hard-cut. + +--- + +## §11 m's decisions (2026-05-27) + +All 7 questions answered via `AskUserQuestion` in 2 batches (4 + 3) at 21:0?. 5 picks on-recommendation, 2 diverged. Decisions below; the underlying question list lives in §10 above as the historical record. + +### Tier 1 — fork UI + zoom + cross-party + +- **Q1 (Fork cluster on a node): Inline checkbox list below node header.** [= REC] **Locks §3.2.** Every fork on a given node renders as a checkbox in an "Optionen:" cluster line below the node header. Always visible, no hover, no extra click. Vertical real estate per node is acceptable because the default `Gewählt` mode keeps the tree compact (most events have zero forks). +- **Q2 (Zoom interaction): Collapse siblings to one-line summaries.** [= REC] **Locks §6.2.** `[Fokus]` chip on the anchored node folds sibling branches at each ancestor depth to a `… 4 weitere Schritte verborgen — [zeigen]` line. The anchored node's subtree renders full. Breadcrumb at the top of the proceeding card. Toggle off restores everything. +- **Q3 (Multi-proceeding anchor scope): Other timelines auto-collapse to header-only.** [≠ REC; m diverged from "stay expanded"] **Locks new §6.5.** When an anchor is pinned on a multi-proceeding page, the non-anchored proceedings fold to a one-line header card (`upc.rev.cfi ▸ ausblenden — [zeigen]`). Clicking the header line restores that proceeding's full timeline. Rationale (interpreted): with an anchor pinned, the page is *about* that anchor — having other proceedings full-render in parallel competes for attention without earning it. The header card preserves the find-header result count and offers a one-click escape if the user wants to compare. +- **Q4 (Cold open content): 6 curated default proceedings.** [= REC] **Locks §8.** No URL params + no Akte → render `upc.inf.cfi`, `upc.rev.cfi`, `upc.apl.merits`, `de.inf.lg`, `epa.opp.opd`, `dpma.opp.dpma` stacked vertically, all forks off, no anchor. Hint: "Suche oder filtere, um andere Verfahren zu sehen." + +### Tier 2 — Akte + Stichtag + migration + +- **Q5 (Akte default anchor): Latest `status='done'` deadline.** [= REC] **Locks §6.4 + §9.** `?project=` → derive anchor by `SELECT … FROM paliad.deadlines WHERE project_id=$p AND sequencing_rule_id IS NOT NULL ORDER BY completed_at DESC NULLS LAST LIMIT 1`. Fallback: next open deadline → proceeding root. The backward chain reads as Akte history; the anchor itself is the most recently completed work; forward is upcoming. +- **Q6 (Stichtag scope): Global, feeds all visible proceedings.** [= REC] **Locks §2.1 + §7.** One date input in the find header. All visible proceedings compute dates against it. When the user has an Akte loaded, the Stichtag pre-fills from the project's latest trigger date but is overrideable. When the anchor is pinned to a `status='done'` deadline, the date input shows that deadline's `completed_at` but can still be overridden for "what-if" exploration. +- **Q7 (Migration cadence): Direct replace at T1 — no flag.** [≠ REC; m diverged from flag-gated dev] **Rewrites §9.** Every slice ships visibly to users at /tools/procedures. T1 must be at minimum equivalent to today's catalog browser (so the slicing has to front-load find header + multi-proceeding render + forks inline + aux inline). The flag-gated dev plan is dropped. cronus's Q11 hard-cut precedent extends here: m would rather ship per-slice visibly than carry a parallel surface during dev. Rationale (interpreted): partial-tracker > no-tracker, and ~50 internal lawyers absorb the per-slice deltas through release comms. + +### §11.1 Changes triggered by m's divergences + +**Q3 divergence — multi-proceeding anchor scope.** New §6.5 added below. The header-card-only render for non-anchored proceedings preserves filter compose (you can still see "upc.rev.cfi matched the filter") while clearing the page's vertical real estate for the anchor's full context. + +**Q7 divergence — direct replace.** §9 rewritten end-to-end. T1 now ships the minimum-viable tracker (find header + multi-proceeding render + forks inline + aux subtrees inline + URL-anchor highlight), replacing the catalog UI at /tools/procedures from the moment it merges. T2-T4 layer zoom, Akte semantics, polish. T5 ("cleanup only") is now just dead-code removal. + +### §11.2 What stays unchanged + +The other 5 picks (Q1, Q2, Q4, Q5, Q6) ratified the inventor proposal. Inline checkbox forks per node, breadcrumb-collapse zoom, 6-curated cold open, latest-done-deadline Akte anchor, global Stichtag — all locked as drafted in §1-§8. + +--- + +## §12 Out of scope + +- Calculator changes. +- Editorial backfill (curie's t-paliad-333). Compound rules render inline as parent_id-chained rules with curie's annotation; no special tracker treatment. +- `/admin/procedural-events`, `/projects/{id}` Verlauf / SmartTimeline. +- youpc.org / Outlook / PDF export. +- Multi-project anchor comparison. +- Free-text scenario flag i18n. + +--- + +## §13 Synthesis links + +- **mBrian** (after m's ratification): file as `[synthesis]` linked `triggered_by` t-paliad-337; `related_to` cronus's unified-procedural-events-tool design + atlas's deadline-system-revision + cronus's earlier Fristenrechner overhaul. +- **Cross-refs in this repo**: `docs/design-unified-procedural-events-tool-2026-05-27.md` (cronus, U0-U4 shipped today), `docs/design-deadline-system-revision-2026-05-27.md` (atlas Phase 2), `docs/design-fristenrechner-overhaul-2026-05-26.md` (cronus 2026-05-26). +- **Gitea**: m/paliad#152 (this design), m/paliad#151 (cronus U0-U4), m/paliad#149 (atlas Phase 2). +- **Coder phase** (deferred per inventor SKILL): runs after m ratifies §10 + §11. Slice ordering per §9. NOT atlas (parked at "TRACKER DESIGN READY FOR REVIEW"). Pattern-fluent Sonnet coder picks up T1 first.