diff --git a/.planning/phases/06-turn-by-turn-guidance-live-driving/06-08-SUMMARY.md b/.planning/phases/06-turn-by-turn-guidance-live-driving/06-08-SUMMARY.md new file mode 100644 index 0000000..bda35c8 --- /dev/null +++ b/.planning/phases/06-turn-by-turn-guidance-live-driving/06-08-SUMMARY.md @@ -0,0 +1,203 @@ +--- +phase: 06-turn-by-turn-guidance-live-driving +plan: 08 +subsystem: web-capture-harness +tags: [capture-harness, d16-device-gate, drive-replay, mock-telegram, guidance-legs, dsgn02-gallery, no-red-law, console-hygiene, blocking-checkpoint, tdd] + +# Dependency graph +requires: + - phase: 06-turn-by-turn-guidance-live-driving + plan: 02 + provides: "the four committed D-16 drive fixtures (web/test/fixtures/drives/*.json — the replay ground truth ?drive= names) + the D-04 machine the LIVE pump rides" + - phase: 06-turn-by-turn-guidance-live-driving + plan: 03 + provides: "POST/GET/DELETE /api/guidance — the envelope lifecycle the confirm/tripend legs' teardown executes (DELETE on abandon)" + - phase: 06-turn-by-turn-guidance-live-driving + plan: 04 + provides: "engine A live (deploy 75b0ff14, R2 graph round-trip verified) — the /api/route shape the capture stub answers" + - phase: 06-turn-by-turn-guidance-live-driving + plan: 06 + provides: "the LIVE pump (start gate → cockpit → reroute → teardown) — the surface the captures prove; camera.ts's locked pose" + - phase: 06-turn-by-turn-guidance-live-driving + plan: 07 + provides: "the cron turn-cards + the committed glyph PNGs — Part C's street-source ratification item" + - phase: 05-routing-route-display + plan: 05 + provides: "the capture-leg pattern (one leg = one context + one screenshot, console-token races, the DSGN-02 composer) — extended, never replaced" +provides: + - "web/src/mock/telegram-mock.ts — the ?drive= replay knob: navigator.geolocation replaced by a committed-fixture stream (real-time schedule, lazy clock start at the first watch arm, window.__ARAHARAH_DRIVE pause()/resume() freeze), honest unknown-name fallback" + - "web/scripts/capture.mjs — the seven guidance legs (active/list/rerouting/confirm/tripend/dark + guidance-gallery-compare) with the engine-A-shaped /api/route stub (consult = the drive model with real graph street names; reroutes = a merge model held 5s), the D-15 coordinate-hygiene scan, the computed-color NO-RED scan" + - "web/screenshots/{shell-guidance-active,shell-guidance-list,shell-guidance-rerouting,shell-guidance-confirm,shell-guidance-tripend,shell-guidance-dark,guidance-gallery-compare}.png — the seven committed captures (force-added; the DSGN-02 fidelity artifact rides the blocking checkpoint)" + - "web/src/route/route.ts + web/src/main.ts — TWO Rule-1 device-gate fixes: the D-09 confirm card survives a live fix (G7b); the pump's accepted fixes ride the chain's surfaces — puck + freshness (G7c, updatePuck dep)" +affects: [06-08 task 2 (the ONE REAL DRIVE — BLOCKING, awaiting the human), phase-6 verification close, DSGN-02 gallery review] + +# Tech tracking +tech-stack: + added: [] # zero new dependencies — Playwright/routing imports only + patterns: + - "fixture-replay through the REAL watch: the ?drive= knob swaps navigator.geolocation, so the shell's unmodified D-15 throttle + D-04 machine consume the committed stream — captures prove the shell, never bypassing validation (the trust boundary's law)" + - "root-absolute import.meta.glob: Vite 8's importGlob matches NO relative pattern escaping src/ (../test/... compiles empty — verified by the dev-server probe); /test/fixtures/drives/*.json works" + - "engine-A-shaped stub by construction: POST #1 = consult (drive model, street names snapToGraph'd off the LOCAL kl-roadgraph.v1.bin at each post-maneuver segment midpoint); later POSTs = merge models held REROUTE_HOLD_MS — the REAL http-source validation still runs on every answer" + - "computed-color NO-RED law: class lists cannot carry the token, so the rerouting/confirm legs scan getComputedStyle for rgb(237, 63, 28) across the banner/confirm subtrees" + +key-files: + created: + - web/screenshots/shell-guidance-active.png + - web/screenshots/shell-guidance-list.png + - web/screenshots/shell-guidance-rerouting.png + - web/screenshots/shell-guidance-confirm.png + - web/screenshots/shell-guidance-tripend.png + - web/screenshots/shell-guidance-dark.png + - web/screenshots/guidance-gallery-compare.png + - .planning/phases/06-turn-by-turn-guidance-live-driving/06-DEVICE-GATE.md + modified: + - web/src/mock/telegram-mock.ts + - web/scripts/capture.mjs + - web/src/route/route.ts + - web/src/main.ts + - web/index.html + - web/test/route-surface.test.mjs + +key-decisions: + - "The replay plays REAL-TIME (the recorded schedule), never compressed: the machine's grace/storm clocks read wall time (route.ts's now()), so compressed playback would desync every D-04 timing; the ?drive= clock starts LAZILY at the first watchPosition arm (the route draw) so no fix is ever emitted before a consumer exists." + - "The /api/route stub lives in capture.mjs via Playwright interception (not index.html): it keeps the plan's file set, cannot leak into any shipped artifact (it never exists outside the capture run), and the client-side http-source validation still gates every answer." + - "Street names come from the LOCAL road graph (routing/data/kl-roadgraph.v1.bin) snapped at each post-maneuver segment midpoint — the same OSM-derived source engine A serves, so the film reads real KL streets (Jalan Tun Sambanthan, Jalan Petaling, ...); a graph-absent fork degrades to the honest streetUnnamed fallback." + - "TWO device-gate-blocking bugs were fixed rather than papered over: the confirm card evaporating on a live fix (the D-09 exit guard breaking under exactly the drive's step 6) and the puck/freshness freeze (a navigation UI whose position marker never moves and whose strip falsely flips SIGNAL LOST at 45s). Both pinned by new G-gates; both found by tracing the live-drive path, not by capture failure alone." + +patterns-established: + - "the guide wait mode: state-token race + DOM text polls + theme-slot honesty + whole-console coordinate scan — the D-15/T-06-04 hygiene law carried into capture legs" + +requirements-completed: [GUID-01, GUID-02, GUID-03, GUID-04, GUID-05, GUID-06, PX-01, PX-03] # automated halves proven on film; the ONE REAL DRIVE (the phase's exit gate) is BLOCKING — see Known Stubs / Checkpoint + +# Metrics +duration: 48min +completed: 2026-10-24 +--- + +# Phase 6 Plan 8: The Verification Close — Replay Captures + THE ONE REAL DRIVE Gate Summary + +**The shell is proven on film: the ?drive= fixture-replay knob streams the committed corridor/missed-turn drives through the LIVE pump and seven capture legs freeze the cockpit — banner with real OSM street names, collapsed-default list with the NEXT lamp, the calm no-red REROUTING state, the bottom-register abandon confirm, the trip-end deletion card, the dark-theme chassis — beside the mockup in the DSGN-02 guidance gallery — while two real device-gate bugs were caught and fixed before the road: the abandon confirm evaporating on a live fix, and the puck/freshness freeze that would have flipped SIGNAL LOST mid-drive; the ONE REAL DRIVE itself is now the BLOCKING human gate (06-DEVICE-GATE.md).** + +## Performance + +- **Duration:** 48 min +- **Started:** 2026-10-24T12:10:00Z (approx; fresh dispatch after verified-dead prior passes) +- **Completed (automated half):** 2026-10-24T12:58:00Z approx +- **Tasks:** 1 of 2 (task 1 complete + committed; task 2 = the BLOCKING device gate — awaiting the human) +- **Files:** 14 (7 created, 7 modified) + the checkpoint file + +## Accomplishments + +- **The ?drive= replay knob** (task 1, step 1): `installMockWebApp` reads `drive` from location.search (harness-only module), validates the name through a slug guard + defensive fixture shape check against the committed `web/test/fixtures/drives/*.json`, and replaces `navigator.geolocation` with a replay source. The REAL pump arms its REAL `createGuidanceWatch` against it — the unmodified D-15 throttle and D-04 machine consume the committed stream; no test-only bypass of validation (the threat model's trust-boundary law). The clock starts lazily at the first watch arm (the route draw) and plays REAL-TIME; `window.__ARAHARAH_DRIVE = { pause(), resume(), name }` freezes/resumes emission mid-stream. An unknown name emits one honest token (`ARAHARAH-DRIVE state=unknown`) and falls back — never a crash, never arbitrary data (T-06-08). +- **The seven guidance legs** (task 1, step 2), exactly per the UI-SPEC capture table: + - `shell-guidance-active.png` — `?mock=android&dest=merdeka-118&fixpair=central-market-to-merdeka-118&drive=corridor-follow`: banner `GUIDE // NEXT` + white `85 M` + beige `JALAN TUN SAMBANTHAN` + orange arrow on the plate, compacted strip (`data-guidance="active"`), the guidance card (`GUIDE` register, Merdeka 118, `4 MIN · 1.9 KM · ETA HH:MM`, progressbar, END TRIP), collapsed-default LIST toggle, matte-black chassis `rgb(26,26,26)`. + - `shell-guidance-list.png` — scripted banner tap → `aria-expanded=true`, `CLOSE` toggle, the NEXT row lamp + real text rows. + - `shell-guidance-rerouting.png` — `drive=missed-turn-excursion` captured INSIDE the REROUTING window (the stub holds the merge answer 5s): `GUIDE // REROUTING`, `—` dash, the calm copy, the blinking gantry, the last glyph held — **zero functional-red computed colors** in the banner or card. + - `shell-guidance-confirm.png` — scripted END TRIP → the bottom-register confirm card (`GUIDE // CONFIRM`, `Abandon route?`, `YES, ABANDON` primary, `CONTINUE`) — no red. + - `shell-guidance-tripend.png` — scripted YES, ABANDON → the center-register trip-end card with the visible deletion clause; banner/list cleared; the full-height strip returned. + - `shell-guidance-dark.png` — `scheme=dark`: the theme-slot honesty check + the chassis Rams-constant. + - `guidance-gallery-compare.png` — the DSGN-02 composite beside `active_route_guidance/screen.png` (the composer generalized with mockup params; legs 8/13 byte-identical behavior). +- **The engine-A-shaped route stub**: the shell's route consult rides `/api/route` through the composed ladder; the guidance legs intercept it with an answer built from committed data — the pair's ODbL geometry + the drive's recorded maneuverIdx/kinds + street names snapped off the LOCAL road graph at each post-maneuver segment midpoint (engine A's deriveSteps semantics). Reroute requests get a merge model from the requesting fix (the replay controller's buildRerouteModel semantics), held 5s so the calm window is photographable. The REAL `validatedResult` still runs on every answer. +- **D-15 console hygiene carried into captures**: every guidance leg scans its WHOLE console capture for coordinate-bearing lines (`assertNoCoordinateLines`) — the legs assert `ARAHARAH-GUIDE state=` tokens and the ABSENCE of coordinates; the replay source itself logs nothing per fix (T-06-04: no new logging). +- **Two device-gate bugs caught and fixed BEFORE the road** (see Deviations): + - The D-09 confirm card evaporated on the next accepted fix (renderCockpit rebuilt the guidance card over the ONE exit guard) — G7b pins the survival. + - The pump's accepted fixes never touched the chain's surfaces: the puck froze at the boot fix while the camera rode the snapped line (the UI-SPEC's recorded call: "the puck … carr[ies] progress"), and `lastFix` stayed at boot so the 45s staleness law would falsely flip SIGNAL LOST mid-drive and re-run the chain — one injected `updatePuck` dep composes `lastFix = fix` + `marker.update` (the RAW fix; the camera rides the SNAPPED foot) + `setStale(false)`. G7c pins the call + main.ts's composition. +- **Suite state:** web **148 passed / 0 failed** (146 baseline untouched-green + G7b + G7c), bot 125/125, routing 65/65; all typechecks clean; `npm run web:capture` **20/20** (all 13 prior legs unbroken); zero new dependencies. + +## Task Commits + +1. **task 1: the replay knob + the seven legs + the gallery** (with the two Rule-1 fixes committed separately first) + - `fca2a90` fix(06-08): the D-09 confirm card survives a live fix — renderCockpit guards the card rebuild (G7b RED→GREEN, atomic test+fix) + - `d0d5a7d` feat(06-08): the ?drive= fixture-replay knob — the D-16 browser leg's fix source + - `17bb950` feat(06-08): the seven guidance capture legs + the DSGN-02 guidance gallery + - `ed86196` art(06-08): the seven committed guidance captures — the shell proven on film + - `b83a88e` fix(06-08): the pump's accepted fixes ride the chain's surfaces — puck + freshness (G7c) + - `5eeccdf` art(06-08): regenerate the guidance captures — the puck rides the line + +## Files Created/Modified + +- `web/src/mock/telegram-mock.ts` — the ?drive= knob: fixture glob (root-absolute pattern), slug + shape validation, the replay geolocation (real-time schedule, lazy clock, pause/resume), the honest unknown-fallback token +- `web/scripts/capture.mjs` — the guide wait mode, the stub installer, the seven legs, the generalized composer, the coordinate + computed-color scans, the expected list at 20 +- `web/src/route/route.ts` — the confirm-card renderCockpit guard (G7b) + the updatePuck dep call per accepted fix (G7c) +- `web/src/main.ts` — updatePuck wiring: lastFix refresh + marker.update + setStale(false), the camera untouched +- `web/index.html` — the runner-page knob comment (docs-only; the knob is read inside the mock module) +- `web/test/route-surface.test.mjs` — G7b + G7c (147→148) +- `web/screenshots/*.png` — the seven committed captures +- `.planning/phases/06-turn-by-turn-guidance-live-driving/06-DEVICE-GATE.md` — the blocking gate's protocol + checklist + +## Decisions Made + +See key-decisions: real-time replay, the Playwright-side stub, graph-snapped street names, and the two fix-over-paper-over calls. + +## Deviations from Plan + +### Auto-fixed Issues + +**1. [Rule 1 - Bug] The D-09 confirm card evaporated on a live fix** +- **Found during:** task 1's confirm-leg design (traced the live-drive path before filming) +- **Issue:** `renderCockpit` rebuilt the guidance card over the open confirm on every accepted fix — the ONE PX-03 exit guard survived only between fixes; G7 tested confirm without a subsequent fix so the gate never saw it. The real drive's step 6 (END TRIP on a live road, fixes every ~2–5s) would have hit it within one watch tick. +- **Fix:** renderCockpit skips the card rebuild while `confirmOpen`; banner/list still re-render. G7b pins: confirm mounts → live fix → confirm still shown → YES ABANDON still tears down. +- **Files modified:** web/src/route/route.ts, web/test/route-surface.test.mjs +- **Commit:** fca2a90 + +**2. [Rule 1+2 - Bug/critical gap] The pump's fixes never rode the chain's surfaces (frozen puck + false SIGNAL LOST)** +- **Found during:** task 1's active-leg design (the puck's visual trail on the probe capture) + the 45s staleness trace +- **Issue:** the UI-SPEC's recorded call pins "the puck … carr[ies] progress", but the pump's onWatchFix moved only the camera — the puck froze at the boot fix and the driver would lose it within seconds; and `lastFix` never refreshed during guidance, so the strip's 45s staleness law would flip SIGNAL LOST (red) mid-drive and re-run the chain (a marker jump + a 60s nudge poll on the road). +- **Fix:** one injected dep (`updatePuck`) called per accepted fix; main.ts composes `lastFix = fix` + `marker.update` (raw fix) + `setStale(false)`; the camera untouched (the guidance camera owns the viewport). G7c pins the dep call + the main.ts source-scan composition. +- **Files modified:** web/src/route/route.ts, web/src/main.ts, web/test/route-surface.test.mjs +- **Commit:** b83a88e + +**3. [Rule 3 - Blocking] The route consult needed a steps-bearing answer for the legs to exist at all** +- **Found during:** the first capture run (every guidance leg failed: the fixture-backend fallback's `steps: []` model puts the arrive mark at 0m → instant arrival → teardown before any assert) +- **Issue:** the plan's interfaces name only the mock's fix source; but the LIVE pump's cockpit needs maneuver marks the fixture backend never serves (D-10's honesty law — fixture steps stay empty). +- **Fix:** the engine-A-shaped `/api/route` stub in capture.mjs (Playwright interception, installed pre-goto): consult = the drive model (committed geometry + recorded maneuverIdx/kinds + graph-snapped street names), reroutes = merge models held 5s. No index.html behavior change, nothing shipped; the client-side validation still gates every answer. +- **Files modified:** web/scripts/capture.mjs +- **Commit:** 17bb950 (rode the legs commit) + +**4. [Rule 3 - Blocking] Vite 8's import.meta.glob matches no relative pattern escaping src/** +- **Found during:** the knob build (the eager glob compiled to `Object.assign({})` — zero fixtures) +- **Fix:** the root-absolute pattern `/test/fixtures/drives/*.json` (verified by the dev-server probe; all four drives inline into the harness bundle, production tree-shake verified clean in both directions). + +### Judgment calls within plan laws (not deviations) +- The replay's pause() freezes EMISSION only; the shell's wall clock keeps running (the machine's grace windows inflate across a pause) — legs that pause close before any machine timing matters; documented in the mock's header. +- The unknown-name token (`ARAHARAH-DRIVE state=unknown`) is the knob's ONLY console line (the plan's sanctioned honest token); a successful load is silent — diagnostics ride `window.__ARAHARAH_DRIVE.name`. + +## Auth Gates + +None — the capture run is offline (harness stubs + Playwright interception); no Telegram/network credentials needed. + +## Known Stubs + +**Task 2 (the ONE REAL DRIVE) is NOT RUN — by design, never faked.** It is the phase's declared exit gate (D-16) and a `checkpoint:human-verify gate="blocking"` task: physical GPS, real road geometry, and human legibility/haptic judgment are the declared device-gate protocol. `.planning/phases/06-turn-by-turn-guidance-live-driving/06-DEVICE-GATE.md` carries the full checklist (Parts A/B/C). The phase stays OPEN until the drive's per-step verdict lands; a FAIL holds it open (the Phase 3 UNVERIFIED precedent). Everything automatable on the path is green: web 148/148, bot 125/125, routing 65/65, captures 20/20. + +## Threat Surface Scan + +No new surface beyond the plan's ``: the replay knob feeds the REAL pump with committed, attributed fixtures (unknown names fail honest — the Tampering mitigation); the guidance legs assert state tokens and scan their whole console for coordinate-bearing lines (the D-15 hygiene law carried into captures — T-06-04); no new production logging (the knob is harness-only, tree-shaken from web/dist — verified in both directions this plan); the real-drive protocol rides the product's own privacy posture (no location history exists; the KV spot-check proves the post-trip deletion on real infrastructure). No threat flags. + +## Issues Encountered + +- The prior 06-08 dispatches died without landing work (verified quiet + clean before starting); this session started fresh and landed the whole automated half. +- Concurrent processes are writing the shared tree again (.planning/*, AGENTS.md, README, mockup code.html files, a bot command file) — every commit staged ONLY this plan's files individually; none of the concurrent files were touched. +- Node lives under nvm; every shell command sourced `~/.nvm/nvm.sh` first (all prior plans' precedent). + +## User Setup Required + +For the device gate itself: nothing beyond the standing deploy posture (`npm run deploy -w bot`; the R2 graph already uploaded; the R2 dashboard activation possibly still pending — see 06-DEVICE-GATE.md's executor notes). + +## Next Phase Readiness + +- **The blocking checkpoint** (task 2): Parts A (gallery), B (the drive), C (the street-source ratification) await the user; the verdict rides 06-08-SUMMARY.md's update + 06-DEVICE-GATE.md. +- **The phase verifier**: D-16's three legs now have their evidence — recorded drives (06-02), captures (this plan), the drive pending (the gate). The two new fixes (G7b/G7c) are pinned by gates, not claims. +- **Phase 7**: the gallery artifact + the recorded calls are the DSGN-02 close-out material. + +--- +*Phase: 06-turn-by-turn-guidance-live-driving* +*Automated half completed: 2026-10-24; the ONE REAL DRIVE awaits the user (BLOCKING)* + +## Self-Check: PASSED + +- All 7 committed captures verified present on disk + in git (`ed86196`, `5eeccdf`); all 6 plan commits verified in git log (fca2a90, d0d5a7d, 17bb950, ed86196, b83a88e, 5eeccdf) — zero deletions in any of them. +- Acceptance greps re-run at close: `import.meta.glob` over `/test/fixtures/drives/*.json` + the `__ARAHARAH_DRIVE` surface present in telegram-mock.ts; all 7 UI-SPEC leg names present in capture.mjs asserting ARAHARAH-GUIDE tokens. +- `npm test -w web` 148/148 (G7b + G7c included), bot 125/125, routing 65/65, all typechecks clean; `npm run web:capture` 20/20 with the coordinate-hygiene scan green on every guidance leg. +- STATE.md and ROADMAP.md untouched by this executor (per the dispatch's explicit instruction; their working-tree diffs are other processes' concurrent writes). +- The prior dispatch's "quiet tree" note held this time: every commit staged only this plan's files. diff --git a/.planning/phases/06-turn-by-turn-guidance-live-driving/06-DEVICE-GATE.md b/.planning/phases/06-turn-by-turn-guidance-live-driving/06-DEVICE-GATE.md new file mode 100644 index 0000000..b8f5023 --- /dev/null +++ b/.planning/phases/06-turn-by-turn-guidance-live-driving/06-DEVICE-GATE.md @@ -0,0 +1,68 @@ +# 06-08 Device Gate — THE ONE REAL DRIVE (D-16) + DSGN-02 Gallery Review + +**Status: BLOCKING — awaiting the human.** Everything automatable is green: web 148/148 +(146 pre-existing + G7b confirm-survival + G7c puck/freshness), bot 125/125, routing +65/65, all typechecks clean, `npm run web:capture` 20/20 with the seven guidance legs +committed (`ed86196`, `5eeccdf`). Per the plan's law: **device results are never faked** — +this file records the protocol; the SUMMARY records the verdict verbatim once the drive +runs. A FAIL holds the phase open (the Phase 3 UNVERIFIED precedent). + +--- + +## Part A — Gallery fidelity review (5 min, no device needed) + +Open **`web/screenshots/guidance-gallery-compare.png`** (committed at `5eeccdf`): the +implemented cockpit (`shell-guidance-active.png`, `?drive=corridor-follow`, harness +build) beside `stitch_minimalist_route_navigator/active_route_guidance/screen.png`. + +Confirm fidelity against 06-UI-SPEC: +- Banner ink hierarchy: **white distance** (`85 M`), **beige street** (`JALAN TUN + SAMBANTHAN` — real OSM name via the graph snap), **orange arrow** on the 48×48 plate, + register line in chassis-subtle (`GUIDE // NEXT`). +- **No red anywhere in guidance chrome**; radius-0 everywhere; no shadow/blur/glass. +- Recorded calls (the spec wins over the mockup — the composite makes them visible): + no incident band, no lane matrix, no speedometer/limit medallion, no + REROUTE-VIA-TELEGRAM-BOT / REPORT HAZARD / AUDIO buttons, 32×32 glyph at 3px stroke, + distance in pure-white (not orange). + +**Approve** or list deviations (tokens.css wins over the mockup; the spec records calls). + +## Part B — THE ONE REAL DRIVE (the phase's exit gate) + +One drive, phone mounted, safe location to start. Steps 2–7 each get a **PASS/FAIL + +verbatim notes** recorded in 06-08-SUMMARY.md afterwards. + +| # | Step | Verify | +|---|------|--------| +| 1 | `npm run deploy -w bot` (graph already uploaded — `kl-roadgraph.v1.bin` in R2) and open the Mini App from the bot | The app boots, destination resolves, route draws | +| 2 | Pick a golden destination (e.g. Merdeka 118 from Central Market), start driving | Banner shows distance + arrow + street; compact strip; guidance-card ETA progresses **without whiplash**; haptic at ~300 m approach and at the maneuver; **the puck rides the route line** (fixed this plan — `b83a88e`) and the strip stays LIVE past 45 s (fixed this plan — same commit) | +| 3 | Miss a turn DELIBERATELY | **No dialog, no blame** — the banner calmly shows `GUIDE // REROUTING` (dash + gantry), then the new route snaps in and `GUIDE // NEXT` returns | +| 4 | Minimize the app mid-drive | Within ~3–4 min a **turn-card arrives in chat** (glyph + street + ETA + distance + OPEN GUIDANCE) | +| 5 | Re-open via the card's OPEN GUIDANCE (or the chat header) | Guidance resumes at the **progressed position** — `GUIDE // RESUMING` (projected numbers), then live on the first fix | +| 6 | Tap END TRIP → confirm card → YES, ABANDON | "Trip ended" card + the deletion clause; the confirm card **survives live fixes** (fixed this plan — `fca2a90`); chat cards stop | +| 7 | (Optional, executor-assisted) KV spot-check | `npx wrangler kv key list --namespace-id=59f58a54bc44483e89872b20a005a5eb --prefix "guidance:"` → **no stale keys** (the D-14 deletion promise on real infrastructure) | + +Record PASS/FAIL per step + anything that felt wrong (legibility in sunlight, haptic +feel, card lag, puck smoothness). + +## Part C — Turn-card street-source ratification (2 min, named review item from 06-07) + +Cards ship **street-bearing by DEFAULT** via cron-side graph reconstruction (one +`loadGraph` R2 read per cold isolate, one `snapToGraph` per carded tick) — a CPU-budget +tradeoff in the cron isolate. **Decide:** +- **Keep the default** (D-12 as written — street names on every card), or +- **Ratify the street-less degradation as final** (bare-verb cards; recorded in + UI-SPEC's recorded-calls fidelity list; 06-07's degradation path becomes the only path). + +--- + +## Executor notes for the run + +- **R2 activation** (06-CONTEXT post-planning): the R2 bucket click-through was pending + the Cloudflare dashboard (code 10042). If R2 is still unactivated, engine A answers + router-pending (designed degradation) and the cron's cards degrade to bare-verb — + the drive is still performable, but note it in the verdict. +- The **known-open cosmetic** from Phase 4: `/cari` may be absent from the client + command menu (Telegram setMyCommands defect; the command works when typed). +- **Never fake**: if a step cannot be executed (weather, road, time), mark it NOT RUN — + do not invent an outcome. The phase stays open on any FAIL or NOT RUN.