Files
ytplayer/plans/phase6-verification.md
2026-10-09 09:11:45 +08:00

9.8 KiB

Phase 6 verification

Final product under test: 4b1f520 (Phase 5 parent 21c1273). No production requests. All historical source worktrees contain matching server and frontend revisions. The complete diagnostic waterfalls and five-run acceptance samples are committed under perf/results/phase6-*.json. KB in these tables means 1,000 bytes.

Cause and controlled trials

See phase6-investigation.md for the three-run tip comparisons, adjacent-commit bisect, rejected cache/handoff prototypes and fixes. The regressing commit is 5d6a154: LTE FCP 1,032 → 1,615 ms immediately across that cut. Phase 2/3/5 medians are 1,044/1,646/1,736 ms. Phase 4 extraction did not introduce the paint regression.

Representative WebKit/LTE sample 2, proxy times relative to tracking start: phase6-before-phase5.json versus phase6-webkit-cold-2026-10-08.json (9408ee0 owned-response diagnostic, before final loader packing). Final medians follow.

Request Phase 5 start/end ms Phase 6 start/end ms
lazy.js 250/417 250/418
styles.css 251/570 251/570
theme-classic.css 1540/1711 250/421
page app.js 1524/2273 1552/2297
first sw.js 2337/2533 2367/2564
worker app.js 2903/3651 absent
FCP 1736 905

The stylesheet becomes available before the parser applies it. The worker starts after paint. Default fetch caching was already in the modern synchronizer; force-cache and a page-to-worker HTTP-cache handoff both still transferred two app bodies in WebKit. A single page-owned response, verified and cached before boot registers the worker, removes the redundant app transfer. Controlled pages and other engines retain native external scripts; no window cache/hash lookup is added to those paths. Each retained stale app requires all shell contracts to match, enforced by the worker.

Final measurements

Exact final command (120 samples: both engines, both profiles, six scenarios, five fresh samples each):

node perf/baseline.mjs --runs 5 --browser all --profile all --scenario all --assert-cold --out perf/results/phase6-final-2026-10-08.json

Final app.js positive-byte responses are exactly one in all 20 cold samples. The earlier separate cold/regression datasets used 9408ee0 and are diagnostics, not the final acceptance build. phase6-native-auto-priority-2026-10-08.json combines that rejected intermediate sweep. Final core contract is 2: the final section-rail script now owns the loader; a stale pre-packing section script would not load app.js. No Phase 5 SHELL file was deleted. app.js and sw-update.js remain byte-for-byte unchanged.

Actual final command output excerpts:

Chromium/LTE: run 4/5... done (653267 bytes, 115 reqs, fcp=1396ms, boot=6478ms)
Chromium/lossy: run 2/5... done (653267 bytes, 115 reqs, fcp=1972ms, boot=10292ms)
WebKit/LTE: run 2/5... done (983326 bytes, 158 reqs, fcp=905ms, boot=2335ms)
WebKit/lossy: run 2/5... done (990152 bytes, 161 reqs, fcp=2748ms, boot=5046ms)

WebKit FCP targets (≤1300/3800 ms) pass. Contemporary Phase 2 three-run medians: 1044/4045 ms; its lossy samples are 4045/3218/5297, all retained. Original baseline WebKit cold wire is 1,179,624 bytes. Final LTE/lossy wire is 983,326/990,152 bytes (16.6%/16.1% lower). The final cold set transfers app.js once in both engines.

Complete final comparison

Five-run medians. Each cell is Phase 5 → Phase 6; bytes are exact body wire bytes.

Browser/profile Cold requests Cold bytes FCP ms LCP ms Boot ms Long tasks ms
chromium/lte 115 → 115 651012 → 653267 1356 → 1388 1356 → 1388 7043 → 6478 278 → 304
chromium/lossy 115 → 115 651096 → 653267 2052 → 1976 2052 → 1976 11342 → 10314 295 → 297
webkit/lte 159 → 158 1097048 → 983326 1739 → 905 1810 → 982 2315 → 2335 0 → 0
webkit/lossy 162 → 161 1105402 → 990152 4303 → 2748 4371 → 2821 5573 → 5046 0 → 0

WebKit does not expose the Long Tasks API; its zero fields mean unmeasured.

Browser/profile Warm boot ms Offline boot ms Offline reload ms Core update ms/bytes CSS update ms/bytes Feature update ms/bytes
chromium/lte 410 → 418 185 → 188 202 → 206 745/125795 → 872/126186 1380/35363 → 1388/35760 1378/33408 → 1392/33762
chromium/lossy 403 → 442 189 → 194 204 → 207 747/125795 → 805/126186 1377/35363 → 1383/35760 1375/33408 → 1386/33762
webkit/lte 83 → 88 86 → 88 100 → 102 1890/147259 → 2015/147626 1455/45659 → 1467/46254 1455/43318 → 1380/41860
webkit/lossy 85 → 89 81 → 85 95 → 98 4192/147259 → 2934/147626 3647/43705 → 3687/44211 3644/41364 → 3693/41860

Limits and exact unmet parity targets

