Skip to content

Windows: fix cleanup guard, expand app-cache catalog, refine cleanup UI - #17

Merged
pasichDev merged 13 commits into
mainfrom
feat/windows-caches-and-gui-fixes
Sep 14, 2026
Merged

pasichDev merged 13 commits into
mainfrom
feat/windows-caches-and-gui-fixes

Conversation

@pasichDev

Copy link
Copy Markdown
Owner

First real pass over Windows. Fixes two blocking bugs, expands the cache
catalog to Windows apps, and refines the cleanup view.

Bug fixes

  • Guard refused every item on Windows. Findings carry the canonical
    verbatim \\?\ path from canonicalize, but the GUI matched them
    against the raw scan targets, so Path::starts_with failed and the
    confirm dialog marked all items "refused". owning_root/guard now
    anchor on the canonical scan roots captured from the scan summary.
  • \\?\ prefix leaked into the UI. A display-only display_path
    strips the verbatim prefix; internal paths stay verbatim so deep
    (>260-char) node_modules keep working during walk and cleanup.

Catalog (+14 rules, 15 → 29)

Adds a roaming-app-data (%APPDATA%) locator root, then evidence-backed
rules 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

  • Hide zero-value recovery segments (sidebar chips + footer totals).
  • Footer Select all for the current category (replaces the Disks label).
  • Severity filters as a left-aligned vertical column — no locale stretches them.
  • Prominent green Scan button on the empty screen.

Tests / verification

  • cargo test --workspace: green on Windows (core 137, application 9,
    guard 6, gui 39, cli 21).
  • Also fixes 4 pre-existing Windows-only test failures (Unix path
    assumptions / verbatim prefixes).
  • cargo build --workspace clean with RUSTFLAGS=-D warnings.

Notes

  • Select all now allows bulk-selecting review-required items
    (previously blocked by design); deletion is still gated by the confirm
    dialog and goes to the Recycle Bin.
  • Not for merge yet — review first.

pasichDev and others added 13 commits August 30, 2026 17:55
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.
@pasichDev
pasichDev merged commit 03705ca into main Sep 14, 2026
10 checks passed
@pasichDev
pasichDev deleted the feat/windows-caches-and-gui-fixes branch September 14, 2026 10:35
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