26 KiB
phase, plan, subsystem, tags, requires, provides, affects, tech-stack, key-files, key-decisions, patterns-established, requirements-completed, duration, completed
| phase | plan | subsystem | tags | requires | provides | affects | tech-stack | key-files | key-decisions | patterns-established | requirements-completed | duration | completed | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 06-turn-by-turn-guidance-live-driving | 06 | web-guidance-wiring |
|
|
|
|
|
|
|
|
|
50min | 2026-10-24 |
Phase 6 Plan 6: The Guidance Pump — Camera, BackButton Graph, Envelope Flows Summary
Guidance is ALIVE in the shell: the drawn route arms the watch, the start gate mounts the cockpit (PX-03 protections, banner/card, the camera locked to the snapped line at the UI-SPEC pose), fixes drive banner/ETA/progress through the real machine, excursions self-heal through the composed engine-a→fixture ladder with a calm banner and exactly one request per storm-guard window, the BackButton walks search→routes→guidance→(confirm)→routes→search with zero dead ends and zero premature closes, minimizing hands the frozen six-field envelope to the cron with keepalive, a ?g= re-open resumes at the controller-computed progressed position, and both trip ends delete the envelope and say so — 146 web tests green (27 net-new this plan), typecheck clean, bot 103 and routing 65 untouched-green.
Performance
- Duration: ~50 min (wall clock across the merged sessions; this session's active span 06:42–07:32 UTC)
- Started: 2026-10-24T06:42:13Z
- Completed: 2026-10-24T07:32Z
- Tasks: 3/3 (all TDD RED→GREEN)
- Files: 6 (1 created, 5 modified)
The Concurrent-Dispatch Merge (read this first)
Two executor sessions ran this plan on one working tree. The dispatch note declared the prior session dead, but its work flushed during this session's execution:
- Task 1: this session authored the RED tests (RS7b walk, RS11-13 camera laws, the fakeMap flyTo/emit extension, mkRecordingWa); the other session's header re-pin notes and its task-1 GREEN (
camera.ts,follow.tsopts,backbutton.tsresolver) landed as commits77b62da(RED — absorbing this session's test edits verbatim) +2f12c41(GREEN). This session verified the merged task 1 end-to-end against the plan before building on it: exact constants, both call shapes, byte-identical no-opts follow, TDD gate order, typecheck, 129/129. - Task 3: mid-GREEN, the other session flushed its own E-family tests (E1-E6) into the shared suite — overlapping G9-G12's scope with a diverging contract (
resumeGuidancevsresume,backAction()on the controller, a built-in fetch stub, controller-side projection). It then converged to this session's API in real time (its E-tests came to callcontroller.resume(...)with the raw-anchor shape) while this session adopted its working-tree edits as the base of record. The final reconciliation (this session's edits): E1's pre-gate probe rebuilt on a genuinely pre-gate scenario (the draft probed afterdriveTohad already activated); E4's fixture given terminal marks (its{arrive, 0}steps would instant-arrive and crash the abandon clicks); G12's UUID assert taught to match a regex-literal in source. Both test families now pin ONE implementation. - Net: every commit is coherent, every test green, no work lost or duplicated in the commits. The SUMMARY is the merged record, per the 06-03 continuation precedent.
Accomplishments
- The D-10 locked-follow camera is real (task 1):
camera.tspins the UI-SPEC pose as named constants (padding {320,64,64,64} — center ≈65% down-screen, pitch 35, zoom 16, 400 ms) and eases to the SNAPPED foot through the Phase 3 follow controller — ONE easing discipline, ONE unlock law. Bearing is NEVER passed (north-up, RS11 pins the key's absence);onRerouteAppliedis the documented no-op (setData happens in the route layer, G6 pins zero camera moves).follow(fix, opts?)spreads over the defaults so every Phase 3/5 call site stays byte-identical (RS13 pins the exact no-opts key set), and the originalEvent law is untouched (RS12: programmatic moves never unlock, a user gesture returns the recenter notch). - The PX-01 graph has no dead ends (task 1 + task 3): the wire grew a context-aware resolver (
BackAction = hidden|close|callback) consulted per click, withwire.sync()re-applying visibility on every state change; the legacy two-arg shape composes internally so RS7 stayed valid unchanged. The controller owns the decision (backAction()): driving → the D-09 confirm card (NOT teardown — E5/RS7b pin guidance alive after Back), confirm open → CONTINUE, ended → the walk to the search root, route → the Phase 5 walk, true root → close (and close() is recorded ZERO times across every pushed-state click). - The pump makes navigation behavior (task 2): the watch arms with the route draw; the first accepted fix opens the 06-02 session; the start gate (≥30 m along) mounts the cockpit — close protection engaged,
[data-guidance="active"]on the shell root (the strip compacts by CSS), banner + guidance card + collapsed list, the camera eased to the snapped line,ARAHARAH-GUIDE state=on_routelogged (G1). Accepted fixes drive the five-slot banner (model-derived distance to the next mark, the turn's verbatim street), the deadband ETA + HH:MM clock, and the stepping progress bar (G2). The OFF_ROUTE grace shows no premature signal (G3); REROUTING swaps calm — dash + gantry + exactly ONEsource.routecall, storm guard holding under an immediate second excursion (G4); failure lands the honest NO REROUTE + card state line (G5); success snaps the new line in via setData with NO camera jump and the gantry stops (G6). - Both exits execute D-14 (tasks 2-3): END TRIP and BackButton land on the ONE confirm card; YES, ABANDON and arrival both stop the watch, release close protection, clear
[data-guidance], empty the banner/list, DELETE the envelope (idempotent pair), and seat the trip-ended card in the center register withstate=ended(G7/G8). - The envelope lifecycle is structural (task 3): minimize POSTs the FROZEN six-field snapshot with
keepalive: trueand the Bearer header — id/chat_id/created_at are server-minted (G9 pins the exact key set and the polyline6 round-trip); a live envelope never double-mints; activated DELETEs (the cron pauses) while RETAINING the id; teardown deletes the SAME id (the idempotent pair, 404-tolerated — G10/E2/E4). Below the start gate nothing ever mints (E1). - Resume works from a killed webview (task 3): the
?g=carrier is UUID-validated before any GET; the envelope passes defensive field validation; the controller projects remaining distance/minutes from startedAtSec + avg speed (≈1167 m / 140 s pinned), renders GUIDE // RESUMING + gantry, draws the rebuilt line, arms the watch, and DELETEs immediately (a resumed boot IS foregrounded — the cron pauses now). The first accepted fix flips the register live through the machine's own resuming path (G11/E3') — and the synthesized terminal marks keep the arrive mark at the line's end (the steps-less-envelope instant-arrival bug, fixed in-implementation). - The composed ladder is code-constructed (task 3):
main.tsbuilds engine-a first with the fixture fallback —(await http.route(req)) ?? (await fixture.route(req))— no env read in the ladder region (G12/E6 structural), the golden-demo path preserved. - Gates re-pinned with their invalidating change: RS6 is now the guidance-implementation boundary (banned tokens only on
../guidance/import lines — and route.ts genuinely contains none outside comments, becauseguidanceView/resumingViewmoved ALL view-data math into guidance/); RS8 admits the ARAHARAH-GUIDE token family (exactly three console lines, no interpolation, no coordinate field names). - Suite state: web 146 passed / 0 failed (124 pre-existing untouched-green + 27 this plan incl. the merged E-family), bot 103, routing 65; web typecheck clean; zero new dependencies.
Task Commits
- task 1: guidance camera + BackButton full state graph (TDD, merged authorship)
77b62datest(06-06): failing camera-law + PX-01 full-walk gates — RS7b walk, RS11 pose, RS12 unlock, RS13 no-opts byte-identity (RED)2f12c41feat(06-06): the D-10 locked-follow guidance camera + the context-aware BackButton resolver (GREEN)
- task 2: the guidance pump — start, effects, chrome, reroute (TDD)
0316be4test(06-06): failing guidance-pump suite G1-G8 + RS6/RS8 re-pins (RED)14e8dfcfeat(06-06): the guidance pump — start gate, effects dispatch, cockpit chrome, silent reroute (GREEN)
- task 3: envelope flows + composed ladder (TDD, merged authorship)
6448e31test(06-06): failing envelope-flow suite G9-G12 (RED)d5e104bfeat(06-06): envelope flows + composed ladder — minimize POST, resume GET, trip-end DELETE (GREEN, includes the reconciled E1-E6)
Files Created/Modified
web/src/guidance/camera.ts— the locked-follow pose (created; the other session's implementation, verified against the plan's constants and behaviors)web/src/map/follow.ts—FollowOptions+ opts-over-defaults follow (byte-identical no-opts key set)web/src/telegram/backbutton.ts— the BackAction resolver + sync(), legacy shape composedweb/src/guidance/guidance.ts—guidanceView+resumingView(the view-data authority; RS6's boundary)web/src/route/route.ts— the pump, effects dispatch, cockpit chrome, confirm/trip-end flows, envelope lifecycle, resume + projection, backActionweb/src/main.ts— the ladder, the resolver wire, ?g= resume, envelope events, guidance-aware recenter + camera skipweb/test/route-surface.test.mjs— RS7b/RS11-13, G1-G12, E1-E6, RS6/RS8 re-pins, the extended fakeMap + document fake + stepped-corridor harness
Decisions Made
See key-decisions. The three with teeth: the orthogonal guidancePhase beside RouteState (the BackButton resolver's second axis); the reroute origin being the grace-completing fix (the honest current position — the new line starts where the car IS); resume's terminal-mark synthesis (the instant-arrival bug caught by the merged tests before it could ship).
Deviations from Plan
Auto-fixed Issues
1. [Rule 3 - Blocking] View-data composition added to web/src/guidance/guidance.ts (not in the plan's files list)
- Found during: task 2 RED authoring
- Issue: the plan mandates "zero maneuver math inline" in route/ (RS6 re-pin) but the banner/list/card views need next-maneuver marks, per-row states, and progress pct — data only the machine's private
maneuverMarksOfcan author correctly. Wiring it in route/ would either duplicate maneuver math or trip the re-pin. - Fix:
guidanceView(snap, listOpen)(+resumingViewin task 3) exported from guidance.ts beside the marks — guidance implementation living in guidance/ exactly as the re-pin's rule states; route/ imports, spreads the results into the builders, and contains zero banned tokens. - Files modified: web/src/guidance/guidance.ts
- Commit:
14e8dfc,d5e104b
2. [Rule 1 - Bug] A steps-less resume model would instantly "arrive"
- Found during: task 3 GREEN (the merged E-tests' steps-less fixtures exposed it)
- Issue: the envelope carries geometry only, so the rebuilt model has
steps: []— the machine's arrive mark lands at along 0, and the FIRST in-threshold fix would fire arrival, tear the trip down, and strand the resume flow. - Fix:
resume()synthesizes the terminal pair{depart, totalM} + {arrive, 0}for steps-less models — the arrive mark sits at the line's end; models with real steps are untouched (the replay suite's pins unaffected). - Files modified: web/src/route/route.ts
- Commit:
d5e104b
3. [Rule 1 - Bug] walkBack left the route card visible under the destination card
- Found during: task 2 (walkBack redesign)
- Issue: the Phase 5 walk cleared layers/endpoints and restored the destination card but never vacated the route stack — the route card stayed mounted below it (a UI-SPEC "card swaps to destination card" violation that RS4's fake shower could not see).
- Fix: the walk calls
showRouteCard(null, "center")before restoring the destination card. - Files modified: web/src/route/route.ts
- Commit:
14e8dfc
4. [Rule 2 - Missing critical] The chain's fix fought the guidance camera
- Found during: task 3 (main.ts integration)
- Issue:
handleLive's staleness re-run callsfollow(fix)with Phase 3 padding — during a live trip it would yank the locked camera to the raw fix with the wrong pose. - Fix: handleLive skips the camera while
guidancePhase === "driving"(marker/strip still refresh; the watch's next throttled ease settles the viewport); the recenter tap re-locks at the GUIDANCE pose. - Files modified: web/src/main.ts
- Commit:
d5e104b
Reconciliation edits to the co-executor's tests (not plan deviations — merged-suite repairs, documented per the merge note)
- E1's pre-gate probe ran after
driveTohad already activated guidance (the POST it expected absent was mandatory) — rebuilt on a genuinely pre-gate scenario (feed(10)below the gate). - E4's fixture
{arrive, 0}steps instant-arrived on the first fix (the trip-end card has no buttons — the abandon clicks crashed); given the terminal pair. - G12's UUID assert now accepts the regex-literal form (a source regex
/[0-9a-f]{8}/cannot match a hex-run regex). - The E-draft's raw-number banner asserts (meters/decimal minutes) were aligned to the 06-05 builders' pinned instrument formats by the co-executor itself before this session touched them (
1.2KM, rounded MIN — GS2/GS8's frozen formats).
Judgment calls within plan laws (not deviations)
- Guidance deps on
RouteControllerDepsare optional in the type — a cards-only boot (no watch factory) degrades to exactly the Phase 5 controller (the injection law; main.ts always wires them in production). startedAtSec= guidance-activation time for fresh trips; the envelope anchor for resumed ones (either honors D-11's write-timing discretion).- ETA remaining seconds derive proportionally from the selected summary duration × snapped remaining fraction (model + projection only, D-07); the first fold seeds at activation so the card is never blank.
createGuidanceCamera(map, followController)keeps the plan's two-arg signature; the map parameter names the viewport and stays unused (the pose rides the follow controller — ONE unlock law).- The guidance logger dedupes consecutive states — activation logs
on_routeonce, REROUTING once, NO REROUTE once,endedonce (RS8's exactly-three-lines form).
Known Stubs
None. Every export is fully wired: the pump drives the real machine and real builders, the envelope flows hit the real endpoints through the injected fetch, resume rebuilds a real model from the frozen snapshot. The startWatch injection point is the plan's own testability seam (production passes createGuidanceWatch(navigator.geolocation, ...)).
Threat Surface Scan
No new surface beyond the plan's <threat_model>: the envelope POST/DELETE and the ?g= GET are exactly the planned boundary — three positions leave the device only as the D-04 excursion origin, the user-initiated minimize handoff (frozen snapshot, no live stream, keepalive-belted), and nothing else (T-06-05 by construction; G9 pins the exact six fields). T-06-04: the console carries only ARAHARAH-ROUTE/GUIDE state tokens (RS8's three lines, no interpolation, no lat/lng on any console line). T-06-06: onEvent wiring is capability-guarded (typeof wa.onEvent === "function", E6) and the haptic/close-protection calls ride the 06-05 guards. The ?g= probe disposition holds client-side: a foreign/failed GET renders an honest boot with zero guidance chrome (G5a/E-block asserts; ownership enforced server-side by 06-03's claim check). The camera hijack row: only originalEvent-bearing moves unlock (RS12). The self-DoS row: the storm guard bounds reroute rate (G4's exactly-one-call pin). No threat flags.
Issues Encountered
- The concurrent dispatch (the merge note above): its task-1 flush landed between this session's read and first edit; its E-tests landed mid-task-3-GREEN. Handling per the 06-02/06-03/06-04 precedents: tree watched and md5-stable checks before every commit; the flushed content adopted as base of record after verification; both test families reconciled into one contract; the final state committed atomically and re-verified stable.
- One transient test-suite hang: a G4 draft left the gantry blink interval running (the runner's event loop never drained) — the test now stops the blink explicitly at its end (the harness pattern note above).
- Node lives under nvm; every verification command sourced
~/.nvm/nvm.shfirst (all prior plans' precedent). No project impact.
User Setup Required
None — client-side wiring only; the endpoints (06-03/06-04), the R2 graph, and the session flow are already provisioned. The real-drive gate (06-08) is the remaining device verification.
Next Phase Readiness
- 06-07 (cron turn-cards): the envelope lifecycle is LIVE — minimize mints, resume/trip-end delete; the cron's projection math is the controller's own formula (startedAtSec + avg speed) and
projectAlongRouteis the one projection authority foreground and cron share. - 06-08 (real drive + captures): the
guide-*classes, the?drive=knob's state tokens (ARAHARAH-GUIDE state=<state>), and the confirm/trip-end surfaces are all capture-ready; the BackButton/confirm walks are replay-proven and need only the device pass. - The verifier: PX-01/PX-03's observable behaviors are claimed AND tested (RS7b/E5 walk, G7/G8 teardowns); GUID-02's client half is replay-proven through the REAL source seam (the ladder), complementing 06-04's engine side.
Phase: 06-turn-by-turn-guidance-live-driving Completed: 2026-10-24
Self-Check: PASSED
- All 6 created/modified files verified on disk and committed (camera.ts created; follow/backbutton/guidance/route/main + the test suite modified).
- All 6 plan commits verified in git log: 77b62da→2f12c41 (task 1 RED→GREEN), 0316be4→14e8dfc (task 2 RED→GREEN), 6448e31→d5e104b (task 3 RED→GREEN) — TDD gate sequence intact for all three tdd tasks; zero file deletions in any plan commit.
npm test -w web: 146 passed / 0 failed;npm run web:typecheckexit 0; bot 103 and routing 65 untouched-green.- Acceptance greps re-run at close: the four camera constants pinned by RS11;
ARAHARAH-GUIDE state=present in route.ts with exactly three console lines, no${and no lat/lng (RS8);createHttpRoutingSource+?? (awaitin main.ts with zero env reads in the ladder region (G12/E6); zero banned tokens outside comments in web/src/route/ (RS6); zero TODO/FIXME/placeholder stub markers. - STATE.md and ROADMAP.md untouched by this executor (orchestrator-owned writes; their working-tree modifications predate this session).