docs(07-01): complete fullscreen capability layer plan — SUMMARY
- 4/4 tasks, 157/157 web tests, typecheck clean; PX-04 fullscreen + safe-area re-resolution shipped
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
---
|
||||
phase: 07-hardening-private-launch
|
||||
plan: 01
|
||||
subsystem: ui
|
||||
tags: [telegram, fullscreen, bot-api-8.0, safe-area, capability-guard, px-04]
|
||||
|
||||
# Dependency graph
|
||||
requires:
|
||||
- phase: 03-shell-map-mini-app
|
||||
provides: the TelegramWebAppLike contract + getWebApp() one-shot accessor; the boot() choreography with the boot-time applySafeArea(resolveSafeInsets(getWebApp())) line
|
||||
- phase: 04-destination-search-kl-gazetteer
|
||||
provides: the homescreen.ts capability-guard shape (BOTH halves: method presence AND isVersionAtLeast("8.0")) copied verbatim into fullscreen.ts
|
||||
- phase: 06-turn-by-turn-guidance-live-driving
|
||||
provides: activateGuidance()/teardownGuidance()/resume()/stopGuidanceArtifacts() edges in route.ts with engageCloseProtection/releaseCloseProtection anchoring the wiring sites; the PX-03 safe-area resolve/apply pair
|
||||
provides:
|
||||
- web/src/telegram/fullscreen.ts — requestGuidanceFullscreen / exitGuidanceFullscreen / watchFullscreenEvents behind the both-halves 8.0 guard, every platform call in try/catch
|
||||
- TelegramWebAppLike grown with five OPTIONAL members: requestFullscreen/exitFullscreen/isFullscreen/lockOrientation/unlockOrientation (8.0+) — no existing member reshaped
|
||||
- watchSafeAreaChanges in safe-area.ts — insets re-resolve through the union authority on safeAreaChanged/contentSafeAreaChanged
|
||||
- route.ts wiring: request at both guidance-start edges (fresh + resumed), exit at both teardown edges (trip end + walk-back), watchFullscreenEvents registered exactly once at the guidance-start edge
|
||||
- main.ts boot-site call: watchSafeAreaChanges(getWebApp()) directly after the boot-time apply line
|
||||
- web/test/fullscreen.test.mjs — FS1..FS9 covering the guard, refusal path, old-client fallback, events, and re-resolution
|
||||
affects: [07-02 (failure-state matrix), 07-03 (_headers), launch-gate verification, any future orientation/fullscreen work]
|
||||
|
||||
# Tech tracking
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns:
|
||||
- "both-halves capability guard (method presence AND isVersionAtLeast(\"8.0\")) before every platform call, try/catch on each call, boolean best-effort return the caller ignores"
|
||||
- "one-authority re-resolution: event handlers re-run the SAME resolveSafeInsets union instead of duplicating inset math"
|
||||
- "observability-only event registration: no-op callback, try/catch-wrapped observer, category-only (no logging) per D-14"
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- web/src/telegram/fullscreen.ts
|
||||
- web/test/fullscreen.test.mjs
|
||||
modified:
|
||||
- web/src/telegram/webapp.ts
|
||||
- web/src/telegram/safe-area.ts
|
||||
- web/src/mock/telegram-mock.ts
|
||||
- web/src/route/route.ts
|
||||
- web/src/main.ts
|
||||
|
||||
key-decisions:
|
||||
- "Fullscreen is requested on the SYNCHRONOUS guidance-start transition (activateGuidance / resume), never an async callback — the transient user-activation window is exactly there (RESEARCH Pitfall 1); the boolean result is deliberately ignored at every call site"
|
||||
- "Orientation handling uses Telegram's own lockOrientation/unlockOrientation (locks the CURRENT orientation only); the DOM Fullscreen API and generic screen.orientation.lock are banned and pinned out by the FS9 source-scan"
|
||||
- "watchFullscreenEvents registered exactly ONCE, in activateGuidance only — not in resume() — so a guidance session registers one watcher; the callback is a deliberate no-op (events are observability, never correctness)"
|
||||
- "The safe-area watch call in main.ts uses the same one-shot getWebApp() as the adjacent apply line rather than the later const wa binding (avoids a forward reference; getWebApp() is idempotent)"
|
||||
|
||||
patterns-established:
|
||||
- "Capability wrapper triad (request/exit/watch) mirrors the close-protection engage/release pairing on the same lifecycle edges"
|
||||
- "Mutation-check discipline: the guard tests were verified to bite by temporarily neutering the 8.0 guard (FS2/FS5 failed under mutation, restored, green again)"
|
||||
|
||||
requirements-completed: [PX-04]
|
||||
|
||||
# Metrics
|
||||
duration: ~25 min
|
||||
completed: 2026-10-25
|
||||
---
|
||||
|
||||
# Phase 7 Plan 1: Fullscreen Capability Layer Summary
|
||||
|
||||
**Telegram-native fullscreen (Bot API 8.0 capability-guarded) at the guidance-start edge with safe-area re-resolution on rotation/fullscreen — a refusal is a silent fallback, never a guidance failure.**
|
||||
|
||||
## Performance
|
||||
|
||||
- **Duration:** ~25 min
|
||||
- **Tasks:** 4/4 completed
|
||||
- **Files modified:** 7 (2 created, 5 modified)
|
||||
|
||||
## Accomplishments
|
||||
|
||||
- **Task 1** — `TelegramWebAppLike` grew with the five 8.0-optional fullscreen members (appended after `disableClosingConfirmation?`, before `onEvent?`; no existing member changed shape) and the new `web/src/telegram/fullscreen.ts` exports exactly `requestGuidanceFullscreen` / `exitGuidanceFullscreen` / `watchFullscreenEvents`, each behind the BOTH-halves guard (method presence AND `isVersionAtLeast("8.0")`), each platform call inside its own try/catch. Zero logging (T-07-09), no DOM-fullscreen and no generic orientation lock (T-07-10).
|
||||
- **Task 2** — `watchSafeAreaChanges(wa)` in `safe-area.ts`: registers `safeAreaChanged` and `contentSafeAreaChanged` handlers that each re-run `applySafeArea(resolveSafeInsets(wa))` — the same union authority, never a duplicated computation — wrapped in try/catch (T-07-06b). `resolveSafeInsets`/`applySafeArea` behaviour untouched; no storage writes.
|
||||
- **Task 3** — the harness mock satisfies the grown contract in the same change (counters + `__isFullscreen` state; version comes from the `?mock=` profile, never hard-coded), and `web/test/fullscreen.test.mjs` landed FS1–FS9: guard halves (FS1/FS2), exact-once call (FS3), throwing-platform refusal (FS4), the exit mirror (FS5), event categories + throwing-observer containment (FS6), the old-client fallback (FS7/SC2.e), safe-area re-resolution with a finally-restored document stub (FS8), and the comment-stripped source-scan ban (FS9) asserting the banned APIs are absent AND the 8.0 guard is present.
|
||||
- **Task 4** — wiring: `requestGuidanceFullscreen` at both guidance-start edges (`activateGuidance` + `resume`, directly after `engageCloseProtection`), `exitGuidanceFullscreen` at both teardown edges (`teardownGuidance` + `stopGuidanceArtifacts`, directly after `releaseCloseProtection`), `watchFullscreenEvents` registered exactly once at the guidance-start edge with a deliberate no-op callback, and `watchSafeAreaChanges(getWebApp())` called at the `main.ts` boot site directly after the boot-time apply line. No new logging anywhere.
|
||||
|
||||
## Verification
|
||||
|
||||
- `npm run web:typecheck` — exit 0.
|
||||
- `npm test -w web` — **157 passed, 0 failed** (148 baseline + 9 new FS cases); FS1–FS9 all PASS.
|
||||
- All plan acceptance greps exact: `requestGuidanceFullscreen(` = 2, `exitGuidanceFullscreen(` = 2, `watchFullscreenEvents(` = 1, `engageCloseProtection(` = 2, `releaseCloseProtection(` = 2 in route.ts; `watchSafeAreaChanges(` = 1 in main.ts; anti-pattern grep in fullscreen.ts = 0; `console\.` = 0.
|
||||
- Mutation check: neutering the version guard made FS2/FS5 fail (the tests pin the guard), file restored, suite green again.
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
None — plan executed as written. (One cosmetic self-correction during task 1: the fullscreen.ts header comment initially named the banned API strings verbatim, which would have tripped the plan's plain-grep `documentElement.requestFullscreen|screen.orientation.lock = 0` acceptance criterion; reworded to "the DOM Fullscreen API plus the generic screen-level orientation lock" — FS9's comment-stripped scan is unaffected since it reads the code, not the prose intent.)
|
||||
|
||||
## Auth Gates
|
||||
|
||||
None.
|
||||
|
||||
## Known Stubs
|
||||
|
||||
None — no placeholder values, no unwired data paths. The `watchFullscreenEvents` no-op callback is a DESIGN decision (RESEARCH Open Question 1: the events are observability, never correctness), not a stub.
|
||||
|
||||
## Self-Check: PASSED
|
||||
|
||||
- FOUND: web/src/telegram/fullscreen.ts
|
||||
- FOUND: web/test/fullscreen.test.mjs
|
||||
- FOUND: af0c0e9 (task 1 — contract + wrapper)
|
||||
- FOUND: 95ad3ea (task 2 — safe-area watch)
|
||||
- FOUND: aec8b07 (task 3 — mock + FS suite)
|
||||
- FOUND: 5b124e0 (task 4 — edge wiring)
|
||||
Reference in New Issue
Block a user