diff --git a/CHANGELOG.md b/CHANGELOG.md index df10d90..9111e9d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ entry per wave, newest first; the first six waves (V1–V6, the MVP) predate the are recorded in PLAN.md §B and §J. Each entry carries the opening sentence of its row and the reason the wave was built. +## V52.2 — vite-plugin-pwa 2, and a service worker that did not change by one byte of content + +The second of V52's three majors. + +_Why:_ Approved 09/10/2026 with V52. The one upgrade of the three whose failure would reach visitors rather than developers, so its proof is the artifact visitors receive. + ## V52.1 — Vitest 5, measured against Vitest 4 on the same commit The first of V52's three majors, each in its own pull request. diff --git a/PLAN.md b/PLAN.md index 32bfd57..c0b8546 100644 --- a/PLAN.md +++ b/PLAN.md @@ -619,6 +619,7 @@ before features, and the one that produces wrong data comes first of all. | **V51 — delivered** | **A store that fits on a screen.** No behaviour change, and the proof is the suite: the 906 unit tests and the 97 Chromium e2e tests that passed before pass unchanged after. **(1) `lab-store.ts`, 1 050 → 530 lines.** The 250-line `onmessage` chain becomes a dispatch table in `store/responses.ts`, one entry per `WorkerResponse` kind, typed as a mapped type so the compiler refuses a kind with no handler and a handler for a kind that does not exist. The chain's last `else` used to catch every unlisted kind as an error silently; that safety net is now a compile error instead. The bodies were moved by script, not retyped. The state shape and starting values go to `store/state.ts`, V47's stale-response fence to `store/fence.ts`, the threshold artifact builder to `store/artifacts.ts`; `lab-store.ts` keeps the actions and re-exports its public names, so no importer changed. Feature slices were considered and not done: the actions share one worker and one `send`, and slicing them would have moved code without separating anything. **(2) Tests named after waves** renamed after what they pin: `v35` → `honest-evaluation`, `v36` → `imbalance-ensemble`, `v37` → `knn-and-helpers`, `v38` → `french-numbers`, `v39` → `column-recipe`, `v40` → `quality-score`. The two mixed files (`v35`, `v36`) were renamed, not split, to keep the change mechanical. **(3) Duplicated helpers**: `numbersOf`, `missingRatio` and the binned shares, copied identically in `drift.ts` and `reference.ts`, now live once in `quality/distribution.ts`. The two quantile functions were left apart on purpose: on an empty list one returns 0 and the other NaN, and merging them would have been a behaviour change. **Measured side effect**: the coverage gate from V49 fired. The 35 branches became 35 functions, so the function denominator rose from 2 142 to 2 174 while covered functions barely moved, and the floor of 54 % failed at 53.72 %. Rather than lowering the floor, a table-driven test (`store/responses.test.ts`, 17 cases) now pins which fields each state-only answer writes, which is also the check a moved body needs; function coverage is back to 54.46 %. **What this wave deliberately does not do**: change a single handler body, split the mixed test files, or unify the quantile functions. 923 unit tests, 123 e2e. | Approved 09/10/2026 after V50. Only after V47 to V50, as the plan required: the store's concurrency rules and the metrics were pinned by tests before their code moved, so a regression in the move would have failed loudly. | | **V52 — pending** | **Major upgrades, one at a time, each measured.** Vitest 5, vite-plugin-pwa 2, TypeScript 7. Each in its own pull request with the before/after numbers that matter for it (suite time, build time, service-worker behaviour offline). | V44's rule: a major update keeps its migration cost visible. | | **V52.1 — delivered** | **Vitest 5, measured against Vitest 4 on the same commit.** The first of V52's three majors, each in its own pull request. The migration guide was read first and the repository searched for every pattern it names: no `toThrow('')`, no `sequential`, no `bench`, no removed `vitest/*` entrypoint, every `vi.mock` already at the top level of its file. Two changes could still have moved results silently, and both were measured rather than assumed. **`clearMocks` now defaults to `true`**: the 924 unit tests pass unchanged on the first run, so no test relied on calls accumulating across tests. **Coverage paths are now matched relative to the root**: the four figures move by rounding only (statements 64.93 → 64.92 %, lines 66.06 → 66.05 %, branches and functions identical; five statements fewer in the denominator), every V49 floor still met. Timing on the same machine stays inside its own noise: three coverage runs on Vitest 4 took 124 to 143 s, three on Vitest 5 131 to 134 s; plain runs 82 to 87 s on both. **Node**: Vitest 5 requires Node 22.12, so `engines` moves from `>=20` to `>=22.12` and the README says so; CI and `.nvmrc` were already on 22. **What this sub-wave deliberately does not do**: adopt Vitest 5's new options (`sharedViteServer`, artifact directory) or touch the other two majors. 924 unit tests, 123 e2e. | Approved 09/10/2026 with V52. The safest of the three majors goes first: the suite it runs is also the instrument that proves it changed nothing. | +| **V52.2 — delivered** | **vite-plugin-pwa 2, and a service worker that did not change by one byte of content.** The second of V52's three majors. The 2.0.0 release notes list two consumer-facing changes: Node 20.19 as a floor (already covered by V52.1's 22.12) and `@vite-pwa/assets-generator` 2 accepted as a peer (not used here). A service worker breaks late and on someone else's machine, so the output was compared rather than trusted. Built on the same commit with 1.3.0 and 2.0.0: **98 precache entries, 5 675.73 KiB, in both**; the same 98 URLs; `sw.js` identical once revision hashes are masked; the same Workbox runtime file down to its content hash (`workbox-2ff6bd68.js`); the web manifest byte-identical. The offline e2e test (the whole lab working after the first visit, network cut) and the update-prompt unit tests pass unchanged. **What this sub-wave deliberately does not do**: change any PWA option. 924 unit tests, 123 e2e. | Approved 09/10/2026 with V52. The one upgrade of the three whose failure would reach visitors rather than developers, so its proof is the artifact visitors receive. | V12 (consented generative chat) remains pending a product decision. No wave starts without an explicit launch command. diff --git a/package-lock.json b/package-lock.json index cf45794..91a1899 100644 --- a/package-lock.json +++ b/package-lock.json @@ -63,14 +63,14 @@ "typescript": "^6.0.3", "typescript-eslint": "^8.71.1", "vite": "^8.3.3", - "vite-plugin-pwa": "^1.3.0", + "vite-plugin-pwa": "^2.0.0", "vite-plugin-static-copy": "^4.1.1", "vitest": "^5.0.3", "wrangler": "^4.147.0", "yaml": "^2.9.1" }, "engines": { - "node": ">=20" + "node": ">=22.12" } }, "node_modules/@75lb/deep-merge": { @@ -14839,9 +14839,9 @@ } }, "node_modules/vite-plugin-pwa": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/vite-plugin-pwa/-/vite-plugin-pwa-1.3.0.tgz", - "integrity": "sha512-c5kMgN+ITrOtHXp8PAtk2uOIEea6XjP/unCGxOWWBzQ6qa65qj/awHg0wf+QF9E/2u9vh86LqxPwzEPNbM2r5A==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/vite-plugin-pwa/-/vite-plugin-pwa-2.0.0.tgz", + "integrity": "sha512-6G9dsPKT9QKYpeTuTLJM28zZL3HsXUTUM/QUZBEgQk2jbfrPJDq2i8gTewAKqi1c9Mt6MiidrL4SFI+HthiQMg==", "dev": true, "license": "MIT", "dependencies": { @@ -14852,13 +14852,13 @@ "workbox-window": "^7.4.1" }, "engines": { - "node": ">=16.0.0" + "node": ">=20.19.0" }, "funding": { "url": "https://github.com/sponsors/antfu" }, "peerDependencies": { - "@vite-pwa/assets-generator": "^1.0.0", + "@vite-pwa/assets-generator": "^1.0.0 || ^2.0.0", "vite": "^3.1.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0", "workbox-build": "^7.4.1", "workbox-window": "^7.4.1" diff --git a/package.json b/package.json index 33289ad..8778207 100644 --- a/package.json +++ b/package.json @@ -90,7 +90,7 @@ "typescript": "^6.0.3", "typescript-eslint": "^8.71.1", "vite": "^8.3.3", - "vite-plugin-pwa": "^1.3.0", + "vite-plugin-pwa": "^2.0.0", "vite-plugin-static-copy": "^4.1.1", "vitest": "^5.0.3", "wrangler": "^4.147.0",