SmartTimeline — 7-event lookahead + dependency display + enforced sequence (Slice 2 extension) #31

Open
opened 2026-05-09 10:04:22 +00:00 by mAi · 2 comments
Collaborator

Source: m @ 2026-05-09 12:02 verbatim:

in a case view, we should have our Verlauftab show likely 7 possibly upcoming events, with dates and dependencies of previous events — enforced sequences maybe. can't have SoD before SoC you know.

Three layered requirements

1. 7-event lookahead window

The Verlauf tab on /projects/<id> (Case-level only — see §5 of the design doc for higher-level aggregation) renders a forward-looking section showing the next ~7 likely upcoming events. "Likely" here = the projected rows from FristenrechnerService.Calculate after AnchorOverrides are applied (i.e. predictions conditioned on actuals already entered).

Not 7 fixed-rule predictions — 7 active upcoming events: skip rules that don't apply because their condition_flag is unsatisfied or because the proceeding has progressed past them. Numerically tunable; 7 is the default lookahead, not a hard cap. "Mehr anzeigen" expands the list.

This is a UX layer over Slice 2's projection output — Slice 2 already needs FristenrechnerService.Calculate integration; the 7-cap is a render-side filter.

2. Dependency display

Each projected (and actual) row should surface its provenance — which prior event it depends on for its date math. The data already exists: every paliad.deadline_rules row has a parent rule it triggers from (the rule chain is what lagrange's design §6 calls the "AnchorOverrides reflow chain"). What's missing is the UI affordance.

Proposed surface (open for refinement):

  • Per-row footer "folgt aus: <parent rule code/name> (<actual date | predicted date | datum offen>)".
  • Optional collapsed dependency-tree view ("Pfad anzeigen") that walks parent→child rules from the trigger date to this row.
  • Hover/click affordance to highlight the dependency chain visually.

This is purely additive to lagrange's design; no schema change.

3. Enforced sequences ("can't have SoD before SoC")

The SoC→SoD pair is the canonical example. UPC RoP R.23 (Statement of Defence) is triggered by service of the Statement of Claim — without an SoC date, an SoD due-date prediction is meaningless. Two enforcement levels possible:

  • Soft (predict-with-warning): SoD row renders as "voraussichtlich — abhängig von SoC (Datum offen)", dated cell empty, predicted-faded styling.
  • Hard (block anchor write): at the click-to-anchor write path (Slice 2's POST /api/projects/{id}/timeline/anchor), reject {rule_code: 'sod', actual_date: ...} if the parent rule (soc) has no anchored actual yet. Return a 409 with a suggested-fix message ("SoC zuerst eintragen").

Design call: probably both — soft default in the projection (Slice 2), hard block on write (Slice 2 anchor endpoint). Capture the parent-rule expectation as a structural property of deadline_rules, not a code-side switch — the rule data already has the dependency edge; the API just needs to read it before allowing a write.

Open question: are there cases where a successor's actual date legitimately precedes the predecessor's? E.g. a counterclaim filed before the main claim's response — but that's a different proceeding (CCR sub-project per §4) so its rule chain is independent. Inside a single proceeding's rule tree, sequence violations should always be errors. Confirm.

Mapping to the existing design

This extends Slice 2 of docs/design-smart-timeline-2026-05-08.md (lagrange, merged @ 487fec2). Slice 2 already includes:

  • FristenrechnerService.Calculate integration → projected rows in the timeline
  • Click-to-anchor inline date editor
  • appointments.deadline_rule_id FK
  • paliad.deadlines.source = 'anchor'
  • New "Zukunft anzeigen" macro chip pair

This issue layers three additions on top:

  • Render-side 7-event lookahead cap with "Mehr anzeigen"
  • Provenance/dependency annotation per row + optional dependency-tree expansion
  • Sequence enforcement at the anchor write path + soft annotation in the projection

None of these requires a Slice 2 redesign — they're additive. Slice 2's coder shift can absorb them, OR they can split into a Slice 2.5 if the original Slice 2 is already in flight when this lands. Tag whichever path m picks at greenlight time.

Open questions

  1. Lookahead default: 7 events fixed, or proceeding-type-dependent (e.g. UPC_INF gets 10 since the cascade is denser, EPA_OPP gets 5)?
  2. Dependency display density: footer-line on every row vs. expand-on-click? Footer-line risks visual noise; expand-on-click adds a tap.
  3. Hard sequence enforcement: 409 reject vs. 200 with soft_warning: true and a UI confirm modal? Reject is cleaner; confirm-and-write lets the user override when the rule doesn't match reality (e.g. a procedural quirk we haven't modelled).
  4. Cross-track sequences: if a counterclaim sub-project (per §4) has its own rule chain, do parent-track and child-track sequences ever cross-reference? Standard CCR-on-validity does not; flagging in case there's a corner case.

Out of scope

  • Cross-matter dependency chains (different proceedings). Counterclaim sub-projects (§4) keep independent chains.
  • Real-time recompute of the lookahead on every keystroke. Recompute on (a) page load, (b) anchor write, (c) explicit user refresh.
  • Visualising the dependency graph as a Gantt / DAG chart. Phase out into a separate issue if m wants it.

Filed overnight per m's autonomy directive @ 2026-05-08 23:09. Review at m's pace; this is captured for Slice 2 planning.

**Source:** m @ 2026-05-09 12:02 verbatim: > in a case view, we should have our Verlauftab show likely 7 possibly upcoming events, with dates and dependencies of previous events — enforced sequences maybe. can't have SoD before SoC you know. ## Three layered requirements ### 1. 7-event lookahead window The Verlauf tab on `/projects/<id>` (Case-level only — see §5 of the design doc for higher-level aggregation) renders a forward-looking section showing the next ~7 likely upcoming events. "Likely" here = the projected rows from `FristenrechnerService.Calculate` after `AnchorOverrides` are applied (i.e. predictions conditioned on actuals already entered). Not 7 fixed-rule predictions — 7 *active* upcoming events: skip rules that don't apply because their `condition_flag` is unsatisfied or because the proceeding has progressed past them. Numerically tunable; 7 is the default lookahead, not a hard cap. "Mehr anzeigen" expands the list. This is a UX layer over Slice 2's projection output — Slice 2 already needs `FristenrechnerService.Calculate` integration; the 7-cap is a render-side filter. ### 2. Dependency display Each projected (and actual) row should surface its **provenance** — which prior event it depends on for its date math. The data already exists: every `paliad.deadline_rules` row has a parent rule it triggers from (the rule chain is what lagrange's design §6 calls the "AnchorOverrides reflow chain"). What's missing is the UI affordance. Proposed surface (open for refinement): - Per-row footer `"folgt aus: <parent rule code/name> (<actual date | predicted date | datum offen>)"`. - Optional collapsed dependency-tree view ("Pfad anzeigen") that walks parent→child rules from the trigger date to this row. - Hover/click affordance to highlight the dependency chain visually. This is purely additive to lagrange's design; no schema change. ### 3. Enforced sequences ("can't have SoD before SoC") The SoC→SoD pair is the canonical example. UPC RoP R.23 (Statement of Defence) is triggered by service of the Statement of Claim — without an SoC date, an SoD due-date prediction is meaningless. Two enforcement levels possible: - **Soft (predict-with-warning):** SoD row renders as `"voraussichtlich — abhängig von SoC (Datum offen)"`, dated cell empty, predicted-faded styling. - **Hard (block anchor write):** at the click-to-anchor write path (Slice 2's `POST /api/projects/{id}/timeline/anchor`), reject `{rule_code: 'sod', actual_date: ...}` if the parent rule (`soc`) has no anchored actual yet. Return a 409 with a suggested-fix message ("SoC zuerst eintragen"). Design call: probably both — soft default in the projection (Slice 2), hard block on write (Slice 2 anchor endpoint). Capture the parent-rule expectation as a structural property of `deadline_rules`, not a code-side switch — the rule data already has the dependency edge; the API just needs to read it before allowing a write. Open question: are there cases where a successor's actual date legitimately precedes the predecessor's? E.g. a counterclaim filed before the main claim's response — but that's a different proceeding (CCR sub-project per §4) so its rule chain is independent. Inside a single proceeding's rule tree, sequence violations should always be errors. Confirm. ## Mapping to the existing design This extends **Slice 2** of `docs/design-smart-timeline-2026-05-08.md` (lagrange, merged @ 487fec2). Slice 2 already includes: - `FristenrechnerService.Calculate` integration → projected rows in the timeline - Click-to-anchor inline date editor - `appointments.deadline_rule_id` FK - `paliad.deadlines.source = 'anchor'` - New "Zukunft anzeigen" macro chip pair This issue layers three additions on top: - Render-side 7-event lookahead cap with "Mehr anzeigen" - Provenance/dependency annotation per row + optional dependency-tree expansion - Sequence enforcement at the anchor write path + soft annotation in the projection None of these requires a Slice 2 redesign — they're additive. Slice 2's coder shift can absorb them, OR they can split into a Slice 2.5 if the original Slice 2 is already in flight when this lands. Tag whichever path m picks at greenlight time. ## Open questions 1. **Lookahead default**: 7 events fixed, or proceeding-type-dependent (e.g. UPC_INF gets 10 since the cascade is denser, EPA_OPP gets 5)? 2. **Dependency display density**: footer-line on every row vs. expand-on-click? Footer-line risks visual noise; expand-on-click adds a tap. 3. **Hard sequence enforcement**: 409 reject vs. 200 with `soft_warning: true` and a UI confirm modal? Reject is cleaner; confirm-and-write lets the user override when the rule doesn't match reality (e.g. a procedural quirk we haven't modelled). 4. **Cross-track sequences**: if a counterclaim sub-project (per §4) has its own rule chain, do parent-track and child-track sequences ever cross-reference? Standard CCR-on-validity does not; flagging in case there's a corner case. ## Out of scope - Cross-matter dependency chains (different proceedings). Counterclaim sub-projects (§4) keep independent chains. - Real-time recompute of the lookahead on every keystroke. Recompute on (a) page load, (b) anchor write, (c) explicit user refresh. - Visualising the dependency graph as a Gantt / DAG chart. Phase out into a separate issue if m wants it. Filed overnight per m's autonomy directive @ 2026-05-08 23:09. Review at m's pace; this is captured for Slice 2 planning.
Author
Collaborator

