test-web-app

test-web-app — origin migration harness

The browser half of a two-project pair used to rehearse moving a GitHub Pages app from volksswitch.github.io onto a subdomain — without stranding users who never return to the website to learn the new URL.

Repo Role
Volksswitch/test owns test.scad and its presets
Volksswitch/test-web-app (this one) the app, served from GitHub Pages

Self-contained: it depends on no files from any other project. It is trivial in function and exact in mechanism — every part that decides whether an already-installed client learns about a new deployment is copied from the real app, so the rehearsal exercises the real failure modes rather than an approximation.

Live at https://volksswitch.github.io/test-web-app/app.html

What is faithfully mirrored

Mechanism Why it matters
Cache-first sw.js with app.html in SHELL, no revalidation This is what strands users: an existing client never re-requests app.html, so it never sees a redirect
APP_RELEASE + latest_app_version.json The only channel that reaches a cache-frozen client
Two manifests on raw.githubusercontent.com, one per repo Not in the shell cache, so they reach the network from any origin — and are a separate blocking risk on filtered networks
checkForAppUpdate loop guard + 8 s cache-teardown fallback The fallback is what recovers a client when reg.update() cannot work
controllerchange-armed single reload Reloads exactly once, never mid-work
Relative start_url / scope Lets the app install cleanly on whatever origin serves it
Project folder handle in IndexedDB Origin-scoped — lost on migration unless carried across
Settings in localStorage Origin-scoped — lost on migration unless carried across

The “What survived this origin” panel reports all three storage layers directly. That panel is the instrument the whole exercise is built around.

Local testing caveat

app.html skips service worker registration on localhost, inherited from the real app. The migration behaviour therefore cannot be rehearsed locally — it only exists on a real deployed origin. Local serving is fine for checking rendering and the folder picker.

Releasing

node scripts/release.mjs          # bump by one
node scripts/release.mjs --show   # report current values

Bumps APP_RELEASE, CACHE_NAME and latest_app_version.json in lockstep, then commit and push. A release is not done until the served app.html carries the new APP_RELEASE — the manifest lags ~3.5 minutes behind (see LEARNINGS.md, Finding 2).

The plan

  1. r1 — baseline. Load it, open the project folder, set the settings, install as a PWA, then leave it alone.
  2. r2, r3 — trivial changes proving the update channel reaches a cache-frozen client.
  3. r4 — the “get ready to move” release: a timeout-guarded probe of the new host, inert until that host answers, so it is safe to ship before DNS exists.
  4. CNAME — add the file, create the DNS record, enable the custom domain, wait for the certificate. See DNS-INSTRUCTIONS.md.
  5. Verify every stranded-user bucket recovers, and measure exactly what storage survives.
  6. Port the proven logic into the real app.

Findings are recorded in LEARNINGS.md as they happen — including a genuine bug this harness already found in the real app.