Skip to content

[4.2.0] general quality of life fixes#42

Draft
TheAngryRaven wants to merge 4 commits into
masterfrom
BETA
Draft

[4.2.0] general quality of life fixes#42
TheAngryRaven wants to merge 4 commits into
masterfrom
BETA

Conversation

@TheAngryRaven

@TheAngryRaven TheAngryRaven commented Jun 11, 2026

Copy link
Copy Markdown
Owner

Rolls up the full remediation of the professional code review (scored 4.5/10) — all 17 findings addressed across two PRs: #41 (critical: C1–C3, H1, H2) and #43 (high: H3–H14). Host test suite grew 65 → 131 tests, line coverage ~51% → 84.5% (CI gate raised 1% → 80%), and the pinned NMEA replay goldens are unchanged throughout — no timing drift on real-track data.

Correctness fixes (#41)

  • C1 — Uninitialized start/finish line. All line members zero-initialized; loop() skips start/finish detection until a valid line is set (isStartFinishLineConfigured()); setters reject degenerate (A==B, e.g. the example's 0.00 placeholders) or non-finite lines. Calling loop() before setup was UB with phantom-crossing potential.
  • C2 — UTC midnight rollover. Every duration now goes through timeSinceMidnightDelta() (wrap-normalized); the crossing interpolator computes its fix-pair delta in double with a 10 s coherence clamp (CROSSING_MAX_FIX_GAP_MS) before converting back — the old path underflowed unsigned subtraction (~4.29-billion-ms laps stuck as best lap) and hit double→unsigned conversion UB. The time != 0 validity sentinel is gone; a crossing at exactly 00:00:00.000 counts.
  • C3 — False course match on no-match laps. The detector re-anchors its lap-distance window after every completed proximity pass, so cumulative distance can no longer falsely match a 2×-length layout.
  • H1 — GPS input validation. NaN/Inf, out-of-range, and (0,0) fixes rejected in DovesLapTimer, WaypointLapTimer, and CourseDetector; non-finite alt/speed sanitized; single-fix teleports >500 m dropped with a 3-fix re-accept that never credits the gap to the odometer.
  • H2 — Crossing-buffer wraparound. The interpolator unwinds the ring chronologically, so a kart parked in the zone (standing start, red flag) can't make the buffer seam masquerade as the crossing.

Robustness & memory (#43)

  • H4 — Low-rate GPS. Crossing validation scales with the straddle pair's spacing instead of failing every crossing at 1 Hz; the zone-exiting fix is buffered (at 1 Hz the crossing usually happens right before it); a geometric backstop keeps extension-crossings out; rejected crossings surface via getRejectedCrossingCount().
  • H5 — Detection can no longer hang forever. Lap Anything is reachable via three routes: candidate rejections (existing), COURSE_DETECT_MAX_NO_MATCH_PASSES (3) completed no-match laps (getNoMatchCount()), and an odometer failsafe (4 × longest course, 2000 m floor) for drivers who never re-enter waypoint proximity.
  • H7 — Lap Anything deactivates all course timers (previously 8 full crossing pipelines ran forever); new isCourseTimerActive(index).
  • H8 — Deleted WaypointLapTimer's 1.6 KB write-only proximity buffer (ProximityBufferEntry, WAYPOINT_LAP_BUFFER_SIZE removed); instance ~1.8 KB → ~150 B.
  • H14 — Unit conversions unified behind shared constexpr constants in GeoMath.h (knots/kmh/mph/feet), replacing three mutually inconsistent literals across five files.

Honesty / documentation

  • H3 — AVR double is 32-bit: compile-time #warning on 4-byte-double targets; README/CLAUDE.md state plainly that Mega/Uno count laps but run with degraded odometer/interpolation accuracy.
  • H6 — Memory claims corrected: CourseManager is ~29 KB statically allocated regardless of course count, pruning saves CPU and frees zero bytes, and it does not fit on AVR Mega. The "~24 KB drops to ~5 KB" claim is gone.
  • H9 — Doc lies fixed: README direction-detection rewritten to the actual both-sectors temporal-order algorithm; getPaceDifference() documented as ms per meter; pointLineSegmentDistance() documented as meters; doc-claim spot check added to the release checklist.

Tests & CI

  • H11: new suites for the previously untested modules — test_course_manager.cpp, test_waypoint_lap_timer.cpp, test_low_rate_gps.cpp — plus Fix code-review findings C1–C3, H1, H2: line init, midnight rollover, detection window, input validation, buffer wraparound #41's test_midnight_rollover.cpp, test_input_validation.cpp, test_buffer_wraparound.cpp and CourseDetector re-anchor regressions. Key regression tests verified failing against pre-fix code.
  • H10: test Makefile now tracks all header dependencies (touch header && make rebuilds — no more false greens on stale binaries).
  • H13: coverage gate raised to 80%.
  • H12: all workflow actions pinned to verified commit SHAs, peaceiris/actions-gh-pages v3 → v4, Dependabot (github-actions, weekly) added, gh-pages/badge deploys gated to refs/heads/master.

New public API (backward compatible)

isStartFinishLineConfigured(), getRejectedCrossingCount() (DovesLapTimer) · getNoMatchCount() (CourseDetector) · isCourseTimerActive(index) (CourseManager). Removed: ProximityBufferEntry, WAYPOINT_LAP_BUFFER_SIZE (write-only internals).

Known deferred items

  1. H3 full fix — local-tangent-plane math to restore real accuracy on 32-bit-double AVR (architecture change; currently warn-and-document).
  2. H6 full fix — placement-new storage pool so CourseManager allocates only courseCount timers (currently honestly documented as 8-slot static).
  3. H14 long-term — standardizing the public API on one speed unit (breaking; future major version).

Expected in CI on this PR: the Mega/Uno compile cells now print the intentional H3 #warning; first master merge exercises the v4 gh-pages deploy for docs + coverage badge.

https://claude.ai/code/session_01XNmVH6ySJ6Dz2QKDjB69mE

claude and others added 2 commits June 11, 2026 03:54
…n window, input validation, buffer wraparound

Addresses the C1/C2/C3/H1/H2 findings from the professional code review:

- C1: zero-initialize all crossing-line members, gate checkStartFinish()
  on a new startFinishLineConfigured flag (exposed via
  isStartFinishLineConfigured()), and reject degenerate/non-finite lines
  in all three line setters. loop() before setStartFinishLine() was
  reading indeterminate doubles (UB, phantom crossings).

- C2: normalize every duration across the UTC midnight wrap via a shared
  timeSinceMidnightDelta() helper (DovesLapTimer + WaypointLapTimer).
  The crossing interpolator now computes its fix-pair delta in double,
  wrap-normalized and clamped to CROSSING_MAX_FIX_GAP_MS (10s), before
  converting back to unsigned long - the old path underflowed unsigned
  subtraction and pushed an out-of-range double through double->unsigned
  conversion (UB). Crossing validity is now a bool return instead of the
  time != 0 sentinel, so a legitimate crossing at exactly 00:00:00.000
  is no longer discarded.

- C3: CourseDetector re-anchors the lap-distance window after every
  completed proximity pass, match or no match. Previously a no-match lap
  left distanceSinceWaypoint accumulating, falsely matching a 2x-length
  layout on the next pass (same root cause as the v4.1.0 rejection-
  cooldown fix, CLAUDE.md issue 13).

- H1: validate GPS input in DovesLapTimer::loop(), WaypointLapTimer::loop()
  and CourseDetector::update(): reject NaN/Inf/out-of-range/(0,0) fixes,
  sanitize non-finite alt/speed, drop single-fix teleports >500m, and
  re-accept sustained relocations after 3 consecutive far fixes without
  crediting the gap to the odometer. A single NaN or (0,0) fix previously
  poisoned odometers for the whole session and hung course detection.

- H2: unwind the crossing ring buffer chronologically before scanning for
  the straddling pair. Once the ring wrapped (kart parked in the zone -
  standing start, red flag), the seam pair (newest entry adjacent to
  oldest) masqueraded as the crossing, fabricating or invalidating laps.

Adds 23 new host unit tests in three new suites (test_midnight_rollover,
test_input_validation, test_buffer_wraparound) plus two CourseDetector
re-anchor regression tests; the C3 and H2 tests were verified to fail
against the pre-fix code. All 89 tests green, NMEA replay goldens
unchanged.

https://claude.ai/code/session_01XNmVH6ySJ6Dz2QKDjB69mE
…4j17

Fix code-review findings C1–C3, H1, H2: line init, midnight rollover, detection window, input validation, buffer wraparound
@github-actions

github-actions Bot commented Jun 11, 2026

Copy link
Copy Markdown

GCC Code Coverage Report

📂 Overall coverage

Metric Coverage
Lines 🟡 1089/1288 (84.5%)
Functions 🟡 168/202 (83.2%)
Branches 🔴 508/812 (62.6%)

📄 File coverage

File Lines Functions Branches
src/CourseDetector.cpp 🟢 98/104 (94.2%) 🟢 18/20 (90.0%) 🟡 39/46 (84.8%)
src/CourseManager.cpp 🟡 143/162 (88.3%) 🔴 17/23 (73.9%) 🟡 73/96 (76.0%)
src/CourseManager.h 🟢 30/30 (100.0%) 🟢 10/10 (100.0%) 🔴 10/20 (50.0%)
src/DovesLapTimer.cpp 🟡 488/564 (86.5%) 🟡 45/58 (77.6%) 🔴 278/452 (61.5%)
src/DovesLapTimer.h 🔴 129/195 (66.2%) 🟡 43/50 (86.0%) 🔴 40/92 (43.5%)
src/GeoMath.h 🟢 21/21 (100.0%) 🟢 4/4 (100.0%) 🟡 21/24 (87.5%)
src/WaypointLapTimer.cpp 🟡 159/188 (84.6%) 🟡 24/29 (82.8%) 🔴 40/66 (60.6%)
src/WaypointLapTimer.h 🟡 21/24 (87.5%) 🟡 7/8 (87.5%) 🔴 7/16 (43.8%)

claude and others added 2 commits June 11, 2026 17:55
…ection fallbacks, dead memory, doc lies, CI hardening

H3  - #warning on 4-byte-double targets (classic AVR) + README/CLAUDE.md
      caveats: lap counting works, odometer/interpolation accuracy degraded.
H4  - Crossing validation no longer conflates zone size with GPS sample
      density: the straddle-pair sum bound scales with the pair's own
      spacing (CROSSING_PAIR_SPACING_FACTOR), the zone-exiting fix is
      buffered so low-rate passes have a straddle pair at all, and an
      on-segment geometric check backstops the looser bound. Rejected
      crossings surface via getRejectedCrossingCount() instead of dying
      silently on debug serial. At 1 Hz the lap counter now works.
H5  - Lap Anything is reachable from every failure mode: CourseDetector
      counts completed no-match passes (getNoMatchCount()), CourseManager
      falls back after COURSE_DETECT_MAX_NO_MATCH_PASSES of them, and an
      odometer failsafe (4 x longest course, 2000m floor) catches drivers
      who never re-enter waypoint proximity.
H6  - Memory docs corrected: pruning saves CPU, frees zero bytes; the
      ~29 KB 8-slot timer array is static regardless of course count;
      CourseManager does not fit on AVR Mega. (Real deallocation via a
      placement-new pool deferred - see PR.)
H7  - _activateLapAnything() deactivates all course timers; new
      isCourseTimerActive(index) getter.
H8  - Deleted WaypointLapTimer's write-only 50-entry proximity buffer
      (1.6 KB/instance), ProximityBufferEntry, WAYPOINT_LAP_BUFFER_SIZE.
      Closest-approach scalars carry the lap split; instance now ~150 B.
      Also replaced the closestTime==0 validity sentinel (midnight bug
      class) with the INFINITY distance sentinel.
H9  - README direction-detection section rewritten to match the actual
      both-sectors temporal-order algorithm; getPaceDifference documented
      as ms-per-meter everywhere; pointLineSegmentDistance documented as
      meters; doc-claim spot check added to the release checklist.
H10 - test/Makefile lists every header (src, mocks, replay runner, NMEA
      fixtures) as prerequisites - 'touch header && make' rebuilds now.
H11 - New suites: test_course_manager.cpp (accept/reject/fallbacks/prune/
      deactivation), test_waypoint_lap_timer.cpp (state machine + lap
      accounting), test_low_rate_gps.cpp (1Hz/5Hz + rejection counter).
      Line coverage 51% -> 84.5%.
H12 - All workflow actions pinned to verified commit SHAs (resolved via
      git ls-remote), peaceiris/actions-gh-pages bumped v3 -> v4,
      dependabot.yml added (github-actions, weekly, grouped), gh-pages/
      badge deploys gated on github.ref == refs/heads/master.
H13 - COVERAGE_GATE raised 1% -> 80% (measured 84.5%).
H14 - Shared constexpr unit-conversion constants in GeoMath.h
      (GEOMATH_KNOTS_TO_KMH / KMH_TO_MPH / MPH_TO_KMH / METERS_TO_FEET,
      derived from exact mile definitions); all five scattered literals
      replaced; METERS_TO_FEET aliases the shared constant.

H4 and H5 regression tests verified failing against the pre-fix code.
131 host tests green; NMEA replay goldens unchanged.

https://claude.ai/code/session_01XNmVH6ySJ6Dz2QKDjB69mE
…-h14

Fix code-review findings H3–H14: low-rate GPS, detection fallbacks, dead memory, doc honesty, CI hardening
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants