Skip to content

Fix code-review findings H3–H14: low-rate GPS, detection fallbacks, dead memory, doc honesty, CI hardening#43

Merged
TheAngryRaven merged 1 commit into
BETAfrom
claude/code-review-fixes-h3-h14
Jun 12, 2026
Merged

Fix code-review findings H3–H14: low-rate GPS, detection fallbacks, dead memory, doc honesty, CI hardening#43
TheAngryRaven merged 1 commit into
BETAfrom
claude/code-review-fixes-h3-h14

Conversation

@TheAngryRaven

Copy link
Copy Markdown
Owner

Works through review findings H3–H14 (follows up on #41, which covered C1–C3/H1/H2). All 131 host tests green, coverage gate raised and passing, NMEA replay goldens unchanged. The H4 and H5 regression tests were verified to fail against the pre-fix code.

Code fixes

H4 — low-rate GPS silently killed lap counting. The straddle-pair validation no longer compares against the zone size in absolute meters; it scales with the pair's own spacing (CROSSING_PAIR_SPACING_FACTOR, 1.25 — geometrically, a genuine straddle's distance sum can never exceed its spacing). The zone-exiting fix is now buffered too, since at 1 Hz the crossing usually happens between the last in-zone fix and the exit fix — without it there's no straddle pair at all. A geometric backstop requires the interpolated point to land on the line segment within the threshold (not the infinite extension), and rejected crossings surface through the new getRejectedCrossingCount() instead of dying on debug serial. Verified: 1 Hz / ~19 m spacing now counts laps; pre-fix it counted zero, forever, silently.

H5 — Lap Anything unreachable from the most likely failure mode. CourseDetector counts completed no-match proximity passes (getNoMatchCount()); CourseManager falls back after COURSE_DETECT_MAX_NO_MATCH_PASSES (3). A second, independent failsafe fires when the odometer exceeds 4 × the longest configured course (2000 m floor) — covering drivers who never re-enter the 10 m waypoint zone, which pass counting can't see.

H7 — Lap Anything left all 8 course timers running forever. _activateLapAnything() now deactivates every course entry. New isCourseTimerActive(index) getter for observability.

H8 — 1.6 KB write-only buffer deleted. WaypointLapTimer keeps only the three closest-approach scalars the lap split ever used; ProximityBufferEntry and WAYPOINT_LAP_BUFFER_SIZE are gone. Instance size: ~1.8 KB → ~150 B. Also replaced the _closestTime == 0 validity sentinel (same midnight-bug class fixed in #41) with the INFINITY distance sentinel.

H14 — unit-conversion constants unified. GeoMath.h now owns GEOMATH_KNOTS_TO_KMH, GEOMATH_KMH_TO_MPH, GEOMATH_MPH_TO_KMH, GEOMATH_METERS_TO_FEET, derived from the exact nautical/statute-mile definitions. All five scattered literals (1.852, 0.621371, 1.60934 — mutually inconsistent at the 7th digit) replaced; METERS_TO_FEET aliases the shared constant.

Honesty fixes

H3 — AVR 32-bit double. A #warning now fires on 4-byte-double targets, and the README/CLAUDE.md state plainly: lap counting works on Mega/Uno, but position quantizes at ~0.2–0.75 m and odometer/interpolation accuracy is degraded; full precision needs a real 64-bit-double MCU.

H6 — memory claims corrected. Measured: CourseManager ≈ 29 KB (host/64-bit double), 28.8 KB of it the by-value 8-slot timer array, allocated regardless of configured course count. Docs now say pruning saves CPU and frees zero bytes, and that CourseManager does not fit on AVR Mega. The "~24 KB drops to ~5 KB after pruning" fiction is gone from README and CLAUDE.md.

H9 — doc lies fixed. README direction-detection section rewritten to the actual both-sectors temporal-order algorithm; getPaceDifference() documented as ms per meter in both README and header; pointLineSegmentDistance() documented as returning meters. A doc-claim spot-check step was added to the release checklist in CONTRIBUTING.md.

Test & CI fixes

H10 — Makefile header deps. All headers (src, mocks, replay runner, NMEA fixtures) are prerequisites of every test binary. The review's exact repro (touch ../src/DovesLapTimer.h && make → "Nothing to be done") now rebuilds.

H11 — the untested modules are tested. New test_course_manager.cpp (9 tests: accept, reject→fallback through CourseManager where issue #13 manifested, both H5 fallbacks, H7 deactivation, prune, reset), test_waypoint_lap_timer.cpp (10 tests), test_low_rate_gps.cpp (4 tests). Line coverage: ~51% → 84.5%.

H13 — coverage gate raised 1% → 80%, just under measured coverage, so deleting behavioral tests fails CI.

H12 — CI supply chain. Every action pinned to a commit SHA verified via git ls-remote against the upstream repos (annotated tags peeled to commit SHAs); peaceiris/actions-gh-pages bumped v3 → v4 while pinning; .github/dependabot.yml (github-actions ecosystem, weekly, grouped) keeps pins fresh; gh-pages/badge deploy steps now require github.ref == 'refs/heads/master', closing the any-branch workflow_dispatch overwrite hole.

Deferred items / decisions for you

These came up during the work and are intentionally not in this PR — flagging rather than guessing:

  1. H3's real fix — reimplementing the geo math as local-tangent-plane offsets from a reference point (float-friendly, restores AVR accuracy) is an architecture change touching every distance call. The PR ships the honest-docs + #warning option instead. Want the tangent-plane version pursued?
  2. H6's real fix — a placement-new storage pool so CourseManager only allocates courseCount timers (and could actually release on prune). Doable but invasive; current behavior is now honestly documented. Worth it, or is "CourseManager needs a 256 KB-class MCU" acceptable as policy?
  3. H14 long-term — standardizing the public API on one speed unit is a breaking change; deferred to a future major version. The shared constants eliminate the drift risk meanwhile.
  4. peaceiris/actions-gh-pages v3 → v4 — inputs are compatible and it's the maintained line, but it's a behavior-bearing bump to the docs/badge deploys; watch the first master deploy.
  5. The first CI run on this PR will show the new #warning in the Mega/Uno compile-examples cells — that's intended signal, not a regression (compile-sketches doesn't fail on warnings).

https://claude.ai/code/session_01XNmVH6ySJ6Dz2QKDjB69mE


Generated by Claude Code

…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
@github-actions

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%)

@TheAngryRaven TheAngryRaven merged commit b4203d1 into BETA Jun 12, 2026
8 checks passed
@TheAngryRaven TheAngryRaven deleted the claude/code-review-fixes-h3-h14 branch June 12, 2026 01:04
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