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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,135 @@
{
"date": "2026-10-08T04:01:24.068Z",
"frontendCommit": null,
"sourceRoot": null,
"sourceCommit": "4b1f5204f8fcd207305ee50fff29985497e58e3b",
"frontendBuildTag": "bb9fea44045d",
"commit": "4b1f5204f8fcd207305ee50fff29985497e58e3b",
"runsConfigured": 1,
"browsers": {
"chromium": {
"lte": {
"offline": {
"requestCount": {
"median": 0,
"min": 0,
"max": 0,
"values": [
0
]
},
"wireBytes": {
"median": 0,
"min": 0,
"max": 0,
"values": [
0
]
},
"fcp": {
"median": 40,
"min": 40,
"max": 40,
"values": [
40
]
},
"lcp": {
"median": 40,
"min": 40,
"max": 40,
"values": [
40
]
},
"domContentLoaded": {
"median": 147,
"min": 147,
"max": 147,
"values": [
147
]
},
"bootDone": {
"median": 152,
"min": 152,
"max": 152,
"values": [
152
]
},
"reloadDuration": {
"median": 169,
"min": 169,
"max": 169,
"values": [
169
]
}
}
}
},
"webkit": {
"lte": {
"offline": {
"requestCount": {
"median": 0,
"min": 0,
"max": 0,
"values": [
0
]
},
"wireBytes": {
"median": 0,
"min": 0,
"max": 0,
"values": [
0
]
},
"fcp": {
"median": 63,
"min": 63,
"max": 63,
"values": [
63
]
},
"lcp": {
"median": 97,
"min": 97,
"max": 97,
"values": [
97
]
},
"domContentLoaded": {
"median": 93,
"min": 93,
"max": 93,
"values": [
93
]
},
"bootDone": {
"median": 99,
"min": 99,
"max": 99,
"values": [
99
]
},
"reloadDuration": {
"median": 118,
"min": 118,
"max": 118,
"values": [
118
]
}
}
}
}
}
}

View File

@@ -56,7 +56,7 @@
"disconnected": true
},
{
"message": "/127.0.0.1:38489/api/version.",
"message": "/127.0.0.1:41337/api/version.",
"disconnected": true
},
{
@@ -64,7 +64,7 @@
"disconnected": true
},
{
"message": "/127.0.0.1:38489/api/recommendations?fp=163577c02a53bc40.",
"message": "/127.0.0.1:41337/api/recommendations?fp=163577c02a53bc40.",
"disconnected": true
},
{
@@ -72,7 +72,7 @@
"disconnected": true
},
{
"message": "/127.0.0.1:38489/api/version.",
"message": "/127.0.0.1:41337/api/version.",
"disconnected": true
},
{
@@ -80,7 +80,7 @@
"disconnected": true
},
{
"message": "/127.0.0.1:38489/api/recommendations?fp=163577c02a53bc40.",
"message": "/127.0.0.1:41337/api/recommendations?fp=163577c02a53bc40.",
"disconnected": true
},
{
@@ -88,7 +88,7 @@
"disconnected": true
},
{
"message": "/127.0.0.1:38489/api/version.",
"message": "/127.0.0.1:41337/api/version.",
"disconnected": true
}
]

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,191 @@
{
"date": "2026-10-08T03:15:23.029Z",
"frontendCommit": null,
"sourceRoot": "/home/josh/development/personal/ytplayer-codex/wt-assets/perf/.tmp/phase6-merged-bootstrap",
"sourceCommit": "9408ee07e56db5bbb8319f8da862b549ab948bce",
"frontendBuildTag": "c4bb42682ab8",
"commit": "9408ee07e56db5bbb8319f8da862b549ab948bce",
"runsConfigured": 5,
"browsers": {
"chromium": {
"lte": {
"warm": {
"requestCount": {
"median": 4,
"min": 3,
"max": 5,
"values": [
4,
4,
5,
4,
3
]
},
"wireBytes": {
"median": 7990,
"min": 7979,
"max": 7990,
"values": [
7990,
7990,
7990,
7990,
7979
]
},
"fcp": {
"median": 136,
"min": 108,
"max": 144,
"values": [
140,
116,
136,
108,
144
]
},
"lcp": {
"median": 148,
"min": 136,
"max": 168,
"values": [
168,
148,
136,
156,
144
]
},
"domContentLoaded": {
"median": 409,
"min": 382,
"max": 418,
"values": [
409,
382,
418,
412,
402
]
},
"bootDone": {
"median": 425,
"min": 398,
"max": 433,
"values": [
425,
398,
433,
430,
417
]
},
"longTaskTotal": {
"median": 63,
"min": 56,
"max": 65,
"values": [
63,
65,
63,
57,
56
]
}
}
}
},
"webkit": {
"lte": {
"warm": {
"requestCount": {
"median": 0,
"min": 0,
"max": 0,
"values": [
0,
0,
0,
0,
0
]
},
"wireBytes": {
"median": 0,
"min": 0,
"max": 0,
"values": [
0,
0,
0,
0,
0
]
},
"fcp": {
"median": 92,
"min": 79,
"max": 94,
"values": [
92,
92,
87,
94,
79
]
},
"lcp": {
"median": 92,
"min": 79,
"max": 94,
"values": [
92,
92,
87,
94,
79
]
},
"domContentLoaded": {
"median": 89,
"min": 77,
"max": 92,
"values": [
89,
90,
84,
92,
77
]
},
"bootDone": {
"median": 95,
"min": 83,
"max": 98,
"values": [
95,
96,
91,
98,
83
]
},
"longTaskTotal": {
"median": 0,
"min": 0,
"max": 0,
"values": [
0,
0,
0,
0,
0
]
}
}
}
}
}
}

