Skip to content

Remove managed data from the Setup screen - #79

Merged
RobbinBouwmeester merged 1 commit into
mainfrom
feat/remove-managed-data
Sep 11, 2026
Merged

RobbinBouwmeester merged 1 commit into
mainfrom
feat/remove-managed-data

Conversation

@RobbinBouwmeester

Copy link
Copy Markdown
Member

Uninstalling MuMDIA left everything the application had downloaded or built behind, with nothing in the interface that could remove it. Measured on one development machine: 8.9 GB.

Item Size Written by
python\ 4.7 GB the managed Python environment
libraries\ 4.3 GB the DIA-NN predicted-library cache
configs\, diann.json, console-*.txt 8 KB settings and remembered paths

An MSI removes exactly what it placed under Program Files. All of the above is written at runtime under %LOCALAPPDATA%\MuMDIA (or ~/.local/share/MuMDIA), so the installer has no record of it.

Why not an uninstaller action

  • An upgrade reinstalls over the same data directory and reuses a several-hundred-megabyte download and a library cache that costs hours to rebuild.
  • An MSI "uninstall" also runs during some upgrade paths, so a silent delete would throw away a predicted spectral library as a side effect of a version change.

Leaving the files is the right default; having no way to remove them was the bug.

What this adds

A Managed data card at the bottom of the Setup screen. components::inventory lists what exists, item by item, with the bytes each occupies; each row names the exact paths and takes two clicks. Six items: primary, ms2pip, thermo, diann, libraries, settings.

Every directory name now comes from a constant exported by the module that writes there (components::THERMO_DIR_NAME, diann::MANAGED_DIR_NAME, diann::LIBRARY_CACHE_NAME, diann::STATE_FILE_NAME, settings::CONFIG_DIR_NAME), so a rename cannot leave something behind that nothing offers to remove.

Safety

This is a recursive delete driven by a string from the frontend, so:

  • remove_in resolves the real parent directory and refuses anything resolving outside the data directory. Canonicalising the item itself would follow a link and delete its target, which is why the check is on the parent;
  • a symbolic link is refused outright, since the application creates none there;
  • an id that is not one of the six fails before the disk is touched;
  • components_remove refuses entirely while a search, an installation or a library build is running, because those hold the files it would delete. A poisoned lock counts as busy.

Each install tracker gains a forget. Their terminal done is sticky on purpose so a caller polling for it cannot miss the transition; without forget, a removed component went on reporting itself installed until the application restarted.

Sizing the folder walks every file in a Python environment, so the card refreshes when the Setup screen is opened, after a removal, and once when an installation finishes. Never on the 900 ms installation poll, and not at startup.

Validation

  • cargo fmt --check, cargo clippy --all-targets -D warnings, cargo test --lib: 87 passed (83 before; four new tests cover listing, removal, the refusal of unknown ids and the absent-path size).
  • Two concurrent cargo test runs in separate target directories, both 87 passed, which is the check the earlier shared-temp-dir flakes need.
  • ci/check_desktop_ui.py: 114 element ids, 32 commands, both directions agree. ci/check_doc_refs.py clean. node --check desktop/ui/app.js.
  • Read-only check against the real installation on this machine: all six item definitions resolve, they account for 8.79 GB, and no file in the directory is left uncovered.

Not exercised: the card has no browser-level test, so the rendering and the two-click flow want one manual pass in a rehearsal build. Nothing was deleted from the development machine during this work.

🤖 Generated with Claude Code

Uninstalling MuMDIA left everything the application had downloaded or built
behind, with nothing in the interface that could remove it: 8.9 GB on one
development machine, of which 4.7 GB was the managed Python environment and
4.3 GB the predicted-library cache. An MSI removes exactly what it placed under
Program Files, and all of this is written at runtime under %LOCALAPPDATA%\MuMDIA
(or ~/.local/share/MuMDIA).

Deliberately not a WiX uninstall custom action. An upgrade reinstalls over the
same data directory and reuses that download and that cache, an MSI uninstall
also runs during some upgrade paths, and a spectral library is hours of
prediction rather than a download, so a silent delete there would destroy real
work as a side effect of a version change.

The Setup screen gains a "Managed data" card instead. `components::inventory`
lists what exists item by item with the bytes it occupies, each row names the
exact paths, and removal takes two clicks. The six items are primary, ms2pip,
thermo, diann, libraries and settings; every directory name now comes from a
constant exported by the module that writes there, so a rename cannot leave
something behind that nothing offers to remove. Checked against a real
installation: every file present is covered by an item.

Two safety properties, both tested. `remove_in` resolves the real PARENT
directory and refuses anything resolving outside the data directory, and
refuses a symbolic link outright, because this is a recursive delete driven by
a string from the frontend; canonicalising the item itself would follow a link
and delete its target. `components_remove` refuses entirely while a search, an
installation or a library build is running, since those hold the files it would
delete, and a poisoned lock counts as busy.

The install trackers keep a terminal `done` on purpose so a caller polling for
it cannot miss the transition, so each of them gains a `forget`; without it a
removed component went on reporting itself installed until the application
restarted.

Sizing the folder walks every file in a Python environment, so the card
refreshes when the Setup screen is opened, after a removal, and once when an
installation finishes, never on the 900 ms installation poll.

Desktop tests 83 -> 87, and two concurrent `cargo test` runs both pass, which
is the check the earlier shared-temp-dir flakes need.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@RobbinBouwmeester
RobbinBouwmeester merged commit da1c9b3 into main Sep 11, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant