Fix code-review findings H3–H14: low-rate GPS, detection fallbacks, dead memory, doc honesty, CI hardening#43
Merged
Conversation
…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
GCC Code Coverage Report📂 Overall coverage
📄 File coverage
|
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.
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 newgetRejectedCrossingCount()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.
CourseDetectorcounts completed no-match proximity passes (getNoMatchCount());CourseManagerfalls back afterCOURSE_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. NewisCourseTimerActive(index)getter for observability.H8 — 1.6 KB write-only buffer deleted.
WaypointLapTimerkeeps only the three closest-approach scalars the lap split ever used;ProximityBufferEntryandWAYPOINT_LAP_BUFFER_SIZEare gone. Instance size: ~1.8 KB → ~150 B. Also replaced the_closestTime == 0validity sentinel (same midnight-bug class fixed in #41) with theINFINITYdistance sentinel.H14 — unit-conversion constants unified.
GeoMath.hnow ownsGEOMATH_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_FEETaliases the shared constant.Honesty fixes
H3 — AVR 32-bit double. A
#warningnow 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 thatCourseManagerdoes 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-remoteagainst the upstream repos (annotated tags peeled to commit SHAs);peaceiris/actions-gh-pagesbumped v3 → v4 while pinning;.github/dependabot.yml(github-actions ecosystem, weekly, grouped) keeps pins fresh; gh-pages/badge deploy steps now requiregithub.ref == 'refs/heads/master', closing the any-branchworkflow_dispatchoverwrite hole.Deferred items / decisions for you
These came up during the work and are intentionally not in this PR — flagging rather than guessing:
#warningoption instead. Want the tangent-plane version pursued?CourseManageronly allocatescourseCounttimers (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?peaceiris/actions-gh-pagesv3 → 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.#warningin 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