diff --git a/plans/phase2-plan.md b/plans/phase2-plan.md new file mode 100644 index 0000000..003ba05 --- /dev/null +++ b/plans/phase2-plan.md @@ -0,0 +1,64 @@ +# Phase 2 — incremental service-worker asset sync + +Base: `codex/phase1` at `7434f2f`; branch: `codex/phase2`. + +1. Add tests first in `frontend/asset-sync-core.test.js`, extend + `frontend/sw.test.js` / `frontend/sw-update.test.js`, and deliberately extend + `frontend/shell-consistency.test.js` and `server/static-delivery.test.js`. +2. Add pure UMD `frontend/asset-sync-core.js`: exact hashed URL planning, + group-based blocking sets (everything except explicit background groups), + contract-bump blocking, verified resumable writes, capped six-way concurrency, + three retries, missing-entry checks and changed-file N-1 retention/N-2 pruning. + Register it in `frontend/assets.json`, `frontend/index.html` and the retained + legacy SHELL. Do not include unrelated shipped test/source files in downloads. +3. Integrate in `frontend/sw.js`: persistent `ytplayer-assets` utility cache, + per-build candidate manifests, atomic active-manifest promotion on activation, + verified exact lookups, plain-URL resolution, navigation/SPA index fallback, + resumable install, honest CACHE_STATUS, and quota logging. Preserve thumbnails, + fonts, share-target handling and network-only APIs. Delete legacy shell caches + only after commit and retain verified old bytes/manifest for N-1 compatibility. +4. Integrate in `frontend/sw-update.js`: a thin sync-core refresh caller, + preserved opt-in ready fast path, and playback checks immediately before + activation and every reload callback. Keep a legacy fallback for rollback. + Never change the banner rule, update outcome logic or audio/timer machinery. +5. Required server gap: inject ASSET_SYNC mode and a versioned core-module URL + into the served worker in `server/asset-manifest.js` / `server/server.js`. + Keep served worker hash headers accurate after injection. `ASSET_SYNC=0` + selects the legacy worker install/update path; test both modes. For cold + installs, share already downloaded HTTP asset bytes without accepting stale + plain responses or weakening hash verification; report remaining URL gaps. +6. Extend `perf/migration.mjs`: actual b77938a old helper, ready:true reply, + proof no refresh re-download, exactly one banner/reload, N-1 old-tab requests, + offline boot; Chromium/WebKit, with and without `perf/proxy.mjs` stalls. + Add browser checks for interrupted downloads, eviction repair and rollback. +7. Run `perf/baseline.mjs` reduced update/cold/warm/offline measurements against + `perf/results/after-phase0-2026-10-07.json`; record requested asset paths and + compressed bytes. Acceptance: JS-only change fetches JS + index + manifest; + CSS-only change <30 KB; zero font/icon update downloads; no duplicate cold + shell transfer (or explain an evidenced gap). All required unit suites green + after each implementation commit, and browser checks pass in both engines. +8. Review full diff against master §2c/§3.2/§6b; commit a ≤350-word + `plans/phase2-report.md` with hashes, measurements, gaps and iPhone checks; + write DONE02 only after completion. No push, merge, deploy or production call. + +Risks: an install must not silently switch the active tab's manifest; incomplete +sync must not delete old data; exact hashes must not resolve to unrelated current +bytes; worker/page HTTP caches can duplicate font transfers; cache quota competes +with saved audio. Rollback preserves both schemes until its own commit succeeds. + +## Required owner decision before implementation + +The production `b77938a` helper already running in legacy tabs does not check +Player._wantsPlaying: applyUpdate sends SKIP_WAITING and schedules an unconditional +reload after four seconds. A read-only Node VM reproduction using that exact git +source with Player._wantsPlaying=true produced: +`{"wantsPlaying":true,"messages":["SKIP_WAITING"],"reloads":1}`. +A newly installed worker cannot cancel a timer in an already-running old page. +Refusing SKIP_WAITING still leaves that old timer able to reload via the old worker. + +Recommended policy: enforce the playback guarantee in all upgraded clients and +require paused playback for the one-time legacy Refresh UI migration. Legacy +migration browser tests use paused playback; already-open playing tabs are never +automatically reloaded. This explicit legacy exception needs owner clarification +because the brief states the guarantee without an exception. COMMON.md requires +QUESTION and stopping for an unanswered user-visible behavior decision.