StorageScope v0.5.0 — Search + Performance Upgrade
v0.5.0 — Search + Performance Upgrade
15 PRs since v0.4.5 (#75–#89). All backwards-compatible additions; no breaking API changes. The cumulative story is the search bar becoming a real Mac-app search surface (multi-word AND, find-next, recents, badge, empty states) plus the first round of scan-phase performance work (signpost instrumentation, derived-cache reuse, background-persisted disk writes).
Search
- Multi-word AND search with path-segment matching + substring highlight (#84) — queries split on whitespace and require every term to match. Terms also match against
/-split path segments, soDocuments reportmatches bothDocumentsas a path segment ANDreportas a substring of name. Matched substrings render in accent color via a newHighlightedTextSwiftUI view struct (file list + Folder Tree). - Search-result count badge (#86) — pill-shaped
N matchesbadge inStorageItemTableheader when a search is active. Distinguishesnil(no search) from zero matches so the empty-state view can tell them apart. - Search-empty vs filter-empty distinction (#87) —
FilterRecoveryViewnow distinguishesnoScan,noMatches(search active, zero hits), andfilteredEmpty(filter chips, zero hits) with state-appropriate iconography and copy. - Cmd+G find-next navigation (#88) — Mail/Finder convention. Cmd+G advances through search-result rows and wraps around; Cmd+Shift+G reverses. Sets
selectedItemIDso the matched row takes focus. Menu items gate on search-active. - Search recents persistence (#89) —
SearchRecentsStoremirrors theRecentsStorering-buffer pattern; recent terms surface as.searchSuggestionson the search field with Clear Recents. Persists across launches via UserDefaults.
Performance
- os_signpost instrumentation on scan phases (#81) —
enumerate,verify,persist, andindexspans wrap the hot paths so Instruments → Points of Interest can profile. Zero behavioral change — no-ops when no profiler is attached. - Cache duplicateGroups + verifiedDuplicateGroups per scanFinishedAt (#79) — mirrors the existing
cleanupCandidatescache pattern. Avoids re-walking size-group / verified-group aggregation on every Duplicate Review view transition. - Background-persist RecentsStore writes off the main actor (#80) — heavy JSON encode + UserDefaults write detaches to
.utilitypriority;@Published entriesstill updates synchronously so SwiftUI sees immediate change. Matches the v0.3.0hashCache.persist()pattern. - Extend ScanBenchmarkReport with per-phase durations (#83) —
enumerateDuration,verifyDuration,persistDuration, andtotalDurationcomputed property.duplicateVerificationDurationkept as deprecated alias for backward compat.
UI / chrome
- File → Open Recent submenu (#82, bonus) — mirrors macOS convention for non-document apps: lists recently-scanned folder paths so users can re-launch a scan without reaching for the sidebar. Dynamic rebuild on each menu open via
NSMenuDelegate; gates on!store.isScanning. - keyboard-shortcuts.html docs page (#76) — documents every v0.4.5 + v0.5.0 hotkey (Cmd+G/Cmd+Shift+G originally listed as "Coming in v0.5.0"; now shipping).
- architecture.html docs page (#75) — documents the ScanStore tier-2 sub-store extraction pattern +
filterBindingbridge + derived cache invalidation, with an ASCII store-hierarchy diagram. - Cross-page version bump to v0.4.5 (#77, #78) — index landing page
What's newticker + cross-page nav links bumped to v0.4.5 (carried forward to v0.5.0 in the prep PR). - Expand changelog with v0.4.5 subsections + v0.4.0 release (#85) — backfilled the full v0.4.5 section structure (Sidebar / Item rows / Trash review / Mac menu / Overview-Inspector / Refactors / Accessibility) and the v0.4.0 release section so the changelog reads as a contiguous history.
Validation
swift test— 90 tests across 10 suites passplutil -lint Config/StorageScope.entitlements Resources/PrivacyInfo.xcprivacy— cleanbash -nacross all scripts — clean./script/public_upload_audit.sh— passes- DMG:
exports/StorageScope-0.5.0.dmg, SHA25609691b50ca0c60318a5f3544fcb8fa1a3f44007843188a8e348f2080ac9fb871—hdiutil verifyconfirmed
Why v0.5.0 (not v0.4.6)
Per semver: pre-1.0 minor is the standard "feature-bearing release" bump. v0.5.0 ships the second major UX arc (search) — a meaningful feature surface, not a patch on v0.4.5's polish work. The 15 PRs are all backwards-compatible additions; no breaking API changes to FileSystemScanner.scan(...) or ScanStore's public surface.
Deferred
- Tier 3 SelectionState / Tier 4 TrashReviewState extractions — still pending; same lazy-var + closure-injection template from v0.4.5 Tiers 1-2.
- Tier 5
@Observablemacro migration — still blocked bydidSetobservers on tracked properties (deferred to v1.0.0). - Sparkle 2.x auto-update — still gated on notarization (PR #19's
script/notarize_dmg.shscaffolding from v0.4.0 waits on Apple Developer ID credentials).