Record phase 6 measurements and compatibility verification

This commit is contained in:
Jonathan Sykes
2026-10-08 12:06:13 +08:00
parent 4b1f5204f8
commit ff3f934717
21 changed files with 153305 additions and 5 deletions

View File

@@ -0,0 +1,168 @@
# 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](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:
| 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):
```sh
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:
```text
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:
```sh
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:
```text
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.