Files

19 KiB
Raw Permalink Blame History

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 05 web-guidance-surface
guidance-cockpit
d06-maneuver-banner
d09-confirm-card
d14-trip-end
px03-close-protection
d08-haptics
committed-glyphs
token-only-css
machine-blink
tdd
copy-gates
phase provides
06-turn-by-turn-guidance-live-driving/02 the GuidanceState union (idle/on_route/off_route/rerouting/resuming/no_reroute) the banner's register words + calm-state swaps render, and the haptic cue vocabulary (approach/maneuver/arrive) fireHaptic dispatches
phase provides
06-turn-by-turn-guidance-live-driving/04 the engineering-A workspace the guidance card's route/telemetry model flows from (banner/card builders consume view data, never re-derive)
phase provides
05-routing-route-display/05 the builder law (route-card.ts: actions-interface-first, createElement+textContent only), the shell register classes (.card/.card-header/.card-actions/.route-telemetry/.route-stack), the 64px bottom composite, and RS5/RS9/RS10 gate shapes guidance-surface mirrors
phase provides
03-mini-app-shell-geolocation/03 the strings-module copy gate pattern (COPY1..COPY7), the machine-blink gantry precedent (cards.ts), the strip the CSS compacts under [data-guidance]
web/src/guidance/glyphs/*.svg + web/src/guidance/glyphs.ts — the 8-glyph committed maneuver set (single source; PNGs rasterize from these exact files in plan 07) with svgHost, the shell's ONE sanctioned innerHTML site (a static import value, gated by GS6)
web/src/guidance/banner.ts — SEVEN builders: buildGuidanceBanner (five-slot discipline, GUIDE // NEXT|REROUTING|RESUMING|NO REROUTE, aria-expanded toggle), buildManeuverList (tap-out + NEXT/FUTURE/PAST rows), startGantryBlink/stopGantryBlink, buildGuidanceCard (progressbar + ONE btn-secondary), buildConfirmCard (the ONE btn-primary), buildTripEndCard
web/src/guidance/haptics.ts — fireHaptic: the three D-08 cues behind ?. chains, silent no-op without the API
web/src/guidance/close-protection.ts — engage/releaseCloseProtection: PX-03 layers gated BEFORE each call (isVersionAtLeast("7.7") body-swipe, ("6.2") native-close net)
web/src/telegram/webapp.ts — the contract grows by OPTIONAL members only: HapticFeedback (6.1+), vertical-swipe guards (7.7+), closing-confirmation pair (6.2+), isActive (8.0+)
web/src/i18n/strings.ts — the 18 ShellStrings guidance keys, en + ms verbatim (COPY8 pins every value)
web/src/shell.css — the guidance cockpit block: banner chassis + 1px separator, CSS-only strip compaction under [data-guidance="active"], list panel + row states + lamp, 4px progress bar — token vars only, zero motion/depth/radius/hex
web/test/guidance-surface.test.mjs — GS1..GS14: five-slot banner, list row states, gantry duty cycle, sanctioned-innerHTML + inline-copy gates, card copy + btn-primary placement, CSS token scan, capability-guard fakes
web/test/glyph-raw-loader.mjs — the Node-side ?raw hook (tests exercise the committed glyph strings verbatim)
06-06 guidance wiring (composes these builders with the 06-02 state machine + wires the guards)
06-07 turn-card PNGs (rasterize glyphs/*.svg)
06-08 capture legs (the guide-* classes are the capture surface)
added patterns
builder law extended to guidance: pure (locale, view, actions) => HTMLElement compositions, Node-tested through a minimal document fake (theme.test stub pattern) — no browser in the suite
the ONE sanctioned innerHTML site: glyphs.ts svgHost parses a STATIC committed import (GS6 pins the count: 0 in banner.ts, exactly 1 at GLYPHS[kind] in glyphs.ts)
registers are code-composed instrument constants: `${loc.guideRegister} // ${stateWord}` — the state words NEXT/REROUTING/RESUMING/NO REROUTE/CONFIRM/END and unit formats live in code, never the locale tables
distance '—' iff distanceM === null (pure view): the UI-SPEC state table decides who passes null — RESUMING legally shows projection numbers
capability guards: typeof wa.isVersionAtLeast === "function" && wa.isVersionAtLeast("7.7") BEFORE the call, then ?. on the member — no-throw proven on gateless fakes and null
CSS-only strip compaction: [data-guidance="active"] selectors touch layout only; strip.ts is source-gated to never mention data-guidance (GS11)
created modified
web/src/guidance/glyphs.ts
web/src/guidance/glyphs/depart.svg
web/src/guidance/glyphs/straight.svg
web/src/guidance/glyphs/left.svg
web/src/guidance/glyphs/right.svg
web/src/guidance/glyphs/slight-left.svg
web/src/guidance/glyphs/slight-right.svg
web/src/guidance/glyphs/uturn.svg
web/src/guidance/glyphs/arrive.svg
web/src/guidance/haptics.ts
web/src/guidance/close-protection.ts
web/test/guidance-surface.test.mjs
web/test/glyph-raw-loader.mjs
web/src/guidance/banner.ts
web/src/i18n/strings.ts
web/src/shell.css
web/src/telegram/webapp.ts
web/test/copy-gate.test.mjs
web/test/route-surface.test.mjs
web/test/build-artifact.test.mjs
Glyph geometry follows the UI-SPEC table verbatim, including the uturn machined staple with NO arrowhead and arrive as the promoted phase-5 pin (12×12 square + 3×8 tail + shaft) — the table is the binding source, not turn-glyph convention.
The banner gantry renders ONLY in rerouting/resuming: NO REROUTE is a designed deferral, not a loading state — no blink (GS1 pins the absence).
Banner z-index 3 sits above the list tap-out (z 2): while the list is open the banner stays the CLOSE toggle; every other tap (map included) collapses via the full-viewport transparent layer — the UI-SPEC's tap-out law kept whole.
Confirm + trip-end bodies are text-body-sm: the UI-SPEC typography table assigns the state-line role (degradation copy, confirm body) to body-sm; the trip-end card joins that family.
svgHost throws nothing and parses via <template> per the plan; the caller sizes the host (32 banner / 24 list) — the committed SVGs carry no size of their own.
guidance-surface gate family (GS*): behavioral cases through the document fake + structural comment-stripped scans (sanctioned-innerHTML count, inline-copy ban with an explicit instrument-word allowlist, CSS token purity, btn-primary placement)
the ?raw loader twin pattern: node:module register hook in web/test/glyph-raw-loader.mjs makes Vite-?raw modules Node-testable byte-verbatim — reusable for any future raw-asset import
copy-gate growth: COPY8 pins all 18 guidance values verbatim in en + ms; COPY1's floor moves 40→58 so the surface cannot silently shrink
GUID-01
GUID-04
PX-03
16min 2026-10-24

Phase 6 Plan 5: The Guidance Cockpit Surface — Glyphs, Banner, Cards, Guards Summary

The guidance cockpit exists as seven pure, Node-tested DOM builders + two capability-guarded modules: the five-slot banner that never blanks across all six machine states, the honest collapsible maneuver list with the 8×8 NEXT lamp, the evolved guidance card with a stepping progress bar and exactly one secondary CTA, the ONE confirm surface carrying the verbatim privacy copy, the trip-end card, and the 8-glyph committed set imported ?raw as the single source — every word from the strings module in en+ms, every pixel from tokens, zero motion, zero depth, zero red.

Performance

  • Duration: 16 min
  • Started: 2026-10-24T06:05:55Z
  • Completed: 2026-10-24T06:21:45Z
  • Tasks: 4/4 (tasks 2–4 RED→GREEN; task 1 atomic with its COPY gate)
  • Files: 21 (13 created, 8 modified)

Accomplishments

  • The 8-glyph committed set is real once (GUID-01): 8 hand-authored 32×32 SVGs per the UI-SPEC geometry table — 3px stroke, square caps, miter joins, orthogonal/45° segments only (the uturn staple is the arc-free proof case; GS7 greps every file for the arc-free law and pins each raw string byte-equal to its committed file). glyphs.ts imports them ?raw (single source) and exposes svgHost — the shell's ONE sanctioned innerHTML site, parsing a static import value, counted by GS6 (0 in banner.ts, 1 in glyphs.ts at GLYPHS[kind]). PNGs for the chat turn-cards rasterize from these exact files in plan 07.
  • The banner renders the machine's every mood (D-04/D-06): GS1 drives all five banner-bearing states and proves the five slots — register (GUIDE // NEXT|REROUTING|RESUMING|NO REROUTE), 48×48 plate with the 32×32 committed glyph, distance (250+M / 1.2+KM / honest —), street (verbatim, streetUnnamed fallback) or the calm-state copy — never a blank slot mid-swap. The root is one full-width <button> with aria-expanded/aria-controls→guide-maneuver-list/label; LIST↔CLOSE is the real-word toggle. The machine-blink gantry rides only rerouting/resuming; GS5 proves the ~500 ms duty cycle, idempotent restart (no stacked timers), and stop-clears.
  • The list is honest and collapsible (D-06): labelled role="region" card panel (id = the banner's aria-controls target) + a transparent full-viewport tap-out (GS4 proves one tap dismisses); NEXT/FUTURE/PAST rows carry real text, 24×24 aria-hidden glyphs, the 8×8 orange lamp on NEXT only, and right-aligned {n} M/{n.n} KM distances.
  • The route card evolved (D-06): GUIDE register, verbatim destination headline, the live telemetry row (18 MIN · 7.8 KM · ETA 18:42 — instrument formats identical under ms), a role="progressbar" 4px bar with the full aria value set and instant inline width, the no-reroute state line ONLY when degrading (GS8b), and ONE .btn-secondary END TRIP — GS12 pins .btn-primary at exactly one occurrence in banner.ts: the confirm card (D-09), whose YES, ABANDON/CONTINUE carry the verbatim en+ms privacy copy (GS9, both locales, both actions). The trip-end card (GS10) renders GUIDE // END with the deletion copy and zero buttons.
  • The guards degrade to honest no-ops (GUID-04/D-08/PX-03/T-06-06): fireHaptic routes approach/maneuver/arrive to selectionChanged()/impactOccurred("medium")/notificationOccurred("success") behind ?. chains (GS13/GS13b — no-throw with no API and with null); close protection gates BEFORE each call — body-swipe off at isVersionAtLeast("7.7"), the native-close net at ("6.2"), release inverting both, gateless fakes and null proven silent (GS14/GS14b/GS14c). The webapp contract grew by OPTIONAL members only; every existing fake ran untouched.
  • Copy is gated, not promised: the 18 guidance keys exist in en+ms with verbatim UI-SPEC values (COPY8 pins all 36 strings); COPY1's floor is 58; GS6b bans every copy value as a literal in banner.ts while allowlisting the instrument words; the theme audit stayed CLEAN (0 off-token values).
  • The shell.css block dresses the cockpit in tokens only (GS11): zero transition/animation/box-shadow/border-radius, zero hex literals; strip compaction is pure CSS under [data-guidance="active"] and strip.ts is source-gated to never know about it.
  • Gates grew with the family: RS10 floor 16→24 (36 src files found), BA9's input list += web/src/guidance printing 69507 / 204800 gz bytes — the budget held without touching the ceiling.
  • Suite state: web 124 passed / 0 failed (100 pre-existing untouched-green), bot 103, routing 65; all workspaces green; typecheck clean everywhere.

Task Commits

  1. task 1: the 8-glyph committed set + glyphs.ts + strings keys (atomic)
    • 0023ab3 feat(06-05): the 8-glyph committed maneuver set + glyphs.ts + the 18 guidance strings keys
  2. task 2: banner + maneuver-list builders + gantry blink (TDD)
    • a60443a test(06-05): failing guidance-surface suite GS1-GS7 (RED)
    • 432f33a feat(06-05): the maneuver banner + collapsible list builders + the machine-blink gantry (GREEN)
  3. task 3: guidance/confirm/trip-end card builders + shell.css block (TDD)
    • f0931d6 test(06-05): failing guidance-card suite GS8-GS12 (RED)
    • 79836f0 feat(06-05): guidance/confirm/trip-end card builders + the token-only shell.css guidance block (GREEN)
  4. task 4: capability guards + webapp members + gate bumps (TDD)
    • 47b1524 test(06-05): failing capability-guard suite GS13-GS14 (RED)
    • da42c77 feat(06-05): capability guards — haptics + close protection + optional webapp members + RS10/BA9 gate bumps (GREEN)

Files Created/Modified

  • web/src/guidance/glyphs/*.svg (8) — the committed 32×32 set (single source)
  • web/src/guidance/glyphs.ts — GLYPH_KINDS/GLYPHS (?raw) + svgHost (the one innerHTML site)
  • web/src/guidance/banner.ts — the seven builders + MANEUVER_LIST_ID + the blink timers
  • web/src/guidance/haptics.ts — fireHaptic + HapticCue
  • web/src/guidance/close-protection.ts — engage/releaseCloseProtection (version-gated)
  • web/src/telegram/webapp.ts — 6 optional members (HapticFeedback, 2 swipe, 2 closing-confirmation, isActive)
  • web/src/i18n/strings.ts — +18 keys × 2 locales, values verbatim
  • web/src/shell.css — the guidance cockpit block (banner, compacted strip, list, progress bar)
  • web/test/guidance-surface.test.mjs — GS1..GS14 + helpers (document fake, recording fakes)
  • web/test/glyph-raw-loader.mjs — the Node ?raw load hook
  • web/test/copy-gate.test.mjs — COPY1 floor 58 + COPY8 (36 verbatim pins)
  • web/test/route-surface.test.mjs — RS10 floor 24
  • web/test/build-artifact.test.mjs — BA9 input list += guidance family

Decisions Made

See key-decisions: verbatim glyph geometry (no uturn arrowhead), gantry only in the two wait states, banner-above-tap-out z-order, body-sm for confirm/trip-end bodies, sizeless committed SVGs sized by the caller.

Deviations from Plan

Auto-fixed Issues

1. [Rule 3 - Blocking issue] Node could not import the ?raw module family the plan requires testing

  • Found during: task 2 RED authoring
  • Issue: the plan mandates ?raw imports (the committed SVGs are the single source) and Node tests asserting GLYPHS content — but plain Node cannot load .svg modules, so guidance-surface.test.mjs could not even load banner.ts.
  • Fix: a 20-line node:module load hook (web/test/glyph-raw-loader.mjs) registered before the suite's dynamic imports: any ?raw specifier exports the real file's text byte-verbatim — tests exercise exactly what Vite ships. Test infrastructure only; zero product code.
  • Files modified: web/test/glyph-raw-loader.mjs (new), web/test/guidance-surface.test.mjs (register call)
  • Commit: a60443a

Test-side fixes during GREEN (not deviations — executor test bugs caught by verification)

  • GS7 compared raw to committed.trim() while the committed files carry a trailing newline — both sides trimmed (commit 432f33a).
  • GS11's banned-token scan originally ran over raw CSS including the block's own prose comments — now strips comments first (prose is not a call site, the GEO3 pattern; commit 79836f0).
  • GS12 assumed two btn-secondary literals; the shared secondaryButton helper centralizes the class (better shape) — assertion updated to pin the helper (commit 79836f0).
  • The close-protection version gates were first hidden behind a versionGate(wa, version) helper, which could never satisfy the plan's acceptance grep isVersionAtLeast("7.7") — gates inlined so the literals exist verbatim (commit da42c77).

Known Stubs

None. Every export is a fully wired implementation; the guidance chrome renders only over live data (the plan's empty-state law: guidance renders only over a route). The blink intervals are wired for caller teardown (stopGantryBlink) with plan 06 composing the swaps — the API makes a leak visible by design.

Threat Surface Scan

No new surface beyond the plan's <threat_model>: no network endpoints, no auth paths, no storage, no logging (the builders never touch console/fetch/storage; banner.ts's only DOM writes are createElement/textContent + the gated static innerHTML). T-06-06 is implemented and test-proven: version gates BEFORE every call, ?. member chains, no-throw on gateless fakes and null (GS13b/GS14). The gantry DoS disposition holds: one WeakMap-keyed interval per element, idempotent start, stop clears — GS5 pins no-post-stop flips. The confirm card is plain DOM in the app's own register (the spoofing disposition's accept stands). No threat flags.

Issues Encountered

  • Node lives under nvm; every shell command sourced ~/.nvm/nvm.sh first (all prior plans' precedent). No project impact.
  • The theme/dist/rams.css base layer already resets border-radius: 0 on every button — the banner button needed no literal in the guidance block, keeping the GS11 scan clean without a sanctioned-exception debate.

User Setup Required

None — builders, guards, tokens, and tests; zero new dependencies, zero env vars.

Next Phase Readiness

  • 06-06 (wiring): everything to compose is exported and tested — buildGuidanceBanner(locale, {state, glyph, distanceM, street, listOpen}, {onToggle}) consumes GuidanceState directly; the machine's reroute-requested/effects map onto the guards; data-guidance="active" on the shell root triggers the CSS compaction; engage/release close protection bind guidance start/trip end.
  • 06-07 (turn-cards): rasterize web/src/guidance/glyphs/*.svg (stroke #EB8008 on #1A1A1A plate) — the committed geometry is the single source; the web side will not change.
  • 06-08 (captures): the guide-* classes (guide-banner, guide-list, guide-progress, guide-confirm) are the capture surface; ?drive= profiles can assert GUIDE // NEXT|REROUTING registers verbatim via the COPY8-pinned strings.

Phase: 06-turn-by-turn-guidance-live-driving Completed: 2026-10-24

Self-Check: PASSED

  • All 20 created/modified files verified present on disk (8 SVGs, 4 guidance modules, 2 test files, strings/shell.css/webapp.ts, 3 gate suites).
  • All 7 plan commits verified in git log: 0023ab3 (task 1), a60443a→432f33a (task 2 RED→GREEN), f0931d6→79836f0 (task 3 RED→GREEN), 47b1524→da42c77 (task 4 RED→GREEN) — TDD gate sequence intact for every tdd task.
  • npm test -w web: 124 passed / 0 failed (100 pre-existing untouched-green); bot 103, routing 65; web typecheck clean; theme audit CLEAN (0 off-token values).
  • Acceptance greps re-run at close: isVersionAtLeast("7.7")/("6.2") present in close-protection.ts; btn-primary exactly once in banner.ts; innerHTML once (glyphs.ts at GLYPHS[kind]); zero functional-red in the guidance block; zero TODO/FIXME/placeholder markers.
  • RS10 ≥24 green (36 files found); BA9 printed 69507 / 204800 gz and green.
  • STATE.md, ROADMAP.md, REQUIREMENTS.md untouched by this executor (their working-tree diffs are the orchestrator's own concurrent writes, present before execution started).