jobizzness / jobizzness/bench

A phone can run a stale bundle forever, and nothing says which one it is on

Open
#89 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
1
Forks
0
Avg merge
1h 21m
Merged PRs (30d)
41

Description

A phone can be running an arbitrarily old cockpit bundle, indefinitely, and there is no way for anyone — the developer or a specialist debugging with them — to find out which one.

## The evidence

`src/client/sw.ts:17`:

```js
/** Bumped when the shell's file list changes; old caches go on activate. */
const CACHE = "bench-shell-v1";
```

The comment describes the wrong trigger. The shell's **file list** almost never changes — it is `/`, `app.js`, `sw.js`, the stylesheet and the icons. The shell's **contents** change on every single deploy. So the cache name has been `bench-shell-v1` for the life of the project and `activate`'s cleanup (`sw.ts:64-72`, which deletes every cache whose name is not `CACHE`) has never had anything to delete.

That alone would be harmless, because `fresh()` (`sw.ts:39-52`) is network-first. The problem is the fallback:

```js
try {
const response = await fetch(request);
if (response.ok) await cache.put(key, response.clone());
return response;
} catch (unreachable) {
const kept = await cache.match(key);
if (kept) return kept;
throw unreachable;
}
```

One failed fetch — a phone launching before the radio is up, a dead spot, a timeout — and the app boots from a cached `app.js` that may be weeks old. It then keeps running that bundle for the whole session. Nothing on screen says so.

This has already cost real time. Across several rounds of "it still does X on my phone" it was never possible to tell whether the developer was seeing current code misbehaving or old code behaving exactly as it used to, and diagnosis went the wrong way more than once as a result.

## What to build

**1. A cache name that changes when the contents do.** Derive it from a build stamp written at build time rather than a hand-maintained literal. `scripts/hosted-manifest.mjs` already runs as a build step and is the natural place to generate one.

**2. A build stamp that can be read from the device.** Somewhere a developer can reach without tooling — the Settings dialog is the obvious home, beside the machine name. It needs to identify the build unambiguously (a commit sha or a build timestamp), not a version number nobody bumps.

**3. Say when the running bundle is stale.** If the service worker has fetched a newer shell than the one this page is running, the cockpit should say so and offer to reload. A cockpit silently a week behind the daemon it is talking to is the failure this ticket exists to end.

## Acceptance criteria

- [ ] The service-worker cache name changes on every build, without anyone editing a literal.
- [ ] Old caches are actually deleted on activate — verifiable by deploying twice and checking only one remains.
- [ ] The running build is identifiable from inside the app on a phone, with no devtools.
- [ ] A page running an out-of-date bundle says so rather than looking identical to a current one.
- [ ] A genuinely offline launch still gets the cached shell — do not fix staleness by removing the offline fallback, which is the reason the service worker exists (`sw.ts:3-14`).
- [ ] `pnpm typecheck` and `pnpm test` pass, with exactly #78's four failures.

## Out of scope

- #84's layout work.
- Changing the network-first strategy itself.
- Any push-notification work.

## Verification

```
pnpm typecheck
pnpm test
```

Neither proves the important half. Manual: deploy, load on a device, deploy again, and confirm the device notices — and separately, with the network disabled, confirm the app still opens on the cached shell rather than a browser error.

## Related

- #55 — proving things against a real device. Every "it still does X on my phone" round-trip in the last day would have been shorter with this in place.

Contributor guide

Open the contributing guide

Research direction

Start with src/client/sw.ts:17 and the cache lifecycle at lines 39-72, then inspect scripts/hosted-manifest.mjs to understand the build step. Trace where the Settings dialog renders device information and how the page can learn about a newer service-worker shell. Run pnpm typecheck and pnpm test, then manually verify deployment updates, stale-bundle notification, cache cleanup, and offline launch.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
build-system, devtools, frontend
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.