SmartTimeline Slice 2 + the layered #31 features shipped on branch mai/gauss/smarttimeline-slice-2.

Commits:

  • 85d7dd4 feat(t-paliad-173): SmartTimeline Slice 2 backend — projection + anchor + skip + sequence guard
  • 331efc8 feat(t-paliad-173): SmartTimeline Slice 2 frontend + #31 layered features

#31 layer-by-layer:

  • Layer 1 (lookahead cap): default 7, ?lookahead=N override (1..50). Past predicted-overdue rows + court-set rows exempt. "+ Mehr anzeigen" / "− Weniger" toggle remembered in localStorage per project.
  • Layer 2 (dependency display): "Folgt aus: (, <Date|Datum offen>)" footer on every row with a deadline_rule_id whose rule has a parent. "[Pfad anzeigen]" expander.
  • Layer 3 (sequence enforcement): 409 hard-reject at POST /api/projects/{id}/timeline/anchor when the rule has a parent rule with no anchored actual. 409 body returns the missing rule code + name DE+EN + bilingual messages so the frontend renders inline error with a "Stattdessen erfassen" link.

Migration 076 was applied live (tracker 75 → 76); deploy re-applies idempotently.

m/maria — ready for review.

SmartTimeline Slice 2 + the layered #31 features shipped on branch mai/gauss/smarttimeline-slice-2. **Commits:** - 85d7dd4 feat(t-paliad-173): SmartTimeline Slice 2 backend — projection + anchor + skip + sequence guard - 331efc8 feat(t-paliad-173): SmartTimeline Slice 2 frontend + #31 layered features **#31 layer-by-layer:** - Layer 1 (lookahead cap): default 7, ?lookahead=N override (1..50). Past predicted-overdue rows + court-set rows exempt. "+ Mehr anzeigen" / "− Weniger" toggle remembered in localStorage per project. - Layer 2 (dependency display): "Folgt aus: <Name> (<Code>, <Date|Datum offen>)" footer on every row with a deadline_rule_id whose rule has a parent. "[Pfad anzeigen]" expander. - Layer 3 (sequence enforcement): 409 hard-reject at POST /api/projects/{id}/timeline/anchor when the rule has a parent rule with no anchored actual. 409 body returns the missing rule code + name DE+EN + bilingual messages so the frontend renders inline error with a "Stattdessen <predecessor> erfassen" link. Migration 076 was applied live (tracker 75 → 76); deploy re-applies idempotently. m/maria — ready for review.
Author
Collaborator

