GeometryEnricher: tier-3 heading-delta fallback (issue #29) #122
No reviewers
Labels
No labels
area:companion
area:docs
area:shared
area:tooling
area:watchapp
blocker
kind:chore
kind:feature
kind:spike
kind:test
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
robert/PedalPebble!122
Loading…
Reference in a new issue
No description provided.
Delete branch "area/geometry-enricher"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes part of #29 (see the flagged exception below).
What this does
Implements
GeometryEnricher(tier 3,EnrichmentTier.GEOMETRY): the always-available, offline, no-street-names last resort in the enrichment chain (D26/D40). Per the issue's 2026-09-01 update, this is the default cue-sheet path for most new users today (BRouter, tier 1/#27, needs a separate install plus segment files; map matching, tier 2/#28, is online and opt-in per D13) - so this implements the tightened design, not the original 5m-segment spec.Design
RouteGeodesy.bearingDegrees/pointAtDistanceMeters(added for #55) rather than diffing consecutive RDP segments directly.CueSheetReviewAnalysisalready uses).sweeping-bend-vs-sharp-turn.gpxfixture: a ~57° gentle bend (radius 300 m) produces nothing, a ~60° sharp turn (radius 8 m) of near-identical total magnitude produces a cue - the explicit "a naive total-delta accumulator would get this wrong" case.tier = EnrichmentTier.GEOMETRY(the field the wire layer reads intoNAV_CUE_CONFIDENCE = 0, FR-N17) andstreetName = nullalways.Success(emptyList()), not a decline signal the way tier 0's empty-GPX-cue-text case is.Fixtures (
companion/core/src/test/resources/gpx/)All synthetic-but-exact closed-form geometry (straight segments + circular arcs of known radius/angle), not scraped tracks - see
GeometryEnricherTest's own KDoc for why that's the right call specifically for "hand-checked expected cue counts" (independently re-derived via a second haversine/bearing reimplementation outside the Kotlin code, not by trusting the implementation to grade its own homework):winding-descent.gpxroundabout.gpxsweeping-bend-vs-sharp-turn.gpxstraight-route.gpxAlso included
GeometryEnricherintoRouteStore's tier3 slot and bumpedCURRENT_ENRICHER_VERSIONto 2, per that constant's own KDoc ("wiring a new tier in here is one of the two events that constant must be bumped for") - otherwise the new tier would exist but never actually run for a real user.Flagged, not faked
The issue's "output compared against a BRouter cue sheet on a known route and the differences documented" criterion needs
BRouterEnricher(#27), which does not exist in this codebase yet (confirmed by search - only mentioned in comments/KDoc). Rather than build a stub/fake BRouter comparison, I've added a dependency edge (#29 depends on #27) via the API. That comparison should happen once #27 lands.Testing
Real
./gradlew :companion:core:test --rerun-tasksrun: 353 tests, 0 failures, 0 errors (44 test classes, including the new 6-caseGeometryEnricherTest). Also ran:companion:route:compileDebugKotlinand:companion:route:testto confirm theRouteStorewiring compiles and the module's existing (currently empty) unit test task still passes.https://claude.ai/code/session_01DAoXbRmJUf2uxNYBfdAXPt