Windows: fix cleanup guard, expand app-cache catalog, refine cleanup UI - #17
Merged
Merged
Conversation
Add a roaming-app-data locator root (%APPDATA%) to the schema, platform adapters and resolver, plus 14 evidence-backed rules for Windows app caches: JetBrains IDEs and Toolbox, Android Studio, Dart pub, VS Code, Chrome/Comet, Discord/Notion/Antigravity, Epic and Steam, and Windows crash dumps and temp. Restamp the catalog review date to 2026-08-30 and update the golden rule list (15 -> 29).
normalize_roots, the safe-cleanup plan, the exclusion collapse and the JSON scan-roots test assumed Unix path spellings and failed on Windows because of verbatim \\?\ prefixes and drive-relative roots. Compare canonical forms and assert absoluteness portably so the suite is green on every platform.
Anchor owning_root and the guard on the canonical scan roots so cleanup no longer refuses every item on Windows, and strip the verbatim \\?\ prefix for display only (deep paths keep it). Hide zero-value recovery segments, replace the footer Disks label with a category-wide Select all, stack the severity filters as a left-aligned vertical column so no locale stretches them, and give the empty screen a prominent green Scan button.
Hide the Automatic / Rebuild / Manual filter tabs when no finding has that recovery class, and fall back to All if the active filter's class disappears, so the sidebar never offers an empty tab.
The recovery-class filter row is meaningless before a scan, so keep it out of the pre-scan sidebar and show it only once findings exist.
Re-run guard::check immediately before the destructive call so a path that became a reparse point, a protected location or an escape after the first check is refused rather than acted on. Add paranoid tests for the exact TOCTOU race: a validated directory whose own path is swapped for a junction (Windows) or symlink (Unix) before removal must fail the captured-identity re-check and leave the swap target untouched.
Add a line to the cleanup result making the safety contract explicit — items were moved to the Trash/Recycle Bin and recovery is handled by the operating system, not erased. Localized across all ten locales.
Only TableBuilder is used and PNG assets decode through `image` directly, so the image/svg loader features were dead weight. Dropping all_loaders removes resvg/usvg/ttf-parser and one quick-xml consumer (~33 crates), trimming build time and attack surface. The remaining quick-xml advisory (RUSTSEC-2026-0194/0195) is a Linux-only accessibility (AT-SPI) transitive dep parsing local D-Bus XML and is not reachable on Windows; a full bump needs a newer eframe/accesskit and is left as a separate change.
The scanner canonicalizes its roots for guard safety, which on Windows hands every walked entry to the classifier as a verbatim `\?\C:\...` path. Every rule table — catalog `exact` targets, `$HOME`-relative rules, group rules — is built from plain `C:\...` roots, so `path_eq`, `strip_prefix(home)` and `is_under` all silently failed and the entire home-anchored catalog matched nothing on Windows. Only filename-based marker rules (node_modules, __pycache__, ...) survived, which is why real caches such as ~/.cache/huggingface (13 GB) or %LOCALAPPDATA%\.dartServer never appeared in a scan. Normalize the incoming path once at the classifier boundary (RuleEngine::classify_with_metadata and classify_group) by stripping the verbatim prefix, so matching sees the same spelling the tables use while the untouched real path is still what the finding reports. Add a cross-platform regression test that feeds a verbatim-prefixed path and a unit test for the stripping itself.
…ache Ground three large, previously-missed developer caches in real disk data (measured on a Windows dev box): - Flutter/Dart `build/` (hundreds of MB per project): the `dist`/`build` marker arm only fired on package.json/pyproject.toml/CMake evidence, so Flutter output next to `pubspec.yaml` was skipped. Add a dedicated arm. - `.dartServer` (~1.3 GB): the Dart Analysis Server cache dart.dev documents at %LOCALAPPDATA%\.dartServer; rebuilt on the next launch, so automatic recovery / auto-cleanable. - `~/.cache/huggingface` (~13 GB here): Hugging Face Hub model/dataset cache, re-downloaded on demand; review-required because a refetch can be many gigabytes. Each rule carries a real HTTPS provenance source. Update the golden rule list and count (29 -> 31).
…ions
Two independent fixes to the cleanup flow:
- Moving findings to Trash ran cleaner::clean() inline on the UI thread,
so a large batch froze the window for the whole operation and the
result notice, taken via Option::take() and never restored, flashed
for a single frame instead of staying open. Add
chystik_core::cleaner::clean_streaming(), which reports a
Started/Removed/Skipped event per item; the GUI now runs it on a
worker thread (mirroring the existing scan worker), paints a progress
modal from the events, and shows a result notice with an animated
success check-mark (paint_success_check) only when something actually
moved. clean() is now clean_streaming() with the events dropped, so
the validate/identity-check/guard flow itself is unchanged.
- A versioned store (~/.local/share/claude/versions and friends, see
rules::GROUP_RULES) keeps every build it ever fetched while only the
newest runs, so a scan reported each superseded build as its own
finding — N look-alike rows differing only by a version number. Tag
such findings with their shared store directory
(Finding::version_group) and collapse 2+ of them into one table row
("Claude Code — 2 older versions · 128 MB") with a tooltip listing
each build. Grouping is display-only: every member is still a real,
independently selectable and deletable Finding, and bulk-select
actions read the pre-collapse index list (ViewCache::all_rows) so
collapsing a group never shrinks what "Select all" reaches.
Adds GUI-side tests for both (worker lifecycle covered by the existing
scan-worker pattern; grouping, sorting and the Age-column key covered
in crates/chystik-gui/src/app.rs).
…feedback The flatpak advisory hint (/var/lib/flatpak/repo) ran without sudo or --system, so it silently targeted the nonexistent per-user flatpak repo instead of the root-owned system one, failing with an "openat(config): No such file or directory" error. The advisory command copy-to-clipboard feedback relied solely on a hover tooltip, which disappears the moment the pointer leaves after the click that triggered it. Add a floating pill next to the row that shows without requiring continued hover.
- cargo fmt the copy-feedback overlay from the previous commit; the hand-formatted chained calls didn't match rustfmt's output. - Drop the unused `GB` test constant in format.rs — dead_code under -D warnings, breaking every native-platform test build (Windows, macOS). - python.pip.cache's reviewed_at moved to 2026-08-30 earlier in this branch (Windows app-cache catalog work); two CLI tests still asserted the old 2026-08-26 value.
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.
First real pass over Windows. Fixes two blocking bugs, expands the cache
catalog to Windows apps, and refines the cleanup view.
Bug fixes
verbatim
\\?\path fromcanonicalize, but the GUI matched themagainst the raw scan targets, so
Path::starts_withfailed and theconfirm dialog marked all items "refused".
owning_root/guard nowanchor on the canonical scan roots captured from the scan summary.
\\?\prefix leaked into the UI. A display-onlydisplay_pathstrips the verbatim prefix; internal paths stay verbatim so deep
(>260-char)
node_moduleskeep working during walk and cleanup.Catalog (+14 rules, 15 → 29)
Adds a
roaming-app-data(%APPDATA%) locator root, then evidence-backedrules with official sources: JetBrains IDEs + Toolbox, Android Studio,
Dart pub, VS Code, Chrome/Comet, Discord/Notion/Antigravity, Epic and
Steam, plus Windows crash dumps (review) and temp (advisory). Skipped
Ubisoft (install-dir/protected) and EA (anti-cheat, no source).
UI
Tests / verification
cargo test --workspace: green on Windows (core 137, application 9,guard 6, gui 39, cli 21).
assumptions / verbatim prefixes).
cargo build --workspaceclean withRUSTFLAGS=-D warnings.Notes
(previously blocked by design); deletion is still gated by the confirm
dialog and goes to the Recycle Bin.