docs(06): create phase plans (8 plans, 4 waves)
This commit is contained in:
@@ -0,0 +1,253 @@
|
||||
---
|
||||
phase: 06-turn-by-turn-guidance-live-driving
|
||||
plan: 06
|
||||
type: execute
|
||||
wave: 3
|
||||
depends_on: [06-02, 06-04, 06-05]
|
||||
files_modified:
|
||||
- web/src/telegram/backbutton.ts
|
||||
- web/src/map/follow.ts
|
||||
- web/src/guidance/camera.ts
|
||||
- web/src/route/route.ts
|
||||
- web/src/main.ts
|
||||
- web/test/route-surface.test.mjs
|
||||
autonomous: true
|
||||
requirements: [GUID-02, GUID-05, GUID-06, PX-01, PX-03]
|
||||
must_haves:
|
||||
truths:
|
||||
- "Guidance activates when the route is drawn and the first accepted fix is ≥ GUIDANCE_START_ALONG_M along it — never without a route (PX-03's precondition)"
|
||||
- "The Telegram BackButton walks search → routes → guidance → (confirm) → routes → search and never dead-ends; close() fires only at the true root (PX-01)"
|
||||
- "BackButton from guidance opens the abandon confirm card; back while the confirm is open means CONTINUE (D-09)"
|
||||
- "The camera rides the SNAPPED line (locked follow, padding {top:320,bottom:64,left:64,right:64}, pitch 35, north-up); user pan unlocks → the recenter control returns (D-10)"
|
||||
- "A missed turn flows to a silent /api/route reroute and the new line snaps in — banner calm, no blame (GUID-02 wired)"
|
||||
- "Minimize POSTs the envelope (keepalive, best-effort D-13); re-open DELETEs it (cron pauses — structural); a fresh boot with ?g=<id> resumes at the progressed position (GUID-05/GUID-06)"
|
||||
- "Arrival AND abandon both: delete the envelope (idempotent), stop the watch, release close protection, show the trip-ended card (D-14)"
|
||||
artifacts:
|
||||
- path: "web/src/guidance/camera.ts"
|
||||
provides: "locked-follow guidance camera over the snapped line"
|
||||
exports: ["GUIDANCE_CAMERA_PADDING", "GUIDANCE_ZOOM", "GUIDANCE_EASE_MS", "createGuidanceCamera"]
|
||||
- path: "web/src/route/route.ts"
|
||||
provides: "the guidance controller wiring: pump, effects dispatch, chrome updates, envelope flows"
|
||||
- path: "web/src/telegram/backbutton.ts"
|
||||
provides: "the context-aware full-state-graph wire (predicate + handler as one change)"
|
||||
key_links:
|
||||
- from: "web/src/route/route.ts"
|
||||
to: "web/src/guidance/guidance.ts"
|
||||
via: "watch → shouldAcceptFix → stepGuidance → effects"
|
||||
pattern: "stepGuidance"
|
||||
- from: "web/src/route/route.ts"
|
||||
to: "web/src/guidance/banner.ts"
|
||||
via: "chrome re-render per accepted fix"
|
||||
pattern: "buildGuidanceBanner"
|
||||
- from: "web/src/route/route.ts"
|
||||
to: "/api/guidance"
|
||||
via: "POST on deactivated (keepalive), DELETE on activated + trip end"
|
||||
pattern: "/api/guidance"
|
||||
- from: "web/src/main.ts"
|
||||
to: "routing/src/http-source.ts"
|
||||
via: "engine-a first, fixture fallback — the composed ladder, code-constructed"
|
||||
pattern: "createHttpRoutingSource"
|
||||
- from: "web/test/route-surface.test.mjs"
|
||||
to: "web/src/route/route.ts"
|
||||
via: "RS6 re-pinned (guidance IMPLEMENTATION lives in web/src/guidance/) + the PX-01 full-walk test"
|
||||
pattern: "RS6|walkBack"
|
||||
---
|
||||
|
||||
<objective>
|
||||
Wire the guidance brain (06-02) into the live shell through the chrome (06-05) and the server (06-04/03): the full PX-01 BackButton state graph, the D-10 locked-follow camera, the fix pump dispatching banner/list/card/haptics/reroute, and the minimize/resume/trip-end envelope flows — completing GUID-02/05/06's client half and D-14's in-app half.
|
||||
|
||||
Purpose: this is where navigation becomes behavior. The BackButton walk (PX-01) only exists now that the full state graph does; the envelope lifecycle (D-11's structural foreground gate) only works when the app POSTs on minimize and DELETEs on return.
|
||||
Output: camera + pump + BackButton graph + envelope flows wired in route.ts/main.ts, RS6 re-pinned, PX-01 walk proven with a recording fake.
|
||||
</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-PATTERNS.md
|
||||
@.planning/phases/06-turn-by-turn-guidance-live-driving/06-RESEARCH.md
|
||||
|
||||
<interfaces>
|
||||
<!-- From 06-02 (web/src/guidance/): createGuidanceSession/stepGuidance (events fix |
|
||||
reroute-started | reroute-failed | reroute-applied; effects haptic | reroute-requested |
|
||||
arrival), projectAlongRoute, watch.ts {shouldAcceptFix, createGuidanceWatch},
|
||||
eta.ts {updateEta, composeEtaClock}, constants GUIDANCE_START_ALONG_M etc. -->
|
||||
|
||||
<!-- From 06-05 (web/src/guidance/): buildGuidanceBanner / buildManeuverList / buildGuidanceCard /
|
||||
buildConfirmCard / buildTripEndCard / startGantryBlink / stopGantryBlink / GLYPHS;
|
||||
fireHaptic(wa, cue); engageCloseProtection(wa) / releaseCloseProtection(wa);
|
||||
webapp.ts now has HapticFeedback?, disableVerticalSwipes?, enableClosingConfirmation?,
|
||||
isActive?, onEvent("activated"|"deactivated"). -->
|
||||
|
||||
<!-- From 06-04: createHttpRoutingSource({ endpoint, bearer, fetchImpl? }) — backend "engine-a",
|
||||
fail-honest nulls. From 06-03: POST /api/guidance → {id}; GET/DELETE /api/guidance?id=.
|
||||
Envelope snapshot: {destinationId, destinationName, distanceM, durationS, geometry
|
||||
(polyline6), startedAtSec}. Session token: web/src/session/store.ts getSession(). -->
|
||||
|
||||
<!-- Existing seams (PATTERNS): wireBackButton(wa, hasOverlay, walkBack) — predicate + handler
|
||||
as ONE change; createFollowController(map, onModeChange) with the movestart originalEvent
|
||||
unlock law; createRouteController(deps) — all DOM/map concerns injected (RS gates run in
|
||||
Node); recenter control data-attribute states; console law: ARAHARAH-GUIDE state=<state>
|
||||
tokens only, never coordinates (the RS8 family). -->
|
||||
|
||||
<!-- UI-SPEC camera table (binding): guidance start → easeTo snapped, padding {top:320,
|
||||
bottom:64,left:64,right:64}, pitch 35, zoom 16 (GUIDANCE_ZOOM), 400 ms (GUIDANCE_EASE_MS);
|
||||
per accepted fix → easeTo the SNAPPED point; user pan (originalEvent) unlocks; recenter
|
||||
re-locks; reroute snap-in → NO camera jump (setData only); trip end → camera holds.
|
||||
Bearing NEVER rotates (north-up, recorded call). -->
|
||||
|
||||
<!-- UI-SPEC BackButton contract (binding): guidance Back → abandon confirm card; confirm open
|
||||
+ Back → CONTINUE (dismiss, stay); YES, ABANDON → teardown → route card state; trip-ended
|
||||
card Back → search root; route-state Back → Phase 5 walk. -->
|
||||
</interfaces>
|
||||
|
||||
**RS6 re-pin (PATTERNS caution 3):** the gate currently bans `progress`/`maneuver`/`btn-primary` tokens in web/src/route/. This plan's route.ts gains guidance REFERENCES — re-pin RS6 in the same change: the ban becomes "guidance IMPLEMENTATION lives in web/src/guidance/ — route/ files may import from ../guidance/ and call it, but must not define maneuver/progress rendering inline" (structural: the tokens are allowed only on `import … from "../guidance/…"` lines and direct call sites).
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto" tdd="true">
|
||||
<name>task 1: Guidance camera (locked follow) + BackButton full state graph</name>
|
||||
<files>web/src/guidance/camera.ts, web/src/map/follow.ts, web/src/telegram/backbutton.ts, web/test/route-surface.test.mjs</files>
|
||||
<read_first>
|
||||
- web/src/map/follow.ts (the mode machine + programmatic-move lock + CAMERA_PADDING_PX — extend, don't reinvent)
|
||||
- web/src/telegram/backbutton.ts (wireBackButton — the predicate + handler-as-one-change law; the Phase 5 header comment reserved this extension)
|
||||
- web/src/ui/recenter.ts (data-attribute state swaps; the control returns unlocked on pan)
|
||||
- web/test/route-surface.test.mjs RS7 (the recording fake-wa walk test — extend for the full graph)
|
||||
- .planning/phases/06-turn-by-turn-guidance-live-driving/06-UI-SPEC.md Camera Behavior + BackButton Contract tables (BINDING parameters)
|
||||
</read_first>
|
||||
<behavior>
|
||||
- createGuidanceCamera.easeToSnapped(point): fakeMap.easeTo recorded with center=snapped point, padding {top:320,bottom:64,left:64,right:64}, pitch 35, zoom 16, duration 400 — bearing NEVER passed (north-up)
|
||||
- programmatic moves (originalEvent undefined) do NOT unlock follow; a movestart WITH originalEvent unlocks → recenter control's follow notch clears (Phase 3 semantics)
|
||||
- follow.ts's existing follow(fix) behavior is unchanged when called without opts (Phase 3/5 routes keep their camera law)
|
||||
- PX-01 walk with the recording fake: root → hidden; route state → shown, click → Phase 5 walk back; guidance → shown, click → confirm card opens (NOT teardown); confirm open → click → confirm dismissed (CONTINUE), guidance alive; YES ABANDON → chrome clears → route card state → click → Phase 5 walk → destination card (root) → hidden; trip-ended card → click → search root, hidden; close() recorded ZERO times anywhere except an explicit root close path
|
||||
</behavior>
|
||||
<action>
|
||||
1. `web/src/map/follow.ts`: extend `follow(fix, opts?: { padding?: {top,bottom,left,right}; pitch?: number; zoom?: number; durationMs?: number })` — opts spread over the CURRENT defaults so existing callers are byte-identical in behavior. Keep the lock/originalEvent law untouched.
|
||||
2. `web/src/guidance/camera.ts`: named exports `GUIDANCE_CAMERA_PADDING = { top: 320, bottom: 64, left: 64, right: 64 }`, `GUIDANCE_ZOOM = 16`, `GUIDANCE_EASE_MS = 400`, `GUIDANCE_CAMERA_PITCH = 35`; `createGuidanceCamera(map, followController)` returning `{ easeToSnapped(point: RoutePoint): void; onRerouteApplied(): void }` — easeToSnapped calls followController.follow(point, { padding: GUIDANCE_CAMERA_PADDING, pitch: GUIDANCE_CAMERA_PITCH, zoom: GUIDANCE_ZOOM, durationMs: GUIDANCE_EASE_MS }); onRerouteApplied is a documented no-op camera-wise (setData happens in the route layer — UI-SPEC: no camera jump on reroute).
|
||||
3. `web/src/telegram/backbutton.ts`: grow the wire's doc-header to the 3+ state graph and extend the predicate/handler so `walkBack` is CONTEXT-AWARE via an injected `resolveAction(): BackAction` where `BackAction = { kind: "hidden" } | { kind: "close" } | { kind: "callback"; fn: () => void }` — keep the old two-argument call shape working (hasOverlay + walkBack compose into the resolver internally) so Phase 5 call sites and RS7 stay valid; the visible-iff-pushed-state and never-close-from-pushed laws hold for every new state.
|
||||
4. RED→GREEN in `web/test/route-surface.test.mjs`: extend RS7's recording-fake block with the full-walk scenario per the behavior list (the confirm-card steps assert the CALLBACKS the fake receives — the confirm surface itself is 06-05's, wired in task 2), plus camera tests with the route-surface fakeMap pattern (easeTo args recorded; unlock law).
|
||||
</action>
|
||||
<verify>
|
||||
<automated>npm test -w web && npm run web:typecheck</automated>
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- camera.ts exports the three constants with EXACT UI-SPEC values (test pins them, RS4 style)
|
||||
- fakeMap easeTo assertions: padding/pitch/zoom/duration exact; no bearing key ever present
|
||||
- follow.ts without opts behaves byte-identically (existing follow tests untouched-green)
|
||||
- RS7 extended: full walk recorded, close() count === 0 across all pushed-state clicks
|
||||
- typecheck clean
|
||||
</acceptance_criteria>
|
||||
<done>The camera rides the snapped line at the UI-SPEC pose and unlocks only on user gesture; the BackButton resolver walks every state with zero dead ends and zero premature closes</done>
|
||||
</task>
|
||||
|
||||
<task type="auto" tdd="true">
|
||||
<name>task 2: The guidance pump in route.ts — start, effects, chrome, reroute</name>
|
||||
<files>web/src/route/route.ts, web/test/route-surface.test.mjs</files>
|
||||
<read_first>
|
||||
- web/src/route/route.ts IN FULL (the controller you are evolving: injected deps, setState funnel, fail-honest catch, console law, D-10 reserved note)
|
||||
- web/src/guidance/guidance.ts + watch.ts + eta.ts (06-02 contract — pump against it, never re-implement it)
|
||||
- web/src/guidance/banner.ts + haptics.ts + close-protection.ts (06-05 chrome + guards)
|
||||
- web/src/route/route-card.ts (the card the guidance card evolves from)
|
||||
- .planning/phases/06-turn-by-turn-guidance-live-driving/06-UI-SPEC.md State Coexistence table (BINDING: OFF_ROUTE shows no premature signal; REROUTING holds last honest numbers; NO REROUTE state line; list re-render on reroute-apply)
|
||||
</read_first>
|
||||
<behavior>
|
||||
- route drawn + fix < GUIDANCE_START_ALONG_M along → still Phase 5 route state (no guidance chrome)
|
||||
- route drawn + fix ≥ 30 m along → guidance activates: engageCloseProtection, disableVerticalSwipes path via engage, [data-guidance="active"] on the shell root, banner + guidance card + collapsed list mount, camera easeToSnapped, ARAHARAH-GUIDE state=on_route token logged (category-only)
|
||||
- accepted fixes pump stepGuidance: banner distance/street update, ETA via updateEta + composeEtaClock, progress bar pct = alongM/totalM, haptic effects → fireHaptic, OFF_ROUTE → banner UNCHANGED (no premature signal), REROUTING → register swap + reroute copy + distance "—" + gantry blink start
|
||||
- reroute-requested effect → source.route({origin: fix, destinationId}) (the composed ladder from task 3); success → reroute-applied event → new line setData, list re-render (scroll top), gantry stop, camera NO jump; failure/throw → reroute-failed → NO REROUTE banner state + card state line (fail-honest, calm)
|
||||
- arrival effect → trip-end flow (task 3's teardown: DELETE envelope idempotent, stop watch, release protection, trip-ended card, chrome clears)
|
||||
- END TRIP tap → confirm card (bottom); YES, ABANDON → same teardown; CONTINUE → dismiss
|
||||
</behavior>
|
||||
<action>
|
||||
1. Extend `RouteControllerDeps` with injected guidance concerns: `wa` (TelegramWebAppLike | null), `shellRoot` (the element receiving data-guidance), `register` (the register shower), banner/card/list mount points, `console` stays the module's own (state tokens only: `ARAHARAH-GUIDE state=<state>` — RS8 family; never coordinates).
|
||||
2. Implement the guidance controller INSIDE route.ts's injected-deps shape: a `startGuidance(model)` / `pumpFix(fix)` / `teardownGuidance(reason: "arrival" | "abandon")` triple held in the controller closure, using ONLY 06-02's machine + 06-05's builders (zero maneuver math inline — RS6's re-pinned ban enforces it). Pump: `shouldAcceptFix` gate → `stepGuidance` → effects dispatch (haptics via fireHaptic; reroute via the injected source; arrival → teardown) → chrome updates (banner five slots, ETA via updateEta/composeEtaClock, progress pct, list rows via the model's steps + projectAlongRoute). REROUTING: startGantryBlink on mount, stopGantryBlink on resolve. The confirm card + trip-end card mount into the injected bottom/center registers per UI-SPEC placement.
|
||||
3. RED→GREEN in `web/test/route-surface.test.mjs` with the fakeDeps pattern: guidance activation gate (stationary vs moving first fix), pump updates (banner distance from a known fix, ETA state, progress pct), OFF_ROUTE no-premature-signal, REROUTING calm state + exactly one source.route call, reroute failure → NO REROUTE + card state line, reroute success → list re-rendered + no camera jump, END TRIP → confirm → YES ABANDON → teardown effects recorded (close-protection release + watch stop + DELETE fetch recorded via stubFetch), console tokens category-only.
|
||||
4. RE-PIN RS6 in the same change: tokens `progress`/`maneuver`/`btn-primary` banned in web/src/route/ EXCEPT on `from "../guidance/…"` import lines and direct call expressions of imported names (structural scan per the context note).
|
||||
</action>
|
||||
<verify>
|
||||
<automated>npm test -w web && npm run web:typecheck</automated>
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- route-surface.test.mjs green including: activation gate, pump updates, no-premature-signal, exactly-one-reroute-call, NO REROUTE degradation, teardown-on-abandon (release + stop + DELETE recorded), ARAHARAH-GUIDE tokens category-only
|
||||
- RS6 re-pinned and green (guidance implementation lives in web/src/guidance/)
|
||||
- grep `ARAHARAH-GUIDE state=` matches web/src/route/route.ts; grep `console\.` in route.ts shows only state-token lines (no `${lat` / coordinate interpolation)
|
||||
- typecheck clean
|
||||
</acceptance_criteria>
|
||||
<done>Driving works end-to-end in Node fakes: motion starts guidance, fixes drive the cockpit, excursions self-heal silently through the real /api/route, and both exit paths tear down cleanly</done>
|
||||
</task>
|
||||
|
||||
<task type="auto" tdd="true">
|
||||
<name>task 3: Envelope flows — minimize POST, resume GET, trip-end DELETE + composed ladder</name>
|
||||
<files>web/src/main.ts, web/src/route/route.ts, web/test/route-surface.test.mjs</files>
|
||||
<read_first>
|
||||
- web/src/main.ts lines 40–70 and 340–470 (the composition root: fixture source construction, route controller creation, session/boot choreography, BackButton wiring)
|
||||
- web/src/session/store.ts (getSession — the Bearer getter for http-source)
|
||||
- bot/src/kv/guidance-sessions.ts (the frozen snapshot fields the POST body must carry EXACTLY)
|
||||
- .planning/phases/06-turn-by-turn-guidance-live-driving/06-RESEARCH.md Pattern 5 (envelope lifecycle as structural foreground gate; write-at-minimize + earliest-signal belt) + Pitfall 2 (the minimize race — fetch keepalive)
|
||||
- web/test/destination-preload.test.mjs (the ?param reader pattern — ?g= follows it)
|
||||
</read_first>
|
||||
<behavior>
|
||||
- deactivated event during guidance → POST /api/guidance with the frozen snapshot shape (geometry re-encoded via encodePolyline6 from the live model; startedAtSec = trip start) using fetch(…, { keepalive: true }) — recorded by stubFetch even when the harness simulates immediate freeze
|
||||
- activated event during guidance → DELETE /api/guidance?id=<stored id> (cron pauses — structural); the id is retained for trip-end idempotent DELETE
|
||||
- fresh boot with ?g=<uuid> → GET /api/guidance?id= → envelope → model rebuilt (decodePolyline6 + deriveCumulativeDistanceM + destination fields) → RESUMING state (projected numbers from startedAtSec + avg speed; GUIDE // RESUMING banner + gantry) → first accepted fix → live ON_ROUTE; a failed/foreign GET → honest destination-less boot (Phase 4 flow), never a fake route
|
||||
- composed ladder in main.ts: engine-a first, fixture fallback on null — `route: (req) => (await http.route(req)) ?? (await fixture.route(req))` code-constructed (no env reads)
|
||||
- trip end (arrival or abandon) → DELETE envelope (404-tolerant), watch stop, close-protection release, data-guidance removed, trip-ended card; BackButton from trip-end walks to search root
|
||||
</behavior>
|
||||
<action>
|
||||
1. In `main.ts`: build the composed RoutingSource ladder beside the existing fixture construction (code-constructed per the types.ts no-registry law): `const httpSource = createHttpRoutingSource({ endpoint: "/api/route", bearer: () => getSession() });` then the wrapper `{ name: "ladder", route: async (req) => (await httpSource.route(req)) ?? (await fixtureSource.route(req)) }` handed to createRouteController. Keep the golden-demo path: with no graph/no token, engine-a nulls fall through to the fixture corpus (captures stay stable).
|
||||
2. Envelope lifecycle in the controller closure (exposed to main.ts via the controller): `onDeactivated` → POST (keepalive fetch, body = frozen snapshot only — id/chat_id/created_at are SERVER-minted; store the returned id); `onActivated` → DELETE ?id; `teardownGuidance` → DELETE ?id (tolerate 404) + watch stop + release + trip-end card. Wire `wa.onEvent?.("deactivated"|"activated", …)` with capability guards.
|
||||
3. `?g=` resume in main.ts's boot choreography (destination-preload pattern): read `new URLSearchParams(location.search).get("g")`, UUID-validate, GET envelope, rebuild the model, create the guidance session in RESUMING state (projection: `remainingM = distanceM × (1 − min(1, (nowSec − startedAtSec) × avgSpeed / distanceM))`, avgSpeed = distanceM/durationS), render RESUMING chrome (banner register + gantry + projected ETA card numbers), flip to live on first accepted fix.
|
||||
4. RED→GREEN in `web/test/route-surface.test.mjs`: stubFetch records POST (keepalive true, snapshot fields exactly the frozen six), DELETE on activated + on teardown (idempotent second DELETE tolerated), ?g= boot → RESUMING → first fix → ON_ROUTE (fake wa events + URL stub), failed GET → Phase 4 boot flow (no guidance chrome).
|
||||
</action>
|
||||
<verify>
|
||||
<automated>npm test -w web && npm run web:typecheck</automated>
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- stubFetch assertions: POST /api/guidance body has EXACTLY destinationId/destinationName/distanceM/durationS/geometry/startedAtSec (no id/chat_id/created_at — server-minted), keepalive true; DELETE called with the stored id on activated AND teardown
|
||||
- ?g= resume test: RESUMING state rendered (GUIDE // RESUMING register + projected numbers), first fix flips to live ON_ROUTE
|
||||
- main.ts grep `createHttpRoutingSource` and `?? (await` (the composed ladder) present; grep for env reads in the backend selection → 0 (code-constructed law)
|
||||
- full web suite green; typecheck clean
|
||||
</acceptance_criteria>
|
||||
<done>The envelope lifecycle is structural (no key, no push), the minimize race is belt-and-braces (keepalive + earliest signal), resume works from a killed webview via ?g=, and both trip ends execute the deletion + honest messaging</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<threat_model>
|
||||
## Trust Boundaries
|
||||
|
||||
| Boundary | Description |
|
||||
|----------|-------------|
|
||||
| Minimize/freeze → envelope POST | A backgrounding webview may freeze mid-fetch (Pitfall 2) — best-effort honesty, not a security boundary |
|
||||
| ?g= deep link → resume GET | The guidance id is an opaque UUID traveling in the URL; ownership enforced server-side by the claim check |
|
||||
| User gestures → camera | Only originalEvent-bearing moves unlock follow — synthetic moves cannot hijack the driving camera |
|
||||
|
||||
## STRIDE Threat Register
|
||||
|
||||
| Threat ID | Category | Component | Disposition | Mitigation Plan |
|
||||
|-----------|----------|-----------|-------------|-----------------|
|
||||
| T-06-05 | Information Disclosure | envelope POST + reroute calls | mitigate-by-design | Exactly three positions ever leave the device: reroute origins (real excursions only), the minimize envelope (user-initiated handoff), nothing else. On-route fixes stay local (06-02's structural gate). The envelope carries the frozen route snapshot only — no live coordinate stream. |
|
||||
| T-06-04 | Information Disclosure | console + state tokens | mitigate | ARAHARAH-GUIDE state tokens only — tested to contain no coordinates (RS8 family); no payload/claim values in any log line. |
|
||||
| T-06-06 | Tampering (old-client crash) | onEvent("deactivated"/"activated") wiring | mitigate | `wa.onEvent?.()` optional chains; event names ignored by older clients by contract; capability guards proven in 06-05's fakes. |
|
||||
| — | Spoofing (?g= probe) | resume GET | mitigate (server, 06-03) | Foreign/absent id → 404 → honest Phase 4 boot; the client renders no guidance chrome without a validated envelope. |
|
||||
| — | DoS (self) | reroute requests | accept | The D-04 storm guard (20 s) bounds reroute rate client-side; replay tests prove exactly-one-call under excursion storms. |
|
||||
</threat_model>
|
||||
|
||||
<verification>
|
||||
- `npm test -w web && npm run web:typecheck` green (RS6 re-pinned; PX-01 full walk; envelope flows; camera laws)
|
||||
- Zero dead ends in the BackButton graph (RS7 extended walk, close() only at true root)
|
||||
- Console carries only ARAHARAH-GUIDE/ARAHARAH-ROUTE state tokens
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
Guidance is ALIVE in the shell: motion activates it, fixes drive the cockpit, missed turns self-heal through the real router with a calm banner, minimizing hands off to the cron (envelope live), re-opening resumes at the progressed position, the BackButton walks the full graph through the abandon confirmation, and both trip ends delete the record and say so. PX-01/PX-03's observable behaviors are claimed and tested.
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/06-turn-by-turn-guidance-live-driving/06-06-SUMMARY.md`
|
||||
</output>
|
||||
Reference in New Issue
Block a user