Verify persisted settings and save-before-play through production updates

This commit is contained in:
Jonathan Sykes
2026-10-09 15:09:09 +08:00
parent 0b8e398469
commit ea221a4e90
6 changed files with 1684 additions and 0 deletions

View File

@@ -0,0 +1,131 @@
# Persisted settings across production updates
## Result
No Phase 1–5 persistence regression was reproduced. No runtime fix or breaking
commit is justified. The old b77938a shell (verified tag `1175f1a1d2c1`) upgraded
through its own banner/Refresh UI flow at the same origin to current main
`cf27d4f15a29747123437862ab4e461fd78178e6`. All 24 existing setting keys and all 14 checked controls were preserved
on Chromium and WebKit. The original worktree base/live deployment snapshot
`0b8e398` was also tested separately: both engines preserve the same 24/24 keys,
controls, profile/import policy; Chromium again saves and plays the complete
clip before/after. This avoids conflating concurrent main changes.
Both servers are actual archived Bun implementations, with isolated DB/media
directories. A local proxy supplies deliberately older profile copies and blocks
profile writes; no credentials or real online profiles are used. Settings values
were set using real controls/change handlers, and EQ using its actual preset
button. The installed page was reloaded before recording its exact `_ytpdata`
JSON; old/new raw snapshots are in the results file. Refresh UI and import use
the existing button handlers via `.click()` on the DOM element: physical
Playwright hit-testing was obstructed by the bottom nav at large font size.
This tests persistence/update handlers, not modal pointer geometry.
## Every-key comparison
Values below are identical on both engines; no key was removed or reset.
| Key | Old (after reload) | Upgraded | Status |
| --- | --- | --- | --- |
| quality | `"360p"` | `"360p"` | same |
| volume | `1` | `1` | same |
| audioOnly | `false` | `false` | same |
| autoPreload | `true` | `true` | same |
| p2pShare | `true` | `true` | same |
| p2pReceive | `true` | `true` | same |
| saveBeforePlay | `true` | `true` | same |
| repeatMode | `"all"` | `"all"` | same |
| loopOne | `true` | `true` | same |
| shuffle | `false` | `false` | same |
| theme | `"light"` | `"light"` | same |
| fontScale | `"large"` | `"large"` | same |
| levelVolume | `false` | `false` | same |
| liveAudioIOS | `false` | `false` | same |
| parallelSaves | `2` | `2` | same |
| density | `"compact"` | `"compact"` | same |
| perfMode | `true` | `true` | same |
| reduceMotion | `true` | `true` | same |
| layout | `"f7-swipe"` | `"f7-swipe"` | same |
| autoBackupEnabled | `false` | `false` | same |
| autoBackupIntervalDays | `7` | `7` | same |
| serviceVideo | `false` | `false` | same |
| foldedCards | `{}` | `{}` | same |
| eq | `{"preset":"bass","g":[5,7,5,3,1,0,0,0,0,0]}` | `{"preset":"bass","g":[5,7,5,3,1,0,0,0,0,0]}` | same |
Save before playing and Auto-save playlist videos stayed ON; audio-only OFF.
Quality stayed 360p, layout f7-swipe, loop/repeat ON, light theme, large font,
compact density, performance/reduced motion ON and two parallel saves.
The tested b77938a build already has ten-band EQ, so its Bass boost curve was
unchanged. The five-band compatibility migration in app.js was not triggered.
## Behaviour and alternative overwrite paths
Chromium saved the complete 30,290-byte H.264/AAC clip before and after the
upgrade, set cachedIds, used an OPFS blob source, reached readyState ≥3 and
advanced playback time. The existing copy was deleted before the second open
to force a genuinely new post-upgrade download. Linux WebKit reports native
OPFS unsupported on both builds; preservation/UI checks pass but successful
native storage/playback there is not claimed or shimmed.
Profile tests exercise the launch path with `syncedAt:200`:
| Server updatedAt | Server Save before playing | Device result, both engines |
| ---: | --- | --- |
| 100 | false | Local true and every local setting retained |
| 300 | false | Server false adopted; layout classic and defaults/remote values applied |
A copy with old *values* but a newer timestamp can therefore disable autosave.
This is existing last-write-wins behavior, not an update migration regression:
`pullProfileIfNewer()` and `applyProfileData()` at b77938a already implement the
same timestamp comparison and whole-settings replacement. Equal timestamps
also retain local settings (unit test). A genuine older timestamp cannot reset
local settings in these tests.
`API.loadData()` reads localStorage in web mode; boot overlays loaded.settings
on DEFAULT_SETTINGS. Phase 4 extraction does not create a second data object.
The Phase 3 head loader only reads `_ytpdata` and sets appearance attributes;
it never writes settings. `syncOnLaunch()` invokes profile reconciliation
after the first render. `/api/user/data` was monitored/mocked with false
autosave settings and received zero requests: fingerprint sync is not a settings
pull at launch. `saveDataToStorage()` pushes metadata to `/api/user/sync`,
without a settings field.
Importing a backup containing opposite settings through the actual file input
and Import button preserved the current settings. `importBackup()` merges
playlists/history/positions but does not apply `imp.settings`. Intentional
profile adoption/share-link loading uses `applyProfileData()` and *does* replace
settings; this is already documented on the existing confirmation UI.
## Verification
```sh
node perf/settings-persist.mjs --browser all --target main --allow-unsupported-webkit
node perf/settings-persist.mjs --browser all --target 0b8e398 --allow-unsupported-webkit --out perf/results/settings-persist-live-base.json
node --test frontend/*.test.js
(cd server && bun install && bun run test)
```
Without `--allow-unsupported-webkit`, unverified native WebKit storage exits 2.
Any assertion failure exits 1 even with that allowance. The server-side proxy
is essential: WebKit worker network requests bypass page-route mocks.
The two shared Chromium Settings errors (`null.addEventListener`) are recorded
in the results; they already occur on the old build. They did not stop the
playback/autosave handlers from persisting or saving. This is not an assertion
that every Settings interaction is error-free.
Only tests, harness and documentation changed; no runtime implementation or
save behavior changed. A phase bisect and failing-then-fixed runtime test cannot be supplied
honestly because no setting loss was reproduced on either target.
## Phone checks
On the installed PWA, inspect Settings → Playback → Save before playing, ensure
Audio-only is OFF and no explicit streaming override is selected. Auto-save
playlist videos is a separate policy. Check the linked profile and whether
another device/imported profile pushed a newer copy with the toggle OFF.
Compare settings before/after an online launch. Re-check origin/PWA identity,
iOS Clear Website Data/storage eviction/private mode, free quota and Downloads
failure details. Native iPhone OPFS, suspension, quota sharing and storage reset
remain unverified by Linux WebKit. A phone-side failing sequence/settings export
is needed before changing the sync policy or save logic.