Files
ytplayer/plans/settings-persist-investigation.md

132 lines
6.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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.