Explain display setup in Settings, stop iOS form zoom, lock the page behind the drawer
CI / verify (pull_request) Successful in 1m12s
CI / infrastructure-smoke (pull_request) Successful in 49s
CI / package-release (pull_request) Successful in 47s
CI / migration-smoke (pull_request) Successful in 2m18s
CI / image-build (pull_request) Successful in 1m3s
CI / deploy-smoke (same-origin) (pull_request) Successful in 49s
CI / package-publication (pull_request) Successful in 54s
CI / deploy-smoke (split) (pull_request) Successful in 3m38s

A second real-iPhone review of the Stage 1 Dashboard found three
defects. This fixes them, and ADR 0065 records the decisions.

- Settings -> Displays now sets up a screen in one place. A "Set up a
  new screen" panel shows the platform display page to open on the
  screen, a Copy link button, and Add display directly beneath it; the
  step-by-step version is folded into a <details>. The addresses come
  from a new GET /api/v1/devices/setup, which requires
  core.devices.manage and lists each running display module's
  /display/<module-id> page. Nothing names Signage. With no display
  module installed, the panel says so and offers no Add display.
- iOS Safari zoomed into the pairing field because the shared
  .ek-control rendered at 14px. On phones and touch screens it now
  renders at max(1rem, 16px). The viewport is untouched, so zoom stays
  available, and a test guards that. The shared focus trap now returns
  focus with preventScroll, so closing a dialog no longer moves the page
  under the phone header.
- While the phone drawer is open, the page behind it no longer scrolls.
  The root's overflow is hidden, a non-passive touchmove listener
  cancels drags outside the drawer's list and overscroll past its ends,
  and root overscroll is turned off. The list itself still scrolls.
  Closing restores the exact scroll position unless another page opened.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
ekklesia
2026-10-15 22:56:22 -05:00
co-authored by Claude Opus 5.5
parent 5f9b536bc6
commit 906c015ca8
20 changed files with 1072 additions and 35 deletions
+26
View File
@@ -484,6 +484,32 @@ The Stage 1 review corrections
- None of these defects showed until the product was assembled, so a change to the shell's layout
also gets a real-browser look at wide, collapsed, and phone widths in Light and Dark.
The second review's corrections
([ADR 0065](../architecture/decisions/0065-display-setup-phone-forms-and-drawer-scroll-lock.md)) are
proven here:
- `apps/api/tests/device-pairing.integration.ts` covers `GET /api/v1/devices/setup`. It names each
display page, is `no-store`, and refuses an unpaired or paired screen.
- `surfaces/shell/tests/displays-settings.test.tsx` covers the setup steps on the API origin: Copy
link with and without a clipboard, several modules, none installed, a failed read, and a refused
non-root-relative page.
- `surfaces/shell/tests/scroll-lock.test.ts` covers:
- the root locked and its previous styles restored;
- drags outside the drawer cancelled, and drags inside it allowed except past its ends;
- pinch left alone;
- the scroll position restored unless a new page opened.
- `surfaces/shell/tests/settings-navigation.test.tsx` covers the drawer locking and releasing the
page, and a wide screen never locking.
- `surfaces/shell/tests/viewport.test.ts` keeps zoom available on both shell pages.
- `packages/ui/tests/tokens.test.ts` holds text controls at 16px or more on phones and touch screens.
- `packages/ui/tests/interaction.test.tsx` checks that the focus trap returns focus without scrolling.
- The deploy smoke checks, in real Chromium:
- the setup steps on the API origin;
- the page locked behind the open drawer and released after;
- the pairing field at 16px or more on a phone.
- iOS Safari's own zoom and pull-to-refresh are not reproducible in Chromium, so a change here also
needs a look on a real iPhone.
Unit suites (`core/tests/module-storage.test.ts`, `core/tests/module-storage-lifecycle.test.ts`) use an
injected in-memory provider and never touch the network. They prove the parts the protocol cannot:
binding determinism and collision-safety, scoping and cross-module isolation, key validation, lazy