Strict zero regression versus the recorded Phase 5 run is NOT achieved. Chromium/LTE FCP is 1388 versus 1356 ms (+32); cold bytes 653267 versus 651012 (+2255, 0.35%); long tasks 304 versus 278 ms. The verified loader, CSP permission, contract checks and metadata add code/bytes; parser insertion also changes task boundaries. The whole timing delta has not been causally isolated. Three-run contemporary Phase 5 LTE medians were FCP 1368, boot 7090 and long tasks 294 ms. Final Chrome boot improves to 6478/10314 ms (Phase 5 7043/11342).

Warm/offline/update deltas in the complete table remain explicit. Contemporary five-run Phase 5 warm boots were Chrome 426/446 and WebKit 88/88 ms; final values 418/442 and 88/89 ms. Contemporary Phase 5 core-update times were Chrome 869/799 and WebKit 1955/2776 ms; final 872/805 and 2015/2934 ms. Metadata adds roughly 0.4 KB to core updates. Periodic lossy stalls depend on request order; timing comparisons cannot establish exact parity. The extra CPU/cache work is small, but zero cost was not proved, and the positive timing deltas are not dismissed.

Every final update passed assertChangedAssets: only app.js, theme-glass.css or presenter.js is downloaded as application code, with index/API/worker metadata; fonts/icons are not re-downloaded. Whole CSS-update wire remains above 30 KB, a pre-existing Phase 5 gap. Readiness and completion remain separately measured.

Real iPhone Safari/PWA code-cache behavior, OPFS quota pressure, forced cache eviction and uninterrupted locked-screen/background audio for 30 minutes were not verified. The historical media fixture is invalid for autoplay: these are home-launch metrics, not media-start measurements. No playback code changed. Other selected layouts may prefetch 4079 unused classic CSS bytes; that preload never applies, and the selected stylesheet retains its original cascade order.

Compatibility verification on the final product

All commands below ran on 4b1f520, build 31617662d2f0:

node perf/migration.mjs --browser all --profile unthrottled --out perf/results/phase6-migration-unthrottled-2026-10-08.json
node perf/migration.mjs --browser all --profile lossy --out perf/results/phase6-migration-lossy-2026-10-08.json
node perf/hidden-timers.mjs
node perf/lazy.mjs --browser all --out perf/results/phase6-lazy-2026-10-08.json
node perf/seams.mjs --browser all
ASSET_SYNC=0 node perf/baseline.mjs --runs 1 --browser all --profile lte --scenario offline --out perf/results/phase6-sync-rollback-2026-10-08.json
ASSET_HASHING=0 node perf/baseline.mjs --runs 1 --browser all --profile lte --scenario offline --out perf/results/phase6-hashing-rollback-2026-10-08.json
node --test frontend/*.test.js
node --test perf/measurement.test.mjs
(cd server && bun install && PATH="$PWD/../perf/.tmp/test-venv/bin:$PATH" bun run test)

Actual output excerpts:

Migration unthrottled: chromium banners=1 updateReloads=1 cachedFiles=122 userInitiatedOnly=true offline=true playbackGuard=true evictionRepair=true
Migration unthrottled: webkit banners=1 updateReloads=1 cachedFiles=122 userInitiatedOnly=true offline=true playbackGuard=true evictionRepair=true
Migration lossy: chromium durationMs=25233 banners=1 updateReloads=1 legacyURLs=21 userInitiatedOnly=true offline=true
Migration lossy: webkit durationMs=22860 banners=1 updateReloads=1 legacyURLs=21 userInitiatedOnly=true offline=true
Hidden timers: Page errors: none; Result: ALL ASSERTIONS PASSED
Lazy: chromium PASS; webkit PASS
Seams: chromium checked=[shell,presenter,remote,party,share,stats] offlineNetworkRequests=0 errors=[]
Seams: webkit checked=[shell,presenter,remote,party,share,stats] offlineNetworkRequests=0 errors=[]
Frontend: tests 223; pass 223; fail 0; skipped 0
Measurement: tests 3; pass 3; fail 0
Server: sum of per-file output: 184 pass; 0 fail

Both rollback modes launched offline with zero network in Chromium and WebKit. The archived b77938a fixture was rebuilt by the migration script each time. Legacy reload remains user-initiated; its pre-existing Refresh UI timer exception is unchanged. New-page playback guards, old-client readiness, one banner, old plain/?v=oldTag/?__ytpfresh URLs, already-open old tabs and cached offline reload remain covered. Four expected WebKit disconnected API transport errors per migration were recorded and matched to failed API requests; no script errors. The seam harness's historical Phase 4 artifact was restored after saving the new output as phase6-seams-2026-10-08.json.

Self-review re-read the complete product diff and master §§3.2/3.3/6/6b. No frontend import was added to server code; no original shell file was removed; no auto skipWaiting, live stateful re-evaluation, playback edit, push or deploy. Cache responses are exact-key checked; stale bodies under a new URL are no-store and carry no decoded transport encoding. Core contract 2 blocks loader-free N-1 packing, while same-contract app fallback and executed feature pinning remain covered by both-engine smoke. Failed quota writes never delete saved music.