Skip to content

Harden destructive ops, persistence, and safety UX - #1

Merged
adamXbot merged 2 commits into
mainfrom
harden-destructive-ops-and-safety-ux
Aug 6, 2026
Merged

Harden destructive ops, persistence, and safety UX#1
adamXbot merged 2 commits into
mainfrom
harden-destructive-ops-and-safety-ux

Conversation

@adamXbot

Copy link
Copy Markdown
Owner

Summary

Hardens BananaBlitz's highest-blast-radius paths (it's a Full-Disk-Access, no-sandbox utility that wipes and immutably-locks ~/Library directories) and closes the safety-UX gaps around them. All changes are build-verified with xcodebuild test (40 tests passing, +18 over baseline).

Data safety / correctness

  • Atomic lockFileSystemGuard.lockTarget now moves the original aside → creates+locks the empty file → deletes the backup, and restores on any failure. Previously it deleted first and could destroy data on a partial failure. A distinct error names the backup path if rollback itself can't restore.
  • Corrupt/unreadable state.json is preserved (move, then in-memory-copy fallback) before any save can overwrite it, and saving is blocked if it can't be preserved — so one bad byte can no longer silently wipe history.
  • Unattended cleans downgrade the destructive "Lock with Immutable File" strategy to a plain wipe unless explicitly opted in (new Settings toggle, default off) — scheduled runs have no confirmation gate.
  • Single clean mutex centralised on AppState, so the onboarding first-run clean can't race a scheduled/catch-up clean on the same paths.

Safety UX

  • Menu bar surfaces manual-blitz pass/fail inline (was discarded).
  • "Reset All Settings" now confirms.
  • Dry-run flags delete-then-lock rows, offers the recovery script in place, and uses accurate reversibility copy.
  • Onboarding FDA step explains the grant, offers troubleshooting + a "Skip for now" escape, and responds to Return; scan step distinguishes "needs access" from "not found" with an FDA banner.
  • Truthful replaceWithFile + Daemon Containers copy; single-source level descriptions; labelled (accessible) filter pills; disclosure chevron on target rows; Reduce-Motion support.

Tests

+18 covering: lock partial-failure restore (both createFile and flag-set branches), corrupt/unreadable-state preservation + save-block, the clean mutex (incl. real async-completion release and the empty-workload path), and the unattended-downgrade wiring.

Review process

The four data-safety fixes were put through an adversarial multi-lens review (failure-ordering, mutex-leak, regression, test-adequacy); the findings — most notably a backup-failure path that could have re-introduced the persistence data-loss bug — were resolved in this branch.

Deliberately deferred (need live-app verification or empirical validation)

  • CleanButton real ButtonStyle / focus ring (custom DragGesture press animations; needs eyes-on verification).
  • Full keyboard nav beyond Continue.
  • Per-target "may disrupt the menu bar" warnings — the brick risk is inferred, not observed; only the clear case (Daemon Containers) was corrected.

🤖 Generated with Claude Code

adamXbot and others added 2 commits June 14, 2026 18:38
Data safety / correctness:
- FileSystemGuard.lockTarget is now crash-safe: move the original aside,
  create+lock the empty file, then delete the backup; restore on any
  failure so a partial failure can never destroy data. Added injectable
  seams (immutable-flag setter, lock-file creator) for the failure paths.
- AppState preserves an undecodable/unreadable state file (move, then
  in-memory copy fallback) before any save can overwrite it, and blocks
  saving entirely if it can't be preserved.
- Scheduled/unattended cleans downgrade the destructive "Lock with
  Immutable File" strategy to a plain wipe unless explicitly opted in
  (new Settings toggle, default off).
- Centralised the in-flight clean mutex on AppState so the onboarding
  first-run clean can't race a scheduled/catch-up clean on the same paths.

Safety UX:
- Menu bar surfaces manual-blitz pass/fail outcome inline.
- Reset All Settings now confirms before wiping state.
- Dry-run flags delete-then-lock rows, offers the recovery script in
  place, and uses accurate reversibility copy.
- Onboarding FDA step explains the grant, offers troubleshooting + a
  "Skip for now" escape; scan step distinguishes "needs access" from
  "not found" with an FDA banner.
- Truthful replaceWithFile and Daemon Containers descriptions;
  accessible (labelled) level filter pills.

Tests: +18 (now 40) covering lock partial-failure restore (both
branches), corrupt/unreadable-state preservation + save-block, the clean
mutex incl. real async-completion release, and the unattended-downgrade
wiring.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Single source of truth for level risk copy: ScanStepView now uses
  CleaningLevel.description instead of its own divergent strings.
- TargetRowView shows a rotating disclosure chevron (and an
  accessibility hint) so the expand-on-tap detail is discoverable.
- Onboarding clean banana suppresses its continuous spin under Reduce
  Motion and is marked decorative for VoiceOver.
- Onboarding Continue responds to Return (.defaultAction), still gated
  by canProceed so it can't skip the FDA/scan steps.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@adamXbot
adamXbot merged commit 4f69f89 into main Aug 6, 2026
1 check passed
@adamXbot
adamXbot deleted the harden-destructive-ops-and-safety-ux branch August 6, 2026 15:08
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