SmartTimeline Slice 4 — SHIPPED on mai/schroedinger/smarttimeline-slice-4

This closes the 4-slice phasing of t-paliad-169 (design docs/design-smart-timeline-2026-05-08.md).

Commits:

  • 7da8802 backend — levelPolicy(projectType) + lane aggregation + metadata.bubble_up honoured + envelope wire shape {events, lanes}
  • 7e57507 frontend — lane-grouped render in shape-timeline.ts, lane filter chip, Client-level Timeline-Ansicht toggle, custom-milestone bubble-up checkbox, CSS + i18n

Layered features (per §5.1):

  • Patent → lanes per child case, kinds=[deadline, milestone], statuses=[done, open, overdue], projection skipped
  • Litigation → lanes per child patent, kinds=[milestone], statuses=[done]
  • Client → lanes per child litigation, kinds=[milestone], statuses=[done]; default = matter-list, opt-in via Timeline-Ansicht toggle (state persists per project in localStorage)
  • Case → unchanged: full detail + CCR parallel-track render (Slices 1-3)

Bubble-up (Q5 lock-in): metadata.bubble_up=true overrides the level policy filter at Patent/Litigation/Client. counterclaim_created (Slice 3 path) now sets bubble_up=true on both parent and child audit rows. third_party_intervention and scope_change default-on by event_type (no current write path; ready for future routes). custom_milestone default-off; user opts in via the form checkbox.

