diff --git a/ROADMAP.md b/ROADMAP.md index bbb1e44..95802f7 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -26,7 +26,7 @@ Acceptance: real create/edit/save flows persist after reload; background updates - [x] Cover team creation, membership changes, editing and deletion. - [x] Cover Open Practice to team-race conversion, duration/follow-up edits and persisted lap limits. - [x] Cover Race Day start/pause/resume/finish controls and switching to the next queued heat, with a simulated decoder socket (no real AMMC hardware). -- [ ] Cover session-type-specific start sequences (heat/qualification/race/team_race countdown and audio) and other transitions beyond Open Practice. +- [x] Cover session-type-specific start sequences (heat/qualification/race/team_race countdown and audio) and other transitions beyond Open Practice. - [x] Verify leaderboard/TV/team sorting heading alignment at 390/900/1600 px and preserved race positions. - [x] Verify OBS views have no interactive sorting controls. - [x] Cover actual popup launching and compact OBS layout automatically. @@ -36,6 +36,8 @@ Verified 2026-09-09: the OBS overlay popup opens via a real click on the admin " Verified 2026-09-08: Race Day start/pause/resume/finish and next-heat selection pass end to end (`tests/browser_race_day.js`) against a simulated decoder socket, with native-dialog auto-accept added to the browser harness so an unexpected `alert()`/`confirm()` fails the test instead of hanging it. Found and fixed two real bugs in the process: Open Practice sessions on a track-mode (sponsor) event showed a ready/green preflight but were silently blocked from starting by a stricter assignment check; and the Race Day view never refreshed when the decoder connected, disconnected, or errored, so its Start button and preflight checklist could stay stale after a page load. +Verified 2026-09-10 (`tests/browser_race_day_start_sequences.js`): unlike Open Practice, heat/qualification/final/team_race sessions run the real countdown-light-audio sequence in `src/race_audio.js` before a session is allowed to transition to "running" - confirmed a heat session stays `status: "ready"` immediately after clicking Start, that the Start button visibly ticks down through real countdown digits, and that it only becomes `running` once the full sequence (countdown, 5-light step, start delay) completes. For all four types, confirmed the announced-event log shows `drivers_ready` then `start_sequence` (plus `qualifying_start` in between for qualification only, nowhere else), and that pause/resume/finish behave the same as they already do for Open Practice. Every effect/voice was silenced via `raceAudio.events` so the test depends only on the sequence's own timers, not on real audio/TTS playback completing in a headless browser with no sound hardware - kept the test both fast and independent of any audio asset actually loading. + ## 2. Connection and save status Acceptance: users can distinguish server contact, pending edits, an active save and a failed save; a health check never falsely confirms a failed write. @@ -159,6 +161,18 @@ Deferred 2026-09-09 at the user's request - the largest remaining item, on par w - [ ] Build compact mobile controls for start/stop, track call, flags and next heat. - [ ] Test concurrent control and accidental repeated commands. +## 7. Track layout changes and stat continuity + +Reported 2026-09-10 by the user: an indoor club running in the same physical building often reconfigures the track layout (different wall/gate placement) while everything else - the venue, the class, the drivers - stays the same. Nothing in the app currently knows a layout change happened, so every lap-time comparison silently keeps treating before-the-change and after-the-change laps as if they were run on the same track: personal bests and the "track record" audio cue (`RACE_AUDIO_EVENT_DEFINITIONS` in `src/race_audio.js`) would announce a "record" that's actually just a different, possibly easier, layout; the training pace baseline and "stable pace" cue would judge consistency against a lap time that no longer means anything; and the Results Archive would let someone compare two sessions across a layout change as if they were comparable, with no indication they aren't. + +No design decided yet - open questions before this can be built: +- Scope: is a layout global to the installation, or per class (a club might run different classes on different sub-layouts at once)? +- How a change is recorded: an explicit admin action ("mark a new layout as of now", maybe with a name/date) versus something automatic - automatic detection isn't realistic, lap times alone don't reveal *why* they changed. +- What happens to stats spanning the change: hide cross-layout comparisons entirely, keep them but label which layout each figure belongs to, or reset PBs/records at the boundary while keeping session history intact for the record? +- Whether this becomes a new stored entity (a `trackLayouts` list with an id/name/startedAt) or a simpler incrementing counter on club settings that every PB/record/baseline calculation is scoped by. + +Revisit as its own design conversation once the scope question above is answered. + ## PDF export character encoding Fixed 2026-09-09, reported while exporting an old race from the new Results archive - correctly suspected as a general PDF export bug, not specific to that one feature. `buildSimplePdf` in `server.js` (the shared renderer behind every PDF export: race results, start lists, heat sheets, team reports, and the archive) declared its font with no `/Encoding` at all, so viewers fell back to the standard font's built-in encoding, which has no å/ä/ö glyphs - and separately, the content stream was written as UTF-8, so even a correctly-encoded font would have received the wrong bytes (a multi-byte UTF-8 sequence where a single WinAnsi byte was expected), the classic "åäö" mojibake pattern. Fixed by declaring `/Encoding /WinAnsiEncoding` and writing the content stream through a proper WinAnsi (~CP1252) byte mapper instead of UTF-8 - Swedish å/ä/ö/Å/Ä/Ö map directly to their Latin-1 byte values, with the handful of CP1252 "smart punctuation" code points (curly quotes, en/em dash, €, etc.) mapped explicitly; anything else falls back to `?` rather than corrupting the byte stream. diff --git a/tests/browser_race_day_start_sequences.js b/tests/browser_race_day_start_sequences.js new file mode 100644 index 0000000..a2ee897 --- /dev/null +++ b/tests/browser_race_day_start_sequences.js @@ -0,0 +1,138 @@ +import assert from "node:assert/strict"; +import { startFakeDecoder } from "./browser_fake_decoder.js"; +import { RACE_AUDIO_EVENT_DEFINITIONS } from "../src/race_audio.js"; + +// Practice types skip the countdown/light/audio sequence entirely (see +// startSessionWithAudio in src/app.js) - already covered by browser_race_day.js. +// heat/qualification/final/team_race all run the real sequence in src/race_audio.js's +// runStartSequence, gating the session's transition to "running" until it completes - +// this file exercises that for each of those four types, plus pause/resume/finish. +// +// Every effect/voice is silenced via raceAudio.events so the sequence's own audio +// playback (real