298 lines
32 KiB
Markdown
298 lines
32 KiB
Markdown
# Roadmap: araharah
|
||
|
||
## Overview
|
||
|
||
araharah turns Telegram into a privacy-respecting turn-by-turn navigator for KL: a bot handles
|
||
identity, search, and launch; a Telegram Mini App renders Rams-styled route guidance; Valhalla
|
||
routing, self-hosted Photon lookup, OpenFreeMap tiles, and MapLibre GL JS v6 supply the OSM
|
||
geodata layer; one Cloudflare Worker (static assets + webhook + `/api/*`) serves it all with
|
||
KV-only TTL storage. The roadmap follows the research's strict dependency funnel — design tokens
|
||
first (design fidelity is the flagged #1 sink for v1), then the bot/identity security floor,
|
||
then the Mini App shell with geolocation, then KL destination search, then routing and route
|
||
display, then live turn-by-turn guidance including backgrounded chat turn-cards, and finally a
|
||
hardening pass that earns the private launch. Two phases deliberately surface the project's
|
||
biggest unknowns early: WebView geolocation quirks (Phase 3) and KL search quality (Phase 4).
|
||
|
||
## Phases
|
||
|
||
**Phase Numbering:**
|
||
- Integer phases (1, 2, 3): Planned milestone work
|
||
- Decimal phases (2.1, 2.2): Urgent insertions (marked with INSERTED)
|
||
|
||
Decimal phases appear between their surrounding integers in numeric order.
|
||
|
||
- [ ] **Phase 1: Design Tokens + Rams Foundation** - Distill the Telemetry Rams system into a single token package and Rams-styled map basemap, with a mockup-vs-implementation approval artifact — before any screen is built
|
||
- [ ] **Phase 2: Bot Skeleton + initData Security** - grammY bot on one Cloudflare Worker: /start, command menu, /privacy, and HMAC-validated identity with TTL-only KV storage
|
||
- [x] **Phase 3: Mini App Shell + Geolocation** - Telegram WebApp shell that boots, authenticates, and reads a reliable live location across the Android/iOS/Desktop client matrix (completed 2026-10-23)
|
||
- [x] **Phase 4: Destination Search + KL Gazetteer** - Free-text KL search that resolves landmarks despite Malay abbreviations and typos, venue cards, and Mini App launch with destination preloaded (completed 2026-10-23)
|
||
- [x] **Phase 5: Routing + Route Display** - Valhalla-backed route calculation shown as a Rams route line with quiet alternative cards; the full search→route→render loop lands (completed 2026-10-23)
|
||
- [x] **Phase 6: Turn-by-Turn Guidance (Live Driving)** - Client guidance state machine: maneuver banner, missed-turn auto-recalculation, honest ETA, haptics, seamless resume, and backgrounded chat turn-cards (completed 2026-10-24)
|
||
- [x] **Phase 7: Hardening + Private Launch** - Device-matrix QA, graceful failure states, privacy-by-construction audit, and golden-route regression before real drivers (planned 2026-10-25) (completed 2026-10-25)
|
||
|
||
## Phase Details
|
||
|
||
### Phase 1: Design Tokens + Rams Foundation
|
||
**Goal**: The Telemetry Rams design system exists as one centralized, importable token set — including map basemap cartography — with a user-approved mockup-vs-implementation gallery proving the fidelity bar before any product screen is built.
|
||
**Depends on**: Nothing (first phase)
|
||
**Requirements**: DSGN-01, DSGN-02
|
||
**Success Criteria** (what must be TRUE):
|
||
1. Every rendered Rams component derives exclusively from the centralized token set (exacted palette, 8px grid, radius-0, typography) — an audit sweep finds zero off-token color/spacing/typography values in the component sheet (DSGN-01)
|
||
2. A side-by-side gallery comparing the rendered token/component sheet against the `stitch_minimalist_route_navigator/` mockup screens exists and is approved by the user — establishing the DSGN-02 approval artifact mechanism reused by every later UI phase
|
||
3. A Rams-styled MapLibre basemap (OpenFreeMap `liberty` style forked to Rams tokens: grayscale grounding, muted land/water, prepared accent for route highlighting) renders in a browser (DSGN-01, map cartography)
|
||
4. Design authority is singular: the duplicate inline Tailwind token blocks and the conflicting root `DESIGN.md` typography are superseded by the token package as the one source of truth (resolves the CONCERNS.md design-source conflict)
|
||
**Plans**: 4 plans
|
||
|
||
Plans:
|
||
- [x] 01-01-PLAN.md — Repo hygiene + Tailwind v4 token package (`theme/`) + self-hosted fonts + DESIGN.md supersession (D-01/02/04/05/06/07/16)
|
||
- [x] 01-02-PLAN.md — Component sheet: `theme/src/components.css` + `sheet.html` consuming tokens only (D-03/D-11)
|
||
- [x] 01-03-PLAN.md — Rams basemap: token-derived OpenFreeMap liberty fork + KL preview (D-08/09/10)
|
||
- [x] 01-04-PLAN.md — Off-token audit (D-13) + Playwright captures (D-14) + DSGN-02 approval gallery (D-12), blocking user checkpoint
|
||
|
||
Notes:
|
||
- Repo hygiene lands here first: scrub `*:Zone.Identifier` artifacts, `.gitignore` for OS junk/`node_modules`/secrets (pre-dates any credential handling).
|
||
- Project skill `.agents/skills/design-taste-frontend/` applies to all UI phases under its *existing brand/design system* special case: keep the Rams palette/type, app-screen house rules for dashboard-like surfaces, real-browser inspection for the gallery artifact. Telemetry Rams tokens are binding where skill defaults would differ.
|
||
- Standard patterns (no research phase needed): mockups are the spec; token extraction from the mockup Tailwind config.
|
||
**UI hint**: yes
|
||
|
||
### Phase 2: Bot Skeleton + initData Security
|
||
**Goal**: Users can reach araharah through Telegram with a working command surface, and the backend's identity + privacy architecture is provably sound from the first deploy — the initData validator is the first backend artifact.
|
||
**Depends on**: Phase 1
|
||
**Requirements**: ONBD-01, PRIV-01, PRIV-02
|
||
**Success Criteria** (what must be TRUE):
|
||
1. A new user sends /start and receives a concise explanation plus an always-available command menu (/help, /privacy) that answers correctly (ONBD-01)
|
||
2. /privacy gives an honest, visible statement of what araharah stores and does not store (PRIV-01) — the in-app "trip ended, data deleted" messaging half completes with guidance in Phase 6, riding this requirement's message design
|
||
3. Tampered, stale, and replayed initData payloads are rejected with CI test vectors and known-good HMAC cases passing; only validated identities receive a one-time session token (security gate — the phase's exit criterion)
|
||
4. A storage spot-check shows KV with TTL-only namespaces and zero persistent coordinates or user profiles — privacy by construction holds from the first line of backend code (PRIV-02; re-audited in Phase 7)
|
||
**Plans**: 3 plans
|
||
|
||
Plans:
|
||
- [x] 02-01-PLAN.md — bot workspace scaffold + Wave-0 test harness (RED initdata suite)
|
||
- [x] 02-02-PLAN.md — initData HMAC validator (rejection classes) + TTL-only KV sessions (GREEN)
|
||
- [x] 02-03-PLAN.md — command surface (en/ms, aliases) + Worker wiring (/telegram/webhook, /api/session) + deploy checkpoint
|
||
|
||
Notes:
|
||
- One Cloudflare Worker deployable (static assets + webhook + `/api/*`); KV `chat_sessions` (minutes TTL) is the first namespace; the `guidance_sessions` (~2h TTL) envelope is only designed with its consumer in Phase 5.
|
||
- Standard patterns (no research phase needed): grammY + Workers hosting is first-class documented; verify exact grammY initData typings at phase start (research gap).
|
||
**UI hint**: no
|
||
|
||
### Phase 3: Mini App Shell + Geolocation
|
||
**Goal**: The Mini App opens inside Telegram, establishes a validated session, and obtains the user's live location reliably — with every fallback path that keeps location flowing when the primary path dies, verified on real devices.
|
||
**Depends on**: Phase 2
|
||
**Requirements**: GEO-01, GEO-02, GEO-03, PX-02
|
||
**Success Criteria** (what must be TRUE):
|
||
1. On a real Android phone and iOS phone, the user grants location and sees their live position rendered on the Rams basemap; the permission grant persists across session restarts via LocationManager (version-gated) (GEO-01)
|
||
2. When in-app location fails (Desktop Telegram without geolocation, or denied permission), the chat "send location" keyboard fallback recovers the origin and the app proceeds with it (GEO-02)
|
||
3. Location denial shows a deliberate denied state (never a blank map), and the app renders correctly under Telegram light and dark themes while the map keeps Rams cartography constant (PX-02, platform themes)
|
||
4. No coordinate written anywhere persists: storage remains TTL-ephemeral only, spot-checkable at phase exit (GEO-03)
|
||
5. Device-matrix exit pass: Android + iOS + Desktop + plain browser each demonstrate boot → session → position, exercising the full fallback chain (pitfall research device-matrix criterion)
|
||
**Plans**: 4 plans
|
||
|
||
Plans:
|
||
|
||
**Wave 1** (baseline):
|
||
- [x] 03-01-PLAN.md — `web/` workspace + Wave-0 test runner; TTL-only location-pin KV, GEO-02 chat keyboard handler, and the `GET /api/location` relay route
|
||
|
||
**Wave 2** *(blocked on Wave 1 completion)*:
|
||
- [x] 03-02-PLAN.md — Location chain: three source adapters normalizing to one `Fix`, the D-04 state machine with freshness as a separate axis, memory-only session store, Telegram platform wrappers, Mock-Telegram harness, and the GEO-01/02/03 + PX-02 gates
|
||
|
||
**Wave 3** *(blocked on Wave 2 completion)*:
|
||
- [x] 03-03-PLAN.md — Rams shell: UI-SPEC copy module, token-only stylesheet, MapLibre v6 bootstrap with the WebGL2 gate, marker/follow/recenter, status strip and state cards, and the map-first boot choreography
|
||
|
||
**Wave 4** *(blocked on Wave 3 completion)*:
|
||
- [x] 03-04-PLAN.md — Worker `[assets]` binding + one-command deploy + D-14 build-artifact gate; Playwright capture harness with the GEO-03 runtime probe; blocking device-matrix exit gate
|
||
|
||
Cross-cutting constraints (truths appearing in 2+ plans, binding at every wave):
|
||
- denied/blank is forbidden — every dependency-failure state renders a deliberate Rams surface (03-02, 03-03, 03-04)
|
||
- zero coordinate persistence — TTL-ephemeral KV only; grep gate + runtime probe (03-01, 03-02, 03-03, 03-04)
|
||
- Rams token-only styling — Telemetry Rams tokens binding over skill defaults (03-02, 03-03, 03-04)
|
||
|
||
Notes:
|
||
- Highest platform-integration uncertainty in the project — research recommends `/gsd-research-phase` (Android LocationManager stale-fix workaround, `getLiveData()` wrapper, WebView permission bridges, browser testing harness).
|
||
- BackButton wiring and safe-area groundwork are built here as shell infrastructure; the observable PX-01/PX-03 behaviors are claimed by Phase 6 where the full state graph exists.
|
||
- Research findings that shaped the plan: `getLiveData()` does not exist (D-05's gated streaming is our own `Fix`-shaped abstraction with a pluggable cadence — Phase 6 picks poll vs `watchPosition`); the Android stale-fix inverts the naive D-04 chain reading, so freshness is a separate axis from availability; Desktop Telegram has no geolocation at all (issue #77), making the chat-keyboard path the only Desktop origin; `GET /api/location` is required scope; MapLibre v6 is ESM-only and WebGL2-only (the map-less shell state is a deliberate `--color-surface-dim` field, not a crash); Bot API 10.2's origin restriction is enforced as of 2026-07-20.
|
||
- 03-04 task 3 is a **blocking human checkpoint**: real Android, iOS, and Telegram Desktop are listed in RESEARCH as required with no fallback. If no device is available, Success Criterion 5 is recorded UNVERIFIED and the phase is held open rather than silently closed.
|
||
**UI hint**: yes
|
||
|
||
### Phase 4: Destination Search + KL Gazetteer
|
||
**Goal**: Users type a destination the way locals actually write it and get the right KL-metro landmark back, then step into the Mini App already aimed at their destination.
|
||
**Depends on**: Phase 3
|
||
**Requirements**: SRCH-01, SRCH-02, SRCH-03, ONBD-02, ONBD-03
|
||
**Success Criteria** (what must be TRUE):
|
||
1. Typing "KLCC" — plus the golden query set ("Sunway Pyramid", "DUKE", mall and kampung-style queries) — returns the right KL landmark in a shortlist (SRCH-01)
|
||
2. Abbreviated, typo'd, and missing-space queries ("Jln Ampang" ↔ "Jalan Ampang", "Tmn", glued words) resolve to the same result as the canonical spelling (SRCH-02)
|
||
3. Choosing a result sends a native venue card in chat confirming the destination before navigation opens (SRCH-03)
|
||
4. Tapping through from the search result launches the Mini App with the destination preloaded — no re-entry in the webview (ONBD-02); adding araharah to the phone home screen and launching from there lands in the app ready to search (ONBD-03)
|
||
5. The self-hosted Photon KL bake-off is concluded against the real-query acceptance corpus with the decision (and any gazetteer/fallback escalation) documented — the search-quality experiment closes, it doesn't stay open
|
||
**Plans**: 4 plans
|
||
|
||
Plans:
|
||
|
||
**Wave 1** *(the shared foundation — a fourth npm workspace, `search/`)*:
|
||
- [x] 04-01-PLAN.md — `@araharah/search` workspace: the `SearchSource`/`GazetteerEntry` contract, the JUPEM-derived abbreviation table as editable DATA, the symmetric normalizer, the hand-rolled OSA distance, the disjoint-tier scorer, the curated KL gazetteer with locals' aliases, the lazy three-environment loader, plus the root GPL-3.0 `LICENSE` and the ODbL-1.0 data notice (D-04/05/06/07/08/09/15)
|
||
|
||
**Wave 2** *(parallel — the measurement instrument and the chat surface)*:
|
||
- [x] 04-02-PLAN.md — the pinned golden corpus (D-13), the D-14 bake-off runner + the in-suite Nyquist gate, the Overpass top-up tool (D-06), the JSON→SQLite converter (D-05), and `docs/SEARCH-QUALITY.md` recording the measured result and the escalation lever (SRCH-01, SRCH-02)
|
||
- [x] 04-03-PLAN.md — the `/cari` command (D-01), the single-message `sendVenue` card with 2-4 inline alternates (D-02/D-10), the honest out-of-area refusal, the OPEN deep link carrying a plain gazetteer id with NO crypto (D-11), `MINI_APP_URL` config, and the four `commands.test.mjs` landmines defused in the same change (SRCH-03, ONBD-02)
|
||
|
||
**Wave 3** *(the webview hand-off + the blocking device gate)*:
|
||
- [x] 04-04-PLAN.md — the two-carrier destination reader (`?dest=` primary, `initData.start_param` secondary) with one shared validation, the memory-only resolver, the honest "destination unavailable" state, ONBD-03's minimal `addToHomeScreen`/`checkHomeScreenStatus` hooks behind a Bot API 8.0 guard, the build-artifact drift gate, the destination-preload capture, and the blocking Android/iOS/Desktop device gate (ONBD-02, ONBD-03)
|
||
|
||
**Cross-cutting constraints** *(must_haves.truths asserted by 2+ plans)*:
|
||
- The deep-link carrier correction (plain id via `?dest=` URL param read from `location.search`, `start_param` secondary, NO crypto) — plans 03, 04
|
||
- The D-14 corpus gate as an executable in-suite assertion (top-3 ≥ 90% on positives, negatives honestly refused) — plans 01 (admission rule), 02 (runner + suite)
|
||
- Category-only logging / no query text persisted (D-15) — plans 01 (no logging in the module), 03 (category-only literals), 04 (state-token capture signal)
|
||
|
||
Notes:
|
||
- Budgeted bake-off: research recommends `/gsd-research-phase` (gazetteer sourcing/structure ~200 entries, Malay normalizer, photon-vs-fallback decision; funds a GraphHopper MY dump on the VPS).
|
||
- **D-03 supersedes the roadmap's "VPS provisioning begins here" note** — the search backend is the in-Worker curated gazetteer ($0 infrastructure); Photon-on-VPS is deferred to Phase 5 (Valhalla needs the VPS anyway) and stays behind the `SearchSource` interface as backend #3.
|
||
- **Mechanism correction (RESEARCH Pitfall 1, plan 04-03/04-04):** a `web_app` inline button's `WebAppInfo` carries ONLY a `url` — there is no `start_param` field (verified against the installed grammY typings), so the deep link's plain gazetteer id travels as `?dest=<slug>` in that URL and the webview reads `location.search` first, `initData.start_param` second. The D-10/D-11 intent (venue card → one tap → Mini App preloaded with a plain id, no crypto) is unchanged; a structural gate asserts no crypto in the deep-link path.
|
||
- The bilingual alias scheme: `/cari` + `/search` are registered together (the Phase 2 D-04 precedent of pairing `/start`↔`/mula`, `/privacy`↔`/privasi`); `/pergi_ke` stays reserved for Phase 5 and its future-stub ban is narrowed to `/pergi_ke`, not removed.
|
||
**UI hint**: no
|
||
|
||
### Phase 5: Routing + Route Display
|
||
**Goal**: The product exists end-to-end: current location to Rams-drawn route with quiet alternative choices, on routing infrastructure fast enough for the guidance phase to build on.
|
||
**Depends on**: Phase 4
|
||
**Requirements**: RTNG-01, RTNG-02
|
||
**Success Criteria** (what must be TRUE):
|
||
1. A user sees their calculated route drawn on the Rams-styled map — grayscale basemap grounding with the accent route line — from their current location to the chosen destination (RTNG-01)
|
||
2. The user can choose among up to 3 alternatives presented as quiet Rams cards (time, distance, one-line difference) and the selection redraws (RTNG-02)
|
||
3. 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 *(SC3 amended 2026-10-24 per 05-CONTEXT.md — the fixture-backend pivot; RTNG-01's "calculated route" is satisfied by fixture calculation, the arbitrary-origin router is a documented deferral)*
|
||
**Plans**: 5 plans
|
||
|
||
Plans:
|
||
|
||
**Wave 1** *(parallel foundations — the fifth npm workspace + the frozen Phase 6 contract)*:
|
||
- [x] 05-01-PLAN.md — the `routing/` workspace (`@araharah/routing`): the `RoutingSource` contract with the documented backend ladder (D-01/D-04), the route model's day-one step-geometry + snapped-progress fields (D-07), the polyline6 codec (external-vector-tested), the geo math, the fixture backend with the 200 m matching law + honest-null pending semantics (D-03), the committed empty fixture schema with ODbL header, and the three-environment loader proof (RTNG-01)
|
||
- [x] 05-03-PLAN.md — the `guidance_sessions` envelope as a TYPES-ONLY frozen contract (D-06/D-07): envelope + inline route snapshot types, the 7200 s TTL constant, the `guidance:<id>` key scheme, and seven GE gates proving no KV namespace, no runtime writes, no premature consumer (Phase 6 builds on the frozen shape)
|
||
|
||
**Wave 2** *(blocked on Wave 1 completion — the data product and the visible surface, in parallel)*:
|
||
- [x] 05-02-PLAN.md — the golden-pair corpus: 15 pinned public KL pairs (D-02), the maintainer fetch tool against the public OSRM demo (D-12 boundary in its header), the committed populated fixture dataset, and the RT1–RT10 offline tolerance gate as CLI + in-suite Nyquist gate — public-origin proof, geometry↔summary consistency, codec round-trip, size budget, alternatives floor (RTNG-01, RTNG-02)
|
||
- [x] 05-04-PLAN.md — the web route surface per the approved 05-UI-SPEC: the four-layer orange casing stack added once after building-3d (D-09), origin ring + destination pin, the bottom route card + alternates chips (D-08), the designed router-pending card (D-03), fit-bounds camera law, the auto-consult wiring, the two-state BackButton walk (D-10), and the RS1–RS10 gates (RTNG-01, RTNG-02)
|
||
|
||
**Wave 3** *(blocked on Wave 2 completion — the phase's closing gates)*:
|
||
- [x] 05-05-PLAN.md — the verification close: BA9 bundle-budget gate (≤ 200 KB gz, measured + printed) + BA10 fixture-parity over the production build (D-11), the five `?fixpair=`-driven route capture legs + the DSGN-02 route-gallery artifact, and the Worker-side no-route-proxy gates (D-05) (RTNG-01, RTNG-02)
|
||
|
||
**Cross-cutting constraints** *(must_haves.truths asserted by 2+ plans)*:
|
||
- Honest-null pending semantics (an unknown destination / uncovered origin resolves to `null` and renders the designed pending card — never a blank map, never a fake route, D-03) — plans 01, 04, 05
|
||
- No logging / no storage / no runtime network in the routing path (D-12/D-15 analogs; the Worker gains no `/api/route`) — plans 01 (module zero-laws), 03 (types-only envelope), 04 (state-token signals), 05 (RP gates)
|
||
- The capture signal is a STATE TOKEN, never coordinates (`ARAHARAH-ROUTE state=drawn|pending`, paired with DOM text checks) — plans 04 (RS8 source law), 05 (capture legs)
|
||
- Fixtures are committed PUBLIC data — every pinned origin provably equals a gazetteer landmark coordinate; the bundle carries every pairId; the harness knob accepts pairIds only — plans 02 (RT2b), 05 (BA10, ?fixpair)
|
||
|
||
Notes:
|
||
- GUID-05/06 upstream design obligations land here deliberately: the route model carries step geometry + snapped-progress support from day one, and the ephemeral `guidance_sessions` KV envelope (id, chat ref, route snapshot ref, ~2h TTL) is designed here so the backgrounded turn-card service in Phase 6 has its session contract already defined.
|
||
- Standard patterns (no research phase needed — light pass only): fixture precompute against the public OSRM demo server at BUILD time (maintainer machine, fixed public coordinates) + committed encoded-polyline storage; no exotic APIs. *(The "documented preprocess pipeline for Valhalla + graph/tiles build" note is superseded by the fixture-backend pivot — 05-CONTEXT.md D-01/D-04; Valhalla-on-VPS is RoutingSource backend #3, documented, not shipped.)*
|
||
**UI hint**: yes
|
||
|
||
### Phase 6: Turn-by-Turn Guidance (Live Driving)
|
||
**Goal**: While driving, araharah behaves like real navigation — prominent maneuvers, silent self-healing recalculation, honest ETAs, haptic cues, seamless resume — and guidance survives the app being minimized via best-effort chat turn-cards.
|
||
**Depends on**: Phase 5
|
||
**Requirements**: GUID-01, GUID-02, GUID-03, GUID-04, GUID-05, GUID-06, PX-01, PX-03
|
||
**Success Criteria** (what must be TRUE):
|
||
1. During a drive, the user sees a prominent next-maneuver banner (distance + arrow + street name) with a collapsible full maneuver list (GUID-01), ETA and remaining distance progressing with each location fix without visible whiplash (GUID-03), and a haptic cue at maneuver points (GUID-04)
|
||
2. After a missed turn, the app silently recalculates from the current position — no asking, no blaming — and reroute storms are held back by the debounce/hysteresis state machine (GUID-02, verified via recorded-drive replays plus a real drive)
|
||
3. Minimizing the app mid-drive switches the bot to pushing chat turn-cards (map snapshot + next maneuver + ETA, best-effort projection) for the remainder of the trip (GUID-05, served by the Phase 5-designed ephemeral guidance session); re-opening mid-trip resumes live guidance seamlessly at the progressed position (GUID-06)
|
||
4. The Telegram BackButton walks the full app states (search → routes → guidance → back to search) and never dead-ends (PX-01 — full state graph only exists now); closing during guidance requires passing the "abandon route?" confirmation, with safe areas respected and vertical-swipe-close disabled during guidance (PX-03)
|
||
5. Ending a trip deletes the ephemeral guidance session and shows the "trip ended, data deleted" messaging — completing the in-app half of PRIV-01's promise at the trip boundary
|
||
**Plans**: 8 plans
|
||
|
||
Plans:
|
||
|
||
**Wave 1** *(parallel foundations — the pure cores + the envelope going live)*:
|
||
- [x] 06-01-PLAN.md — Engine A pure core: pinned CSR binary codec (with street-name table), GPS-fix snapping, typed-array A* + step/turn derivation, proven against a committed mini-graph by A*≡Dijkstra equivalence (D-01/D-05, GUID-02)
|
||
- [x] 06-02-PLAN.md — Guidance pure core: the D-04 reroute state machine with named constants, D-07 EMA+deadband ETA, D-15 distance throttle, four committed D-16 drive fixtures + replay/eta suites (GUID-02/03/04/06)
|
||
- [x] 06-03-PLAN.md — The frozen envelope goes LIVE: mint/get/delete TTL-only service + Bearer-gated /api/guidance POST/GET/DELETE (claim-only chat), GE4–GE7 re-pinned in the same change (GUID-05, D-14 server half)
|
||
|
||
**Wave 2** *(blocked on Wave 1 — the real graph + the cockpit chrome, in parallel)*:
|
||
- [x] 06-04-PLAN.md — Engine A server surface: Overpass→CSR build tool + real KL graph, R2 bucket/upload/fork docs, isolate-memoized worker-router behind Bearer-gated /api/route, client http-source backend #2, RP1/RP2 re-pins, A*-CPU measurement gate (D-01/D-03, GUID-02)
|
||
- [x] 06-05-PLAN.md — Guidance chrome per 06-UI-SPEC: committed 8-glyph set, banner/list/guidance-card/confirm/trip-end builders, close-protection + haptics capability guards, strings keys en+ms, shell.css guidance rules, guidance-surface suite + RS10/BA9 bumps (GUID-01/04, PX-03)
|
||
|
||
**Wave 3** *(blocked on Wave 2 — integration)*:
|
||
- [x] 06-06-PLAN.md — Guidance integration: D-10 locked-follow camera, the fix pump (banner/ETA/haptics/reroute), PX-01 full BackButton state graph, minimize-POST/resume-GET/trip-end-DELETE envelope flows, RS6 re-pin (GUID-02/05/06, PX-01/03, D-14 web half)
|
||
- [x] 06-07-PLAN.md — Cron turn-cards: pure projectTurnCards + the repo's first scheduled() handler + triggers.crons, street-bearing cards by default via graph reconstruction (street-less only as graph-absent degradation per D-03; D-12 with 06-08 Part C ratification), KV-write-budget pin, committed 8-glyph PNG set via sharp (GUID-05, D-11/12/13)
|
||
|
||
**Wave 4** *(the phase's closing gates)*:
|
||
- [x] 06-08-PLAN.md — Verification close: ?drive= replay knob + seven guidance capture legs + DSGN-02 gallery, then the ONE REAL DRIVE device gate (blocking checkpoint) (D-16, all reqs)
|
||
|
||
**Cross-cutting constraints** *(shared invariants enforced in multiple plans; no verbatim-duplicated truths)*:
|
||
- **Claim-only chat identity (T-06-02):** envelope chat_id derives from the Bearer claim server-side — never a request body — in 06-03 (mint/read/delete), 06-06 (POST composition), 06-07 (cron push target)
|
||
- **Fail-honest degradation (D-03):** absent/tampered graph → null → router-pending (06-01 decode, 06-04 `/api/route`, 06-07 street reconstruction); never a throw, never a wrong answer
|
||
- **TTL-only KV (GE1):** every envelope write carries `expirationTtl: 7200`; active DELETE on trip end (06-03 service, 06-06 flows, 06-07 zero-write cadence)
|
||
- **Privacy logging:** category-only logs, never coordinates/chat ids in output (06-03, 06-06, 06-07, 06-08 capture assertions)
|
||
|
||
Notes:
|
||
- Highest behavioral uncertainty (reroute triggers, ETA smoothing, battery) — research recommends `/gsd-research-phase` (backgrounded turn-card "best-effort projection" framing + static map snapshot generation; product decision needed for what "good enough" means minimized).
|
||
- Schedule slack budgeted here per research; backgrounded turn-cards are folded into this phase per roadmap instructions with the session contract pre-designed upstream (Phase 5).
|
||
**UI hint**: yes
|
||
|
||
### Phase 7: Hardening + Private Launch
|
||
**Goal**: Real KL drivers get an honest, robust experience: every failure state designed, the privacy promise holding under audit, performance within free-tier budgets, and a known-limitations document that tells the truth — then the launch.
|
||
**Depends on**: Phase 6
|
||
**Requirements**: PX-04
|
||
**Success Criteria** (what must be TRUE):
|
||
1. Guidance supports fullscreen and remains usable in landscape (driving posture) across the full real device matrix — Android, iOS, Desktop, browser (PX-04) — folded into the phase's device-matrix QA pass including the battery drain target (<10%/hr during guidance)
|
||
2. Every empty/error/timeout/off-road/no-geometry state renders gracefully (no blank screens, no broken layouts); version-gating fallbacks behave sanely on older Telegram clients
|
||
3. Privacy verification passes: an architecture audit shows no persistent per-user location history or profile anywhere — coordinates exist only in TTL-expiring KV, and logs carry no coordinate data (re-verifies PRIV-02, GEO-03 end-to-end)
|
||
4. The golden-route regression pass is green, Worker budgets audit clean (subrequests/CPU, cache hit-rate), and the "known limitations" doc (OSM data gaps, no traffic confidence, no lane guidance) ships before the first real drivers
|
||
**Plans**: 6 plans
|
||
|
||
Plans:
|
||
|
||
**Wave 1** (four parallel plans — no file overlap):
|
||
- [x] 07-01-PLAN.md — Fullscreen capability layer: the Telegram 8.0-guarded `requestFullscreen()` wrapper, the grown `TelegramWebAppLike` contract, the safe-area re-resolution on inset events (WIRED at the `web/src/main.ts` boot site), the route controller's guidance-start/trip-end wiring + the fullscreen-event watcher, and the FS1–FS9 suite (PX-04, D-03)
|
||
- [x] 07-02-PLAN.md — Landscape geometry as CSS-only media queries (tokens binding), the FM1–FM7 failure-state matrix (empty/error/timeout/no-geometry/off-road/old-client/location-timeout), and the landscape capture legs (PX-04, SC2)
|
||
- [x] 07-03-PLAN.md — The consolidated `npm run privacy-audit` tool: source gates over ALL src trees, the KV TTL gate, the category-only log gate, the positive fetch-host allowlist, the production-bundle scan, the live KV expiry probe, and the signed audit record (D-01, D-02)
|
||
- [x] 07-05-PLAN.md — The parked debts paid: IN-01's dead export + intent comments, IN-02's stale wrangler comment, IN-03's exact-900s boundary pin, the `/cari` re-arm attempt, the A1/A3 closure — plus `docs/KNOWN-LIMITATIONS.md` and the `/help` pointer line (D-07, D-08)
|
||
|
||
**Wave 2** *(blocked on Wave 1 completion — shares `package.json` with 07-03 and imports 07-03's live-probe library)*:
|
||
- [x] 07-04-PLAN.md — The consolidated `npm run budget-audit` tool: the re-run A* CPU ladder, the bundle-byte budgets, the KV write classes with the cron's zero-write law, the per-request-class subrequest inventory, the re-run golden corpora, the static-asset `_headers` policy, and the checked-in current-vs-free-tier budget record (D-06)
|
||
|
||
**Wave 3** *(blocked on Waves 1–2 — the blocking launch gate)*:
|
||
- [x] 07-06-PLAN.md — The launch gate: the consolidated 4-client × 7-interaction walk, the recorded Android battery measurement, the six-item D-09 checklist, and the milestone completion record (D-04, D-05, D-09)
|
||
|
||
**Cross-cutting constraints** *(must_haves.truths asserted by 2+ plans, binding at every wave)*:
|
||
- Category-only logging — no coordinate, chat id, or route payload in any log statement, including the fullscreen path (07-01, 07-03)
|
||
- TTL-only KV write law — every write carries a named-constant `expirationTtl`; the cron tick writes zero times (07-03, 07-04)
|
||
- Old-client sanity — missing Bot API 8.0 methods are a designed silent no-op, never an error surface (07-01, 07-02)
|
||
- Honest measurement — every recorded number is measured from reality (CPU ladder, battery run, device legs), never synthesized or assumed (07-04, 07-06)
|
||
|
||
Notes:
|
||
- No exclusive feature requirements beyond PX-04 — this phase hardens the outcomes of Phases 1–6 and is the last chance to catch the "looks done but isn't" failures for a navigation tool whose empty states ARE the polish surface.
|
||
- The two manual behaviors (the physical device walk and the battery run) live in the 07-06 blocking LAUNCH-GATE checkpoint — never synthesized. NOT-RUN legs are recorded honestly and keep the checklist unsigned.
|
||
**UI hint**: no
|
||
|
||
## Requirements Coverage
|
||
|
||
| Phase | Requirements |
|
||
|-------|--------------|
|
||
| 1 | DSGN-01, DSGN-02 |
|
||
| 2 | ONBD-01, PRIV-01, PRIV-02 |
|
||
| 3 | GEO-01, GEO-02, GEO-03, PX-02 |
|
||
| 4 | SRCH-01, SRCH-02, SRCH-03, ONBD-02, ONBD-03 |
|
||
| 5 | RTNG-01, RTNG-02 |
|
||
| 6 | GUID-01, GUID-02, GUID-03, GUID-04, GUID-05, GUID-06, PX-01, PX-03 |
|
||
| 7 | PX-04 |
|
||
|
||
**Coverage:** 22/22 v1 requirements mapped — no orphans, no duplicates. (PRIV-01's in-app trip-boundary messaging and PX-01/PX-03 groundwork are noted where they're staged, but each requirement maps to its owning phase exactly once.)
|
||
|
||
## v1.x Candidates (post-v1, not roadmap phases)
|
||
|
||
Per research: voice guidance (gated on iOS WKWebView TTS spike), live trip share via `sendLocation(live_period)`, toll vs toll-free toggle (Valhalla `use_tolls`), speed-limit display where OSM `maxspeed` exists. These hang off validated routing + guidance — plan a v1.x milestone after user validation, do not pull into the spine above.
|
||
|
||
## Progress
|
||
|
||
**Execution Order:**
|
||
Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6 → 7
|
||
|
||
| Phase | Plans Complete | Status | Completed |
|
||
|-------|----------------|--------|-----------|
|
||
| 1. Design Tokens + Rams Foundation | 0/TBD | Not started | - |
|
||
| 2. Bot Skeleton + initData Security | 0/TBD | Not started | - |
|
||
| 3. Mini App Shell + Geolocation | 0/4 | Ready to execute | - |
|
||
| 4. Destination Search + KL Gazetteer | 0/4 | Ready to execute | - |
|
||
| 5. Routing + Route Display | 0/TBD | Not started | - |
|
||
| 6. Turn-by-Turn Guidance (Live Driving) | 0/TBD | Not started | - |
|
||
| 7. Hardening + Private Launch | 0/6 | Ready to execute | - |
|
||
|
||
---
|
||
*Roadmap created: 2026-10-22*
|