2026-07-12 18:49:10 -04:00
|
|
|
import type { ContextSession, WeekendContext, WeekendSession } from '../types'
|
feat(race-hub): trustworthy defaults and fan-facing analysis hierarchy (#75)
Make bare /race-hub resolve to a completed session and never open empty
post-session analysis for a future race.
- Backend: add `default_analysis_session` to the Weekend context. It never
resolves to a future session (picks the richest completed session, ties
toward the later one; 0 when everything is upcoming). Existing
`default_session_key` and deep links are unchanged.
- Frontend default resolution prefers the most recently completed weekend
(`pickAnalysisFocusMeeting`) and consumes `default_analysis_session`, falling
back to the switcher when only upcoming sessions exist.
- New `sessionState` lib maps timing + coverage to user language
(upcoming/live/preparing/partial/ready/cancelled); the session rail, active
sub-bar, and WeekendSwitcher now label states instead of raw x/11 counts.
- Future sessions render a purpose-built PreSessionView (expected availability +
countdown) instead of empty Winner/Podium/Pole/Strategy/Compare cards.
- Analysis navigation regrouped into Story / Analysis / Data & Context; every
existing tab is preserved. Diagnostics (renamed from Data Status) is now a
secondary action and the raw dataset strip is hidden behind an explicit
toggle, so operational coverage no longer precedes fan content.
- Loading/error states offer Retry and a path back to Weekend.
Tests: Go query tests for future-exclusion; Vitest for default selection,
future pre-session, partial state, error/retry, grouped nav, and sessionState;
hermetic Playwright for bare/completed/future/return-to-Weekend; new
race-hub-future visual snapshots. Seed adds a far-future session inside the
Monaco meeting (kept in-meeting so Command Center focus is unaffected).
Note: `default_analysis_session` is an additive field on the existing
`/weekend` contract (no new endpoint), per the spec's "context contract" scope.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-12 18:29:34 -04:00
|
|
|
import { isSessionComplete } from './coverage'
|
2026-07-12 18:49:10 -04:00
|
|
|
import { sessionStartTime } from './schedule'
|
feat(race-hub): trustworthy defaults and fan-facing analysis hierarchy (#75)
Make bare /race-hub resolve to a completed session and never open empty
post-session analysis for a future race.
- Backend: add `default_analysis_session` to the Weekend context. It never
resolves to a future session (picks the richest completed session, ties
toward the later one; 0 when everything is upcoming). Existing
`default_session_key` and deep links are unchanged.
- Frontend default resolution prefers the most recently completed weekend
(`pickAnalysisFocusMeeting`) and consumes `default_analysis_session`, falling
back to the switcher when only upcoming sessions exist.
- New `sessionState` lib maps timing + coverage to user language
(upcoming/live/preparing/partial/ready/cancelled); the session rail, active
sub-bar, and WeekendSwitcher now label states instead of raw x/11 counts.
- Future sessions render a purpose-built PreSessionView (expected availability +
countdown) instead of empty Winner/Podium/Pole/Strategy/Compare cards.
- Analysis navigation regrouped into Story / Analysis / Data & Context; every
existing tab is preserved. Diagnostics (renamed from Data Status) is now a
secondary action and the raw dataset strip is hidden behind an explicit
toggle, so operational coverage no longer precedes fan content.
- Loading/error states offer Retry and a path back to Weekend.
Tests: Go query tests for future-exclusion; Vitest for default selection,
future pre-session, partial state, error/retry, grouped nav, and sessionState;
hermetic Playwright for bare/completed/future/return-to-Weekend; new
race-hub-future visual snapshots. Seed adds a far-future session inside the
Monaco meeting (kept in-meeting so Command Center focus is unaffected).
Note: `default_analysis_session` is an additive field on the existing
`/weekend` contract (no new endpoint), per the spec's "context contract" scope.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-12 18:29:34 -04:00
|
|
|
|
|
|
|
|
/**
|
2026-07-12 18:49:10 -04:00
|
|
|
* User-facing lifecycle state for a weekend session.
|
feat(race-hub): trustworthy defaults and fan-facing analysis hierarchy (#75)
Make bare /race-hub resolve to a completed session and never open empty
post-session analysis for a future race.
- Backend: add `default_analysis_session` to the Weekend context. It never
resolves to a future session (picks the richest completed session, ties
toward the later one; 0 when everything is upcoming). Existing
`default_session_key` and deep links are unchanged.
- Frontend default resolution prefers the most recently completed weekend
(`pickAnalysisFocusMeeting`) and consumes `default_analysis_session`, falling
back to the switcher when only upcoming sessions exist.
- New `sessionState` lib maps timing + coverage to user language
(upcoming/live/preparing/partial/ready/cancelled); the session rail, active
sub-bar, and WeekendSwitcher now label states instead of raw x/11 counts.
- Future sessions render a purpose-built PreSessionView (expected availability +
countdown) instead of empty Winner/Podium/Pole/Strategy/Compare cards.
- Analysis navigation regrouped into Story / Analysis / Data & Context; every
existing tab is preserved. Diagnostics (renamed from Data Status) is now a
secondary action and the raw dataset strip is hidden behind an explicit
toggle, so operational coverage no longer precedes fan content.
- Loading/error states offer Retry and a path back to Weekend.
Tests: Go query tests for future-exclusion; Vitest for default selection,
future pre-session, partial state, error/retry, grouped nav, and sessionState;
hermetic Playwright for bare/completed/future/return-to-Weekend; new
race-hub-future visual snapshots. Seed adds a far-future session inside the
Monaco meeting (kept in-meeting so Command Center focus is unaffected).
Note: `default_analysis_session` is an additive field on the existing
`/weekend` contract (no new endpoint), per the spec's "context contract" scope.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-12 18:29:34 -04:00
|
|
|
*
|
2026-07-12 18:49:10 -04:00
|
|
|
* Live comes only from Weekend Context's FIA-backed active identity — never from
|
|
|
|
|
* the scheduled start/end window alone. Preparing / partial / ready / unavailable
|
|
|
|
|
* come from structured `availability.local_analysis` when a context ref exists,
|
|
|
|
|
* otherwise from local dataset coverage after the scheduled start.
|
feat(race-hub): trustworthy defaults and fan-facing analysis hierarchy (#75)
Make bare /race-hub resolve to a completed session and never open empty
post-session analysis for a future race.
- Backend: add `default_analysis_session` to the Weekend context. It never
resolves to a future session (picks the richest completed session, ties
toward the later one; 0 when everything is upcoming). Existing
`default_session_key` and deep links are unchanged.
- Frontend default resolution prefers the most recently completed weekend
(`pickAnalysisFocusMeeting`) and consumes `default_analysis_session`, falling
back to the switcher when only upcoming sessions exist.
- New `sessionState` lib maps timing + coverage to user language
(upcoming/live/preparing/partial/ready/cancelled); the session rail, active
sub-bar, and WeekendSwitcher now label states instead of raw x/11 counts.
- Future sessions render a purpose-built PreSessionView (expected availability +
countdown) instead of empty Winner/Podium/Pole/Strategy/Compare cards.
- Analysis navigation regrouped into Story / Analysis / Data & Context; every
existing tab is preserved. Diagnostics (renamed from Data Status) is now a
secondary action and the raw dataset strip is hidden behind an explicit
toggle, so operational coverage no longer precedes fan content.
- Loading/error states offer Retry and a path back to Weekend.
Tests: Go query tests for future-exclusion; Vitest for default selection,
future pre-session, partial state, error/retry, grouped nav, and sessionState;
hermetic Playwright for bare/completed/future/return-to-Weekend; new
race-hub-future visual snapshots. Seed adds a far-future session inside the
Monaco meeting (kept in-meeting so Command Center focus is unaffected).
Note: `default_analysis_session` is an additive field on the existing
`/weekend` contract (no new endpoint), per the spec's "context contract" scope.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-12 18:29:34 -04:00
|
|
|
*/
|
|
|
|
|
export type SessionState =
|
|
|
|
|
| 'upcoming'
|
|
|
|
|
| 'live'
|
|
|
|
|
| 'preparing'
|
|
|
|
|
| 'partial'
|
|
|
|
|
| 'ready'
|
2026-07-12 18:49:10 -04:00
|
|
|
| 'unavailable'
|
feat(race-hub): trustworthy defaults and fan-facing analysis hierarchy (#75)
Make bare /race-hub resolve to a completed session and never open empty
post-session analysis for a future race.
- Backend: add `default_analysis_session` to the Weekend context. It never
resolves to a future session (picks the richest completed session, ties
toward the later one; 0 when everything is upcoming). Existing
`default_session_key` and deep links are unchanged.
- Frontend default resolution prefers the most recently completed weekend
(`pickAnalysisFocusMeeting`) and consumes `default_analysis_session`, falling
back to the switcher when only upcoming sessions exist.
- New `sessionState` lib maps timing + coverage to user language
(upcoming/live/preparing/partial/ready/cancelled); the session rail, active
sub-bar, and WeekendSwitcher now label states instead of raw x/11 counts.
- Future sessions render a purpose-built PreSessionView (expected availability +
countdown) instead of empty Winner/Podium/Pole/Strategy/Compare cards.
- Analysis navigation regrouped into Story / Analysis / Data & Context; every
existing tab is preserved. Diagnostics (renamed from Data Status) is now a
secondary action and the raw dataset strip is hidden behind an explicit
toggle, so operational coverage no longer precedes fan content.
- Loading/error states offer Retry and a path back to Weekend.
Tests: Go query tests for future-exclusion; Vitest for default selection,
future pre-session, partial state, error/retry, grouped nav, and sessionState;
hermetic Playwright for bare/completed/future/return-to-Weekend; new
race-hub-future visual snapshots. Seed adds a far-future session inside the
Monaco meeting (kept in-meeting so Command Center focus is unaffected).
Note: `default_analysis_session` is an additive field on the existing
`/weekend` contract (no new endpoint), per the spec's "context contract" scope.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-12 18:29:34 -04:00
|
|
|
| 'cancelled'
|
|
|
|
|
|
2026-07-12 18:49:10 -04:00
|
|
|
export interface SessionStateInput {
|
|
|
|
|
weekendSession?: WeekendSession
|
|
|
|
|
context?: WeekendContext | null
|
|
|
|
|
now: Date
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function contextRefFor(
|
|
|
|
|
context: WeekendContext | null | undefined,
|
|
|
|
|
sessionKey: number | undefined,
|
|
|
|
|
): ContextSession | undefined {
|
|
|
|
|
if (!context || !sessionKey) return undefined
|
|
|
|
|
const refs = [
|
|
|
|
|
context.active_session,
|
|
|
|
|
context.default_analysis_session,
|
|
|
|
|
context.previous_completed_session,
|
|
|
|
|
context.next_session,
|
|
|
|
|
]
|
|
|
|
|
return refs.find((ref) => ref?.session.session_key === sessionKey)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function fromAvailability(ref: ContextSession): SessionState | undefined {
|
|
|
|
|
const { schedule, live_session, local_analysis } = ref.availability
|
|
|
|
|
if (live_session === 'active') return 'live'
|
|
|
|
|
if (schedule === 'unavailable' || local_analysis === 'unavailable') return 'unavailable'
|
|
|
|
|
if (local_analysis === 'not_applicable') return 'upcoming'
|
|
|
|
|
if (local_analysis === 'pending') return 'preparing'
|
|
|
|
|
if (local_analysis === 'partial') return 'partial'
|
|
|
|
|
if (local_analysis === 'complete') return 'ready'
|
|
|
|
|
return undefined
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Resolve fan-facing session state. Prefer Weekend Context availability; never
|
|
|
|
|
* assert Live from wall-clock schedule alone.
|
|
|
|
|
*/
|
|
|
|
|
export function resolveSessionState({
|
|
|
|
|
weekendSession,
|
|
|
|
|
context,
|
|
|
|
|
now,
|
|
|
|
|
}: SessionStateInput): SessionState {
|
|
|
|
|
if (weekendSession?.source === 'cancelled') return 'cancelled'
|
|
|
|
|
|
|
|
|
|
const sessionKey = weekendSession?.session.session_key
|
|
|
|
|
const active = context?.active_session
|
|
|
|
|
if (
|
|
|
|
|
active &&
|
|
|
|
|
sessionKey &&
|
|
|
|
|
active.session.session_key === sessionKey &&
|
|
|
|
|
active.availability.live_session === 'active'
|
|
|
|
|
) {
|
|
|
|
|
return 'live'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const ref = contextRefFor(context, sessionKey)
|
|
|
|
|
if (ref) {
|
|
|
|
|
const fromCtx = fromAvailability(ref)
|
|
|
|
|
if (fromCtx) return fromCtx
|
|
|
|
|
}
|
feat(race-hub): trustworthy defaults and fan-facing analysis hierarchy (#75)
Make bare /race-hub resolve to a completed session and never open empty
post-session analysis for a future race.
- Backend: add `default_analysis_session` to the Weekend context. It never
resolves to a future session (picks the richest completed session, ties
toward the later one; 0 when everything is upcoming). Existing
`default_session_key` and deep links are unchanged.
- Frontend default resolution prefers the most recently completed weekend
(`pickAnalysisFocusMeeting`) and consumes `default_analysis_session`, falling
back to the switcher when only upcoming sessions exist.
- New `sessionState` lib maps timing + coverage to user language
(upcoming/live/preparing/partial/ready/cancelled); the session rail, active
sub-bar, and WeekendSwitcher now label states instead of raw x/11 counts.
- Future sessions render a purpose-built PreSessionView (expected availability +
countdown) instead of empty Winner/Podium/Pole/Strategy/Compare cards.
- Analysis navigation regrouped into Story / Analysis / Data & Context; every
existing tab is preserved. Diagnostics (renamed from Data Status) is now a
secondary action and the raw dataset strip is hidden behind an explicit
toggle, so operational coverage no longer precedes fan content.
- Loading/error states offer Retry and a path back to Weekend.
Tests: Go query tests for future-exclusion; Vitest for default selection,
future pre-session, partial state, error/retry, grouped nav, and sessionState;
hermetic Playwright for bare/completed/future/return-to-Weekend; new
race-hub-future visual snapshots. Seed adds a far-future session inside the
Monaco meeting (kept in-meeting so Command Center focus is unaffected).
Note: `default_analysis_session` is an additive field on the existing
`/weekend` contract (no new endpoint), per the spec's "context contract" scope.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-12 18:29:34 -04:00
|
|
|
|
2026-07-12 18:49:10 -04:00
|
|
|
// Settling temporal state with no analysis yet — even without a matching ref.
|
|
|
|
|
if (
|
|
|
|
|
context?.temporal_state === 'session_settling' &&
|
|
|
|
|
weekendSession &&
|
|
|
|
|
weekendSession.source === 'none'
|
|
|
|
|
) {
|
|
|
|
|
return 'preparing'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!weekendSession) return 'unavailable'
|
feat(race-hub): trustworthy defaults and fan-facing analysis hierarchy (#75)
Make bare /race-hub resolve to a completed session and never open empty
post-session analysis for a future race.
- Backend: add `default_analysis_session` to the Weekend context. It never
resolves to a future session (picks the richest completed session, ties
toward the later one; 0 when everything is upcoming). Existing
`default_session_key` and deep links are unchanged.
- Frontend default resolution prefers the most recently completed weekend
(`pickAnalysisFocusMeeting`) and consumes `default_analysis_session`, falling
back to the switcher when only upcoming sessions exist.
- New `sessionState` lib maps timing + coverage to user language
(upcoming/live/preparing/partial/ready/cancelled); the session rail, active
sub-bar, and WeekendSwitcher now label states instead of raw x/11 counts.
- Future sessions render a purpose-built PreSessionView (expected availability +
countdown) instead of empty Winner/Podium/Pole/Strategy/Compare cards.
- Analysis navigation regrouped into Story / Analysis / Data & Context; every
existing tab is preserved. Diagnostics (renamed from Data Status) is now a
secondary action and the raw dataset strip is hidden behind an explicit
toggle, so operational coverage no longer precedes fan content.
- Loading/error states offer Retry and a path back to Weekend.
Tests: Go query tests for future-exclusion; Vitest for default selection,
future pre-session, partial state, error/retry, grouped nav, and sessionState;
hermetic Playwright for bare/completed/future/return-to-Weekend; new
race-hub-future visual snapshots. Seed adds a far-future session inside the
Monaco meeting (kept in-meeting so Command Center focus is unaffected).
Note: `default_analysis_session` is an additive field on the existing
`/weekend` contract (no new endpoint), per the spec's "context contract" scope.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-12 18:29:34 -04:00
|
|
|
|
2026-07-12 18:49:10 -04:00
|
|
|
const start = sessionStartTime(weekendSession.session)
|
feat(race-hub): trustworthy defaults and fan-facing analysis hierarchy (#75)
Make bare /race-hub resolve to a completed session and never open empty
post-session analysis for a future race.
- Backend: add `default_analysis_session` to the Weekend context. It never
resolves to a future session (picks the richest completed session, ties
toward the later one; 0 when everything is upcoming). Existing
`default_session_key` and deep links are unchanged.
- Frontend default resolution prefers the most recently completed weekend
(`pickAnalysisFocusMeeting`) and consumes `default_analysis_session`, falling
back to the switcher when only upcoming sessions exist.
- New `sessionState` lib maps timing + coverage to user language
(upcoming/live/preparing/partial/ready/cancelled); the session rail, active
sub-bar, and WeekendSwitcher now label states instead of raw x/11 counts.
- Future sessions render a purpose-built PreSessionView (expected availability +
countdown) instead of empty Winner/Podium/Pole/Strategy/Compare cards.
- Analysis navigation regrouped into Story / Analysis / Data & Context; every
existing tab is preserved. Diagnostics (renamed from Data Status) is now a
secondary action and the raw dataset strip is hidden behind an explicit
toggle, so operational coverage no longer precedes fan content.
- Loading/error states offer Retry and a path back to Weekend.
Tests: Go query tests for future-exclusion; Vitest for default selection,
future pre-session, partial state, error/retry, grouped nav, and sessionState;
hermetic Playwright for bare/completed/future/return-to-Weekend; new
race-hub-future visual snapshots. Seed adds a far-future session inside the
Monaco meeting (kept in-meeting so Command Center focus is unaffected).
Note: `default_analysis_session` is an additive field on the existing
`/weekend` contract (no new endpoint), per the spec's "context contract" scope.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-12 18:29:34 -04:00
|
|
|
if (start && start > now) return 'upcoming'
|
|
|
|
|
|
2026-07-12 18:49:10 -04:00
|
|
|
if (isSessionComplete(weekendSession.datasets)) return 'ready'
|
|
|
|
|
if (weekendSession.source === 'none') return 'preparing'
|
|
|
|
|
if (weekendSession.source === 'partial') return 'partial'
|
|
|
|
|
return 'ready'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @deprecated Prefer resolveSessionState with Weekend Context. */
|
|
|
|
|
export function sessionState(session: WeekendSession, now: Date): SessionState {
|
|
|
|
|
return resolveSessionState({ weekendSession: session, now })
|
feat(race-hub): trustworthy defaults and fan-facing analysis hierarchy (#75)
Make bare /race-hub resolve to a completed session and never open empty
post-session analysis for a future race.
- Backend: add `default_analysis_session` to the Weekend context. It never
resolves to a future session (picks the richest completed session, ties
toward the later one; 0 when everything is upcoming). Existing
`default_session_key` and deep links are unchanged.
- Frontend default resolution prefers the most recently completed weekend
(`pickAnalysisFocusMeeting`) and consumes `default_analysis_session`, falling
back to the switcher when only upcoming sessions exist.
- New `sessionState` lib maps timing + coverage to user language
(upcoming/live/preparing/partial/ready/cancelled); the session rail, active
sub-bar, and WeekendSwitcher now label states instead of raw x/11 counts.
- Future sessions render a purpose-built PreSessionView (expected availability +
countdown) instead of empty Winner/Podium/Pole/Strategy/Compare cards.
- Analysis navigation regrouped into Story / Analysis / Data & Context; every
existing tab is preserved. Diagnostics (renamed from Data Status) is now a
secondary action and the raw dataset strip is hidden behind an explicit
toggle, so operational coverage no longer precedes fan content.
- Loading/error states offer Retry and a path back to Weekend.
Tests: Go query tests for future-exclusion; Vitest for default selection,
future pre-session, partial state, error/retry, grouped nav, and sessionState;
hermetic Playwright for bare/completed/future/return-to-Weekend; new
race-hub-future visual snapshots. Seed adds a far-future session inside the
Monaco meeting (kept in-meeting so Command Center focus is unaffected).
Note: `default_analysis_session` is an additive field on the existing
`/weekend` contract (no new endpoint), per the spec's "context contract" scope.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-12 18:29:34 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Short label suitable for chips and the session switcher. */
|
|
|
|
|
export function sessionStateLabel(state: SessionState): string {
|
|
|
|
|
switch (state) {
|
|
|
|
|
case 'upcoming':
|
|
|
|
|
return 'Upcoming'
|
|
|
|
|
case 'live':
|
|
|
|
|
return 'Live'
|
|
|
|
|
case 'preparing':
|
|
|
|
|
return 'Preparing'
|
|
|
|
|
case 'partial':
|
|
|
|
|
return 'Partial'
|
|
|
|
|
case 'ready':
|
|
|
|
|
return 'Ready'
|
2026-07-12 18:49:10 -04:00
|
|
|
case 'unavailable':
|
|
|
|
|
return 'Unavailable'
|
feat(race-hub): trustworthy defaults and fan-facing analysis hierarchy (#75)
Make bare /race-hub resolve to a completed session and never open empty
post-session analysis for a future race.
- Backend: add `default_analysis_session` to the Weekend context. It never
resolves to a future session (picks the richest completed session, ties
toward the later one; 0 when everything is upcoming). Existing
`default_session_key` and deep links are unchanged.
- Frontend default resolution prefers the most recently completed weekend
(`pickAnalysisFocusMeeting`) and consumes `default_analysis_session`, falling
back to the switcher when only upcoming sessions exist.
- New `sessionState` lib maps timing + coverage to user language
(upcoming/live/preparing/partial/ready/cancelled); the session rail, active
sub-bar, and WeekendSwitcher now label states instead of raw x/11 counts.
- Future sessions render a purpose-built PreSessionView (expected availability +
countdown) instead of empty Winner/Podium/Pole/Strategy/Compare cards.
- Analysis navigation regrouped into Story / Analysis / Data & Context; every
existing tab is preserved. Diagnostics (renamed from Data Status) is now a
secondary action and the raw dataset strip is hidden behind an explicit
toggle, so operational coverage no longer precedes fan content.
- Loading/error states offer Retry and a path back to Weekend.
Tests: Go query tests for future-exclusion; Vitest for default selection,
future pre-session, partial state, error/retry, grouped nav, and sessionState;
hermetic Playwright for bare/completed/future/return-to-Weekend; new
race-hub-future visual snapshots. Seed adds a far-future session inside the
Monaco meeting (kept in-meeting so Command Center focus is unaffected).
Note: `default_analysis_session` is an additive field on the existing
`/weekend` contract (no new endpoint), per the spec's "context contract" scope.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-12 18:29:34 -04:00
|
|
|
case 'cancelled':
|
|
|
|
|
return 'Cancelled'
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Longer, sentence-style description for headers and empty states. */
|
|
|
|
|
export function sessionStateDescription(state: SessionState): string {
|
|
|
|
|
switch (state) {
|
|
|
|
|
case 'upcoming':
|
|
|
|
|
return 'Session has not started yet.'
|
|
|
|
|
case 'live':
|
|
|
|
|
return 'Session is running now.'
|
|
|
|
|
case 'preparing':
|
2026-07-12 18:49:10 -04:00
|
|
|
return 'Analysis is being prepared — local data is still settling.'
|
feat(race-hub): trustworthy defaults and fan-facing analysis hierarchy (#75)
Make bare /race-hub resolve to a completed session and never open empty
post-session analysis for a future race.
- Backend: add `default_analysis_session` to the Weekend context. It never
resolves to a future session (picks the richest completed session, ties
toward the later one; 0 when everything is upcoming). Existing
`default_session_key` and deep links are unchanged.
- Frontend default resolution prefers the most recently completed weekend
(`pickAnalysisFocusMeeting`) and consumes `default_analysis_session`, falling
back to the switcher when only upcoming sessions exist.
- New `sessionState` lib maps timing + coverage to user language
(upcoming/live/preparing/partial/ready/cancelled); the session rail, active
sub-bar, and WeekendSwitcher now label states instead of raw x/11 counts.
- Future sessions render a purpose-built PreSessionView (expected availability +
countdown) instead of empty Winner/Podium/Pole/Strategy/Compare cards.
- Analysis navigation regrouped into Story / Analysis / Data & Context; every
existing tab is preserved. Diagnostics (renamed from Data Status) is now a
secondary action and the raw dataset strip is hidden behind an explicit
toggle, so operational coverage no longer precedes fan content.
- Loading/error states offer Retry and a path back to Weekend.
Tests: Go query tests for future-exclusion; Vitest for default selection,
future pre-session, partial state, error/retry, grouped nav, and sessionState;
hermetic Playwright for bare/completed/future/return-to-Weekend; new
race-hub-future visual snapshots. Seed adds a far-future session inside the
Monaco meeting (kept in-meeting so Command Center focus is unaffected).
Note: `default_analysis_session` is an additive field on the existing
`/weekend` contract (no new endpoint), per the spec's "context contract" scope.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-12 18:29:34 -04:00
|
|
|
case 'partial':
|
|
|
|
|
return 'Partial analysis available — some datasets are still missing.'
|
|
|
|
|
case 'ready':
|
|
|
|
|
return 'Full analysis is ready.'
|
2026-07-12 18:49:10 -04:00
|
|
|
case 'unavailable':
|
|
|
|
|
return 'Analysis is not available for this session.'
|
feat(race-hub): trustworthy defaults and fan-facing analysis hierarchy (#75)
Make bare /race-hub resolve to a completed session and never open empty
post-session analysis for a future race.
- Backend: add `default_analysis_session` to the Weekend context. It never
resolves to a future session (picks the richest completed session, ties
toward the later one; 0 when everything is upcoming). Existing
`default_session_key` and deep links are unchanged.
- Frontend default resolution prefers the most recently completed weekend
(`pickAnalysisFocusMeeting`) and consumes `default_analysis_session`, falling
back to the switcher when only upcoming sessions exist.
- New `sessionState` lib maps timing + coverage to user language
(upcoming/live/preparing/partial/ready/cancelled); the session rail, active
sub-bar, and WeekendSwitcher now label states instead of raw x/11 counts.
- Future sessions render a purpose-built PreSessionView (expected availability +
countdown) instead of empty Winner/Podium/Pole/Strategy/Compare cards.
- Analysis navigation regrouped into Story / Analysis / Data & Context; every
existing tab is preserved. Diagnostics (renamed from Data Status) is now a
secondary action and the raw dataset strip is hidden behind an explicit
toggle, so operational coverage no longer precedes fan content.
- Loading/error states offer Retry and a path back to Weekend.
Tests: Go query tests for future-exclusion; Vitest for default selection,
future pre-session, partial state, error/retry, grouped nav, and sessionState;
hermetic Playwright for bare/completed/future/return-to-Weekend; new
race-hub-future visual snapshots. Seed adds a far-future session inside the
Monaco meeting (kept in-meeting so Command Center focus is unaffected).
Note: `default_analysis_session` is an additive field on the existing
`/weekend` contract (no new endpoint), per the spec's "context contract" scope.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-12 18:29:34 -04:00
|
|
|
case 'cancelled':
|
|
|
|
|
return 'This session was cancelled.'
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Class suffix used for the coverage dot, so the rail can colour a session by
|
|
|
|
|
* its lifecycle state rather than only by data source.
|
|
|
|
|
*/
|
|
|
|
|
export function sessionStateDotClass(state: SessionState): string {
|
|
|
|
|
switch (state) {
|
|
|
|
|
case 'ready':
|
|
|
|
|
return 'rh-state-ready'
|
|
|
|
|
case 'partial':
|
|
|
|
|
return 'rh-state-partial'
|
|
|
|
|
case 'live':
|
|
|
|
|
return 'rh-state-live'
|
|
|
|
|
case 'upcoming':
|
|
|
|
|
return 'rh-state-upcoming'
|
2026-07-12 18:49:10 -04:00
|
|
|
case 'unavailable':
|
|
|
|
|
return 'rh-state-unavailable'
|
feat(race-hub): trustworthy defaults and fan-facing analysis hierarchy (#75)
Make bare /race-hub resolve to a completed session and never open empty
post-session analysis for a future race.
- Backend: add `default_analysis_session` to the Weekend context. It never
resolves to a future session (picks the richest completed session, ties
toward the later one; 0 when everything is upcoming). Existing
`default_session_key` and deep links are unchanged.
- Frontend default resolution prefers the most recently completed weekend
(`pickAnalysisFocusMeeting`) and consumes `default_analysis_session`, falling
back to the switcher when only upcoming sessions exist.
- New `sessionState` lib maps timing + coverage to user language
(upcoming/live/preparing/partial/ready/cancelled); the session rail, active
sub-bar, and WeekendSwitcher now label states instead of raw x/11 counts.
- Future sessions render a purpose-built PreSessionView (expected availability +
countdown) instead of empty Winner/Podium/Pole/Strategy/Compare cards.
- Analysis navigation regrouped into Story / Analysis / Data & Context; every
existing tab is preserved. Diagnostics (renamed from Data Status) is now a
secondary action and the raw dataset strip is hidden behind an explicit
toggle, so operational coverage no longer precedes fan content.
- Loading/error states offer Retry and a path back to Weekend.
Tests: Go query tests for future-exclusion; Vitest for default selection,
future pre-session, partial state, error/retry, grouped nav, and sessionState;
hermetic Playwright for bare/completed/future/return-to-Weekend; new
race-hub-future visual snapshots. Seed adds a far-future session inside the
Monaco meeting (kept in-meeting so Command Center focus is unaffected).
Note: `default_analysis_session` is an additive field on the existing
`/weekend` contract (no new endpoint), per the spec's "context contract" scope.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-12 18:29:34 -04:00
|
|
|
case 'cancelled':
|
|
|
|
|
return 'rh-state-cancelled'
|
|
|
|
|
default:
|
|
|
|
|
return 'rh-state-preparing'
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Whether a session should render the pre-session (expected availability) view. */
|
|
|
|
|
export function isPreSession(state: SessionState): boolean {
|
|
|
|
|
return state === 'upcoming'
|
|
|
|
|
}
|
2026-07-12 18:49:10 -04:00
|
|
|
|
|
|
|
|
/** Settling / empty post-session — not yet analysable. */
|
|
|
|
|
export function isPreparing(state: SessionState): boolean {
|
|
|
|
|
return state === 'preparing'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function isUnavailable(state: SessionState): boolean {
|
|
|
|
|
return state === 'unavailable' || state === 'cancelled'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Show fan analysis with a partial banner; keep available capabilities. */
|
|
|
|
|
export function isPartialAnalysis(state: SessionState): boolean {
|
|
|
|
|
return state === 'partial'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Canonical default analysis session key from Weekend Context, if any. */
|
|
|
|
|
export function defaultAnalysisSessionKey(
|
|
|
|
|
context: WeekendContext | null | undefined,
|
|
|
|
|
): number | undefined {
|
|
|
|
|
const key = context?.default_analysis_session?.session.session_key
|
|
|
|
|
return key && key > 0 ? key : undefined
|
|
|
|
|
}
|