Files
arah2/.planning/phases/06-turn-by-turn-guidance-live-driving/06-08-PLAN.md
T

173 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
phase: 06-turn-by-turn-guidance-live-driving
plan: 08
type: execute
wave: 4
depends_on: [06-06, 06-07]
files_modified:
- web/src/mock/telegram-mock.ts
- web/scripts/capture.mjs
autonomous: false
requirements: [GUID-01, GUID-02, GUID-03, GUID-04, GUID-05, GUID-06, PX-01, PX-03]
must_haves:
truths:
- "The capture harness replays a committed drive fixture through the LIVE shell via ?drive=<name> (D-16's browser leg)"
- "All seven guidance capture legs exist and assert ARAHARAH-GUIDE state tokens (never coordinates in console)"
- "The DSGN-02 guidance gallery compares the captures against active_route_guidance/screen.png"
- "ONE REAL DRIVE demonstrates: banner legibility, silent reroute self-heal, minimize → turn-cards, resume, trip-end deletion messaging (D-16 device gate)"
artifacts:
- path: "web/src/mock/telegram-mock.ts"
provides: "?drive= fixture-replay fix source with pause/resume controls"
- path: "web/scripts/capture.mjs"
provides: "the 7 guidance legs + gallery composite"
key_links:
- from: "web/src/mock/telegram-mock.ts"
to: "web/test/fixtures/drives/*.json"
via: "import.meta.glob fixture loading; the mock's fix source replays the drive"
pattern: "fixtures/drives"
- from: "web/scripts/capture.mjs"
to: "web/src/mock/telegram-mock.ts"
via: "?drive= profiles + scripted taps drive the legs"
pattern: "drive="
---
<objective>
The phase's verification close (D-16): extend the Mock-Telegram harness with the ?drive= fixture-replay knob, capture the seven guidance legs + DSGN-02 gallery, and run the ONE REAL DRIVE device gate — banner legibility, silent self-heal, minimize/turn-cards, resume, trip-end deletion.
Purpose: replays proved the brain in Node (06-02); captures prove the SHELL renders it; the real drive proves the ROAD behaves. This is the phase's declared protocol (the 03/04 precedent) and its exit gate.
Output: harness knob + 7 captures + gallery artifact + a recorded real-drive verdict.
</objective>
<execution_context>
@$HOME/.config/opencode/get-shit-done/workflows/execute-plan.md
@$HOME/.config/opencode/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/phases/06-turn-by-turn-guidance-live-driving/06-UI-SPEC.md
@.planning/phases/06-turn-by-turn-guidance-live-driving/06-CONTEXT.md
@.planning/phases/06-turn-by-turn-guidance-live-driving/06-VALIDATION.md
@.planning/phases/06-turn-by-turn-guidance-live-driving/06-RESEARCH.md
<interfaces>
<!-- Capture profiles table (06-UI-SPEC — BINDING names + asserts):
harness knob ?drive=<fixture>: the mock's Telegram fix source replays the D-16 JSON stream
through the live shell; pairs with ?dest= + ?fixpair= carriers; asserts ARAHARAH-GUIDE
state=<state> tokens (state tokens only — no coordinates in console, D-15 hygiene)
shell-guidance-active.png mock=android&dest=<golden-id>&fixpair=<pair>&drive=<corridor> light
→ banner (GUIDE // NEXT, arrow, distance, street) + compact strip + guidance card + progress bar + locked pose
shell-guidance-list.png same, after a scripted banner tap → list expanded, NEXT row lamp (collapsed-default proof = the active leg's complement)
shell-guidance-rerouting.png drive=<missed-turn> captured INSIDE the REROUTING window → calm banner (reroute copy, — distance, gantry), NO red anywhere
shell-guidance-confirm.png scripted END TRIP tap → confirm card bottom register, both CTAs, no red
shell-guidance-tripend.png scripted YES, ABANDON → trip-ended card (center), guidance chrome cleared
shell-guidance-dark.png active profile, scheme=dark → PX-02 chrome re-slots, banner Rams-constant
guidance-gallery-compare.png DSGN-02 side-by-side vs stitch_minimalist_route_navigator/active_route_guidance/screen.png -->
<!-- Mock harness (web/src/mock/telegram-mock.ts) + capture script (web/scripts/capture.mjs):
follow their EXISTING leg/profile/carrier patterns exactly (phase 3/4/5 legs stay
unchanged); fixture loading via import.meta.glob over ../test/fixtures/drives/*.json;
expose window.__ARAHARAH_DRIVE = { pause(), resume() } so the capture script can freeze
the replay mid-stream for the REROUTING leg's timing window and drive taps between fixes. -->
<!-- The real-drive checklist (06-VALIDATION manual-only row + D-16):
start a route on a real device → banner + haptic at approach/maneuver → miss a turn
deliberately → silent recalculation (no dialog, no blame) → minimize mid-drive →
turn-cards arrive in chat → re-open (or tap OPEN GUIDANCE) → guidance resumes at the
progressed position → END TRIP → "trip ended" messaging → (optional KV spot-check:
guidance:* key gone). Record the verdict + any defects verbatim. -->
</interfaces>
**The captures assert STATE TOKENS, never coordinates** (the Phase 5 capture law). The gallery is DSGN-02's phase artifact — fidelity review rides the same blocking checkpoint as the drive.
</context>
<tasks>
<task type="auto">
<name>task 1: ?drive= replay knob + the seven guidance capture legs + gallery</name>
<files>web/src/mock/telegram-mock.ts, web/scripts/capture.mjs</files>
<read_first>
- web/src/mock/telegram-mock.ts IN FULL (the mock fix-source architecture — ?drive= extends its source selection; the existing ?fixpair= carrier pattern)
- web/scripts/capture.mjs IN FULL (leg/profile structure, theme carrier, composite/gallery pattern from Phase 5's route legs, console-capture assert style)
- web/test/fixtures/drives/ (the four committed fixtures — ?drive= names map to these files)
- .planning/phases/06-turn-by-turn-guidance-live-driving/06-UI-SPEC.md Capture Profiles table (BINDING: names, profiles, asserts)
</read_first>
<behavior>
- `mock=android&dest=<golden-id>&fixpair=<pair>&drive=corridor-follow` boots into the route state and, past the 30 m activation gate, plays the fixture's fixes on their recorded schedule through the LIVE shell (real pump, real builders, real camera — not the Node fakes)
- window.__ARAHARAH_DRIVE.pause()/resume() freezes/resumes the replay clock (the REROUTING leg captures inside the window; the confirm/tripend legs run after resume)
- each leg's console capture shows the asserted ARAHARAH-GUIDE state tokens and ZERO coordinate-bearing log lines
- all seven PNGs exist under the capture output dir; the gallery composite places them beside the mockup screen.png
- existing legs (boot, denied, route, captures from phases 3–5) still pass unchanged
</behavior>
<action>
1. `web/src/mock/telegram-mock.ts`: add the ?drive= knob — read `drive` from location.search (the existing carrier style), validate against the import.meta.glob record of `../test/fixtures/drives/*.json` (unknown name → honest console token + fall back to the default source, never a crash); the drive source emits each Fix at `t0 + (fix.ts − fixes[0].ts)` on a replay clock that __ARAHARAH_DRIVE.pause()/resume() controls (paused clock stops emission, resume continues mid-stream — the REROUTING leg needs the freeze); console emits nothing but the state-token family.
2. `web/scripts/capture.mjs`: add the seven legs EXACTLY per the UI-SPEC table (names, profiles, asserts): active (light), list (scripted banner tap — page.click on the banner button), rerouting (drive=missed-turn-excursion + pause inside the REROUTING window — poll the console for the `ARAHARAH-GUIDE state=rerouting` token then shoot), confirm (scripted END TRIP tap), tripend (scripted YES, ABANDON tap), dark (scheme=dark), and the gallery-compare composite (the existing Phase 5 composite pattern with active_route_guidance/screen.png). Each leg asserts its state tokens via the existing console-capture helper + the DOM text checks the table names (GUIDE // NEXT, register words); add a NO-RED assertion to the rerouting/confirm legs (scan the captured banner/confirm element's computed colors or the absence of the functional-red token class — the cheapest honest check: assert the elements' class lists contain no red-token class).
3. Run the full capture suite; commit the seven PNGs + gallery; record the guidance gallery path in the SUMMARY for the DSGN-02 review.
</action>
<verify>
<automated>npm run web:capture 2>&1 | tail -20 && node -e "const fs=require('fs');const legs=['shell-guidance-active','shell-guidance-list','shell-guidance-rerouting','shell-guidance-confirm','shell-guidance-tripend','shell-guidance-dark','guidance-gallery-compare'];for(const l of legs){if(!fs.existsSync('web/captures/'+l+'.png'))process.exit(1)};console.log('7 guidance legs ok')"</automated>
</verify>
<acceptance_criteria>
- all 7 PNGs exist under web/captures/ (adjust the path prefix to capture.mjs's actual output dir — verify by reading the script first)
- telegram-mock.ts contains `import.meta.glob` over fixtures/drives and the __ARAHARAH_DRIVE pause/resume surface
- capture.mjs contains the 7 leg names from the UI-SPEC table and asserts ARAHARAH-GUIDE tokens
- prior capture legs unbroken (the suite's existing legs green)
- captures/summary output shows zero coordinate-bearing console assertions
</acceptance_criteria>
<done>The shell is proven on film: seven legs covering active, list, calm rerouting, confirm, trip-end, dark, and the mockup comparison — driven by real committed drive fixtures</done>
</task>
<task type="checkpoint:human-verify" gate="blocking">
<name>task 2: The ONE REAL DRIVE — the phase's device gate (D-16) + DSGN-02 gallery review</name>
<what-built>
Live turn-by-turn guidance end-to-end: Rams maneuver banner + collapsible list + guidance card with honest ETA, haptic cues, silent engine-A rerouting, minimize → chat turn-cards via the Worker cron, seamless resume, BackButton full state graph with the abandon confirmation, and trip-end deletion messaging. Seven capture legs + the DSGN-02 guidance gallery are committed for review beside stitch_minimalist_route_navigator/active_route_guidance/screen.png.
</what-built>
<action>
Blocking human checkpoint (automation-first: task 1's captures + all three workspace suites + the CPU gate are green BEFORE this runs). The user performs Part A (gallery fidelity review) and Part B (the one real drive with the 7-step checklist below). No OpenCode automatable step remains: physical GPS, real road geometry, and human legibility/haptic judgment are the declared device-gate protocol (D-16, phases 3–5 precedent). The executor records the per-step verdict verbatim in the SUMMARY; a FAIL holds the phase open (the Phase 3 UNVERIFIED precedent) rather than silently closing it.
</action>
<how-to-verify>
Part A — gallery (5 min): open the guidance gallery composite (path in 06-08's SUMMARY). Confirm fidelity: banner ink hierarchy (white distance, beige street, orange arrow), no red in guidance chrome, radius-0, token-pure. Approve or list deviations (tokens.css wins over mockup; the spec records calls).
Part B — the drive (one real drive, phone mounted, safe location to start):
1. Deploy fresh (`npm run deploy -w bot` with the graph uploaded — 06-04) and open the Mini App from the bot.
2. Pick a golden destination, start driving. VERIFY: banner shows distance + arrow + street; compact strip; guidance card ETA progresses without whiplash; haptic at ~300 m approach and at the maneuver.
3. Miss a turn DELIBERATELY. VERIFY: no dialog, no blame — the banner calmly shows the rerouting state, then the new route snaps in.
4. Minimize the app mid-drive. VERIFY: within ~3–4 minutes a turn-card arrives in chat (glyph + ETA + distance + OPEN GUIDANCE).
5. Re-open via the card's OPEN GUIDANCE. VERIFY: guidance resumes at the progressed position (resuming state, then live).
6. Tap END TRIP → confirm card → YES, ABANDON. VERIFY: "trip ended" messaging; chat cards stop.
7. (Optional, executor-assisted) KV spot-check: `npx wrangler kv key list --namespace-id=<chat_sessions id> --prefix "guidance:"` shows no stale keys.
Record PASS/FAIL per step + anything that felt wrong (legibility in sunlight, haptic feel, card lag).
</how-to-verify>
<resume-signal>Type "approved" (drive + gallery pass) or list the failing steps/deviations</resume-signal>
</task>
</tasks>
<threat_model>
## Trust Boundaries
| Boundary | Description |
|----------|-------------|
| Capture harness → live shell | The replay knob feeds the REAL pump with committed fixtures — no test-only bypasses of validation |
## STRIDE Threat Register
| Threat ID | Category | Component | Disposition | Mitigation Plan |
|-----------|----------|-----------|-------------|-----------------|
| T-06-04 | Information Disclosure (capture hygiene) | mock + capture console asserts | mitigate | Legs assert STATE TOKENS and assert the ABSENCE of coordinate-bearing log lines (the D-15 hygiene law carried into captures); no new logging is introduced by this plan. |
| — | Privacy (the drive itself) | real-drive protocol | mitigate | The drive uses the product's own privacy posture: no location history exists to leak; the KV spot-check proves the post-trip deletion promise (D-14) on real infrastructure. |
| — | Tampering (fixture/kernel mismatch) | ?drive= knob | mitigate | Unknown drive names fail honest (token + default source) rather than replaying arbitrary data; fixtures are committed and attributed. |
</threat_model>
<verification>
- `npm run web:capture` green with the 7 new legs; prior legs unbroken
- Gallery composite committed (DSGN-02 artifact for the phase)
- The real-drive checklist recorded with a per-step verdict (the phase's exit gate — a FAIL holds the phase open, per the Phase 3 UNVERIFIED precedent)
</verification>
<success_criteria>
D-16 is satisfied on both legs: the recorded drives prove the machine, the captures prove the shell, and ONE REAL DRIVE proves the road — banner, self-heal, turn-cards, resume, deletion — with the gallery review closing DSGN-02 for the phase.
</success_criteria>
<output>
After completion, create `.planning/phases/06-turn-by-turn-guidance-live-driving/06-08-SUMMARY.md`
</output>