Skip to content

pwa(updates): make service-worker upgrades transactional, multi-client safe & edit-loss-proof #485

Description

@qnbs

Parent

Part of #478 — PWA first-class excellence/hardening.

Why this matters

A PWA can update much faster than packaged native software, but that advantage becomes dangerous if a new Service Worker/app shell activates while users have dirty editors, old IndexedDB schemas, local-AI workers, or multiple tabs alive.

The differentiator should be rapid updates without sacrificing writing-session durability.

Core invariant

A PWA update may never knowingly discard acknowledged edits or create an app-code/storage-schema combination that the product has not admitted.

Do not use unconditional skipWaiting() + reload semantics as a substitute for an update protocol when dirty clients exist.

Proposed update state machine

NO_UPDATE
→ UPDATE_DISCOVERED
→ DOWNLOADED_WAITING
→ CLIENTS_ASSESSED
→ SAFE_TO_ACTIVATE | USER_ACTION_REQUIRED
→ ACTIVATING
→ RELOADING/RECONNECTING
→ VERIFIED
→ RECOVERY_REQUIRED (exceptional)

Persist only the minimal metadata needed for recovery/troubleshooting; the Service Worker must not become project-data authority.

Client coordination

Use clients.matchAll() plus the typed multi-context coordination layer from #480 where appropriate.

Before activation determine:

  • number of live clients;
  • dirty/unsaved project state;
  • active storage migration;
  • active backup/export critical section;
  • local-AI/model download state where interruption matters;
  • whether new code requires a storage migration incompatible with old clients.

A background tab must not silently force all other tabs to reload.

Update UX

Safe immediate update

If no dirty/critical state exists:

  • show lightweight “Update ready”;
  • allow Update now;
  • optionally activate at next clean launch according to policy.

Dirty session

If acknowledged edits or critical work exist:

  • clearly show update is waiting;
  • offer Save & update after confirmed durable save;
  • offer Later;
  • never fake a successful save merely to activate.

Multiple clients

Explain when another WorldScript window is preventing activation. Coordinate rather than racing.

Schema/version compatibility

Define an app-code/storage compatibility contract.

Examples:

  • current and previous shell may coexist only if schema/API compatibility allows it;
  • irreversible migration cannot begin while old incompatible clients remain admitted;
  • migration journal/version identifies recovery state;
  • new client encountering old schema follows a tested migration path;
  • old client encountering newer incompatible schema fails safely rather than writing stale structures.

Coordinate with existing IndexedDB encryption migration/journal architecture; do not create a second conflicting migration authority.

Cache strategy

Separate:

Never cache sensitive AI prompts/responses or credential-bearing URLs.

Large local-AI artifacts must not be invalidated merely because the app shell version changes unless compatibility requires it.

Failed update recovery

Exercise:

  • missing/corrupt new asset;
  • activation succeeds but navigation fails;
  • user goes offline between download and activation;
  • storage migration fails;
  • stale waiting worker;
  • old cache remains;
  • browser kills a client mid-update.

Recovery should prefer a known-valid cached shell when safe, or provide a deterministic recovery screen that preserves local project data.

Do not recommend “clear site data” before export/recovery options.

Deployment parity

WorldScript has GitHub Pages and Vercel surfaces. Validate:

  • correct Service Worker scope/base path;
  • update discovery on both;
  • asset URL/base-path behavior;
  • navigation fallback;
  • no deployment-specific stale-cache trap;
  • version/build identity visible for diagnostics.

CI / automated evidence

Build a deterministic browser test harness for:

  1. install version N;
  2. create/edit project and cross save boundary;
  3. publish/simulate version N+1;
  4. discover waiting worker;
  5. exercise dirty and clean clients;
  6. activate;
  7. verify edits and project reopen;
  8. repeat with multiple tabs;
  9. repeat offline during activation;
  10. repeat with a representative schema migration fixture.

Also statically test generated precache composition/policies where practical.

Acceptance criteria

  • Explicit PWA update state machine exists.
  • Dirty clients block unsafe activation/reload.
  • Multiple clients coordinate activation.
  • App-code/storage-schema compatibility is explicit.
  • Provider/AI sensitive traffic is never runtime-cached.
  • Large model artifacts have independent lifecycle from app-shell caches.
  • Failed/interrupted updates preserve recoverable project state.
  • Pages and Vercel update behavior are smoke-tested.
  • Automated N→N+1 lifecycle tests exist.
  • User never needs destructive site-data deletion as normal update recovery.

Non-goals

  • delaying every update until all tabs are closed forever;
  • forcing immediate reload;
  • making Service Worker the storage migration authority;
  • caching AI/provider traffic for perceived offline support;
  • invalidating all origin storage on each release.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions