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

6.8 KiB
Raw Blame History

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

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.