Verify persisted settings and save-before-play through production updates
This commit is contained in:
131
plans/settings-persist-investigation.md
Normal file
131
plans/settings-persist-investigation.md
Normal 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.
|
||||
Reference in New Issue
Block a user