# Phase 5: Routing + Route Display - Context
**Gathered:** 2026-10-24
**Status:** Ready for planning — **with a roadmap amendment** (SC3 rewording, below)
## Phase Boundary
The route EXPERIENCE ships end-to-end in fixture world: a `RoutingSource` interface (mirroring `SearchSource`), a fixture backend whose geometries for 10–20 real KL pairs were precomputed at build time, Rams route rendering (orange casing on the grayscale map), up-to-3 alternatives as a bottom card + chips, selection redraw with camera refit, and an honest "router pending" state for arbitrary origins. The `guidance_sessions` envelope is designed as a types-only frozen contract for Phase 6. **No VPS, no Worker route proxy, no third-party routing calls** — the engine itself is deferred to the WASM-router OSS track (client-side routing, backend #2), with Valhalla-on-VPS documented as backend #3.
**ROADMAP AMENDMENT (planning must apply):** SC3 is reworded from "routes cleanly through self-hosted Valhalla … behind the Worker proxy" to: "the golden-route corpus (10–20 real KL pairs) routes cleanly through the fixture RoutingSource backend with bundle-size and type gates holding; the RoutingSource interface carries the documented backend ladder (fixtures → client-side WASM router → Valhalla-on-VPS) and the 'router pending' state is deliberate and designed." RTNG-01's "calculated route" is satisfied by fixture calculation; the arbitrary-origin router is a documented deferral, not an omission.
## Implementation Decisions
### Routing infrastructure — THE PIVOT (user decision, supersedes roadmap SC3 v1)
- **D-01:** **No VPS this phase. No third-party routing API ever at runtime** (origin+destination to a third party is a core-value privacy leak). Routing is a **`RoutingSource` interface** with a backend ladder: **#1 fixtures (this phase) → #2 client-side WASM router (OSS track, deferred) → #3 Valhalla-on-VPS (documented, provision scripts as a documented path, not shipped)**.
- **D-02:** Backend #1 = **fixture routes for the 10–20 golden KL pairs**, geometries precomputed at BUILD time by a repo script hitting the public OSRM demo server once (build machine, fixed public coordinates — no user data, no runtime dependency), committed as compact encoded polylines. Each pair pins expected distance/duration tolerances.
- **D-03:** Arbitrary origin/destination combinations return an honest **"router pending"** state — a designed, deliberate Rams surface (UI-SPEC scope), never a blank map, never a fake route, never a silent failure.
- **D-04:** The **WASM-router track** (client-side routing in the webview — origin+destination never touch a server; static-hosted; fork-perfect) is captured as the post-v1 OSS project that becomes RoutingSource backend #2, exactly parallel to the search backend #2 pattern. The user's static-hosting/fork-model intent is preserved as the architectural direction, not abandoned.
- **D-05:** The Worker gains **no `/api/route`** this phase. Fixtures ride in the web bundle (gazetteer precedent). The interface stays backend-shaped so a server backend could slot in later without client rework.
### guidance_sessions envelope (Phase 6's contract, frozen now)
- **D-06:** **Types-only contract**: `guidance_sessions` envelope = { id, chat ref, route snapshot (inline), created_at } with a **~2h TTL** — shipped as code types + docs, **no KV namespace, no service, no runtime writes**. Phase 6 builds the service on the frozen shape.
- **D-07:** Route snapshot lives **inline in the envelope record — one key, one TTL**; nothing outlives 2h, nothing reconstructable after expiry. Consistent with the location-pin TTL precedent (Phase 3). The route model itself carries **step geometry + snapped-progress support fields from day one** (GUID-05/06 upstream obligation).
### Route UX surface (UI-SPEC scope; phase-terminal)
- **D-08:** Alternatives present as a **bottom card + chips**: one card for the selected route (time, distance, one-line difference vs best) with compact alternates as selectable chips — tap → redraw. Map stays dominant.
- **D-09:** Route line = **signal-orange casing** (dark under-line for grayscale contrast) + orange center line — Phase 1's reserved accent, per the navigate_map_overview mockup. Destination pin keeps venue semantics; origin = subdued ring. Camera **fits route bounds** on draw.
- **D-10:** **Display-only terminal surface**: selection redraws + camera refits; a restart/search-again affordance returns to the destination state. **No start-guidance button, no turn instructions, no progress UI** — Phase 6. No placeholder-shaped furniture (Phase 3 D-08 law).
### Gates replacing SC3's latency/subrequest budgets
- **D-11:** **Bundle budget**: fixture geometry + route-model code ≤ ~200KB gzipped added to the web bundle, enforced as a BA build-artifact gate. **Type gates**: route model readiness (step geometry + snapped-progress fields) pinned by tests. "Router pending" state covered by UI-SPEC + captures. Latency/subrequest budgets are not applicable to fixture world (documented as such, not faked).
### Privacy (carried + made specific)
- **D-12:** Fixture geometries are public-data routes between public places — no user coordinate ever enters a fixture. The build-time OSRM fetch happens on the maintainer's machine against fixed public points; the script documents this boundary. Runtime: origin stays in memory only (Phase 3 law); no route persists (envelope is types-only this phase).
### OpenCode's Discretion
- Fixture encoding format (encoded-polyline vs simplified GeoJSON) within the ≤200KB budget
- RoutingSource interface shape (async, backend-tagged results, tolerance metadata)
- Which Phase 4 corpus destinations become the 10–20 pairs; realistic origins list
- One-line-difference copy per alternative card (en/ms, clinical tone); "router pending" copy
- Chip/card visual details within the Rams system (UI-SPEC will bind exact geometry)
## Specific Ideas
- The route experience should feel like the mockup distilled: the orange line is THE accent on a grayscale world — nothing else competes.
- "Router pending" copy should be honest and calm: the app knows what routing is, states it isn't wired yet, offers search again. Same clinical register as the denied card.
- Fixture pairs double as the demo script: the 10–20 pairs are the routes a reviewer walks to see the product work.
## Canonical References
**Downstream agents MUST read these before planning or implementing.**
### Phase scope + decisions
- `.planning/ROADMAP.md` §Phase 5 — goal, success criteria **+ this file's SC3 amendment (planning applies it)**
- `.planning/REQUIREMENTS.md` §RTNG-01/02 (+ GUID-05/06 upstream obligations)
- `.planning/phases/04-destination-search-kl-gazetteer/04-CONTEXT.md` — SearchSource pattern to mirror; backend-ladder pattern; fork-model law (GPL-3.0)
- `.planning/phases/03-mini-app-shell-geolocation/03-CONTEXT.md` — map boot, marker/follow controller, memory-only law, location-pin TTL precedent
### Codebase
- `web/src/map/` — MapLibre boot (style never re-set — route layers must be addLayer, not style mutation), marker, follow controller
- `web/src/search/resolve-destination.ts` — the preloaded destination this phase routes TO
- `search/` — the interface+backend+ladder pattern to mirror
- `web/scripts/capture.mjs` + mock profiles — the capture harness the route display must extend (`?dest=` profiles exist)
- `bot/src/i18n/strings.ts` pattern — copy discipline for card/difference strings
## Existing Code Insights
### Reusable Assets
- `search/` workspace: interface + ladder + loader + corpus-gate patterns to mirror for `routing/`
- Phase 4 corpus gate (D-13/D-14) — the fixture-pair tolerance gate follows its shape
- Mock harness profiles (`?dest=`) — route-state capture profiles extend these
- BA build-artifact gates — the bundle-budget gate joins them
### Established Patterns
- npm workspaces + delegate scripts; TDD RED→GREEN; hand-rolled runners
- Interface + documented backend ladder (SearchSource → RoutingSource)
- Types-only frozen contracts (session envelope) with TTL-only storage law
- UI-SPEC gate applies this phase (UI hint: yes) — planning routes through it
### Integration Points
- Destination resolver → route destination input (Phase 4 hands off where Phase 5 begins)
- Route model step geometry + snapped-progress fields → Phase 6 guidance consumes
- `guidance_sessions` envelope types → Phase 6 bot service implements
## Deferred Ideas
- **WASM-router OSS project** — client-side routing in the webview (RoutingSource backend #2); static-hosted, privacy-maximal, fork-perfect; its own post-v1 project
- **Valhalla-on-VPS** — RoutingSource backend #3; docker-compose + Caddy + provision scripts as a documented path (Oracle Always Free candidate; full-MY extract chosen if provisioned)
- **Worker `/api/route` proxy** — only meaningful with a server backend
- **Real routing for arbitrary origins** — arrives with backend #2/#3; the "router pending" state is the honest interim
- Turn instructions/progress UI — Phase 6 (GUID-*)
- Toll-avoidance / costing knobs — v1.x
---
*Phase: 05-routing-route-display*
*Context gathered: 2026-10-24*