Skip to content

sweep/2026-09-22: 3-cycle maintenance sweep - #2

Open
Chartres wants to merge 35 commits into
mainfrom
sweep/2026-09-22
Open

Chartres wants to merge 35 commits into
mainfrom
sweep/2026-09-22

Conversation

@Chartres

Copy link
Copy Markdown
Owner

Sweep summary

Product: mac-dir-stat Branch: sweep/2026-09-22 Cycles: 3 Commits: 34 Tests: 7 → 35

3-cycle Red→Green→Refactor sweep. All 34 commits were built with cargo test passing after each one.

Findings table

Finding Severity Status
UTF-8 byte-slice panic on non-ASCII dir names (dir_tree.rs:190, treemap_view.rs:438) critical fixed
app_open / scan_completed off-taxonomy → KPI buckets permanently zero critical fixed
collect_files().len() every frame (full recursive walk + Vec alloc per frame) critical fixed
is_alive() panics on out-of-range NodeId (stale-id guard was itself unsafe) critical fixed
start_scan didn't clear partial_refresh_receiver → stale graft panic after rescan critical fixed
Keyboard handlers (⌘⌫, Enter, ⇧⌘R) used node data without liveness check critical fixed
telemetry.txt absent → default opted-in; page_view fires before first UI frame major fixed
set_telemetry_opt_out discarded write error silently major fixed
feedback_sent = true even when telemetry off (no send happened) major fixed
feedback_text cleared unconditionally, wiping unsent text major fixed
cleanup.rs:91 path-suffix match not component-bounded (MyLibrary/Caches matched Library/Caches) major fixed
target bare-name rule matched any directory, including ~/Documents/target major fixed
.Trash/.Trashes offered as cleanup candidates (nonsensical + root-owned) major fixed
Library/Containers/com.apple.iCloud.iCloudDrive described as safe to evict (data loss) major fixed
.m2/.gradle rules gave no warning about credential files (settings.xml, gradle.properties) major fixed
move_to_trash failure eprintln-only, no UI feedback major fixed
empty_trash blocked UI thread with synchronous .status() major fixed
empty_trash failure not surfaced in status_message major fixed
Cleanup window category headers repeated (sorted by size, not by category) major fixed
start_scan left pending_action, hovered_dir, cleanup_candidates stale major fixed
poll_scan Done didn't clear pending_action, hovered_dir, scroll_dir_tree_to major fixed
recompute_sizes_upward wrote into dead nodes major fixed
PendingAction::RevealInFinder / MoveToTrash never constructed (dead variants) major fixed
children_sorted, node_count, StrRef::EMPTY dead code minor fixed
BAR_FILL unused color constant; ext_list redundant branch; unused ColorMode import minor fixed
Path truncation in cleanup window was lengthening short paths minor fixed

Tests added

  • test_classify_cargo_target — Cargo.toml-sibling check
  • test_classify_non_cargo_target — no Cargo.toml → not classified
  • test_classify_library_caches — Library/Caches path
  • test_classify_gradle_warning — .gradle warning in description
  • test_no_telemetry_env_var_opts_out — MACDIRSTAT_NO_TELEMETRY=1 path

Refactors

  • One confirm_dialog widget replacing three copy-pasted modal dialogs
  • HashSet::retain replacing manual loop; Option::is_some_and for map_or(false, …) predicates
  • Dead PendingAction variants removed, making the dispatch match exhaustive
  • Single iterative mark_descendants_dead replacing two divergent recursive/iterative walks
  • to_screen() helper eliminating 6 copies of the same rect-conversion in treemap_view
  • Color-mode shortcuts table-driven; ScanProgressInfo derives Default

Not fixed (scope/risk)

  • src/scanner/tree.rs:127 — node()/node_mut() still index without bounds check (changing return type to Option would require touching ~40 call sites; is_alive is now safe so callers can guard before calling)
  • src/flywheel.rs:109 — /dev/urandom fallback entropy (uuid quality only matters for analytics dedup; low impact)
  • src/scanner/tree.rs:33 — u32 arena offset overflow (4 GiB of interned strings is not a realistic concern)
  • Various per-frame allocation patterns in dir_tree.rs (require dirty-tracking/caching refactor)

🤖 Generated with Claude Code

Chartres and others added 30 commits September 22, 2026 00:58
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…anic

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…lorMode import

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
RevealInFinder and MoveToTrash were never built by any caller — the
context menu performs both inline. Removing them makes the dispatch
match exhaustive, so a future variant fails to compile instead of
being silently swallowed by the catch-all arm.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- cleanup_selected pruning: collect-to-Vec then remove-in-loop is
  HashSet::retain, one line instead of twelve
- Option::is_some_and replaces map_or(false, ..) in two predicates
- collapse the nested hover-detection if into one condition

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Delete / empty-trash / batch-delete each hand-built the same modal:
hidden title bar, center anchor, heading + detail label, right-aligned
danger+ghost pair. Extracted to ui::widgets::confirm_dialog returning
Option<bool> (None = undecided, Some = chose), next to the buttons it
uses. Also flattens the Option<Option<_>> result plumbing into plain
Option<NodeId> / Option<Vec<NodeId>> / bool.

Only visual change: the single-delete dialog now uses the same 320/360
width as the other two.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tart_scan

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…an Done branch

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ot-owned)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…-uploaded files)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… parent

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…uping

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ror in status_message

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…Caches, .gradle

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…TRY=1

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ally happened

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
remove_node and clear_descendants each had their own walk marking
descendants dead — one recursive with a per-directory children clone, one
iterative. Both now share the iterative version (no clone, no recursion
depth limit). Also drop a dead `let new_id = …; let _ = new_id;` in
graft_under.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Six copies of the same four-line f64-rect → egui::Rect conversion in
treemap_view collapse to a single helper.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ogressInfo

Cmd+1/2/3 were three copies of the same three-statement body; now one loop
over (key, mode). ScanProgressInfo's zeroed literal was written out twice —
derive Default and spread it.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Chartres and others added 5 commits September 22, 2026 01:56
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…/parent checks

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

This branch has not been deployed

No deployments
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