Cue-sheet review on the phone before riding #55
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
2 participants
Notifications
Due date
No due date set.
Depends on
#27 BRouterEnricher via IBRouterService AIDL
robert/PedalPebble
#30 Cue-sheet caching so each route is enriched once
robert/PedalPebble
Reference
robert/PedalPebble#55
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
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?
Goal
The only practical defence against a mis-enriched route. If BRouter places a turn 30 m off, or the geometric fallback invents a turn on a curve, the rider should find out at home rather than at the junction.
Acceptance criteria
Files
companion/.../route/enrich/CueSheetReviewScreen.ktUpdate — 2026-09-01: show which tier produced each cue
The enrichment chain now reports its tier per cue (D26), and BRouter enrichment carries a measured
divergence from the source route (D25, #27). Both belong in the review — this screen is where a rider
finds out whether to trust the cue sheet.
NAV_CUE_CONFIDENCE = 0) visibly marked as guessesOpened PR #118 (
area/cue-sheet-review->main): #118Covers the original acceptance criteria and the 2026-09-01 tier update, with real dense-cluster and geometric-mismatch detection (documented thresholds, tested against real
GpxCueEnricher/tier-0 fixtures) and edits (delete/correct) persisted through a newCueSheetCache.updateCueson the existing cache row.One line from the 2026-09-01 update is honestly out of scope for now: "BRouter's measured divergence from the source GPX, shown for the route as a whole." That figure is D25's divergence measurement, which is
BRouterEnricher(#27)'s own job to compute — nothing in this codebase carries a divergence number today for this screen to display, and building UI for a number nothing produces would mean fabricating one. Added a dependency edge onto #27 for this reason; a realBRouterEnricherPR should extend wherever it lands that figure (CueSheetOutcomeor similar) and this screen together once it exists.Everything else dispatches generically on
EnrichmentTier/Directionrather than assuming which tiers exist, so #27/#28/#29 landing later needs no changes here — see the PR description for exactly which parts are tested against real tier-0 output vs. hand-builtEnrichmentTier.GEOMETRYfixtures (since #29 doesn't exist yet either).Closed by PR #118 (
area/cue-sheet-review).New
CueSheetReviewScreen(companion/route), reached from a "Review cues" button onRouteDetailScreen(this project has no navigation library, per #46's earlier finding — same local-state-toggle pattern as everywhere else). Shows the full cue list (icon/street/distance), which tier produced the sheet (with an honest "every cue is a geometric guess, tier 3" banner when the whole sheet isEnrichmentTier.GEOMETRY), tap-to-preview viaRoutePreview's newhighlightPointparam (reused, not duplicated), hand delete/correct persisted through a newCueSheetCache.updateCues()that writes back through the exact same cached rowgetOrEnrich/forceReEnrichalready use, and the total cue count + route distance sanity line.Both detection heuristics are real, tested logic, not hand-waved:
findDenseCueClusters(3+ cues within a 40m sliding window — deliberately the same span D27 already reasoned about for the geometric fallback's own heading-delta check) andfindGeometricMismatches(independent ±20m look-behind/look-ahead bearing computation, 20° straight/turn threshold — intentionally more sensitive than D27's 25°, since a false positive here only costs a glance, not a wrong instruction). Two newRouteGeodesy.kthelpers (bearingDegrees,pointAtDistanceMeters) back these.Honestly scoped: only tier 0 (
GpxCueEnricher, #63) exists in any build today — #27 (BRouter), #28 (Valhalla matching), #29 (geometric fallback) are all still open. The tier-display logic dispatches generically on theEnrichmentTierenum (exhaustivewhen, no hardcoded special-casing) so it needs no changes once those land, but the "entirely tier 3" banner is only tested against hand-builtCuedata taggedGEOMETRY, honestly noted as such. "BRouter's measured divergence from the source GPX" (the issue's own 2026-09-01 update) has no real data anywhere in the codebase to display — rather than fabricate a number, this PR added the dependency edge #55 → #27 and left that acceptance line unbuilt; a realBRouterEnricherPR should extendCueSheetOutcomeand this screen together once the figure exists.A genuine, non-fabricated finding from a real fixture: the dense-cluster/mismatch tests run against
bikerouter-style-cues.gpx(the same fixture #30'sCueSheetCacheTestalready uses) and correctly flag both of its real cues as geometric mismatches — not because the cue text is wrong, but becauseGpxCueEnrichersnaps a cue to the nearest RDP-simplified polyline segment rather than the route's actual turn locus, which this independent check has no way to know and correctly calls out as worth a rider's second look either way.Real verification: genuine
./gradlew :companion:core:test :companion:route:assembleDebug :companion:assembleDebug --rerun-tasksfull rebuild, all green (CueSheetReviewAnalysisTest14/14,CueSheetCacheTest11/11,RouteGeodesyTest20/20, full Compose UI compile clean with the required@OptIn(ExperimentalMaterial3Api::class)present).42 issues closed.