- Walked: 2026-05-29 by Claude against commit
eff6655269; that pass verified the repaired registration, manifest, prompt surface, and relaunch cookie in the then-current build. - Reconciled: 2026-07-18 against the current manifest/service worker, install education, native-prompt boundary, standalone launch, offline/update runtime, failure modes, push routing, and deep browser suites. This was a source reconciliation, not a fresh runtime walk.
- Verdict: partial — deep automation proves the application-controlled PWA contract from manifest assets and install-prompt handling through standalone relaunch, offline shell/read/write behavior, update coordination, Background Sync, and failure recovery. OS-level installation/uninstall, Safari Add to Home Screen, deterministic storage-quota exhaustion, and real device push permission/delivery remain platform or manual boundaries.
- Primary specs:
pwa-smoke.spec.ts,pwa-install-update-offline.spec.ts,pwa-lifecycle-deepening.spec.ts, andpwa-failure-modes.spec.ts.
Result at a glance#
| Evidence lane | Current result | Authority limit |
|---|---|---|
| Installability assets | Manifest metadata, icons, screenshots, shortcuts, mobile tags, and JavaScript service worker | Browser contract; not store/launcher review |
| Install prompt and education | Captured beforeinstallprompt, accept/dismiss/cooldown/installed states, and Safari manual copy |
Browser event is simulated; OS install UI is not automated |
| Standalone launch | Signed-in and anonymous cold launch, saved route, iOS/standard detection, and prompt suppression | Emulated standalone context, not physical launcher lifecycle |
| Offline read/write | Warm shell, uncached fallback, health/captive-portal guards, local writes, and real Background Sync | Named routes/actions; not universal offline parity |
| Service-worker update | Waiting worker, deferral, reading-safe state, refresh apply, multi-tab coordination, and cache purge | Harness-controlled worker lifecycle |
| Failure and push boundaries | Registration blocked, stuck apply, reload-loop guard, device registration, and push/click routing | Browser/API shims; no real user permission or carrier delivery |
Evidence map#
The automated contract reaches the browser/OS boundary and then continues from an emulated standalone launch. It cannot click the launcher or Safari share sheet, so those steps remain dashed rather than inferred.
flowchart LR
A[Manifest and service worker] --> B[Browser install eligibility]
B --> C[Captured install prompt]
C --> D[Accepted or dismissed app state]
C -. OS-controlled .-> E[Launcher installation]
F[Safari education] -. manual share sheet .-> E
E -. emulated boundary .-> G[Standalone cold launch]
G --> H[Offline shell and fallback]
H --> I[Local writes and Background Sync]
G --> J[Waiting-worker update]
J --> K[Deferral or coordinated apply]
K --> L[Route-preserving reload and cache purge]
Proven observations#
Install and standalone boundary#
- The document links one manifest; required icons, maskable assets, screenshots,
shortcuts, theme/display fields, mobile metadata, and
sw.jscontent type are pinned by the smoke suite. /welcome/downloadexplains Chrome/Edge/Android prompt behavior and Safari's Share → Add to Home Screen path. The shared install trigger consumes the capturedbeforeinstallpromptevent when the browser supplies it.- Accept, dismiss, 14-day cooldown, installed state, standard standalone media
query, and iOS
navigator.standalonebranches are covered. Signed-in launch restores the saved route; anonymous launch preserves it through/welcome.
Offline and update runtime#
- Warm Home, Explore, Activity, and Library routes remain available offline. An uncached deep route receives the real service-worker document fallback and hydrates explicit retry, shell shortcuts, and recent-content states.
- BFF health failure and captive-portal-shaped HTML keep the offline state honest. A valid health sentinel clears it.
- Local Library/Nisaba/Tara writes expose their current queued state. A real service-worker Arete queue survives reload, replays through Chromium Background Sync, reaches the live BFF, and drains.
- Waiting-worker prompts respect unresolved consent, standard versus reading copy, deferral, next-launch reappearance, queued writes, reduced motion, explicit refresh, controller change, multi-tab coordination, route/scroll preservation, and stale-cache purge.
Failure and push seams#
- A blocked service-worker registration leaves a usable normal-web fallback. Offline and update overlays can coexist, a stuck apply exposes manual reload, and the controller-change guard prevents repeated reload loops.
- Push-device registration and service-worker push/click routing have focused browser coverage. These tests exercise application and worker handlers, not a physical device's permission UX or external push network.
Boundaries and gaps#
- A captured prompt is not an OS installation. Playwright can drive the application event handler and accepted state, but it cannot certify launcher icon creation, OS uninstall, app settings, or browser-specific install UI.
- Safari instructions are not Safari installation evidence. Add to Home
Screen is an OS/share-sheet path with no headless
beforeinstallprompt. - Emulated standalone is not a device matrix. Media-query and
navigator.standalonebranches prove routing logic, not every Android/iOS/ desktop shell, safe-area, keyboard, orientation, and resume behavior. - Named offline paths are not universal offline parity. The suite covers core shell routes, specific cached content, and selected writes. Other dynamic pages, uploads, conflicts, and multi-user data remain online or need their own contracts.
- Queued is not synchronized. Some domain features preserve local writes without a drain; only the Background Sync action proves replay and removal.
- Harnessed update state is not every browser race. Real worker install timing, storage eviction, quota pressure, process death, and browser policy can still differ.
- Push routing is not push delivery. App registration/worker handlers do not prove user permission comprehension, APNs/FCM delivery, OS notification presentation, or production click attribution.
- Targeted checks replace a score, not product judgment. Lighthouse PWA scoring is intentionally not the release gate, while manual real-device installation remains necessary.
Re-run evidence#
The core application-controlled PWA suite can be run serially with:
bash
PW_BROWSER_CHANNEL=chrome pnpm exec playwright test \
-c apps/oshun/web/playwright.config.ts \
apps/oshun/web/e2e/pwa-smoke.spec.ts \
apps/oshun/web/e2e/pwa-install-update-offline.spec.ts \
apps/oshun/web/e2e/pwa-lifecycle-deepening.spec.ts \
apps/oshun/web/e2e/pwa-failure-modes.spec.ts \
--workers=1
Additional focused offline-write and push suites own their respective deep branches. A green run proves the browser/application PWA contract; it must not be summarized as a completed physical-device install or universal offline and push certification.
Source trail#
- Source-reconciled journey
- PWA smoke suite
- Install/update/offline suite
- Lifecycle deepening suite
- Failure-mode suite
- Web manifest
- Service worker
- PWA browser support helpers
Cross-references#
- First-time visitor result
- Offline first-use journey
- PWA update-flow journey
- PWA behavior view
- Authentication/session view
- Notifications view
Open questions#
- What recurring physical-device matrix records Chrome/Edge/Android install, Safari Add to Home Screen, launcher relaunch, safe areas, orientation, update, and uninstall behavior?
- Which routes and mutation types must join the offline contract, and how will each expose freshness, conflict, retry, and durable replay receipts?
- How will deterministic quota/eviction testing complement cross-browser manual storage-pressure sessions?
- Which production push gate covers permission UX, subscription rotation, APNs/FCM delivery, OS presentation, click routing, and revocation?
- Where should service-worker/update telemetry and versioned cache inventories be retained so real-world failures can be compared with the deterministic harness?