Wire shape changed: GET /api/projects/{id}/timeline returns {events, lanes} envelope (was []TimelineEvent). Frontend has a defensive fallback for the rolling deploy window. X-Projection-Total / Lookahead / Tracks headers preserved for Slice 1-3 affordances.

Tests:

  • Unit: TestLevelPolicy (locks the (kinds, statuses, lane_axis) triple per type), TestRowSurvivesPolicy_BubbleUpOverridesFilter (override contract), TestExtractBubbleUp (12 cases covering per-event-type defaults + explicit overrides + malformed metadata), TestChildTypeForAxis
  • Integration (live-DB): TestProjectionService_LevelAggregation_Live walks a Patent → Case-A + Case-B fixture, asserts bubbled-up milestone surfaces under Case-As lane, regular custom_milestone is filtered, deadlines surface at Patent level

Build hygiene: go build / go vet / go test clean (caches reused). bun run build clean — i18n codegen 2171 keys.

Branch ready for review + merge. Awaiting marias gate.

### SmartTimeline Slice 4 — SHIPPED on `mai/schroedinger/smarttimeline-slice-4` This closes the 4-slice phasing of t-paliad-169 (design `docs/design-smart-timeline-2026-05-08.md`). **Commits:** - `7da8802` backend — `levelPolicy(projectType)` + lane aggregation + `metadata.bubble_up` honoured + envelope wire shape `{events, lanes}` - `7e57507` frontend — lane-grouped render in `shape-timeline.ts`, lane filter chip, Client-level `Timeline-Ansicht` toggle, custom-milestone bubble-up checkbox, CSS + i18n **Layered features (per §5.1):** - Patent → lanes per child case, kinds=[deadline, milestone], statuses=[done, open, overdue], projection skipped - Litigation → lanes per child patent, kinds=[milestone], statuses=[done] - Client → lanes per child litigation, kinds=[milestone], statuses=[done]; default = matter-list, opt-in via `Timeline-Ansicht` toggle (state persists per project in localStorage) - Case → unchanged: full detail + CCR parallel-track render (Slices 1-3) **Bubble-up (Q5 lock-in):** `metadata.bubble_up=true` overrides the level policy filter at Patent/Litigation/Client. `counterclaim_created` (Slice 3 path) now sets `bubble_up=true` on both parent and child audit rows. `third_party_intervention` and `scope_change` default-on by event_type (no current write path; ready for future routes). `custom_milestone` default-off; user opts in via the form checkbox. **Wire shape changed:** `GET /api/projects/{id}/timeline` returns `{events, lanes}` envelope (was `[]TimelineEvent`). Frontend has a defensive fallback for the rolling deploy window. `X-Projection-Total / Lookahead / Tracks` headers preserved for Slice 1-3 affordances. **Tests:** - Unit: `TestLevelPolicy` (locks the (kinds, statuses, lane_axis) triple per type), `TestRowSurvivesPolicy_BubbleUpOverridesFilter` (override contract), `TestExtractBubbleUp` (12 cases covering per-event-type defaults + explicit overrides + malformed metadata), `TestChildTypeForAxis` - Integration (live-DB): `TestProjectionService_LevelAggregation_Live` walks a Patent → Case-A + Case-B fixture, asserts bubbled-up milestone surfaces under Case-As lane, regular custom_milestone is filtered, deadlines surface at Patent level **Build hygiene:** `go build` / `go vet` / `go test` clean (caches reused). `bun run build` clean — i18n codegen 2171 keys. **Branch ready for review + merge.** Awaiting marias gate.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: m/paliad#31
No description provided.