Problem
The Schedule is a derived concept (sets + stages → days), but its derivation is smeared across two view modules and a hook:
src/pages/EditionView/tabs/ScheduleTab/list/ListSchedule.tsx (196 lines) and horizontal/Timeline.tsx (141) each do fetch → useScheduleData → inline day/time/stage filter predicates → reveal gate → render, with the predicates written twice against different shapes (List filters flattened sets; Timeline filters nested days).
src/hooks/useScheduleData.ts (181) formats times unconditionally — its interface never states the implicit precondition "only call me at full reveal" — and over-promises fields it never populates (conflictsWith, position).
- The time-of-day buckets exist in a third copy in
TimeFilterSelect.tsx:34-40 (labels).
None of this is unit-testable today; it's only reachable by rendering.
Proposed deepening
One pure schedule-builder — buildSchedule(sets, stages, filters, revealLevel, tz) → masked, grouped, filtered days — with both views as thin renderers. Filters and day-grouping become unit-tested without the DOM.
Relations
Umbrella over three narrow slices already ticketed, which could land as part of (or before) this deepening:
Also: #86 (configurable festival day-end hour) would then be a one-module change, and #47 (multi-mode Schedule tab) gets a pipeline that already takes reveal level as input.
Architecture note
Explore ticket from the 2026-07-13 architecture review (candidate 4). Design to be settled in a grilling session before implementation. Vocabulary per /codebase-design.
Problem
The Schedule is a derived concept (sets + stages → days), but its derivation is smeared across two view modules and a hook:
src/pages/EditionView/tabs/ScheduleTab/list/ListSchedule.tsx(196 lines) andhorizontal/Timeline.tsx(141) each do fetch →useScheduleData→ inline day/time/stage filter predicates → reveal gate → render, with the predicates written twice against different shapes (List filters flattened sets; Timeline filters nested days).src/hooks/useScheduleData.ts(181) formats times unconditionally — its interface never states the implicit precondition "only call me atfullreveal" — and over-promises fields it never populates (conflictsWith,position).TimeFilterSelect.tsx:34-40(labels).None of this is unit-testable today; it's only reachable by rendering.
Proposed deepening
One pure schedule-builder —
buildSchedule(sets, stages, filters, revealLevel, tz)→ masked, grouped, filtered days — with both views as thin renderers. Filters and day-grouping become unit-tested without the DOM.Relations
Umbrella over three narrow slices already ticketed, which could land as part of (or before) this deepening:
useScheduleData's deadloading/errorinterface fieldsconsole.logs in this exact pathAlso: #86 (configurable festival day-end hour) would then be a one-module change, and #47 (multi-mode Schedule tab) gets a pipeline that already takes reveal level as input.
Architecture note
Explore ticket from the 2026-07-13 architecture review (candidate 4). Design to be settled in a grilling session before implementation. Vocabulary per
/codebase-design.