ef8aba3af0
## Related issue N/A — `Refactor / chore`. ## Summary The PWA landed as one squashed PR (`b6976c1b2`, #116) whose headline was installability. #116 was authored around mid-June, when "installable Omnigent on mobile" was an open problem; it merged 2026-06-30, by which point the iOS shell had shipped (#965, 2026-06-22) and the Android shell landed the next day (#1604/#1704). The native shells took over the installed-app story while the PR was in flight, and the PWA was never re-evaluated. What was left was load-bearing for one thing only — the "new version → Reload" prompt — and inert for everything else: - `web/src` had zero uses of `navigator.serviceWorker`, `caches.*`, `BroadcastChannel`, `pushManager`, `backgroundSync` or `setAppBadge`. Notifications deliberately bypass the worker (`web/src/lib/browserNotifications.ts`) and badges go through `nativeBridge.ts`. - `version.json` was emitted, precached, and read by nobody. - Installability was unadvertised (no `beforeinstallprompt`) and unmeasured (no `display-mode` checks), so the worker's one cache entry existed only to satisfy Chrome's "non-empty fetch handler" install heuristic. Web Push (#1751, P2) is the only thing that would need a worker again, and a push worker needs different handlers, VAPID keys and server infra — the retired file is not useful groundwork. ELI5: the service worker was a doorbell that only rang to say "the app has been updated". Nothing else used it, and three native apps now do the "install Omnigent" job it was built for, so the doorbell and its wiring come out. A worker already registered in a browser stays registered after we stop shipping one, so `sw.js` becomes a tombstone that removes itself: ``` deploy 0.10.0 │ ▼ browser fetches /sw.js (no-cache) → installs tombstone → parks in `waiting` │ ├─ old tab still runs old JS, shows its own update banner one last time │ user clicks Reload → SKIP_WAITING → activate │ ├─ purge omnigent-pwa-* caches │ └─ registration.unregister() │ → tab reloads, PWA-free └─ or all tabs close → activate on next visit → same cleanup, no prompt ``` Deliberately no `skipWaiting()` on install, so nobody's agent session is interrupted by an unprompted reload. The purge matches the retired worker's exact cache-name shape, `/^omnigent-pwa-[0-9a-f]{8}$/` — it only ever created `omnigent-pwa-${(hash >>> 0).toString(16).padStart(8, "0")}` — rather than clearing Cache Storage wholesale or trusting a bare prefix, so a tombstone lingering in some browser cannot delete a future feature's caches even if that feature reuses the prefix. `registration.unregister()` leaves no persistent browser state, so registering a worker at `/sw.js` again later is clean. Two things are kept for that reason: the `no-cache` header for `sw.js` in `app.py` (so a cached tombstone can never shadow a future worker) and the embed-island guard that forbids shipping any service worker into a host origin. Tombstone deletion is targeted at **0.11.0** (marked `@deprecated` in `web/sw-src/sw.js` and in the vite plugin). Not in this PR: `emptyOutDir: true` deletes old hashed chunks on deploy, the app lazy-loads most routes, and there is no `ErrorBoundary` anywhere in `web/src`, so a tab left open across a deploy can white-screen on navigation to a lazy route. The prompt was a proactive nudge, never a guard — it never prevented the 404. The gap pre-dates this change (it already applied to anyone who dismissed the banner) and the fix (ErrorBoundary + reload on failed dynamic import) is independent of the PWA, so it is filed separately. ## Test Plan - `pnpm --filter web run type-check`, `run lint`, `run build` — clean; build output contains `sw.js` only, with no `manifest.webmanifest`, no `version.json` and no `pwa-*.png` (`apple-touch-icon.png` / `favicon.svg` retained). - `uv run pytest tests/server/integration/test_app.py::test_web_ui_serves_service_worker_uncached` — passes. - `pnpm exec vitest run src/components/UpdateBanner.test.tsx` — 5 passed; confirms the similarly-named Electron desktop update banner is untouched. - Exercised the rewritten build guard against the real build output, plus eight negative cases, to prove it is not vacuous: a worker that calls `respondWith`, an unscoped cache purge, a *bare-prefix* cache filter, a worker that never unregisters, a stale `__BUILD_VERSION__` token, a re-emitted manifest, a re-emitted `version.json`, and a missing `sw.js` are each rejected. - Round-tripped the anchored cache pattern against the fingerprints the retired worker could produce (uint32 min, max and typical values all render as 8 lowercase hex chars) to confirm the tightened filter still purges every legacy cache name, while leaving unrelated names in the same namespace alone. - `uv run pre-commit run` — all hooks pass. ## Demo N/A — the only visible effect is the absence of the update banner. ## Type of change - [ ] Bug fix - [ ] Feature - [ ] UI / frontend change - [x] Refactor / chore - [ ] Docs - [ ] Test / CI - [ ] Breaking change ## Test coverage - [ ] Unit tests added / updated - [x] Integration tests added / updated - [x] E2E tests added / updated - [x] Manual verification completed - [ ] Existing tests cover this change - [ ] Not applicable ## Coverage notes `tests/e2e_ui/test_pwa_e2e.py` is deleted (it asserted live PWA behaviour) and `conftest._assert_pwa_build` is replaced by `_assert_service_worker_tombstone`, which now enforces the *dangerous* direction: the worker must unregister itself, must intercept nothing, must not purge caches it does not own, and the manifest/version sentinel must be gone. `tests/e2e_ui/test_pwa_build.py` is renamed to `test_embed_service_worker.py` and kept — "the embed island ships no service worker" outlives the PWA. Manual verification covered the parts a test cannot: the emitted build output was inspected by hand, and the guard was run against both the real output and seven mutated inputs (listed in the Test Plan) to confirm each regression is caught. The deleted unit tests covered only the removed components. ## Changelog Removed the "A new version of Omnigent is available" prompt and browser PWA install support; the desktop and mobile apps remain the installable clients. Signed-off-by: Zeyi (Rice) Fan <zeyi.f@databricks.com>
16 lines
475 B
HTML
16 lines
475 B
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
<meta name="theme-color" content="#0d1218" />
|
|
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<title>Omnigent</title>
|
|
</head>
|
|
<body>
|
|
<div id="root"></div>
|
|
<script type="module" src="/src/main.tsx"></script>
|
|
</body>
|
|
</html>
|