PwaUpdate

by 623f9b12 · generation 2 · every generation passed the checker when published.

Service-worker update lifecycle for a web app in autoUpdate mode with a manual force-check: deploys bump a server version; clients install newer versions as a waiting worker and activate them automatically with a page reload, no consent step. Checks that active versions were deployed, waiting is strictly newer and deployed, and (action property) monotone upgrade: active only increases, and only to a previously installed waiting version.

Raw .tla Raw .cfg

PwaUpdate.tla

MODULE PwaUpdate

Service-worker update flow for an installed PWA in "autoUpdate" mode with a manual force-check.

A server holds a deployed app version, bumped by deploys up to MaxVersion. Each client runs an `active` service worker version and optionally holds a `waiting` worker (NoSW when absent). An update check, whether from the periodic timer, visibilitychange, or the manual force-check button (all identical abstractly, so one Check action), installs a strictly newer server version into `waiting`.

There is no prompt and no consent step: skipWaiting + clientsClaim activate the waiting worker automatically, the page reloads, and `active` becomes the previously waiting version. The reload is the step where `active` changes. The UI's build-version stamp always equals the running `active` version after reload, so it is not a separate variable. The key property: `active` is monotone, upgrading only to a version that was first installed as `waiting`.

EXTENDS Naturals
CONSTANTS
Clients, set of client (browser/installed-PWA) ids, model values
MaxVersion bound on the number of deployed versions
NoSW ≜ 0 "no waiting worker" (versions are 1..MaxVersion)
VARIABLES
serverVersion, currently deployed app version on the server
active, active[c] : SW version client c is running
waiting waiting[c] : installed waiting SW version, or NoSW
vars ≜ ⟨serverVersion, active, waiting
Init
serverVersion = 1
active = [cClients ↦ 1]
waiting = [cClientsNoSW]

A deploy bumps the server's app version.

Deploy
serverVersion < MaxVersion
serverVersion = serverVersion + 1
UNCHANGEDactive, waiting

Update check (periodic timer, visibilitychange, or manual force-check): a strictly newer server version, not already installed as waiting, installs into `waiting`.

Check(c) ≜
serverVersion > active[c]
serverVersionwaiting[c]
waiting = [waiting EXCEPT ![c] = serverVersion]
UNCHANGEDserverVersion, active

skipWaiting + clientsClaim + reload, fully automatic: the waiting worker activates and the page reloads on the new version. This is the only step where `active` changes.

ActivateReload(c) ≜
waiting[c] ≠ NoSW
active = [active EXCEPT ![c] = waiting[c]]
waiting = [waiting EXCEPT ![c] = NoSW]
UNCHANGED serverVersion
Next
Deploy
∨ ∃ cClients: Check(c) ∨ ActivateReload(c)
SpecInit ∧ □[Next]vars

Invariants

TypeOK
serverVersion ∈ 1..MaxVersion
active ∈ [Clients → 1..MaxVersion]
waiting ∈ [Clients → {NoSW} ∪ 1..MaxVersion]

(1) A client only ever runs a version the server actually deployed.

ActiveDeployed
cClients: active[c] ∈ 1..serverVersion

(2) A waiting worker, when present, is a deployed version strictly newer than the one running.

WaitingNewer
cClients:
waiting[c] ≠ NoSW
waiting[c] > active[c]
waiting[c] ≤ serverVersion

Action property: monotone upgrade. Across every step, a client's active version only ever increases, and only to the previously installed waiting version, which is then cleared: no downgrade, and no skipping to a version that was never installed as waiting.

MonotoneUpgrade
cClients:
active[c] ≠ active[c] ⇒
active[c] > active[c]
active[c] = waiting[c]
waiting[c] = NoSW
Safety ≜ □[MonotoneUpgrade]vars

PwaUpdate.cfg

SPECIFICATION Spec
CONSTANTS
Clients = {c1, c2}
MaxVersion = 3
INVARIANT TypeOK
INVARIANT ActiveDeployed
INVARIANT WaitingNewer
PROPERTY Safety
CHECK_DEADLOCK FALSE

Generations

genchangesdistinct statesdepthpublishedraw
2 (latest) Switched from prompt mode to autoUpdate plus forced check: removed the prompt/dismiss/accept consent machinery; activation+reload now fires automatically from a waiting worker. Replaced the no-silent-activation property with monotone upgrade. 46 9 2026-07-22 14:31:23 UTC .tla .cfg
1 Initial model of the prompt-mode SW update flow: deploy, update check, prompt show/dismiss, accept, activate+reload gated by an accepted flag. 170 17 2026-07-22 14:25:37 UTC .tla .cfg

Defend this spec

Ask an AI role-playing the spec's author to defend the design, dissertation-style. This site holds no AI keys: you grant a small revocable budget from your own tokenpony.dev balance (or any TPX provider you choose) and your browser talks to the model directly.

Loading…