From 37ffefe11cea84a089dcbc819d7721f18bc98f93 Mon Sep 17 00:00:00 2001 From: araharah-executor Date: Sat, 24 Oct 2026 19:36:54 +0800 Subject: [PATCH] =?UTF-8?q?docs(06):=20A1=20decision=20=E2=80=94=20c3=20no?= =?UTF-8?q?w=20/=20c2=20next=20milestone;=20D-12=20street-bearing=20ratifi?= =?UTF-8?q?ed?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../06-04-SUMMARY.md | 13 ++ .../06-CONTEXT.md | 127 ++++++++++++++++++ 2 files changed, 140 insertions(+) create mode 100644 .planning/phases/06-turn-by-turn-guidance-live-driving/06-CONTEXT.md diff --git a/.planning/phases/06-turn-by-turn-guidance-live-driving/06-04-SUMMARY.md b/.planning/phases/06-turn-by-turn-guidance-live-driving/06-04-SUMMARY.md index 29306b6..e0aec96 100644 --- a/.planning/phases/06-turn-by-turn-guidance-live-driving/06-04-SUMMARY.md +++ b/.planning/phases/06-turn-by-turn-guidance-live-driving/06-04-SUMMARY.md @@ -184,3 +184,16 @@ Forks: the same three steps are `docs/ROAD-GRAPH.md`. - `npm run routing:test`: 65 passed / 0 failed (A1's 625-pair Dijkstra-equivalence sweep green on the bidirectional A*). `npm test -w bot`: 103 passed / 0 failed (RT1–RT11, GE5 one-kv-namespace, re-pinned RP1/RP2). `routing:typecheck` + `bot:typecheck` clean. - STATE.md and ROADMAP.md untouched (their working-tree modifications predate this session — orchestrator-owned writes); only this SUMMARY force-added. - Honest gaps recorded, not papered over: the A1 CPU gate FAILS (escalated with ladder evidence, above); the R2 bucket awaits account-level activation (user_setup). + +## A1 DECISION (maintainer, 2026-10-24) + +**c3 now, c2 next milestone.** Short product reroutes (2–8 km) run 2–8 ms — inside the +free plan's 8 ms budget; cross-metro routes (20–30 km, p95 38–93 ms) degrade honestly +to the router-pending state (engine's 1102 CPU-exhaust path → fail-honest null → the +designed pending card). Workers Paid (c1) rejected — $0 mandate. ALT landmark +preprocessing (c2) is the committed upgrade lever for the NEXT milestone (fixes long +routes while staying $0). The verifier treats GUID-02's engine side as delivered with +this documented degradation class. + +R2 activation still pending user dashboard click (code 10042) — non-blocking for +06-07/06-08; /api/route serves honest nulls until the graph uploads. diff --git a/.planning/phases/06-turn-by-turn-guidance-live-driving/06-CONTEXT.md b/.planning/phases/06-turn-by-turn-guidance-live-driving/06-CONTEXT.md new file mode 100644 index 0000000..8868bb8 --- /dev/null +++ b/.planning/phases/06-turn-by-turn-guidance-live-driving/06-CONTEXT.md @@ -0,0 +1,127 @@ +# Phase 6: Turn-by-Turn Guidance (Live Driving) - Context + +**Gathered:** 2026-10-24 +**Status:** Ready for planning — **with a phase-scope addition** (engine A workstream, D-01) + + +## Phase Boundary + +araharah behaves like real navigation: prominent next-maneuver banner + collapsible list, silent self-healing rerouting powered by a REAL router (engine A: Worker-side A\* over an R2-hosted KL road graph — RoutingSource backend #2, built this phase), honest ETA progression with smoothing, haptic cues, full BackButton state graph with PX-03 close protections, and trip-end data deletion (PRIV-01 in-app half). While minimized, the bot pushes schematic glyph+text turn-cards via a Worker Cron Trigger over the Phase 5-frozen guidance envelope. Verified via scripted drive replays plus one real drive. + +**PHASE-SCOPE ADDITION (user decision):** the "defer WASM-router" deferral from Phase 5 is superseded — **engine A is built IN this phase** as a first-class workstream. The fixture backend remains RoutingSource #1 (golden pairs demo), engine A becomes #2 (arbitrary-origin routing), and GUID-02's rerouting is REAL from day one. + + + + +## Implementation Decisions + +### Routing engine — THE PIVOT #2 (user decision; supersedes the phase-5 deferral) +- **D-01:** **Engine A ships this phase**: OSM → compact road-graph build script (KL: ~30–80MB binary, typed arrays; one-ways + speed weights; turn restrictions deferred), graph hosted in **R2** (upload script committed — forks upload their own), **Worker-side A\*** (JS typed arrays, WASM optional) exposed as **RoutingSource backend #2** via a JSON routing API on the Worker. Satisfies every law: $0, no VPS, fork-friendly, privacy (the Worker is our infrastructure). +- **D-02:** **Valhalla-to-JS port ruled infeasible** (C++/Boost/mmap tile stores) — recorded so it is never re-proposed. geojson-path-finder rejected (demo-grade: no alternatives/one-ways). Engine B (fully client-side webview router — graph on the phone) is the documented evolution of A, deferred post-v1. +- **D-03:** Fixture backend remains #1 (golden-pairs demo path); engine A is #2 and **becomes the guidance engine**: arbitrary current positions route for real. Router-pending state remains for graph-edge cases (e.g. R2 graph absent — a designed degradation, not an error). + +### Reroute semantics (GUID-02) +- **D-04:** The reroute trigger is a **thresholds + grace state machine**: `ON_ROUTE → OFF_ROUTE` (deviation > threshold with a grace window + N consecutive off-route fixes before acting) `→ REROUTING` (engine A call; banner stays calm, no blame) `→ ON_ROUTE` (new route snapped in, list refreshed). Storm guard: minimum time between recalculations. Missed-turn detection = off-route past the maneuver point. All thresholds are named constants, replay-tested. +- **D-05:** **The router snaps** raw GPS fixes to the graph (engine A owns snapping — one authority, no client/server drift). The watch fix streams raw; the router does the rest. + +### Guidance UX surface (UI-SPEC scope) +- **D-06:** Layout: **top maneuver banner** (distance + arrow + street) replacing the status strip's top register during guidance (location register compacts); **collapsible full maneuver list** (collapsed default, expands over the map, tap-out collapses); **bottom guidance card** (the route card evolves): ETA + remaining distance + progress. +- **D-07:** **ETA smoothing: EMA + deadband** — recompute from route model + snapped progress (never raw fix-to-destination distance); display updates only past a named threshold (±1 min / ±5% remaining); constants replay-tested. No visible whiplash. +- **D-08:** **Haptics**: `HapticFeedback.selectionChanged()` at maneuver-approach threshold (~300m), impact at the maneuver point. Graceful no-op where unsupported. +- **D-09:** **PX-03**: closing during guidance requires the **"abandon route?"** Rams confirm card (en/ms); `disableVerticalSwipes()` while guidance is active; safe-area insets respected. **PX-01**: BackButton walks the full graph — search → routes → guidance → back to search — never dead-ends (extends the phase-5 two-state walk). +- **D-10:** **Camera**: locked follow (center ≈65% down-screen, pitch 35°) easing along the snapped line; user pan unlocks follow → the Phase 3 recenter control returns with its semantics. + +### Backgrounded turn-cards (GUID-05) +- **D-11:** Minimize during guidance → app POSTs the guidance session (the frozen envelope contract goes LIVE: KV writes begin, `guidance:`, 7200s TTL). A **Worker Cron Trigger (60–120s)** scans active guidance keys, projects progress along the snapshot, and pushes a chat turn-card when the next maneuver changes (or every N minutes). App re-open resumes foreground guidance; cron pushes pause while foregrounded. +- **D-12:** The card is a **glyph + text card**: committed arrow-glyph icon set (8 cardinal/turn PNGs, token colors) + ETA/distance/street text — no map bitmap, no renderer dependency, fully $0. Bitmap snapshots deferred to v1.x (Workers cannot rasterize; honest best-effort framing). +- **D-13:** "Best-effort" is honest: cron lag, Telegram delivery variance, and TTL expiry are documented behaviors, not failures; the card copy never promises what the mechanism can't (copy table in UI-SPEC). + +### Trip end (PRIV-01 in-app half) +- **D-14:** Ending a trip **deletes the guidance session** (KV record gone — completing the TTL law's promise actively) and shows **"trip ended, data deleted"** messaging (en/ms). Arrival detection = snapped progress ≥ end-of-route threshold; abandon = the PX-03 confirm path. Both delete. + +### Watch cadence + verification (GUID-02/03) +- **D-15:** Battery cadence: `watchPosition` high-accuracy, but the **app throttles by distance** — guidance work runs on ≥10m moved or ≥5s elapsed, whichever first. D-05's gated-streaming law finally flips its watch ON here. +- **D-16:** **Scripted drive replays** verify the state machine: recorded JSON position streams (corridor follow, off-route excursion, missed-turn excursion, GPS jitter) replayed through the machine in tests, asserting every transition, the storm guard, and ETA deadband. **Plus one real drive** as the device gate (phase 3/4 protocol). + +### OpenCode's Discretion +- Graph build toolchain choice (osmium/planetiler-graph/custom overpass extract), binary layout, A\* variant (bidirectional), alternatives generation via penalty runs +- Deviation/storm/ETA constants' initial values (replay-tuned; named, not magic) +- Cron interval within 60–120s; "N minutes" repeat cadence; glyph icon production method (hand SVG → PNG) +- Banner/list micro-layout within the Rams system; exact copy wording within the tone law +- Envelope write timing (on guidance start vs first minimize — either honors the contract) + + + + +## Specific Ideas + +- The guidance screen is the product's cockpit: banner + guidance card are instruments, the map is the world — nothing decorative, everything reading-bearing. +- Reroute messaging follows the clinical-honest law: the banner never blames, never asks — it recalculates, states the new route, moves on. +- The 15 fixture pairs remain the demo script; engine A pairs with them (same destinations, arbitrary origins) for the real-drive gate. + + + + +## Canonical References + +**Downstream agents MUST read these before planning or implementing.** + +### Phase scope + decisions +- `.planning/ROADMAP.md` §Phase 6 — goal, 5 success criteria, research-recommended framing +- `.planning/REQUIREMENTS.md` §GUID-01..06, PX-01, PX-03 (+ PRIV-01 trip half) +- `.planning/phases/05-routing-route-display/05-CONTEXT.md` — the envelope contract being activated; RoutingSource ladder; D-05 cadence law +- `.planning/phases/03-mini-app-shell-geolocation/03-CONTEXT.md` — memory-only law, follow/recenter semantics, capture harness +- `.planning/phases/05-routing-route-display/05-UI-SPEC.md` — shell conventions the guidance UI extends + +### Codebase +- `routing/` — RoutingSource interface engine A implements +- `web/src/location/` — the chain; guidance watch extends it (D-05 flip) +- `web/src/map/follow.ts` + `recenter.ts` — camera semantics reused +- `web/src/route/` — phase 5 route surface evolving into guidance chrome +- `bot/src/kv/` — TTL-only patterns; the envelope service lands beside them +- `bot/wrangler.jsonc` — Cron Trigger wiring surface + + + + +## Existing Code Insights + +### Reusable Assets +- RoutingSource + polyline6 + fixture backend (phase 5) — engine A plugs beneath the same seam +- GuidanceSessionEnvelope types (phase 5, frozen) — the service implements, not redefines +- Follow controller + recenter control (phase 3) — locked-follow camera reuses them +- Mock-Telegram harness + capture profiles — replay fixtures + guidance captures extend them +- glyphs: none yet — the 8-arrow set is new, committed once, reused everywhere + +### Established Patterns +- Interface + backend ladder (now 3 real stages); hand-rolled runners; TDD RED→GREEN +- TTL-only KV with keyed namespaces; category-only logging +- Device gates: real hardware at exit (this phase adds the real drive) + +### Integration Points +- Cron Trigger = new Worker surface (first scheduled handler in the repo) +- R2 = new storage surface (first binding) — upload script + fork docs +- HapticFeedback/BackButton/vertical-swipes = Telegram WebApp APIs behind capability guards + + + + +## Deferred Ideas + +- Engine B: fully client-side webview router (graph on the phone; privacy-maximal endgame) +- Turn restrictions in the graph; contraction hierarchies; CH preprocessing +- Bitmap map snapshots in turn-cards (needs a rasterizer we don't have — v1.x) +- Voice guidance, live trip share, toll toggle, speed limits (v1.x, REQUIREMENTS deferred table) +- Traffic-aware ETAs, incident-aware rerouting (v2) + + + +--- + +*Phase: 06-turn-by-turn-guidance-live-driving* +*Context gathered: 2026-10-24* + +### Post-planning ratification (2026-10-24) +- **A1 CPU decision: c3 now** (short routes in-budget; cross-metro → honest router-pending), **c2 (ALT landmarks) committed as the next-milestone upgrade lever**. c1 (Workers Paid) rejected — $0 law. +- **D-12 ratification: street-bearing turn-cards confirmed** (default stands). +- R2 activation pending user dashboard click (code 10042); non-blocking for cron/captures.