Spike C: BRouter AIDL enrichment of a real komoot GPX #6
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.
Blocks
#27 BRouterEnricher via IBRouterService AIDL
robert/PedalPebble
Reference
robert/PedalPebble#6
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
BRouter is the preferred offline cue-sheet backend. Confirm it can turn a komoot GPX (geometry only, no turn data) into usable turn instructions before Phase 3 depends on it.
Acceptance criteria
IBRouterServicebound successfully from a scratch Android applonlatswith a bike profile andturnInstructionModesetTL,TR,KR, ...) present and positioned at the correct junctionsNotes
AIDL definition: http://brouter.de/brouter/IBRouterService.aidl - docs at https://zod.github.io/brouter/developers/android_service.html . OsmAnd's BRouter adapter is a working reference implementation.
Update — 2026-09-01: BRouter is a router, not a map-matcher
This spike passed on "the returned GPX carries usable voice hints". That is necessary and nowhere
near sufficient, and 19 issues rest on it (D25).
Given via points, BRouter computes its own route between them, under its own profile. It does not
snap a track to OSM the way GraphHopper's or Valhalla's matching endpoints do. Three consequences:
route the rider is not on — the worst failure a navigation device has, because it is confidently
wrong rather than obviously broken.
declines. BRouter detours, silently, and the cues follow the detour.
points, BRouter routes once per leg under a running-time cap. NFR-P5 was filed as "needs a number";
it is not a number problem, it is an unvalidated feasibility problem.
Added criteria:
least three real routes including one urban and one rural
than shown
chosen from evidence and NFR-P5 gets a real number
behaviour
maxRunningTime/ timeout behaviour on a long route recordedAPI and #27 changes shape entirely
right tool
The 20 m divergence check ships in
BRouterEnricherregardless of what this spike finds. It is theonly thing between a bad enrichment and a rider being told to turn where there is no turn.
Labelled
blocker. It gates twelve issues and was not marked.Update — 2026-09-02: divergence is per leg, and the stakes are lower than they were
Per-leg rejection (D41). The 20 m threshold above reads as a whole-route check, and NFR-P8 stated
it as one. Applied that way, one bad 50 m stretch discards the cue sheet for a 100 km route and
drops the rider to the geometric heuristic for the entire ride — a worse outcome than the failure it
protects against.
marked unenriched, so the watch shows no turn rather than a wrong one
here — a route where most legs fail is not a good route with a few gaps
Lower stakes (D40, D42). Two things moved out from under this spike:
reaches BRouter-quality cues with no BRouter install at all. This spike now decides the komoot
path, not navigation as a whole.
the mid-ride critical path. Its blocked-by edges to the re-routing work can be dropped.
Keeps
blocker: import-time enrichment for geometry-only routes still rests on it.Update — 2026-09-03: criteria rewritten from measurement; several questions pre-answered
A server-side dry run of this spike's experiment against live BRouter 1.7.10 (D58–D62 in
docs/DECISIONS.md) answers several criteria in advance and gives the rest concrete numbers.
Struck from this issue (already answered):
Reference-track mode over AIDL— unreachable:rawTrackPathis set by the service, notthe caller, and it is a recalculation cache, not matching. D25's open question is closed.
Street-name availability— no, in any format at any tier. One-line on-device confirmationonly, not an investigation.
Whole-route 20 m validation— unachievable even in the ideal case (BRouter misses its ownoutput by 27.8 m at 100 m via spacing). Replaced by the per-leg curve below.
"Gates twelve issues"— by reachability (D57) this issue gates #27, #64, #73 only. Still arisk blocker; no longer a schedule one.
Pass criteria (concrete):
setClassName("btools.routingapp","btools.routingapp.BRouterService")after adding<queries><package android:name="btools.routingapp"/></queries>— without it,bindServicereturns false indistinguishably from "not installed"
lonlats,profile=trekking,timode=9,acceptCompressedResult=true,pathToFileResult=null,engineMode=0, explicitmaxRunningTimecos(lat₀). Keep threshold 20 m. Wholesale rejection: >10% legs failing OR contiguous failingrun > 500 m. Via spacing ≤ 100 m (2% failing legs adversarial; 250 m gives 20%)
correctMisplacedViaPoints(viaextraParams) and named via points(
lon,lat,"name") — the two levers against divergenceTransactionTooLargeException; byte sizerecorded
<baseDir>/brouter/modes/*_rawtrack.datbetween runs — the shared per-profile raw-trackcache makes consecutive runs non-independent
brouter-routing-app/.../IBRouterService.aidl), notthe brouter.de/brouter URL in the old Notes — that interface has no
timode/profileandwould produce cues silently absent
Fixtures required (the real blocker; #38 needs them anyway):
surface a bike profile dislikes
ti_1.gpx…ti_9.gpxalready generated from liveBRouter 1.7.10 and ready to commit as tier-0 fixtures
.jsonas ground truthVerdict from the dry run: with the cuts above this is one focused day. Blocked on fixtures 1–3,
not on engineering.
PR #95 (merged) supplies one of this spike's named fixture requirements: a real komoot export >= 100 km (fixture list item 2, ~119km). Fixture list items 1 (>=3 real exports: urban/rural/profile-disliked surface), 3 (out-and-back or figure-eight), 5 (RideWithGPS export + ground truth), 6 (Garmin Connect export), and 7 (route outside segment coverage) are all still needed \u2014 and the spike itself still requires actually binding IBRouterService on a real device with BRouter + segment files installed, which cannot happen in this sandbox regardless of fixtures. Not closing.