View File

@@ -0,0 +1,41 @@
{
"commit": "b77938a",
"results": [
{
"browser": "chromium",
"oldTag": "1175f1a1d2c1",
"newTag": "31617662d2f0",
"banners": 1,
"updateReloads": 1,
"cachedFiles": 122,
"durationMs": 25233,
"wireBytes": 631091,
"offline": true,
"legacyURLs": 21,
"profile": "lossy",
"userInitiatedOnly": true,
"playbackGuard": true,
"evictionRepair": true,
"incrementalRefresh": true,
"offlineTransportErrors": 0
},
{
"browser": "webkit",
"oldTag": "1175f1a1d2c1",
"newTag": "31617662d2f0",
"banners": 1,
"updateReloads": 1,
"cachedFiles": 122,
"durationMs": 22860,
"wireBytes": 741571,
"offline": true,
"legacyURLs": 21,
"profile": "lossy",
"userInitiatedOnly": true,
"playbackGuard": true,
"evictionRepair": true,
"incrementalRefresh": true,
"offlineTransportErrors": 4
}
]
}

View File

@@ -0,0 +1,41 @@
{
"commit": "b77938a",
"results": [
{
"browser": "chromium",
"oldTag": "1175f1a1d2c1",
"newTag": "31617662d2f0",
"banners": 1,
"updateReloads": 1,
"cachedFiles": 122,
"durationMs": 9809,
"wireBytes": 640960,
"offline": true,
"legacyURLs": 21,
"profile": "unthrottled",
"userInitiatedOnly": true,
"playbackGuard": true,
"evictionRepair": true,
"incrementalRefresh": true,
"offlineTransportErrors": 0
},
{
"browser": "webkit",
"oldTag": "1175f1a1d2c1",
"newTag": "31617662d2f0",
"banners": 1,
"updateReloads": 1,
"cachedFiles": 122,
"durationMs": 9902,
"wireBytes": 755652,
"offline": true,
"legacyURLs": 21,
"profile": "unthrottled",
"userInitiatedOnly": true,
"playbackGuard": true,
"evictionRepair": true,
"incrementalRefresh": true,
"offlineTransportErrors": 4
}
]
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,191 @@
{
"date": "2026-10-08T03:05:33.492Z",
"frontendCommit": null,
"sourceRoot": "/home/josh/development/personal/ytplayer-codex/wt-assets/perf/.tmp/phase6-native-cached",
"sourceCommit": "9408ee07e56db5bbb8319f8da862b549ab948bce",
"frontendBuildTag": "46ccefbb78f5",
"commit": "9408ee07e56db5bbb8319f8da862b549ab948bce",
"runsConfigured": 5,
"browsers": {
"chromium": {
"lte": {
"warm": {
"requestCount": {
"median": 4,
"min": 2,
"max": 4,
"values": [
4,
4,
2,
3,
4
]
},
"wireBytes": {
"median": 7996,
"min": 86,
"max": 7996,
"values": [
7996,
7996,
86,
7985,
7996
]
},
"fcp": {
"median": 124,
"min": 116,
"max": 132,
"values": [
128,
124,
116,
124,
132
]
},
"lcp": {
"median": 148,
"min": 148,
"max": 156,
"values": [
156,
148,
148,
148,
156
]
},
"domContentLoaded": {
"median": 432,
"min": 397,
"max": 464,
"values": [
464,
397,
432,
438,
413
]
},
"bootDone": {
"median": 448,
"min": 413,
"max": 482,
"values": [
482,
413,
448,
457,
430
]
},
"longTaskTotal": {
"median": 61,
"min": 58,
"max": 79,
"values": [
79,
58,
60,
70,
61
]
}
}
}
},
"webkit": {
"lte": {
"warm": {
"requestCount": {
"median": 0,
"min": 0,
"max": 0,
"values": [
0,
0,
0,
0,
0
]
},
"wireBytes": {
"median": 0,
"min": 0,
"max": 0,
"values": [
0,
0,
0,
0,
0
]
},
"fcp": {
"median": 65,
"min": 61,
"max": 66,
"values": [
66,
63,
65,
61,
65
]
},
"lcp": {
"median": 96,
"min": 92,
"max": 97,
"values": [
97,
96,
92,
93,
96
]
},
"domContentLoaded": {
"median": 93,
"min": 90,
"max": 94,
"values": [
94,
93,
90,
91,
93
]
},
"bootDone": {
"median": 98,
"min": 94,
"max": 98,
"values": [
98,
98,
94,
95,
98
]
},
"longTaskTotal": {
"median": 0,
"min": 0,
"max": 0,
"values": [
0,
0,
0,
0,
0
]
}
}
}
}
}
}

View File

@@ -0,0 +1,191 @@
{
"date": "2026-10-08T03:01:26.249Z",
"frontendCommit": null,
"sourceRoot": "/home/josh/development/personal/ytplayer-codex/wt-assets/perf/.tmp/phase6-native-parser",
"sourceCommit": "9408ee07e56db5bbb8319f8da862b549ab948bce",
"frontendBuildTag": "4ce3d20db0c7",
"commit": "9408ee07e56db5bbb8319f8da862b549ab948bce",
"runsConfigured": 5,
"browsers": {
"chromium": {
"lte": {
"warm": {
"requestCount": {
"median": 4,
"min": 3,
"max": 5,
"values": [
5,
4,
3,
4,
4
]
},
"wireBytes": {
"median": 8001,
"min": 7990,
"max": 8001,
"values": [
8001,
8001,
7990,
8001,
8001
]
},
"fcp": {
"median": 124,
"min": 120,
"max": 140,
"values": [
132,
124,
124,
140,
120
]
},
"lcp": {
"median": 156,
"min": 140,
"max": 160,
"values": [
160,
148,
156,
140,
160
]
},
"domContentLoaded": {
"median": 428,
"min": 405,
"max": 442,
"values": [
442,
428,
429,
405,
417
]
},
"bootDone": {
"median": 446,
"min": 422,
"max": 464,
"values": [
464,
446,
448,
422,
432
]
},
"longTaskTotal": {
"median": 65,
"min": 60,
"max": 79,
"values": [
79,
69,
65,
65,
60
]
}
}
}
},
"webkit": {
"lte": {
"warm": {
"requestCount": {
"median": 0,
"min": 0,
"max": 0,
"values": [
0,
0,
0,
0,
0
]
},
"wireBytes": {
"median": 0,
"min": 0,
"max": 0,
"values": [
0,
0,
0,
0,
0
]
},
"fcp": {
"median": 83,
"min": 81,
"max": 91,
"values": [
82,
91,
83,
88,
81
]
},
"lcp": {
"median": 83,
"min": 81,
"max": 91,
"values": [
82,
91,
83,
88,
81
]
},
"domContentLoaded": {
"median": 80,
"min": 79,
"max": 89,
"values": [
79,
89,
80,
86,
79
]
},
"bootDone": {
"median": 87,
"min": 86,
"max": 96,
"values": [
86,
96,
87,
93,
86
]
},
"longTaskTotal": {
"median": 0,
"min": 0,
"max": 0,
"values": [
0,
0,
0,
0,
0
]
}
}
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,28 @@
[
{
"browser": "chromium",
"checked": [
"shell",
"presenter",
"remote",
"party",
"share",
"stats"
],
"offlineNetworkRequests": 0,
"errors": []
},
{
"browser": "webkit",
"checked": [
"shell",
"presenter",
"remote",
"party",
"share",
"stats"
],
"offlineNetworkRequests": 0,
"errors": []
}
]

View File

@@ -0,0 +1,135 @@
{
"date": "2026-10-08T04:01:09.552Z",
"frontendCommit": null,
"sourceRoot": null,
"sourceCommit": "4b1f5204f8fcd207305ee50fff29985497e58e3b",
"frontendBuildTag": "2bf76ad9d08e",
"commit": "4b1f5204f8fcd207305ee50fff29985497e58e3b",
"runsConfigured": 1,
"browsers": {
"chromium": {
"lte": {
"offline": {
"requestCount": {
"median": 0,
"min": 0,
"max": 0,
"values": [
0
]
},
"wireBytes": {
"median": 0,
"min": 0,
"max": 0,
"values": [
0
]
},
"fcp": {
"median": 44,
"min": 44,
"max": 44,
"values": [
44
]
},
"lcp": {
"median": 44,
"min": 44,
"max": 44,
"values": [
44
]
},
"domContentLoaded": {
"median": 151,
"min": 151,
"max": 151,
"values": [
151
]
},
"bootDone": {
"median": 157,
"min": 157,
"max": 157,
"values": [
157
]
},
"reloadDuration": {
"median": 173,
"min": 173,
"max": 173,
"values": [
173
]
}
}
}
},
"webkit": {
"lte": {
"offline": {
"requestCount": {
"median": 0,
"min": 0,
"max": 0,
"values": [
0
]
},
"wireBytes": {
"median": 0,
"min": 0,
"max": 0,
"values": [
0
]
},
"fcp": {
"median": 68,
"min": 68,
"max": 68,
"values": [
68
]
},
"lcp": {
"median": 101,
"min": 101,
"max": 101,
"values": [
101
]
},
"domContentLoaded": {
"median": 98,
"min": 98,
"max": 98,
"values": [
98
]
},
"bootDone": {
"median": 102,
"min": 102,
"max": 102,
"values": [
102
]
},
"reloadDuration": {
"median": 118,
"min": 118,
"max": 118,
"values": [
118
]
}
}
}
}
}
}

File diff suppressed because it is too large Load Diff

42
plans/phase6-report.md Normal file
View File

@@ -0,0 +1,42 @@
# Phase 6 report
Tested `4b1f520`, from Phase 5 `21c1273`. Adjacent-commit measurements isolate
`5d6a154`: WebKit/LTE FCP 1032→1615 ms. Its selected classic CSS arrived late
(1540–1711 ms); worker installation started after paint. Fonts matched their
preloads. Default/force-cache and HTTP-cache handoff trials still transferred
app.js twice.
Shipped early classic style discovery (`e7a7cdc`), a single verified page-owned
WebKit response and specific CSP hash (`a86fa1c`, refined through `9408ee0`),
worker-owned stale-core contract protection (`97eb31e`), and native parser boot
with low-priority app preloading (`4b1f520`). The loader shares the existing final
core script; core contract 2 prevents unsafe old packing fallback. app.js,
playback and sw-update.js are unchanged.
Five-run final medians:
| Engine/profile | Phase 5→6 FCP ms | Phase 5→6 cold bytes | app bodies |
|---|---:|---:|---:|
| WebKit/LTE | 1739→905 | 1097048→983326 | 2→1 |
| WebKit/lossy | 4303→2748 | 1105402→990152 | 2→1 |
| Chromium/LTE | 1356→1388 | 651012→653267 | 1→1 |
| Chromium/lossy | 2052→1976 | 651096→653267 | 1→1 |
WebKit paint, one-body and below-baseline wire targets pass (−16.6%/−16.1%
versus original wire baseline). Phase 2 measured 1044/4045 ms over three runs.
Strict zero regression is **not achieved**: Chrome/LTE FCP +32 ms, cold bytes
+0.35%, long tasks 278→304 ms; warm boots Chrome 410/403→418/442 and WebKit
83/85→88/89 ms. Metadata adds ~0.4 KB per core update. Added loader/security
work has a cost; complete timing attribution remains unproved. Contemporary
Phase 5 controls and all offline/update deltas appear in
[phase6-verification.md](phase6-verification.md), with actual command excerpts.
Chromium cold boot improves 7043/11342→6478/10314 ms.
Migration passes both engines with/without stalls; banner once, explicit legacy
refresh, old URLs, N-1, offline and playback guards. Lazy/layout/feature seams,
hidden timers, both rollback modes, 223 frontend/184 server/3 measurement tests
pass. No fonts/icons re-downloaded. ASSET_HASHING=0 and ASSET_SYNC=0 remain.
Real iPhone install/update, quota pressure and 30-minute locked-screen audio
require owner checks. The historical fixture measures home launch, not autoplay.

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.