Problem
src/lib/timeUtils.ts exports 12 formatting functions, and nearly every one takes timezone?: string as optional, silently falling back to viewer-local format() when omitted:
return timezone ? formatInTimeZone(date, timezone, dateTimeFormat) : format(date, dateTimeFormat);
Per ADR-0002, times must always display in the festival's IANA timezone, never the viewer's — but the optional parameter doesn't enforce that. Nothing stops a future call site from forgetting to pass festival.timezone and getting wrong-but-plausible output instead of a type error. (All current call sites pass it correctly today — this hardens against future regressions rather than fixing a live bug.)
Separately, the 12 near-synonymous exports (formatDateTime vs formatTimeOnly vs formatTimeRange vs formatDayOnly) force callers to pick the right one from a wide, overlapping set.
Fix
Make timezone a required parameter across the formatter set. Consider consolidating into one formatFestivalTime(date, {parts, use24Hour, timezone}) — worth a design-it-twice pass (/codebase-design) before committing to a shape, since it's a larger interface redesign.
Architecture note
Filed from an architecture review (module/interface/depth vocabulary, see /codebase-design). Touches territory decided in ADR-0002 — not contradicting it, but the ADR didn't address this optional-timezone footgun. Marked speculative in the original review; the required-timezone type fix is the low-risk part, the formatter consolidation is the larger, more speculative part.
Problem
src/lib/timeUtils.tsexports 12 formatting functions, and nearly every one takestimezone?: stringas optional, silently falling back to viewer-localformat()when omitted:Per ADR-0002, times must always display in the festival's IANA timezone, never the viewer's — but the optional parameter doesn't enforce that. Nothing stops a future call site from forgetting to pass
festival.timezoneand getting wrong-but-plausible output instead of a type error. (All current call sites pass it correctly today — this hardens against future regressions rather than fixing a live bug.)Separately, the 12 near-synonymous exports (
formatDateTimevsformatTimeOnlyvsformatTimeRangevsformatDayOnly) force callers to pick the right one from a wide, overlapping set.Fix
Make
timezonea required parameter across the formatter set. Consider consolidating into oneformatFestivalTime(date, {parts, use24Hour, timezone})— worth a design-it-twice pass (/codebase-design) before committing to a shape, since it's a larger interface redesign.Architecture note
Filed from an architecture review (module/interface/depth vocabulary, see
/codebase-design). Touches territory decided in ADR-0002 — not contradicting it, but the ADR didn't address this optional-timezone footgun. Marked speculative in the original review; the required-timezone type fix is the low-risk part, the formatter consolidation is the larger, more speculative part.