docs(07-02): complete landscape + failure-state matrix plan — SUMMARY
- landscape geometry block + FM1-FM7 matrix + capture legs, 3/3 tasks - 4 documented deviations (banner fit, chrome offset 113px, bottom register, no-geometry guard) - verification: web 165/165, theme audit AUDIT CLEAN, capture 22/22 non-blank
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
---
|
||||
phase: 07-hardening-private-launch
|
||||
plan: 02
|
||||
subsystem: ui
|
||||
tags: [landscape, media-query, maplibre, failure-states, telemetry-rams, css-tokens, playwright-capture]
|
||||
|
||||
# Dependency graph
|
||||
requires:
|
||||
- phase: 06-turn-by-turn-guidance-live-driving
|
||||
provides: the guidance cockpit (banner/strip/list/cards in shell.css), the pure D-04 reducer + replay fixtures, the ?drive= capture legs
|
||||
- phase: 07-hardening-private-launch plan 01
|
||||
provides: the fullscreen capability layer + safe-area watch (watched by FM6's old-client vector)
|
||||
provides:
|
||||
- "@media (orientation: landscape) and (max-height: 560px) geometry block in web/src/shell.css (tokens-only, sanctioned-literal list extended)"
|
||||
- "web/test/failure-state-matrix.test.mjs — FAILURE_VECTORS data table + FM1..FM7 named cases pinning every designed failure surface"
|
||||
- "route.ts no-geometry guard: a <2-point geometry is refused before the draw path (pending card / reroute-failed)"
|
||||
- "capture.mjs per-leg viewport + two landscape legs (shell-guidance-landscape.png, shell-route-pending-landscape.png)"
|
||||
affects: [07-06 device matrix (landscape QA legs), SC2 verification, future cockpit geometry work]
|
||||
|
||||
# Tech tracking
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns:
|
||||
- "Landscape as CSS geometry adaptation only — portrait stays default, the map cartography untouched (D-03/D-10)"
|
||||
- "Failure-state matrix as data — named vectors with trigger/expect tokens (RESEARCH Pattern 3)"
|
||||
- "Type step-down inside a media query rides the SAME type-token scale (no new sizes)"
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- web/test/failure-state-matrix.test.mjs
|
||||
modified:
|
||||
- web/src/shell.css
|
||||
- web/scripts/capture.mjs
|
||||
- web/src/route/route.ts
|
||||
|
||||
key-decisions:
|
||||
- "Landscape banner shortened by tightening padding (xs) + one type-token step down (telemetry-num → headline-md, headline-md → label-lg) so the content actually fits the 72px floor the strip literal rides on"
|
||||
- "Chrome-offset literal corrected to 113px (= the list margin-top's own stack: sm + 72 + 1 + 24 + sm) instead of the plan's 104px"
|
||||
- "Bottom register keeps the portrait 64px control-clearance in landscape (measured: it already seats the card inside the landscape height and clears MapLibre's attribution + recenter)"
|
||||
|
||||
patterns-established:
|
||||
- "FM* prefix joins the HS*/GS*/RS* suite convention for named-vector gates"
|
||||
- "Per-leg viewport in the capture harness (default byte-identical to the old hard-coded one)"
|
||||
|
||||
requirements-completed: [PX-04]
|
||||
|
||||
# Metrics
|
||||
duration: 31min
|
||||
completed: 2026-10-24
|
||||
---
|
||||
|
||||
# Phase 7 Plan 02: Landscape Geometry + Failure-State Matrix Summary
|
||||
|
||||
**Landscape cockpit geometry via a tokens-only `@media (orientation: landscape)` block plus the FM1–FM7 failure-state matrix pinning every designed failure surface — with the `<2`-point-geometry draw gap closed in route.ts**
|
||||
|
||||
## Performance
|
||||
|
||||
- **Duration:** 31 min
|
||||
- **Started:** 2026-10-24T19:50:21Z
|
||||
- **Completed:** 2026-10-24T20:21:19Z
|
||||
- **Tasks:** 3/3
|
||||
- **Files modified:** 4
|
||||
|
||||
## Accomplishments
|
||||
- `web/src/shell.css` carries exactly one `@media (orientation: landscape) and (max-height: 560px)` block: banner 72px floor with safe-left/right edge padding (`max()`), plate 40px/glyph 28px, strip riding under 72px chrome, `guide-list` 100dvh-bounded — CSS only, zero radius/shadow/blur/transition, no MapLibre rule; the theme audit stays `AUDIT CLEAN`
|
||||
- `web/test/failure-state-matrix.test.mjs` (new): `FAILURE_VECTORS` as data (exactly 7 classes) + FM1–FM7 — the empty/error/timeout/no-geometry/off-road/old-client/location-timeout classes all assert DESIGNED surfaces (real pending card, calm REROUTING slot, denied/awaiting-pin states), never a blank
|
||||
- FM4's RED gate exposed a real gap: a route whose geometry has fewer than two points reached the consult draw path (a half-drawn line). Closed in `route.ts` (consult + reroute ladder) — the pending card / reroute-failed degradation renders instead
|
||||
- `web/scripts/capture.mjs` accepts a per-leg `viewport` and adds the two landscape legs; `CAPTURE OK — 22/22 non-blank`, both landscape shots visually verified (banner/strip/card geometry measured clean at 844×390: banner 8–81, strip 81+, card 159–326)
|
||||
|
||||
## Task Commits
|
||||
|
||||
1. **task 1: the landscape geometry block in shell.css** — `13ba0bb` (feat)
|
||||
2. **task 2 (RED): the FM1..FM7 failure-state matrix suite** — `b577bc4` (test — FM4 failing by design)
|
||||
3. **task 2 (GREEN): refuse <2-point geometries before the draw path** — `add860b` (fix — FM4 green)
|
||||
4. **task 3: the landscape + failure-state capture legs** — `7536ce5` (feat)
|
||||
|
||||
## Files Created/Modified
|
||||
- `web/src/shell.css` — the landscape geometry block + the extended sanctioned-literal header list
|
||||
- `web/test/failure-state-matrix.test.mjs` — new: FAILURE_VECTORS data table + 8 named FM cases
|
||||
- `web/src/route/route.ts` — the T-07-12 no-geometry guard (consult + reroute)
|
||||
- `web/scripts/capture.mjs` — per-leg viewport + landscape guidance/pending legs + header/expected-array lines
|
||||
|
||||
## Decisions Made
|
||||
- The plan's prescribed landscape banner (min-height 72px alone) did not hold: the banner's content (guide-top + distance + street rows) measured 95px, so the strip literal put the strip BEHIND the banner. Fixed inside the plan's own mechanism (CSS, tokens): vertical padding to `--spacing-space-xs` and the distance/street fonts one step down the same type-token scale — content now measures exactly 72px at 844×390.
|
||||
- The plan's chrome-offset literal (104px) does not close arithmetically against its own list margin-top (sm + 72 + 1 + 24 + sm = 113px); corrected to 113px in both the max-height and the sanctioned-literal comment.
|
||||
- The plan's bottom-register rule (`bottom: safe-bottom + sm`) collided with MapLibre's attribution chip at the viewport bottom; the portrait rule's sanctioned 64px control-clearance composite already seats the card inside the landscape height (measured card 159–326 vs attribution top ≈364), so the landscape override was dropped rather than re-machining a new literal.
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
### Auto-fixed Issues
|
||||
|
||||
**1. [Rule 1 - Bug] Landscape banner content overflowed its 72px floor (strip rendered behind the banner)**
|
||||
- **Found during:** task 3 (the landscape capture leg's screenshot + DOM probe)
|
||||
- **Issue:** The planned block shrank only the plate (48→40px); the measures column (28px/32px telemetry distance + 20px/26px street) kept the banner at 95px while the strip's top literal assumed 72px — a real overlap (PX-04.e violation)
|
||||
- **Fix:** CSS-only, tokens-only: banner vertical padding → `var(--spacing-space-xs)`, `.guide-distance` → `var(--type-headline-md)`, `.guide-street` → `var(--type-label-lg)` (letter-spacing tokens paired). Banner now measures exactly 72px (73 with its 1px separator border) at 844×390
|
||||
- **Files modified:** web/src/shell.css
|
||||
- **Verification:** DOM probe (banner bottom 81 = strip top 81) + re-captured landscape shot visually verified
|
||||
- **Committed in:** 7536ce5 (task 3 commit; shell.css part of the same correction chain)
|
||||
|
||||
**2. [Rule 1 - Bug] The plan's 104px chrome-offset literal does not close against the list's own margin-top (113px)**
|
||||
- **Found during:** task 1 acceptance review
|
||||
- **Issue:** max-height `100dvh - 104px` with margin-top `safe-top + 113px` lets the fully-open list run 9px past the viewport bottom
|
||||
- **Fix:** max-height corrected to `100dvh - 113px - safe-top - safe-bottom`; sanctioned-literal comment updated (104 → 113)
|
||||
- **Files modified:** web/src/shell.css
|
||||
- **Verification:** arithmetic closes; audit clean
|
||||
- **Committed in:** 7536ce5
|
||||
|
||||
**3. [Rule 1 - Bug] The plan's bottom-register rule collided with MapLibre's attribution chip**
|
||||
- **Found during:** task 3 (screenshot + DOM probe: card bottom 382 vs attribution top ≈364 at 844×390)
|
||||
- **Issue:** `bottom: safe-bottom + sm` removed the 64px control-clearance the portrait rule provides; the card's bottom-left corner sat on the attribution chip
|
||||
- **Fix:** dropped the landscape bottom-register override — the portrait rule's sanctioned 64px clearance already seats the card inside the landscape height (159–326)
|
||||
- **Files modified:** web/src/shell.css
|
||||
- **Verification:** DOM probe + re-captured shots (cockpit and pending card both fully visible, nothing clipped)
|
||||
- **Committed in:** 7536ce5
|
||||
|
||||
**4. [Rule 2 - Missing Critical] A `<2`-point geometry reached the consult draw path (T-07-12)**
|
||||
- **Found during:** task 2 (FM4 RED gate)
|
||||
- **Issue:** `consult()` only checked `options.length === 0`; a 1-point option (the http-source validator admits `points.length >= 1`) would have drawn a degenerate half-line
|
||||
- **Fix:** consult filters degenerate options into the pending-card class; the reroute ladder maps a no-drawable-option answer to the honest reroute-failed degradation. (The ?g= resume path in main.ts already had this guard.)
|
||||
- **Files modified:** web/src/route/route.ts
|
||||
- **Verification:** FM4 green; whole web suite 165/165; `npm run web:typecheck` clean
|
||||
- **Committed in:** add860b (GREEN)
|
||||
|
||||
**Total deviations:** 4 auto-fixed (4 × Rule 1/2 bugs-gaps in the prescribed geometry + draw path)
|
||||
**Impact on plan:** All fixes serve the plan's own binding laws (non-overlap, tokens-only, refused-before-draw). No scope creep; no behaviour redesign.
|
||||
|
||||
## Issues Encountered
|
||||
- The plan's acceptance grep `border-radius|box-shadow|backdrop-filter|transition:|animation:` returns 4 on shell.css — these are the file's PRE-EXISTING sanctioned `border-radius: 0` resets (MapLibre chrome pin, recenter, route-chip; baseline verified identical via `git show HEAD`); the landscape block adds zero banned declarations.
|
||||
- Self-referential grep trap in FM6: asserting the file does NOT contain "telegram/fullscreen" made the file contain it — pattern split across a concatenation.
|
||||
|
||||
## Known Stubs
|
||||
None — every failure surface asserted is the real, data-wired designed state.
|
||||
|
||||
## User Setup Required
|
||||
None — no external service configuration required.
|
||||
|
||||
## Next Phase Readiness
|
||||
- PX-04.e's automated half is complete (landscape geometry + on-film evidence); 07-06's device matrix walks the physical landscape/fullscreen legs against these shots
|
||||
- SC2's failure classes are pinned as named vectors; the verifier can rerun `npm test -w web` for the matrix
|
||||
- Web suite baseline moved 157 → 165 (8 FM cases); STATE.md progress untouched per the orchestrator's instruction
|
||||
|
||||
---
|
||||
*Phase: 07-hardening-private-launch*
|
||||
*Completed: 2026-10-24*
|
||||
|
||||
## Self-Check: PASSED
|
||||
|
||||
All four artifact files exist; all four task commits found in git log; the sanctioned-literal grep returns 1; FAILURE_VECTORS declared once as data with 7 entries (FM1 asserts ids); the DOM-stub finally guard present (4). STATE.md and ROADMAP.md untouched (mtimes predate executor start).
|
||||
Reference in New Issue
Block a user