2e6427dca6850f124899d2579d4c9eb0c07e6f72
1275 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
| 2e6427dca6 | Merge: t-paliad-338 T1 — workflow-tracker shell replaces catalog (m/paliad#152) | |||
| 7945bfb364 |
feat(procedures): T2 — anchor pin + zoom + multi-proceeding scope (m/paliad#152)
Layers the anchor / focus interactivity on top of T1's shell per design §6.1–§6.5: - Click-to-pin (📌) on every node with a real rule_id sets the anchor. Clicking the already-anchored pin un-pins. URL state ?event=<id>. - Anchored node renders with a "── DU BIST HIER ──" divider beneath its meta line + the lime left-band styling. The find-header summary surfaces "Anker: <name>" so the user can confirm where they are. - Fokus chip (🔍) on the anchored node toggles zoom (?zoom=1). Zoom renders the anchor's parent chain as a breadcrumb at the top of the proceeding card and renders only the anchored subtree below. A "{n} weitere Schritte verborgen" footer reports what zoom hid. - Multi-proceeding scope (§6.5): when an anchor is pinned and >1 proceeding is visible, non-anchored proceedings auto-collapse to a one-line header card with a [zeigen] / [ausblenden] toggle. The user's explicit expansions persist for the current anchor; pinning a different node clears them. - Auto-pinning from the search input (T1's single-hit behaviour) now routes through onAnchorChanged so the multi-proc scope kicks in consistently. Anchor + zoom state writes through history.replaceState — sharable URL. Un-pinning clears zoom and restores the full multi-proceeding view automatically (lastAnchor tracking). t-paliad-338 |
|||
| bfb38aab41 |
feat(procedures): T1 — workflow-tracker shell replaces catalog (m/paliad#152)
Direct-replace per m's Q7 divergent pick in atlas's design (docs/design-procedures-workflow-tracker-2026-05-27.md §9): /tools/procedures drops the 4-tab catalog (U0-U4 shipped this morning) for the single canonical workflow-tracker shape. T1 ships: - Sticky find header — search input, forum / Verfahren / Partei pill rows, global Stichtag, live result summary. - Per-proceeding timeline cards — one card per matched proceeding, rendered as a chained tree by parent_id with priority-styled bullets (mandatory solid, recommended muted, optional dotted, informational faded, court-set blue). Party badge per node. - Cold-open default: the 6 curated proceedings from design §8 / §11.Q4 (upc.inf.cfi, upc.rev.cfi, upc.apl.unified, de.inf.lg, epa.opp.opd, dpma.opp.dpma) render stacked with a hint above. - Scenario-flag forks — per-proceeding "Optionen" strip on each card's header surfaces the applicable flags (with_ccr, with_amend, with_cci) derived from condition_expr or a fallback map. Tick re-runs the calc. - URL state: ?q, ?forum, ?procs, ?party, ?trigger_date, ?event, ?flags. ?event= scroll-highlights the matching node (no zoom yet — T2 layers). - Legacy ?mode= dropped silently on first state write so bookmarks self-clean. /tools/fristenrechner + /tools/verfahrensablauf 301s still resolve here. Floor T1 honours: every catalog workflow it replaces — pick proceeding (forum + Verfahren pills), search event (search input → auto-narrow + ?event= anchor), wizard narrowing (pills compose), Akte entry (?project= read-only for T1; full overlay in T3). Per-node fork placement (the design's stated final shape — checkbox on the gating node itself, not a card-level strip) is a T2 refinement; T1 keeps forks scoped per proceeding so they're not the global-page strip m's bug #5 flagged. Aux-proceedings inline-expandable (design §5) and the appeal-target chip group are scoped to T4; the calculator currently doesn't surface isSpawn / spawnProceedingCode through TimelineEntry to support them. t-paliad-338 |
|||
| 9fe06094a8 |
Merge: t-paliad-337 — workflow-tracker design for /tools/procedures (m/paliad#152)
atlas shipped the workflow-tracker design after m's 21:01 grilling-round reframe (single timeline-with-forks, find=search+pills+result-timelines, aux inline, zoom from within full tree). 510-line doc, 2 rewrite iterations. 7 Qs answered in 2 batches (4+3). 5 on-recommendation, 2 divergent: - Q3 (divergent): multi-proceeding anchor scope — auto-collapse other proceedings to header-only (new §6.5) - Q7 (divergent): migration strategy — direct replace at T1, no feature flag (§9) 4-slice + cleanup train. T1 ships minimum-viable tracker visibly at /tools/procedures, replacing the catalog UI knuth shipped today. Inventor parks. Head dispatches Sonnet coder (NOT atlas per project memory directive). |
|||
| c8f310c62c |
design(procedures-tracker): fold m's 7 picks — §11 decisions + §6.5 multi-tl anchor + §9 direct-replace migration (t-paliad-337)
5 picks on-recommendation, 2 diverged: Q3 (multi-proceeding anchor scope): m picked 'other timelines auto-collapse to header-only' over the recommended 'stay expanded'. Added §6.5 with the header-card render rule. Q7 (migration cadence): m picked 'direct replace at T1, no flag' over the recommended flag-gated dev. §9 rewritten end-to-end: T1 ships the minimum-viable tracker visibly to users, replacing the catalog UI in the same PR. T2-T4 layer zoom + Akte + polish. T5 is cleanup-only. The 5 on-rec picks: inline checkbox forks (Q1), sibling-collapse zoom (Q2), 6 curated defaults on cold open (Q4), latest-done-deadline Akte anchor (Q5), global Stichtag (Q6) — all locked as drafted in §1-§8. Ready for review. Coder gate held; head decides T1 hire. |
|||
| 7554e86673 |
design(procedures-tracker): rewrite after m's reframe — single timeline-tree, inline forks, no view toggle (t-paliad-337)
m's grilling-round answers (2026-05-27 21:01): 1. One canonical view (full timeline/tree); zoom is an interaction on it, not a separate view. 2. Forks = everything: scenario flags + optionals + appeal-target + court-set picks. 3. Find = combined affordance: text + pills + result-timelines are one thing. 4. Aux proceedings inline as expandable child timelines. Doc rewritten end-to-end. The first draft's three-view toggle + Konstellationen drawer + Querverweise drawer + split-pane/breadcrumb apparatus collapses into: - Sticky find header (search + pill rows + Akte/date) - N matched proceedings rendered as inline-forked timeline-trees - Anchor pin + opt-in zoom mode (collapses siblings, breadcrumb back) - Aux proceedings expand inline at the spawn point 7 open questions in 4+3 batches for AskUserQuestion. T1-T5 migration unchanged in spirit. |
|||
| 23b151c0f3 |
design(procedures-tracker): t-paliad-337 shift-1 — workflow-tracker layer for /tools/procedures (m/paliad#152)
m's reframe (2026-05-27 20:43): /tools/procedures should be a workflow tracker, not a catalog browser. Pick any procedural event, see backward (predecessors) + self (where I am) + forward (successors), with scenario_flags as togglable predicates and alternative constellations explorable. This shift-1 doc covers: - 4-tab UX redo (single-pane radio-revealed entry form to fix the pre-form-leak bug) - Anchor visualisation (vertical waterfall with anchor at centre line) - Three views — Anchor / Verfahren / Konstellationen — toggle preserves anchor + scenario state - Forward walk (current constellation only by default, conditional reveal toggle, view-mode toggle reused from atlas P3) - Backward walk (3 hops default, Akte mode overlays paliad.deadlines actuals onto template chain) - Compound rules drawer (per-anchor Querverweise affordance — column shape owned by curie editorial workstream) - Constellation viewer (inline per-flag preview drawer + full Constellation view for browse) - Akte entry (anchor derives from latest completed deadline) - Migration: T1-T5 flag-gated dev under ?tracker=1, then hard-cut Coder gate held. 11 open questions for m staged for AskUserQuestion in 4+4+3 batches. Decisions append as §13 before the TRACKER DESIGN READY FOR REVIEW signal. |
|||
| 1718ea2eae |
Merge: t-paliad-335 — unified /tools/procedures shipped U0-U4 (m/paliad#151)
knuth shipped all 5 slices in one shift, per cronus's design: U0 |
|||
| 39c8ef343b |
feat(procedures): U4 hard-cut legacy URLs + retire dual surfaces (m/paliad#151)
Per m's Q11 divergence in the design (no 2-week dual-ship), this slice flips /tools/fristenrechner and /tools/verfahrensablauf to permanent 301 redirects to /tools/procedures and deletes the legacy frontend pages. Bookmarks resolve via Location preservation of query params; no ?legacy=1 escape, no in-product affordance pointed back at the retired URLs after the merge. Server: - handleFristenrechnerPage + handleVerfahrensablaufPage now 301 to /tools/procedures, carrying any query string through unchanged. - pillDrillURL in deadline_search_service.go retargets to /tools/procedures so freshly indexed search pills land on the new page directly (cached snapshots still work via the 301). Frontend: - Deleted src/fristenrechner.tsx, src/verfahrensablauf.tsx, src/client/fristenrechner.ts. - src/client/verfahrensablauf.ts loses its DOMContentLoaded auto-boot and the now-unused initI18n / initSidebar imports; procedures.ts is the sole caller of initVerfahrensablauf(). - frontend/build.ts drops the legacy entrypoints and renderXxx HTML outputs. - Sidebar.tsx, Header.tsx, index.tsx, paliadin-context.ts repointed to /tools/procedures. - Unused nav.fristenrechner / nav.verfahrensablauf / tools.verfahrensablauf.* i18n keys removed. Tests: - verfahrensablauf_test.go rewritten to assert both legacy URLs return 301 with the correct Location (query string preserved). |
|||
| 48a07ef4ef |
feat(procedures): U3 fold Verfahrensablauf tree + 3-way detail filter (m/paliad#151)
Mounts the full Verfahrensablauf wizard — proceeding picker, perspective chooser, date inputs, scenario flag rows, detail-mode toggle, view toggle, timeline-container — under the /tools/procedures "Verfahren wählen" tab. Per-rule scenario_flags chips (P0 SSoT) and the Aufnehmen/Entfernen affordances reach the unified page unchanged since they're delegated handlers on the timeline-container. Refactor steps: - Extracted the wizard body markup into a shared TSX component (components/VerfahrensablaufBody) used by both verfahrensablauf.tsx (legacy) and procedures.tsx (unified). U4 will retire the legacy page; the shared component lets U3 ship without code duplication. - Lifted the verfahrensablauf.ts DOMContentLoaded body into initVerfahrensablauf() and re-exported it. The legacy auto-boot stays in place but skips itself when #procedures-panel-proceeding is present, so the unified page imports the module without double-init. procedures.ts calls initVerfahrensablauf() the first time the proceeding tab activates, gated by a one-shot flag to preserve module-local selectedType / lastResponse across tab toggles. |
|||
| bb3d7aabd7 | Merge: hide archived from admin/procedural-events default view | |||
| c8390dd02a |
fix(admin-rules-list): default lifecycle filter to 'published' (hide archived clutter)
m flagged 2026-05-27 20:26: archived rules (e.g. the 5 mig 152 Mängelbeseitigung clones) clutter the /admin/procedural-events default view. They were correctly archived by mig 152 but visually noisy alongside active rules. Fix: default activeLifecycle = 'published'. The 'Alle' chip still exists for when the user wants to see drafts + archived; 'Archived' chip surfaces them on demand. Initial view shows only the active corpus. |
|||
| c8261da492 |
feat(procedures): U2 fold Mode B (Geführt wizard) (m/paliad#151)
Mounts mountWizard() into #procedures-panel-wizard when the Geführt tab activates. Same 5-row wizard, same backend (event search + follow-ups probe) as the legacy /tools/fristenrechner. On R4 launchResult, the wizard hands off to mountResultView which renders into the same overhaul-root inside the panel. The wizard renders into #fristen-overhaul-mode-host while Mode A and the result view write into #fristen-overhaul-root. To keep those IDs unique in the DOM — both modes look up via document.getElementById — the host scaffold is no longer static on the search panel. The new installOverhaulHost() helper tears down any existing host and installs a fresh one inside the active tab's panel before each mount, so two parallel hosts can't cross-wire when the user toggles between the Direkt-suchen and Geführt tabs. The U1/U2 placeholders are dropped from the panel markup since the panels are populated dynamically now. |
|||
| 0568d340a7 |
feat(procedures): U1 fold Mode A (Direkt suchen) (m/paliad#151)
Mounts mountModeA() into #procedures-panel-search when the Direkt-suchen tab activates. The legacy fristenrechner-mode-a code runs unchanged inside a wrapper that reseeds the #fristen-overhaul-root / #fristen-overhaul-mode-host scaffold on every tab activation, so re-clicking the tab always restores a fresh Mode A surface even if the previous interaction committed an event into the result view. `?event=<code>` deep links still resolve: boot detects the param, activates the search tab, and hands directly to mountResultView() — the result lands inside the same root, the user sees the picked event's follow-up rules with the Direkt-suchen tab as the visible context. Search-box-in-filter-strip composition with chip filters (m's Q3 divergence) lands later, after Mode B + Verfahrensablauf are folded — the unified state machine pulls all three behind one search input. |
|||
| 60907e7153 |
feat(procedures): U0 skeleton — /tools/procedures page shell (m/paliad#151)
First slice of the unified procedural-events tool train. Ships only the page chrome — route, sidebar/header, filter strip with search box, four entry-mode tabs (Verfahren wählen / Direkt suchen / Geführt / Aus Akte), and the host containers later slices mount their UI into. No data wiring. Per m's decisions (design §11.5): URL is English (/tools/procedures, not /tools/verfahren); all four tabs visible from boot (not a single-default landing); search box lives in the top filter strip and will compose with chip filters once U1+ wire them. U1 fills #procedures-panel-search (Mode A), U2 fills -wizard (Mode B), U3 fills -proceeding + #procedures-output-tree (Verfahrensablauf), U4 hard-cuts /tools/fristenrechner and /tools/verfahrensablauf to 301 redirects and drops the legacy pages. |
|||
| 66b08813c4 |
Merge: t-paliad-334 — unified procedural-events tool design (m/paliad#151)
cronus shipped 568-line design ratifying a single /tools/procedures page that folds Fristenrechner (Mode A + Mode B + result view) + /tools/verfahrensablauf into one surface with 4 entry tabs and tree+linear-drawer outputs.
12 m's decisions (9 on-recommendation, 3 divergent):
- Q (divergent): English URL '/tools/procedures' (over '/tools/verfahren')
- Q (divergent): all 4 entry tabs visible + search-in-filter-strip (over single default tab)
- Q (divergent): hard-cut 301 redirect (over 2-week dual-ship)
Stays separate (correctly different shape/audience):
- /admin/procedural-events (editorial write surface)
- /projects/{id} Verlauf (per-Akte actuals)
- SmartTimeline (internal projection)
- youpc.org/deadlines (cross-repo, embedded snapshot)
5-slice migration train U0-U4 (no DB mig — purely UX consolidation atop the shipped Phase 2 substrate).
Inventor parks. Head dispatches Sonnet coder per project memory directive (NOT cronus for impl).
|
|||
| 0aaa523494 |
design: fold m's 12 decisions into unified procedural-events doc (m/paliad#151)
- §11.5 m's decisions section (9 on-rec + 3 divergent) - diverged: Q2 /tools/procedures (English), Q3 all-tabs+search-in-filter-strip, Q11 hard cut no dual ship - §11.5.1 changes triggered by divergences (URL rename, all-tabs behaviour, U4 rewrite) - URL refs throughout body updated to /tools/procedures - U4 slice rewritten to 301 hard-cut per Q11 |
|||
| d49ff55c41 |
design: unified procedural-events tool (m/paliad#151 shift-1, draft)
- audit of 6 surfaces with question→dimension matrix - proposal: fold Fristenrechner + Verfahrensablauf into /tools/verfahren - 4 entry paths converge on tree + linear output shapes - mobile narrow-viewport rules + 3 worked personas - 5-slice migration train (U0-U4), no DB migration - 12 open questions in 3 batches for AskUserQuestion |
|||
| ae1c0b861d | Merge: fix admin-rules-edit URL parser regex (post B.6 rename hotfix) | |||
| c8999e2a8b |
fix(admin-rules-edit): accept /admin/procedural-events/{id}/edit in URL parser
Slice B.6 / S6 renamed the canonical edit URL from /admin/rules/{id}/edit
to /admin/procedural-events/{id}/edit. The backend handler + 301 redirect
landed, but the client-side regex in admin-rules-edit.ts:110 was missed —
it still only matches the legacy /admin/rules/.../edit shape. Result:
visiting the canonical URL from the list page shows 'Ungültige
Verfahrensschritt-ID in der URL.' even though the rule exists.
Fix: regex accepts both '/admin/procedural-events/{id}/edit' (canonical)
and '/admin/rules/{id}/edit' (legacy, kept for stale tabs / bookmarks
during the deprecation window).
m flagged 2026-05-27 17:57 on rule cc439590 (RoP.262.2, upc.inf.cfi).
|
|||
| 0365e84dd1 |
Merge: t-paliad-331 P2 + P4 partial — condition_expr validator + trigger_events partial deprecation (m/paliad#149)
ritchie shipped the final two slices of the Phase 2 train.
P2 — condition_expr write-validator:
- New internal/services/condition_expr_validator.go (136 LoC) — locks the grammar to {flag:<str>} OR {op:'and'|'or', args:[<leaf>|<composite>]} per design §4.1
- RuleEditorService.Create + Update reject non-conforming expressions
- 166-LoC test coverage; all 18 existing condition_expr rows validate
P4 (partial) — trigger_events deprecation (mig 156):
- NULLs out the 2 hybrid rules' trigger_event_id (parent_id is the canonical edge per §2.1)
- Adds 'Deprecated: see m/paliad#149' header on the legacy /api/tools/event-deadlines route
- Does NOT drop paliad.trigger_events nor the 5 read sites — those are gated on the editorial reparenting of the 73 orphan globals (NULL proceeding_type_id, served only via trigger_event_id). Editorial work is m's, not coder scope.
Comment on m/paliad#149 (issuecomment-10436) enumerates the exact next steps for the eventual follow-up coder once editorial reparenting completes.
Phase 2 train: P0 + S1+S1a + P1 + P3 + P2 + P4 partial — ALL shipped. Final P4 step waits on editorial.
|
|||
| d6a5dedb2b |
feat(deadline-system): P4 (partial) — partial trigger_events deprecation (m/paliad#149)
Phase 2 P4 partial-scope (head approved 2026-05-27 15:24). The full
drop of paliad.trigger_events + the legacy route + 5 read sites is
gated on an editorial backfill that's not in coder scope — 73 active
sequencing_rules carry proceeding_type_id IS NULL and are addressed
ONLY via trigger_event_id today. Dropping anything would break those
73 orphans.
What this lands:
1. Mig 156 — NULL out trigger_event_id on the 2 hybrid rules that
carry BOTH parent_id AND trigger_event_id. Per design §2.1 /
m's Q1, parent_id is the canonical predecessor link; the
hybrid trigger_event_id was redundant. The 2 rules' parent_id
chains keep the live edge. Live-DB verified post-apply: 0
active hybrid rules remain.
2. Deprecation + Link headers on POST /api/tools/event-deadlines
per RFC 8594 / RFC 9745. The route stays functional so the 73
orphans keep working until reparenting lands.
What this does NOT land (gated on editorial):
- DROP TABLE paliad.trigger_events
- DROP COLUMN paliad.sequencing_rules.trigger_event_id
- Remove the legacy /api/tools/event-deadlines handler
- Remove EventDeadlineService + ExportService::1680 sheet
- Remove deadline_rule_service.go:226 label-fallback path
- Remove event_type_service.go:40+414 reads (33 event_types still
reference trigger_event_id)
- Update cmd/gen-upc-snapshot/main.go:185-202 to skip trigger_events
- Drop the sequencing_rules_trigger_event_id_fkey FK
All of the above lands in a follow-up mig once the orphan count
hits zero. Comment to follow on m/paliad#149 with the editorial-
backlog list.
Verified: live-DB pre/post hybrid count (0 active hybrids remain);
mig idempotent; go vet clean.
Design: docs/design-deadline-system-revision-2026-05-27.md §2.1
(parent_id canonical), §3.4 (legacy route fate), §4.3 (table fate),
§5 (slice train P5 row). t-paliad-331.
|
|||
| 9940dd8216 |
feat(deadline-system): P2 — condition_expr write-validator (m/paliad#149)
Phase 2 P2 (design §4.1). Locks the condition_expr grammar to:
CondExpr := { "flag": "<known_flag>" }
| { "op": "and"|"or", "args": [<CondExpr>, ...] }
Where <known_flag> must exist in paliad.scenario_flag_catalog (today:
with_ccr / with_amend / with_cci; editorial adds via the catalog
table as needed).
Wire-time validation in RuleEditorService.Create and UpdateDraft —
the rule editor surfaces a 400 with a friendly message before the row
hits the DB. Empty / JSON null inputs pass through (the "no gate"
shape; stored as NULL column).
The validator:
* walks the JSON tree once, collecting every leaf flag name
* rejects mutually-exclusive shapes (leaf + composite in one node)
* rejects empty args, bad op values, empty flag strings
* does ONE batch lookup of the collected leaf names against the
catalog (regardless of expression depth)
Tests:
* 9 shape-only unit tests covering every reject path (no DB needed)
* TestValidateConditionExpr_LiveCatalog covers 6 good shapes + 2
unknown-flag cases against the live catalog
* TestConditionExpr_AllLiveRowsValidate runs the validator over
every active+published condition_expr in paliad.sequencing_rules
to enforce the §4.1 invariant on every deploy (today's 18 rows
all conform — verified via Supabase MCP pre-flight)
Live-DB tests skip cleanly when TEST_DATABASE_URL is unset (same
posture as sibling live tests in this package).
Design: docs/design-deadline-system-revision-2026-05-27.md §4.1
(grammar formalisation). t-paliad-331.
|
|||
| f6add95d0a |
Merge: t-paliad-331 P3 — Verfahrensablauf three-way detail filter (m/paliad#149)
ritchie shipped m's headline UX (paliadin priority signal 14:58): 'The new timeline filters for optional / mandatory / show only selected is what I am most waiting for. I want this to be consolidated for all our deadlines so we can simulate all proceedings.' Three-way detail-level filter above the Verfahrensablauf result panel: - Nur Pflicht — only priority='mandatory' rules - Gewählt (default) — mandatory + recommended + every explicit per-rule override in projects.scenario_flags - Alle Optionen — every rule, unselected ones rendered dotted-border + muted State persists per-user via localStorage['verfahrensablauf:view_mode']. Per-rule Aufnehmen/Entfernen chips wire to projects.scenario_flags via the P0 SSoT (rule:<uuid> entries). New files: verfahrensablauf-detail-mode.ts (125), verfahrensablauf-detail-mode.test.ts (96), filter wiring in verfahrensablauf.ts (+204) and views/verfahrensablauf-core.ts (+37). 63 LoC CSS (dotted-border treatment). bun build clean, 264 frontend tests pass (8 new), go vet clean. Ritchie continuing with P2 (condition_expr write-validator) then P4 (legacy deprecation). |
|||
| 480332a5f5 |
feat(deadline-system): P3 — three-way detail filter on Verfahrensablauf (m/paliad#149)
m's headline UX ask (2026-05-27 14:58, paliadin priority signal):
"The new timeline filters for optional / mandatory / show only
selected is what I am most waiting for. I want this to be
consolidated for all our deadlines so we can simulate all
proceedings."
Phase 2 P3. Adds a three-way detail-level filter above the result
panel on /tools/verfahrensablauf:
( ) Nur Pflicht — only priority='mandatory' rules
(•) Gewählt — mandatory + recommended (default) + every
explicit per-rule override the user has set
in projects.scenario_flags
( ) Alle Optionen — every rule, with unselected ones rendered
dotted-border + muted so the user sees what
they're NOT considering
State persists per-user via localStorage["verfahrensablauf:view_mode"].
The filter is pure client-side narrowing on the calc payload — flipping
the toggle re-renders instantly without a fresh backend call.
Per-rule selection (design §2.4a): every optional / recommended card
now carries an [Aufnehmen] / [Entfernen] chip. Clicking writes a
"rule:<uuid>" entry into the project's scenario_flags via the P0 SSoT
PATCH endpoint, recording only deviations from the priority default:
recommended + entfernen → rule:<uuid> = false (explicit deselect)
optional + aufnehmen → rule:<uuid> = true (explicit select)
flipping back to the default deletes the entry
Mandatory rules never expose the chip — they cannot be deselected.
Wire-shape change: CalculatedDeadline gains `ruleId` (the backend already
emits it as `ruleId` in TimelineEntry; only the frontend interface needed
to surface it).
Conditional handling: a conditional rule whose predicate doesn't fire
is treated as unselected in "Gewählt" mode (even when priority=
mandatory) — mandatory means "must be filed IF the predicate fires",
not "always render". The "Alle Optionen" view re-surfaces it so the
lawyer can see what scenario would unlock it.
Cross-surface coherence: hydrating ?project=<id> reads scenario_flags
from the SSoT and pre-fills the existing flag checkboxes (with_ccr /
with_amend / with_cci) so the page reflects the project's persisted
state on first paint. Every flag toggle + every per-rule chip click
PATCHes back. The page also listens for the scenario-flag-changed
CustomEvent fired by peer surfaces (Mode B Fristenrechner result-view)
and re-renders without a fresh fetch.
i18n: 5 new keys (deadlines.detail.{label,mandatory_only,selected,
all_options,optional_unselected_hint,aufnehmen,entfernen}) DE + EN.
CSS: dotted-border + muted treatment on .timeline-item-header--
unselected; .timeline-selection-chip with --add (lime accent) and
--remove (discreet muted) variants.
Tests: 8 new unit tests covering isRuleSelected (4 priority × 2 flag
state matrix) and filterByDetailMode (3 modes × default/override cases).
Verified: bun build clean, bun test 264/264 (8 new), go vet clean.
Design: docs/design-deadline-system-revision-2026-05-27.md §2.4a
(selection state model), §3.3a (view-mode toggle), §6 (Entry A spec).
t-paliad-331. Re-prioritised by m via paliadin 14:58.
|
|||
| 97d90ce651 |
Merge: t-paliad-331 — Phase 2 slices P0 + S1+S1a + P1 (m/paliad#149)
ritchie shipped three slices of the Phase 2 deadline-system revision train per design §5:
P0 — Scenario SSoT (mig 154):
- ALTER TABLE projects ADD COLUMN scenario_flags jsonb DEFAULT '{}'
- New paliad.scenario_flag_catalog table
- GET/PATCH /api/projects/{id}/scenario-flags endpoints
- Verfahrensablauf + result-view checkbox binding read+write through scenario_flags
- Per-rule selection state via 'rule:<uuid>' entries (generalises the with_ccr dropdown pattern, no new column on sequencing_rules)
- New scenario_flags_service.go (375 LoC), scenario-flags.ts client, i18n keys
S1+S1a — Cross-party display + spawn-only picker filter:
- FristenrechnerService.LookupFollowUps stops filtering by party server-side; returns all + primary_party
- UI groups: own-side checked-by-priority, cross-party annotated 'Gegenseitig' badge + unchecked
- SearchEvents SQL adds AND sr.is_spawn = false to filter spawn-only events as triggers
- lookup_events_test.go regression coverage
P1 — upc.apl re-split (m's Q5 divergence, mig 155):
- Reverts upc.apl.unified (id=160) back into upc.apl.merits / upc.apl.cost / upc.apl.order split
- Retargets 16 sequencing_rules to the appropriate split id
- Mig 155 applied to live DB per ritchie's report
Next per m's 14:58 priority signal: P3 (Entry A Verfahrensablauf tree UI with three-way view-mode toggle) — ritchie jumping straight there, then P2 + P4.
|
|||
| 3a4e99cb92 |
feat(deadline-system): P1 — upc.apl re-split into merits/cost/order (m/paliad#149)
Phase 2 P1 / m's Q5 divergence (2026-05-27, verbatim):
"Reverse the unification as suggested in 3. They are different
proceedings, I only wanted the approach to be unified in the
'determinator' — but they are actually different proceedings!"
Mig 155 reverts the mig-096 unification:
Before: id=160 upc.apl.unified active (16 rules), id=11/19/20 inactive
After: id=11 upc.apl.merits (7 rules), id=19 upc.apl.cost (2 rules),
id=20 upc.apl.order (7 rules) all active; id=160 inactive
The 16 rules under id=160 split cleanly by event_code prefix; all 10
parent_id edges among them are bucket-local (pre-flight audit), so
the tree shape survives the rebind unchanged.
Spawn FK retarget: pi.cfi.appeal_spawn flips from 11 (merits) → 20
(orders track) per design §3.1 — PI appeals land on orders, not
merits. The inf/rev/dmgs spawns keep target=11 (merits), now active.
Determinator routing layer (proceeding_mapping.go) keeps its single
"Berufung" front door per m's intent — only the data shape changes.
Pre-flight verified: 0 projects bound to id=160, 0 scenarios reference
upc.apl. Zero data migration on the project side.
Tests: lookup_events_test.go assertions on the three appeal_target
buckets updated to the new codes (endentscheidung → upc.apl.merits,
schadensbemessung → upc.apl.merits, bucheinsicht → upc.apl.order).
Same rule set, post-split coordinates.
Snapshot regen (pkg/litigationplanner/embedded/upc/) deferred: the
current snapshot only contains inf+rev so the apl re-split doesn't
shift its contents; regenerating would surface unrelated active PTs
and pollute this slice. Tracked as a follow-up.
Verified: go vet clean, go test ./internal/services/... -run
LookupEvents|proceeding_codes clean.
Design: docs/design-deadline-system-revision-2026-05-27.md §3.1
(re-split mig), §1.3 (spawn graph post-Q5). t-paliad-331.
|
|||
| 3533d79a25 |
feat(deadline-system): S1+S1a — cross-party display + spawn-only picker (m/paliad#149)
Phase 2 S1 + S1a (pre-ratified from t-paliad-327, folded into the
Phase 2 train).
S1 — Cross-party display:
- FristenrechnerService.LookupFollowUps stops filtering by party
server-side; queryFollowUpRows drops the perspective WHERE clause
and returns every published+active child.
- Server now computes is_cross_party per row (true only when
perspective ∈ {claimant,defendant} AND primary_party is the
opposite side; NULL/both/court is never cross-party).
- FollowUpRule wire shape gains the boolean.
- Frontend renderRule adds a "Gegenseitig" badge + is-cross-party
row class (muted styling, disabled checkbox affordance).
- defaultChecked returns false for cross-party rows.
- countSelected + submitWriteBack skip cross-party rows
unconditionally — even if a user manually checks the box, they
describe opposing-side filings and don't belong in our Akte set
(design §2.4 write-back exclusion).
- i18n: deadlines.overhaul.crossparty.badge / .tooltip (DE+EN).
- CSS: .fristen-overhaul-rule-crossparty + .is-cross-party row
modifier.
S1a — Spawn-only picker filter:
- SearchEvents WHERE now adds `sr.is_spawn = false` so spawn rules
(e.g. appeal_spawn, the inf.cfi → upc.apl.merits hop) no longer
surface as picker hits. Spawn rules are consequences, not
triggers — a lawyer searching "Berufung" wants the appeal-tree
root, not the inf.cfi spawn link.
- Terminal leaves (Duplik etc.) stay pickable per design §2.2's
carve-out: their own anchor is non-spawn, so they surface and
render an honest empty follow-up list.
Honest UX: hiding cross-party follow-ups lied about what the
workflow does next (cf. RoP.029.d falling off when perspective=
claimant on def_to_ccr — the workflow continues, just on the
defendant's docket). The fix makes the data legible without
contaminating the write-back path.
Verified: go vet clean, bun build clean, bun test 256/256,
go test ./internal/services/... -run LookupFollowUps... clean.
Design: docs/design-deadline-system-revision-2026-05-27.md §2.4
(cross-party) + §2.2 (spawn-only picker). t-paliad-331.
|
|||
| 2a69f7fc6c |
Merge: t-paliad-332 — UPC vacations no longer block deadlines (align with paliad t-paliad-121)
brunel aligned the embedded snapshot calendar with paliad-side policy from t-paliad-121: UPC vacation rows stay in the data for informational annotation but no longer trigger IsNonWorkingDay → AdjustForNonWorkingDays leaves dates intact. Changes: - pkg/litigationplanner/embedded/upc/holidays.go: IsNonWorkingDay now returns true only on closure (not vacation). Vacations still surface via AdjustForNonWorkingDaysWithReason for labelling. - pkg/litigationplanner/embedded/upc/holidays.json: regenerated from live paliad.holidays. Was 5 placeholders → now 55 holidays (33 vacation + 22 closures). Includes UPC Winter Vacation rows. - pkg/litigationplanner/embedded/upc/meta.json: snapshot version bump. - snapshot_test.go: +42 lines covering the vacation non-blocking behavior with regression cases. Affects youpc.org/deadlines (consumes pkg/litigationplanner via Go module replace) — picks up automatically on rebuild. |
|||
| 39353d49ed |
fix(litigationplanner): UPC vacations no longer block deadlines (align with paliad t-paliad-121)
youpc.org/deadlines was rolling a deadline "from 2027-01-02 (UPC Winter Vacation)" — i.e. across the UPC judicial vacation as if it were a public holiday. Paliad-side t-paliad-121 already decided vacations are informational only (the Court keeps running through them, RoP / UPC AC decision-on-judicial-vacation 2023-05-26), and `HolidayService.Is NonWorkingDay` in `internal/services/holidays.go` is correct. The embedded snapshot consumed by youpc.org via Go-module replace had drifted: `pkg/litigationplanner/embedded/upc/holidays.go:74` blocked on both `isClosure()` AND `isVacation()`. This commit aligns the embedded calendar with the paliad-side semantics and ships a fresh holiday set so the existing 2026/2027 fix actually takes effect downstream. Code changes (`holidays.go`): - `IsNonWorkingDay`: drop the `|| h.isVacation()` branch — only weekends and `isClosure()` rows trigger the roll. Godoc rewritten to mirror the paliad-side rationale (Court keeps operating, RoP cites, vacation rows kept for informational labels). - `isClosure()`: accept both `"public_holiday"` and `"closure"`. Live paliad DB rows use the `public_holiday` value; the placeholder snapshot shipped with the original Slice C used `closure` as a hand-crafted synonym. Reconciles with `internal/services/holidays.go:132` which already does the same union. Required to make the regenerated JSON (full of `public_holiday`) keep blocking DE national holidays after the regeneration in this commit. - Type-level godoc updated: `SnapshotHolidayCalendar` now documents vacation-is-informational, and the `AdjustForNonWorkingDaysWithReason` precedence note explains that `vacation` kind only fires when a vacation row overlaps a weekend or closure that's already doing the rolling. Data refresh (`holidays.json`): - Regenerated from paliad prod (postgres @ 100.99.98.201:11833, paliad schema). 55 rows for 2026 + 2027: 22 DE public_holiday + 33 UPC vacation (25 Summer Vacation Jul 27–Aug 28, 8 Winter Vacation Dec 24/28–31 + Jan 4–6). The previous placeholder shipped only 5 rows (3 Sommerpause + Neujahr + Tag der Arbeit, no Winter Vacation at all) — which is why a date landing in late Dec / early Jan landed inside an unmodeled gap on the consumer side. - `meta.json` bumped: version → `2026-05-27-1-holidays-only`, `holiday_count` 5 → 55, `source_db_label` flags that only holidays.json was refreshed (see friction note below). Regression test (`snapshot_test.go::TestSnapshotHolidayCalendar`): - 2026-08-04 (Tue, UPC Summer Vacation) — `IsNonWorkingDay` must be false; `AdjustForNonWorkingDays` must NOT mutate the date. - 2027-01-02 (Sat, m's flagged scenario) — must roll forward through Sat/Sun, then STOP on Mon 2027-01-04 (UPC Winter Vacation, no longer blocking). Pre-fix this rolled all the way to Thu 2027-01-07. Cross-repo: youpc.org imports `pkg/litigationplanner` via Go-module replace; the regenerated snapshot ships on its next rebuild. No separate youpc.org commit needed — paliad is the source of truth. Friction note: `cmd/gen-upc-snapshot/main.go` itself is incompatible with the current paliad schema. Migration 140 (`140_drop_deadline_rules`) dropped `paliad.deadline_rules`, but the generator still SELECTs from it (main.go ~L162). Running the tool against prod fails on the rules step. I bypassed the broken path and generated `holidays.json` directly from the DB via psql + jq (same JSON shape that `EmbeddedHoliday` expects, nulls filtered for `omitempty`). The other snapshot files (rules.json, proceeding_types.json, trigger_events.json, courts.json) remain at their pre-existing placeholder state — re-flagged in meta.json's `source_db_label`. Refitting the generator for the post- mig-140 schema is a separate task. go vet + go test ./... clean (256+ Go tests pass, including the new regression cases). |
|||
| d36cc9ee15 |
feat(deadline-system): P0 — per-project scenario_flags SSoT (m/paliad#149)
Phase 2 P0 of the deadline + procedural-events revision. Establishes
paliad.projects.scenario_flags (jsonb) + paliad.scenario_flag_catalog as
the single source of truth for per-project scenario state — replacing
the three fragmented stores athena flagged (project_event_choices,
scenarios.spec, DOM-only). All three were empty per the audit so no
data migration is needed.
The jsonb map carries two key shapes:
* named flags (whitelist via scenario_flag_catalog) — today
with_ccr / with_amend / with_cci
* per-rule selection deviations of shape "rule:<uuid>" — wired up
here for validation; the consumer UI lands in P3
Endpoints:
GET /api/projects/{id}/scenario-flags
PATCH /api/projects/{id}/scenario-flags
PATCH semantics: bool = write; null = delete (priority-driven default
returns); missing key = leave alone. The service validates every key
on write (catalog lookup + UUID rule-membership + mandatory-cannot-be-
deselected) before persisting, so a single bad key fails the whole
patch.
Frontend bind: new scenario-flags.ts client module + Mode B's flag
checkboxes (ccr-flag / inf-amend-flag / rev-amend-flag / rev-cci-flag)
now hydrate from / persist to the project's scenario_flags on every
toggle. Kontextfrei (no project) is unchanged. Cross-surface coherence
via a scenario-flag-changed CustomEvent (peer surfaces — Verfahrens-
ablauf strip, Mode B result-view — will subscribe in P3).
Mig 154 is audit-defensive (set_config of paliad.audit_reason); no
audit trigger fires on paliad.projects today but a future one will
inherit the reason. Seeds the three known flags. CHECK constraints
enforce the top-level shape (jsonb_typeof = 'object') and the
catalog key pattern (lowercase, not 'rule:%' prefix).
Verified against the live DB: 18 projects default to '{}', catalog
has 3 rows, applied_migrations advanced to 154.
Design: docs/design-deadline-system-revision-2026-05-27.md §2.3, §2.4a,
§4.1, §5 (P0 row). t-paliad-331.
|
|||
| a9fd979cdb |
Merge: t-paliad-330 — timeline view dark-mode CSS token migration
brunel converted hardcoded hex to existing design tokens for the .timeline-* classes (Verfahrensablauf at ?view=timeline). No new tokens introduced; 11 existing tokens reused. Layout/spacing untouched. Mirrors the t-paliad-326 playbook applied earlier to the Fristenrechner overhaul CSS, but on the separate timeline view that wasn't in scope then. |
|||
| c48fa93e3d |
fix(verfahrensablauf): dark-mode token migration for timeline view CSS
The /tools/verfahrensablauf?view=timeline page (and the columns-view mirror via `.fr-col-item--*` modifiers) had hardcoded light backgrounds that survived a dark-mode flip. Root cause: four undefined custom properties (`--color-bg-soft`, `--color-border-soft`, `--color-accent-bg`, `--brand-lime`) consumed by the `.timeline-*` and adjacent `.event-card-choices-*` rules, each with a hardcoded hex / RGBA fallback. Since neither :root nor :root[data-theme='dark'] defines those tokens, every consumer fell through to the light fallback in both themes — leaving the conditional-row bg, the popover surface, the option-button bg, the chip-skipped bg, and the popover block-separator border stuck on near-white in dark mode. Earlier t-paliad-326 covered the new Fristenrechner overhaul CSS only; the timeline view styles are a separate block (~L3337-3810 in `frontend/src/styles/global.css`) and were not touched. Migrate every consumer to the existing dual-theme tokens already used across paliad. Same approach m approved for t-paliad-326, no new tokens introduced (all reuse): - Card / popover surfaces (`.event-card-choices-popover`, `.event-card-choices-option`) → `--color-surface` (white light / card-tint dark) so the popover reads as raised above the body in both themes. - Subtle raised surface for conditional row, skipped chip, option hover (`.timeline-item--conditional .timeline-content`, `.fr-col-item--conditional`, `.event-card-choices-chip-part--skipped`, `.event-card-choices-option:hover/:focus-visible`) → `--color-surface-muted`. **This is the visible bug fix m flagged.** - Lime-tint backdrops (`.timeline-context-note` bg, `.event-card-choices-caret:hover/:focus-visible`) → `--color-bg-lime-tint` (lime-alpha 0.10 light / 0.12 dark). - Active-option chip bg (`.event-card-choices-chip-part`) → `--color-accent-soft-bg`. - Lime accent borders / fills (`.timeline-context-note` left border, `.timeline-date--overridden`, `.frist-date-edit-input`, `.event-card-choices-unhide-btn`, `.event-card-choices-option--active`) → `--color-accent` / `--color-accent-fg`. Drops the legacy `#c6f41c` fallback that doesn't match the current brand (`--hlc-lime: #BFF355`). - Neutral borders (`.event-card-choices-caret`, `.timeline-item--hidden .timeline-content`, `.fr-col-item--hidden`, `.timeline-item--conditional .timeline-content`, `.event-card-choices-popover`, `.event-card-choices-option`, `.event-card-choices-block + .event-card-choices-block`) → `--color-border` (warm cream-derived light / cream-alpha dark). - Popover shadow `rgba(0, 0, 0, 0.12)` → `var(--shadow-md)` (auto-deepens to `rgba(0, 0, 0, 0.45)` in dark). - Status red (`.event-card-choices-error`) → `--status-red-fg` (defined in both themes; old `#b00020` fallback unreachable). Zero new tokens introduced — every replacement uses a token already shipped in both :root and :root[data-theme='dark']. Verified by mounting `frontend/dist/assets/global.css` against a representative static DOM (context-note banner, every timeline-item variant — conditional / skipped / hidden / overridden-date / mandatory — popover with active/inactive options, unhide button, error message, all four party-badge stances) and toggling `data-theme` between light and dark: conditional row bg flips from grey to muted-cream-on- midnight, popover lifts off the body via `--shadow-md`, every chip and border stays legible in both themes. bun build + bun test (256 pass) + go vet clean. |
|||
| 5f7a66bbec |
Merge: t-paliad-329 — Phase 2 deadline + procedural-events full revision design (m/paliad#149)
atlas shipped the comprehensive Phase 2 design covering Option B (full revision absorbs t-paliad-327 narrow scope). 776 lines.
Spine: connection schema for all procedural events as ASCII trees per PT + Mermaid spawn graph. parent_id canonical, trigger_event_id deprecated.
Tier 1 (4 questions, all on-recommendation):
- parent_id canonical predecessor link
- Trigger discoverability via derived EXISTS check
- Scenario state SSoT in projects.scenario_flags jsonb (mig 154)
- Cross-party display contract
Tier 2 (4 questions, 1 divergent):
- Q5 m diverged: revert upc.apl.unified back into merits/cost/order split (mig P1 retargets 16 rules)
- Spawn-only events excluded from picker
- Entry A 'sequence-from-proceeding-type' view extends /tools/verfahrensablauf
- Legacy /api/tools/event-deadlines + paliad.trigger_events deprecated
Tier 3: condition_expr grammar formalised ({flag} / {op:and|or,args:[...]}), editorial backfill workflow on /admin/procedural-events parent-NULL filter, trigger_events table dropped.
Shift-2 additions (per m's 14:31-14:35 direction, folded in
|
|||
| 490c8a8c8c |
design(deadline-system): fold m's selection + view-mode + R.109 additions (t-paliad-329)
m's clarification at 14:40 reframed the original "rarity" framing: every
optional rule is a per-scenario selectable card; the Verfahrensablauf
gets a three-way detail-level filter (Nur Pflicht / Gewählt / Alle
Optionen). The CCR-dropdown pattern generalises to per-rule chips.
Three folded additions:
§2.4a — Selection state + detail-level filter. NO new column on
sequencing_rules (reverts the earlier is_edge_case strawman). Extends
projects.scenario_flags jsonb to carry both named flags (with_ccr etc.)
and per-rule entries (rule:<uuid>). Storage only carries deviations
from the priority default (recommended = default-selected,
optional = default-unselected). Whitelist accepts rule:<uuid> when the
UUID resolves to an active rule on the project's PT.
§3.3a — Verfahrensablauf view-mode toggle: three-way segmented control,
localStorage persistence, default "Gewählt". Mode B result view stays
single-purpose (no view-mode toggle there).
§4.2.1 — R.109 translation chain editorial worked example: R.109.1 stays
as optional anchor; R.109.4 reparents to R.109.1 with condition_expr
{flag: with_interpreter_denied} and primary_party=both (parties, not
court); R.109.5 reparents to R.109.1 with {flag: with_translation_granted}.
Introduces two new flags to scenario_flag_catalog.
§6 UI spec updated: two mocked tree states (Gewählt + Alle Optionen)
showing the dotted-border [Aufnehmen] chips, [Entfernen] on selected
optionals, greyed-with-hint on flag-gated conditionals, and the
subtree-hide-on-unselected-ancestor render logic.
§10.0a captures the additions; §10.1 notes they don't change the slice
train (P0 + P3 take the extended scope; no new mig).
|
|||
| b1c9e8dd97 |
design(deadline-system): Phase 2 revision — connection schema + 12 m's decisions (t-paliad-329)
Builds on athena's Phase 1 assessment (
|
|||
| 9aee9e4101 |
Merge: t-paliad-328 — Phase 1 assessment of the deadline + procedural-events system (m/paliad#149)
athena delivered the consultant audit per RFC m/paliad#149 Phase 1: - 738-line doc, read-only, no design proposals - §1 consumer audit: every service / handler / frontend / migration that touches sequencing_rules or procedural_events, cited file:line - §2 health-check: green / yellow / red / dead-code buckets - §3 corpus quality: parent_id 47% coverage, condition_expr keys, spawn distribution, primary_party by PT, court-set, trigger_event_id overlap - §4 editorial gap map per proceeding_type - §5 risk register: 11 items, severities marked - §6 recommendation: Tier 1 model decisions to grill first, Tier 2 surface decisions, Tier 3 editorial+cleanup Headline risks bumped from the RFC's framing: - R1 cross-party filter (high) — 39 rules dropped - R2 picker over-accepts (high) — only 67/222 events are real chain-anchors - R3 4 spawn rules target inactive proceeding_type id=11 (high) — dangling FK - R4 73 legacy globals with NULL PT (medium) — invisible to Mode B - R5 5 surfaces still read legacy trigger_events bigint table (medium) - R6 3 scenario stores, all empty but all live (medium) — clarified: paliad.scenarios.spec jsonb is mig 145, not projects.scenarios as the RFC misstated Phase 2 (inventor) gates on m's go. The inventor reads this + RFC + grills m on Tier 1 before sketching. |
|||
| 810b65463e |
docs(assessment): Phase 1 audit — deadline + procedural-events system (m/paliad#149)
t-paliad-328. Read-only audit of every consumer of paliad.sequencing_rules + paliad.procedural_events + the legacy paliad.trigger_events, plus the rules-corpus quality on the live database. No design — Phase 2 (inventor) gates on this landing. Highlights: - 226 active+published rules / 222 events (1:1 since mig 136) - parent_id chain vs trigger_event_id are functionally disjoint (2/226 overlap); 73 legacy globals own the trigger_event_id lane - 11 risk items captured with file:line; B1 (cross-party follow-up filter) and B2 (picker accepts spawn-only + leaves) confirmed from code at fristenrechner_followups.go:358-367 and :241-287 - 4 spawn rules still point at the inactive upc.apl.merits (id=11); the active appeal type is id=160 (upc.apl.unified) - 6 active proceeding_types are entirely unruled - 3 scenario stores wired (project_event_choices, scenarios table, DOM state); all currently empty, so divergence is dormant - 738 lines (under the 800 cap) Recommendation §6 sequences Tier 1 model decisions ahead of Tier 2 surface decisions and Tier 3 editorial cleanup for the inventor. |
|||
| 33c5fb2983 |
Merge: t-paliad-326 — dark-mode token migration for Fristenrechner overhaul CSS (m/paliad#146 follow-up)
brunel fixed m's bug ('Das CSS vom neuen Fristenrechner scheint wieder keinen Darkmode zu supporten') by migrating the 121 hardcoded hex colors knuth added in S2/S3/S4 to the project's design-token system.
Net: 161 inserts / 123 deletes in frontend/src/styles/global.css. 10 new tokens added to :root and :root[data-theme='dark'] for the few shades that didn't have an existing variable (group dividers, party-stance backgrounds, filter-pill subtle states). All 121 hex usages replaced with var(--color-*) references.
Verified visually via standalone harness: trigger card, 4 priority groups, per-rule rows (claimant/defendant/both/court), Mode A filter strip + result list, Mode B wizard with Filter/Qualifier badges, kontextfrei nudge, write-back footer, success/error toasts — all flip cleanly between light and dark. Layout/spacing/sizing untouched.
bun build + go vet clean.
|
|||
| 76d38c4c84 |
fix(fristenrechner): dark-mode token migration for overhaul CSS (m/paliad#146)
The Fristenrechner overhaul CSS shipped in S2/S3/S4 (commits |
|||
| 233547297c |
Merge: t-paliad-323 Slice S6 — Fristenrechner cleanup (m/paliad#146 SHIPPED)
knuth shipped S6, the final slice of the Fristenrechner overhaul: - frontend/src/client/fristenrechner.ts shrinks by 137 LoC (legacy Pathway-B neutralised; row-stack subtree wired off behind ?legacy=1). - internal/handlers/fristenrechner_event_categories.go dropped — the /api/tools/fristenrechner/event-categories endpoint is gone (route deregistered in handlers.go). - paliad.event_categories table stays for future tools (the hidden 'Ich möchte einreichen' forward-workflow), per design §7-S6. - Deferred follow-ups (knuth's scope discipline): drop the legacy concept-card response shape from /search + lift the dead-code row-stack subtree out of fristenrechner.ts in a separate cleanup PR. Filed as scope note on m/paliad#146 (issuecomment-10414). S1-S6 complete: - S1 |
|||
| ba3e0795f8 |
feat(fristenrechner): Slice S6 — drop cascade endpoint, neutralize legacy Pathway B (m/paliad#146)
Cleanup pass per design §7 / S6, executed as a measured first cut
that drops the cascade endpoint + neutralizes the legacy Pathway B
row-stack / cascade init without lifting the entire ~1500 LoC
subtree out of `fristenrechner.ts`. The dead helpers stay for one
follow-up that can lift them safely.
Backend:
* Deleted `internal/handlers/fristenrechner_event_categories.go`.
* Dropped the `GET /api/tools/fristenrechner/event-categories`
route from `handlers.go`. The `EventCategoryService` itself
stays — it still backs the legacy concept-card search's
`?event_category_slug=` filter, which dies in the same
follow-up that removes the concept-card response shape.
* `paliad.event_categories` TABLE is untouched per design §7
(kept for future tools).
Frontend:
* `loadEventCategoryTree()` reduced to a stub returning `[]` — the
endpoint it fetched no longer exists, and no overhaul surface
calls it.
* `initB1Cascade()`, `initForumFilter()`, `initInboxFilter()`
early-return. Their `DOMContentLoaded` registrations stay so
the bundle exports are stable, but no Pathway B cascade /
chip-strip / inbox-channel wiring fires in `?legacy=1` mode.
* The Pathway B markup in `fristenrechner.tsx` stays in place; it
renders inert when a user hits `?legacy=1&path=b`.
* `buildRowStack`, `renderRowStack`, `runB1Search`, and the row-
stack helper functions remain as unreachable code. Removing
them mechanically requires retiring the entire upper-half
Pathway B B2 search wiring (`runSearch` + `renderConceptCard`
+ `renderSearchResults` + `SearchResponse` types) which is
tangled with the legacy concept-card response shape — deferred
to a follow-up that lands together with the backend
concept-card removal.
Verified — bun build clean (2971 i18n keys unchanged), 256
frontend tests pass, go build + vet clean, live-DB tests
(TestListProceedings, TestSearchEvents, TestLookupFollowUps)
still green.
Follow-up scope tracked in design §7 S6 — pending the helper-tree
lift and the legacy concept-card response-shape removal from
/search.
|
|||
| 8dfdd77079 |
Merge: t-paliad-323 Slice S5 — flip overhaul default; legacy under ?legacy=1 (m/paliad#146)
knuth flipped the overhaul flag per design §7-S5: - isOverhaulMode() inverted: true unless ?legacy=1. - /tools/fristenrechner now lands on the new dual-mode (Direkt suchen + Geführt) by default. - Legacy row stack still reachable via ?legacy=1 for the 2-week deprecation window. - Existing ?overhaul=1 deep links continue to work (no-op pass-through). - Sidebar / header / outbound URLs unchanged — they point at bare /tools/fristenrechner so they pick up the new default automatically. S6 (drop buildRowStack + cascade reads) next on the same branch. |
|||
| 4571bd4980 |
feat(fristenrechner): Slice S5 — flip overhaul default; legacy under ?legacy=1 (m/paliad#146)
`isOverhaulMode()` now returns true unless the URL carries `?legacy=1`. The overhaul UI from S2-S4 (mode tabs + Mode A search + Mode B wizard + shared result view) becomes the default landing for /tools/fristenrechner; the legacy three-step wizard + Pathway A/B + cascade is reachable only via the explicit `?legacy=1` opt-out for the two-week deprecation window before S6 drops the legacy code paths entirely. The pre-existing `?overhaul=1` deep links from S2-S4 still resolve — the detector treats *absence* of `?legacy=1` as overhaul, so bookmarks stay valid. No sidebar / header / outbound link change needed: those all point at the bare `/tools/fristenrechner` URL, which now boots overhaul. Verified — bun build clean (2971 i18n keys unchanged), 256 frontend tests pass, go build + vet clean. |
|||
| 7584b4f428 |
Merge: t-paliad-323 Slice S4 — Fristenrechner Mode B wizard (m/paliad#146)
knuth shipped S4 of the Fristenrechner overhaul (design §3.2, §7-S4): - New frontend/src/client/fristenrechner-wizard.ts (711 LoC) — 5-row 'Geführt' wizard: - R1 event_kind (always asked, ~6 chips) - R2 forum (skipped when R1 narrows to a single forum) - R3 proceeding_type (auto-skipped when narrowed to a single candidate; EventKind EXISTS filter on the catalog) - R4 procedural_event (the landing question) - R5 perspective (async-probed after R4; only fires when the trigger event's follow-ups actually differ by primary_party) - Row Filter/Qualifier badges per §11.Q3 (R1/R2 = Filter, R3/R5 = Qualifier). - R5 has no 'Beide' option per §11.Q8 (qualifier mode in the file path). - Pre-fill+collapse from project: proceeding_type → R3+R2 and our_side → R5 with 'aus Akte' tag. - Backend ProceedingListOptions.EventKind added so R3's catalog query respects the chosen event_kind. - 6 live-DB tests pass — including the kind=proceeding regression check (upc.cfi.interim filtered out as a phase row). 256 frontend tests pass + 7 new for followUpsDifferByParty. Branch rebased on main (post-mig-153 + S3). S5 (flip ?overhaul=1 to default) next. |
|||
| 70985d88b0 |
feat(fristenrechner): Slice S4 — Mode B wizard (m/paliad#146)
Mode B "🧭 Geführt" — the guided 3-5 row wizard defined in
docs/design-fristenrechner-overhaul-2026-05-26.md §3.2. Lands the
user on a single procedural_event (the trigger), then transitions
to the shared §4 result view.
Frontend:
* `fristenrechner-wizard.ts` — row stack with R1..R5:
R1 Was ist passiert? (event_kind, always asked)
R2 Vor welchem Gericht? (jurisdiction, skip if R1 narrows)
R3 In welchem Verfahren? (proceeding_type, auto-skip when
narrowed pool has 1 option)
R4 Welches Schriftstück? (procedural_event, landing)
R5 Welche Seite vertreten Sie? (party, only when follow-ups
differ by primary_party)
Row badges per §11.Q3: R1+R2 = Filter, R3+R4+R5 = Qualifier.
R5 has NO "Beide" option per §11.Q8 — Mode B is the file-mode
where perspective is a qualifier.
* Project prefill — derives R3 + R2 jurisdiction from
project.proceeding_type, R5 from project.our_side. Annotates
pre-filled rows with "aus Akte" tag and implicit rows with
"implizit" tag per §11.Q10 ("erhalten" annotation when a pick is
carried across an upstream change).
* R4-to-result transition — after R4 the wizard fetches /follow-
ups (no dates) to inspect primary_party variance. If both
claimant and defendant rules exist AND R5 isn't already set,
swaps the loading row for the R5 chip picker. Otherwise jumps
straight to mountResultView.
* URL state — `?mode=wizard&kind=…&forum=…&pt=…&r4=…&party=…`
keeps deep-link / back-nav consistent (the launchResult step
sets `event=` so the result view picks up).
* `fristenrechner-result.ts` mountModeShell now dispatches the
"wizard" tab to the wizard module (was a coming-soon
placeholder).
* 18 i18n keys added (DE + EN parity), 145-line CSS block for the
wizard row stack with Filter / Qualifier badge styling and
"aus Akte" annotation chip.
Backend:
* `ProceedingListOptions.EventKind` adds an EXISTS subquery
filter on `paliad.sequencing_rules` ⨯ `paliad.procedural_events`
so Mode B R3 chips only show proceedings whose event roster
contains at least one event of the requested kind (design
§6.3). Endpoint param: `event_kind=` on
/api/tools/proceeding-types.
Test updates:
* `TestListProceedings` switched from SKIP-when-column-missing to
asserting the live filter — mig 153 has landed, `kind` column
is in place. New subtests: kind=proceeding includes
upc.inf.cfi and excludes the phase row upc.cfi.interim;
event_kind=filing narrows to proceedings with filing events.
* `fristenrechner-wizard.test.ts` covers
`followUpsDifferByParty` — the R5 trigger predicate. 7 cases:
asymmetric → true; uniform / both / court / empty → false.
Verified — bun build clean (2971 i18n keys), 256 frontend tests
pass (incl. 7 new), go build + vet clean, live-DB
TestListProceedings passes all 6 subtests against mig 153 data.
|
|||
| 06d6c7540e |
Merge: t-paliad-323 Slice S3 — Fristenrechner Mode A direct search (m/paliad#146)
knuth shipped S3 of the Fristenrechner overhaul (design §3.1, §7-S3):
- New frontend/src/client/fristenrechner-mode-a.ts (507 LoC) — 'Direkt suchen' UI per design §3.1: Filter strip (Forum · Verfahren · Was passierte · Partei) with section-split visual hierarchy per m §11.Q3, free-text search box, ranked result list of procedural_events with click-to-lock-as-trigger.
- Inbox channel as secondary 'Erweitert' chip per §3.3 with CMS→UPC / beA→DE forum nudge.
- Mode tabs pair (Direkt suchen / Geführt) under Step-0 per §11.Q2; wizard tab placeholder until S4.
- Backend ListProceedings(jurisdiction, kind) — kind='proceeding' filter targets mig 153's column (just merged in
|
|||
| 3e55ff8294 |
Merge: t-paliad-325 — mig 153 proceeding_types kind discriminator + ProjectService hardening (m/paliad#147)
ritchie shipped atlas's design (docs/design-proceeding-types-taxonomy-2026-05-26.md):
- mig 153 additive: ADD COLUMN kind text NOT NULL DEFAULT 'proceeding' CHECK in {proceeding,phase,side_action,meta}; UPDATE 4 phase + 10 side_action + 9 meta; per m's Q9 flips is_active=false on the same 23 rows in the same TX. CHECK trigger projects_proceeding_type_kind_check blocks projects.proceeding_type_id from pointing at non-proceeding kinds. Snapshot to paliad.proceeding_types_pre_153 in the same TX. set_config('paliad.audit_reason', ...) defensively.
- ProjectService.SetProceedingType hardened: new ErrInvalidProceedingTypeKind, single-SELECT validator checks category + kind + is_active before assigning.
- 4-angle test (TestProjectService_ProceedingTypeKindGuard) covers happy-path proceeding, rejected phase, rejected inactive, rejected wrong category.
- cmd/gen-upc-snapshot/main.go gains the AND kind='proceeding' filter; embedded snapshot JSON regen flagged as follow-up (needs DATABASE_URL at runtime).
Mode B R3 query now becomes WHERE is_active=true AND kind='proceeding' for a 23-row clean primary list. Phase/side_action/meta rows survive in the table for taxonomic reference but never surface in pickers.
|
|||
| 9d688459e3 |
feat(db): mig 153 — proceeding_types kind discriminator + ProjectService hardening
Adds a `kind` column to paliad.proceeding_types (proceeding / phase /
side_action / meta) so the Mode B R3 Fristenrechner wizard, the
projects.proceeding_type_id binding, and the pkg/litigationplanner
snapshot can filter to primary proceedings only.
Implements the ratified design from docs/design-proceeding-types-
taxonomy-2026-05-26.md (m greenlit 2026-05-27 09:57 after the 11-question
AskUserQuestion round-trip).
Mig 153 is purely additive — ADD COLUMN with a safe DEFAULT, UPDATEs
reclassify 23 non-primary rows (4 phase + 10 side_action + 9 meta), and
a BEFORE INSERT/UPDATE trigger on paliad.projects backstops the new
invariant. Pre-mig audit (Supabase MCP, 2026-05-27) confirmed zero
downstream pressure on the 23 reclassified rows.
- internal/db/migrations/153_proceeding_types_kind.up.sql + .down.sql
- snapshot to paliad.proceeding_types_pre_153 in the same TX
- set_config('paliad.audit_reason', …) defensively
- DO-block asserts 23 reclassified rows before the trigger ships
- Q9 carve-out: is_active=false on every phase/side_action/meta row
- new trigger paliad.projects_proceeding_type_kind_check on
paliad.projects.proceeding_type_id
- internal/services/project_service.go
- extend validateProceedingTypeCategory to also enforce
kind='proceeding' AND is_active=true; new typed error
ErrInvalidProceedingTypeKind
- single SELECT picks up category + kind + is_active
- internal/services/project_service_test.go
- TestProjectService_ProceedingTypeKindGuard covers service-layer
rejection, the active-but-non-proceeding edge, mig 153 trigger
backstop, and the kind='proceeding' happy path
- cmd/gen-upc-snapshot/main.go
- filter proceeding_types query to kind='proceeding' for forward-
compat (the embedded UPC snapshot JSON regen requires DATABASE_URL
access and will land in a follow-up; the current placeholder is
already empty of non-primary rows)
t-paliad-325 / m/paliad#147
|
|||
| 2a2c5b8033 |
feat(fristenrechner): Slice S3 — Mode A direct search (m/paliad#146)
Mode A "⚡ Direkt suchen" — the power-user entry path defined in docs/design-fristenrechner-overhaul-2026-05-26.md §3.1. Renders above the §4 result view; clicking a result row locks the trigger event and transitions to the shared result surface from S2. Frontend: * `fristenrechner-mode-a.ts` — filter strip (Forum / Verfahren / Was passierte / Partei) + free-text search input + result list. Section-split visual hierarchy per m §11.Q3: filter chips in a bordered "Filter (eingrenzen)" strip on top, result list below. Inbox channel chip lives behind an "Erweitert" details summary per §3.3; picking CMS / beA auto-nudges the Forum chip. Party chip retains a "Beide" option (Mode A is filter mode per §11.Q8; Mode B drops it in S4). * `fristenrechner-result.ts` — new `mountModeShell(activeTab)` renders the two mode tabs per §11.Q2 and lazy-imports Mode A. Mode B tab is a placeholder until S4 lands. * `fristenrechner.ts` boot — when `?overhaul=1` is set and `?event` is empty, mountModeShell takes over (default tab = search; `?mode= wizard` opens the wizard tab when S4 ships). With `?event=` the flow still jumps straight to the result view. URL state syncs forum / pt / kind / party / q on every chip click. * 28 i18n keys added (DE + EN parity), 310-line CSS block for the mode tabs + Mode A surface. Backend: * New `ProceedingListOptions { Jurisdiction, Kind }` + service method `ListProceedings(ctx, opts)`. Legacy `ListFristenrechnerTypes` keeps the no-filter signature for existing callers. Handler `/api/tools/proceeding-types` accepts `?jurisdiction=` and `?kind=` query params. * `kind=proceeding` filter targets the taxonomy column landed in mig 153 (parallel branch t-paliad-325, m/paliad#147). Sequenced per the taxonomy doc §7 option (c): mig 153 merges before S3 ships to main, so the filter is never false-positive (no phase / side_action / meta rows leak into the chip strip). Verified — bun build clean (2955 i18n keys, data-i18n attributes clean), 249 frontend tests pass, go build + vet clean. New TestListProceedings — 4 PASS (no-filter, jurisdiction=UPC, jurisdiction=DE, ListFristenrechnerTypes alias) + 1 SKIP for the kind=proceeding case that probes the column and skips when mig 153 hasn't landed yet. S1 + S2 live tests still green. |