Fix: a new install no longer resets settings the user changed - #427
Merged
Conversation
added 2 commits
August 24, 2026 09:36
Reproduced against the published 0.14.0 package: relocate the stems folder in Settings, extract the same release into a fresh folder, and the new install reports the default folder again. The library looks empty even though every stem is still on disk where the user put it. Cause: portable packages keep their data in <app>/data (#399), so settings.json lives INSIDE the install directory. A new install is a new folder, so it starts with an empty data/ and loses everything the user set -- not just the stems location but the port, compute device, separation quality and language too. The restore half of the fix was already in the working tree: migrate_persisted_files plus an ensure_workspace step that seeds a freshly extracted portable package from a per-user copy. What was missing was anything writing that copy. Nothing had, since #399 moved the data directory out of %LOCALAPPDATA% and no writer took over the old location, so the restore read a path that never existed. This adds the write half: - shared_settings_dir() names the per-user location once, for all three platforms. Deliberately the OS-standard data dir -- exactly what local_data_dir() returns for a NON-portable install -- so both layouts share one location and an install that switches between them keeps its settings. - start_backend passes it as STEMDECK_SETTINGS_MIRROR, so the writer and ensure_workspace's reader cannot drift apart. - settings._save() mirrors there after each successful write. Best-effort by construction: it is a redundant copy and must never fail the setting the user just changed. Written via a temp file and replace, because a torn write would be restored verbatim into the next install. Verified end to end against the source backend: relocate the folder in install A, seed install B the way ensure_workspace does, and B reports the user's folder rather than the default. Five tests cover the write half, including that a mirror which cannot be written still saves the setting. Also carries the clippy cleanups already sitting in the tree (derivable Default, match to if let, redundant trim, unneeded return, unused binding) -- audit item F12. Both platforms compile with no warnings; 45 Rust tests on Windows, 46 on Linux, and the Python suite has no new failures against main.
Mirroring only on save left out the people most likely to be bitten: someone who relocated their stems folder in an earlier release and never opens Settings again never triggers a save, so no per-user copy is ever written and their next fresh extract still starts from defaults. Seed the copy on first load instead, from settings that are already on disk. Guarded so an empty state (a genuine first run) can never overwrite a good copy, which would destroy the very thing being preserved. Also pins the Unraid template at 0.14.1.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Confirmed, reproduced, fixed
Reproduced against the published 0.14.0 package, not a local build:
The library looks empty even though every stem is still on disk where the user put it.
Cause
Portable packages keep their data in
<app>/data(#399), so settings.json lives inside the install directory. A new install is a new folder, so it starts with an emptydata/and loses everything the user set — not just the stems location, but the port, compute device, separation quality and language too.The restore half was already in the working tree:
migrate_persisted_filesplus anensure_workspacestep that seeds a freshly extracted portable package from a per-user copy. What was missing was anything writing that copy. Nothing had, since #399 moved the data directory out of%LOCALAPPDATA%and no writer took over the old location — so the restore was reading a path that never existed. On this machine%LOCALAPPDATA%\StemDeckdid not exist at all.The write half
shared_settings_dir()names the per-user location once, for all three platforms. Deliberately the OS-standard data dir — exactly whatlocal_data_dir()returns for a non-portable install — so both layouts share one location and an install that switches between them keeps its settings.start_backendpasses it asSTEMDECK_SETTINGS_MIRROR, so the writer andensure_workspace's reader cannot drift apart.settings._save()mirrors there after each successful write. Best-effort by construction: it is a redundant copy and must never fail the setting the user just changed. Written via temp-file-and-replace, because a torn write would be restored verbatim into the next install.Verified
End to end against the source backend — same scenario that reproduced the bug:
Five tests cover the write half, including that a mirror which cannot be written still saves the setting, and that the mirror tracks later changes (a stale copy would hand back a setting the user had already changed — the same class of bug as losing it).
Python: ruff clean, and no new failures — identical 14 pre-existing Windows-environment failures on
mainand this branch.Also included
The clippy cleanups already sitting in the working tree (derivable
Default,matchtoif let, redundanttrim, unneededreturn, unused binding) — audit item F12. Mechanical, and both platforms compile with zero warnings.Note on scope
This fixes the manual upgrade path, which is what was reported. The in-app updater added in #423 never had this problem: it replaces
backend/and the executable while leavingdata/untouched, so settings already survive that route.