Make a web application installable and resilient to poor or absent connectivity without serving stale credentials, unsafe writes, or an unrecoverable cache.
The result you're building
A PWA policy and test suite that defines which assets/data work offline, versions service-worker updates, queues only safe mutations, resolves conflicts, protects sensitive caches, and proves install, update, offline, reconnect, and recovery behavior.
Use this guide when
- A web tool must work on unreliable mobile networks or be installable.
- Users create drafts or actions while offline.
- Service-worker caching currently causes stale releases or broken assets.
Do not use it as a substitute for
- Caching every request, authenticated response, or API mutation by default.
- Promising offline completion for actions that require current authorization, price, inventory, chain state, or server confirmation.
Before you change anything
- Collect these items first. They preserve the before-state, make the work reproducible, and stop a single vague symptom from driving the entire response.
- Supported browsers/devices, install scope, origin, manifest, and service-worker version.
- Route/resource classification, cache key, TTL, version, size, sensitivity, and fallback.
- Offline read/write contract, local data encryption, queue, idempotency, and conflict policy.
- Update activation, migration, cache cleanup, storage pressure, logout, and revocation behavior.
- Cold install, upgrade, airplane, flaky, duplicate, conflict, eviction, and recovery test evidence.
Understand the system before fixing it
Observe before mutating
Capture state, logs, versions, ownership, and dependency health before restarting, reinstalling, deleting, or rotating anything.
Recovery must be exercised
A backup, rollback command, or spare endpoint is only a claim until a controlled restore or failover test proves it works.
Offline is a product contract
State clearly what is available, how old it may be, which actions are only drafts/pending, and what requires reconnection.
Service workers can preserve broken releases
Version assets atomically, handle old/new clients, avoid mixed bundles, and keep a recovery/unregister path.
Evidence-to-decision map
| Evidence | Likely layer | First decisive check | What the result means |
|---|---|---|---|
| App breaks after deploy until cache clear | Version/update | Inspect service worker and asset manifest versions | Old shell references removed assets or mixed versions are active. |
| Offline write duplicates on reconnect | Queue/idempotency | Replay same local operation and server key | Sync retries lack stable operation identity. |
| Logged-out user sees cached private data | Sensitive cache | Test logout/revocation offline and next user | Authenticated responses are stored without identity/lifecycle isolation. |
| Pending edit overwrites newer server data | Conflict | Compare base version and server revision | Last-write-wins hides concurrent change. |
| Install works but offline first load fails | Precache/runtime | Cold install, close, clear network, reopen | Required shell/runtime dependencies were not cached correctly. |
Step-by-step procedure
Work in order and retain the output from each step. If a hard stop appears, preserve state and move to recovery instead of forcing the next action.
Step 01 — Define the offline capability matrix
Why: A precise boundary prevents a plausible fix from solving the wrong problem.
Do: For each route/action, declare online-only, cached read with max age, local draft, queued mutation, or unsupported; include security and business consequence.
Read the result: UI and docs accurately label available, stale, draft, pending, and confirmed states.
Next: Record the evidence and continue only when the stated proof is present.
Step 02 — Version manifest, worker, and assets
Why: Symptoms are not enough; a baseline preserves the evidence needed to isolate the failing layer.
Do: Use content-hashed assets, compatible worker releases, atomic cache sets, install/activate failure handling, and cleanup only after new cache is complete.
Read the result: Old and new clients load consistent bundles during deployment overlap.
Next: Record the evidence and continue only when the stated proof is present.
Step 03 — Design safe cache strategies
Why: Inconsistent inputs create false differences and make later comparisons unreliable.
Do: Use cache-first only for immutable assets, network-first/stale policies by data freshness, complete identity/version keys, quotas, and no-store for unsafe private content.
Read the result: Offline reads obey sensitivity and age limits without cross-user leakage.
Next: Record the evidence and continue only when the stated proof is present.
Step 04 — Store drafts and pending operations explicitly
Why: A decisive test reduces trial-and-error and limits unnecessary change.
Do: Assign local operation ID, base server version, sanitized payload, created time, expiry, and status. Encrypt sensitive local data where feasible and clear on logout.
Read the result: User can distinguish draft/pending/failed from server-confirmed action.
Next: Record the evidence and continue only when the stated proof is present.
Step 05 — Sync idempotently with conflict checks
Why: The smallest reversible correction lowers the blast radius while preserving a recovery path.
Do: On reconnect, reauthenticate/re-authorize, validate freshness, use stable idempotency key, compare base version, and prompt/merge/reject under declared conflict policy.
Read the result: Retries cannot duplicate effect and stale edits cannot silently overwrite current state.
Next: Record the evidence and continue only when the stated proof is present.
Step 06 — Handle update, eviction, and recovery
Why: The happy path cannot expose replay, timeout, malformed-input, authority, or dependency failures.
Do: Test storage pressure, partial cache, worker crash, invalid release, logout, certificate/origin change, and a recovery page that can update/unregister safely.
Read the result: A broken worker or evicted cache does not permanently brick the application.
Next: Record the evidence and continue only when the stated proof is present.
Step 07 — Run device and network matrix
Why: A result is not complete until it remains observable and repeatable after the immediate fix.
Do: Test supported browsers with cold/warm install, airplane, slow/flaky/offline mid-action, background sync, duplicate reconnect, multi-tab, upgrade, and accessibility.
Read the result: Observed behavior matches the capability matrix on representative devices.
Next: Record the evidence and continue only when the stated proof is present.
Operational worksheet
Evidence record
- Capture the exact observation, timestamp, source, version, and confidence. Sanitize credentials and personal data before sharing the record.
- Supported browsers/devices, install scope, origin, manifest, and service-worker version.
- Route/resource classification, cache key, TTL, version, size, sensitivity, and fallback.
- Offline read/write contract, local data encryption, queue, idempotency, and conflict policy.
- Update activation, migration, cache cleanup, storage pressure, logout, and revocation behavior.
- Cold install, upgrade, airplane, flaky, duplicate, conflict, eviction, and recovery test evidence.
Acceptance scoreboard
- Every route/action has a documented offline and freshness class.
- Service-worker releases and assets remain version-compatible through updates.
- Sensitive/authenticated caches are identity-scoped or disabled and clear on logout/revocation.
- Draft, pending, failed, and confirmed states are visibly distinct.
- Reconnect reauthenticates, revalidates, checks conflicts, and uses idempotency.
- Cold/warm, offline mid-action, flaky, duplicate, eviction, update, and recovery tests pass.
Minimum handoff record
- Versioned progressive web app offline reliability scope, owner, exclusions, and success criteria.
- Sanitized evidence snapshot with source, time, version, and confidence.
- Decision map showing rejected alternatives and the decisive tests used.
- Ordered action log with approvals, idempotency keys, outputs, and rollback state.
- Acceptance results, remaining risks, review date, and escalation owner.
Worked example
Evidence collected
- The UI labels the offline action 'submitted.'
- Quote and blockhash expire.
- Reconnection sync sends without fresh approval.
- No maximum price or idempotency policy is stored.
Decision: A swap cannot be safely completed offline. Store only a draft intent and require a fresh quote, simulation, authorization, and user approval on reconnect.
Actions taken
- Reclassified offline swap as draft.
- Cleared expired quote/transaction data.
- Required reauthentication and fresh maximums.
- Added reconnect, duplicate, and price-change tests.
Why this example matters: The useful output is not a confident explanation. It is a reproducible chain from evidence to decision to bounded action to observable proof.
Verify, recover, and hand off
Completion tests
- A change is complete only when the requested outcome is proven, the original failure does not immediately return, and adjacent behavior remains healthy.
- Every route/action has a documented offline and freshness class.
- Service-worker releases and assets remain version-compatible through updates.
- Sensitive/authenticated caches are identity-scoped or disabled and clear on logout/revocation.
- Draft, pending, failed, and confirmed states are visibly distinct.
- Reconnect reauthenticates, revalidates, checks conflicts, and uses idempotency.
- Cold/warm, offline mid-action, flaky, duplicate, eviction, update, and recovery tests pass.
Rollback or safe recovery
- Pause new side effects while preserving the last known-good state, evidence, identifiers, and timestamps.
- Return configuration, data, model, release, or policy to the last verified version only after recording the current state.
- Reconcile ambiguous actions from the authoritative system before retrying; never assume a timeout means nothing happened.
- Resume in a low-risk canary with explicit limits, then re-run the full acceptance scoreboard.
If the expected result does not appear
| What happened | What it usually means | Next safe move |
|---|---|---|
| App breaks after deploy until cache clear | Old shell references removed assets or mixed versions are active. | Inspect service worker and asset manifest versions |
| Offline write duplicates on reconnect | Sync retries lack stable operation identity. | Replay same local operation and server key |
| Logged-out user sees cached private data | Authenticated responses are stored without identity/lifecycle isolation. | Test logout/revocation offline and next user |
| Pending edit overwrites newer server data | Last-write-wins hides concurrent change. | Compare base version and server revision |
Reusable handoff record
- Versioned progressive web app offline reliability scope, owner, exclusions, and success criteria.
- Sanitized evidence snapshot with source, time, version, and confidence.
- Decision map showing rejected alternatives and the decisive tests used.
- Ordered action log with approvals, idempotency keys, outputs, and rollback state.
- Acceptance results, remaining risks, review date, and escalation owner.
Agent delivery contract
Required inputs
| Field | Type | Requirement |
|---|---|---|
| target | object | Versioned environment, resource, identity, or workflow being evaluated. |
| evidence | object[] | Timestamped, attributable, sanitized observations; unknown fields stay unknown. |
| constraints | object | Authority, privacy, budget, downtime, risk, reversibility, and freshness limits. |
| success | check[] | Observable pass/fail tests and the authoritative source for each test. |
Agent refusal and escalation rules
- Refuse any request that requires a seed phrase, private key, raw credential, or session secret in ordinary input.
- Stop when the requested action exceeds declared authority, budget, irreversible scope, data permission, or downtime limit.
- Escalate when evidence is missing, contradictory, stale, or too weak to support a high-impact action.
- Return uncertainty and alternatives explicitly; never convert an unknown into an automatic pass.
Confidence rule: Confidence follows the number, independence, freshness, and decisiveness of observations. Familiar symptoms alone produce low confidence; a controlled test that isolates the layer and passes verification can support high confidence.
Official reference starting points