plan 0002: sprint mode core — /TRACKS/SPRINT, mode-by-folder, SprintTimer backend, DOVEX race_mode - #116
Merged
Conversation
sprint_select: newest-course-by-date_created ordering (sortable ISO strings, ties resolve to the later file entry) + the circuit-vs-sprint tiebreak decision table (race_mode pref; circuit yields to a sprint course created today). dovex_header: race_mode trailing column (CIRCUIT/SPRINT, empty = circuit, same append mechanism as device_name) and the line-2 splitter now preserves empty middle fields - the strtok version let a blank column shift every later column left (regression test included). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HnTP6BdA9xjLR5hSWE9frb
…imer backend - /TRACKS/SPRINT folder (auto-provisioned; circuit tracks untouched); manifest entries carry their folder kind; buildTrackList scans both via the new scanTrackDir(folder, kind); makeFullTrackPath is kind-aware; FILEPATH_MAX 50->64 - parseTrackFile: track-level "type", per-course finish_* lines and date_created (containsKey idiom, same as sectors) - trackDetectionLoop: nearest entry PER KIND; race_mode setting (new, default circuit) breaks both-in-range ties via sprint_select, with the event-day heuristic parsing the sprint file's newest course date - sprint path skips CourseManager/CourseDetector: createSprintSession() picks the newest course and stands up the library's SprintTimer (start + separate finish + optional splits); sprintTimer != nullptr IS sprint mode, all activeTimer*() helpers duck-type runs as laps - lifecycle: run-count-edge history capture (identical consecutive run times are normal at autocross - value-change dedupe would drop them), each run re-arms the auto-idle grace, sprint idle is engine-aware (running engine at the start line never ends the session) - DOVEX header: sprint course name + race_mode=SPRINT - display: Current Lap / Pace show *waiting* between runs; 'laps' verbiage kept everywhere by design - sim: SprintTimer/CrossingEngine/sprint_select compiled into the TU, prototypes mirrored; all 6 sim tests (incl. lap oracles) green Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HnTP6BdA9xjLR5hSWE9frb
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HnTP6BdA9xjLR5hSWE9frb
Coverage — host-testable units📂 Overall coverage
📄 File coverage
|
… fix) The beta image burst the 320 KB OTA self-flash cap (330,628 B, 100.9%) - and was already at 98.2% before sprint mode. Root cause: the DovesLapTimer library's debug pipeline is gated by a RUNTIME if(_serial) check, so ~150 debug call-sites and their F() strings stay resident in flash on hardware builds that never attach a debug Stream. DovesLapTimer#48 (BETA) adds the DOVES_DISABLE_DEBUG compile-time kill switch; this passes it in compile-sketch/beta/release so the dead pipeline is dropped (~6-8 KB), bringing the image back under the cap with real headroom instead of moving the OTA staging layout. IDE debug builds are unaffected (flag is per-build opt-in; documented in CONTRIBUTING). Requires DovesLapTimer#48 merged to BETA before the compile-sketch gate can pass (CI pulls the library's BETA branch). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HnTP6BdA9xjLR5hSWE9frb
merge) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HnTP6BdA9xjLR5hSWE9frb
This was referenced Aug 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Phase 2, PR A of plan 0002 — the firmware's sprint mode core, consuming the library work merged in DovesLapTimer#47. (PR B = BLE sprint-track sync opcodes, PR C = the on-device course creator — kept separate per one-concern-per-PR.)
/TRACKS/SPRINT/: sprint tracks live in their own auto-provisioned folder; circuit tracks and all existing behavior untouched. Manifest entries carry their folder kind;buildTrackList()walks both via a newscanTrackDir(folder, kind);makeFullTrackPath()is kind-aware.trackDetectionLoop()finds the nearest entry per kind; when both kinds are in range the newrace_modesetting (defaultcircuit) breaks the tie via the host-testedsprint_selectunit —circuityields only to a sprint track whose newest course was created today (event-day heuristic),sprintalways prefers the sprint track (fixed rally layouts).createSprintSession()selects the newest course bydate_created(sortable ISO stamp; autocross venues re-lay the course every event) and stands up the library'sSprintTimer(start + separatefinish_*line + optional splits).sprintTimer != nullptris sprint mode; everyactiveTimer*()helper duck-types runs as laps, so displays/logging/replay work unchanged — "laps" verbiage kept everywhere by design.*waiting*between runs; every other page stays live.race_modetrailing header column (CIRCUIT/SPRINT, empty = circuit; same append mechanism asdevice_name) so the webapp knows to read the laps line as runs. Includes a real parser fix the new column exposed: the strtok line-2 splitter collapsed empty middle fields, shifting every later column left (regression-tested).sprint_select.{h,cpp}(+21 test cases),dovex_headerextensions (+4 cases incl. the empty-field regression).Type of change
Not breaking: legacy logs/tracks parse identically; the DOVEX column and JSON fields are additive; sprint behavior only activates for files in the new folder.
How it was verified
ctest --test-dir tests/build) — 292 cases / 4102 assertions, 0 failedclang-tidyclean — deferred to CISprintTimersince DovesLapTimer#47)Checklist
CHANGELOG.mdupdated under[Unreleased](if user-visible)ARCHITECTURE.md/CLAUDE.mdupdated (if a module or interface changed) — CLAUDE.md file map, subsystem 9, DOVEX + track JSON + settings sections; README settings tabletests/Related issues
Design:
docs/plans/0002-sprint-mode.md. Library side: TheAngryRaven/DovesLapTimer#47 (merged).🤖 Generated with Claude Code
https://claude.ai/code/session_01HnTP6BdA9xjLR5hSWE9frb
Generated by Claude Code