Skip to content

fix(macos): notify when the scan finishes, and make "Stop after current" respond - #377

Merged
caezium merged 2 commits into
mainfrom
fix/scan-notice-and-stop-button
Aug 10, 2026
Merged

fix(macos): notify when the scan finishes, and make "Stop after current" respond#377
caezium merged 2 commits into
mainfrom
fix/scan-notice-and-stop-button

Conversation

@caezium

@caezium caezium commented Aug 10, 2026

Copy link
Copy Markdown
Owner

Two bugs found hand-testing the release candidate.

"Stop after current" looked broken

cancelUpdateAll() set cancelUpdateAllAfterCurrent, which was private and not @Published — so SwiftUI could not observe it and the header button never changed. The stop was queued correctly, but nothing on screen said so, and since it only takes effect after the in-flight item finishes, the click looked ignored for however long that took.

Now published, the label switches to "Stopping after current…", and the button disables so it can't be pressed twice.

The scan finished silently, then notified with ======

The scan is the step people walk away from — minutes on a full disk, ending by just sitting there with a number — but it never opted into a completion notice. The real clean already did, via notifyOnEnd, so the scan now uses the same flag and inherits the Settings toggle: silent for anyone who turned notifications off.

That alone produced a notification whose body was a row of equals signs. The body falls back to the last streamed HUD line, and for a task report that's the ===== separator:

Scanning caches — done
==============================

So the scan supplies its own finalDetail — "12.4 GB found across 37 items." or "Nothing to clean."

Verification

1053 tests, 0 failures. Both paths exercised by hand on a Developer ID-signed local build with the engine bundled.

Not a bug, for the record

Two other things turned up while testing and were both artifacts of the local build, not defects:

  • Repeated password prompts. TCC has the shipped dev.caezium.Burrow at 2 (allowed) but a DerivedData build at 0 (denied), so the scan's .fullDiskAccess(adminBypass: true) gate fires on every elevated step.
  • App scan returning no sizes. A local Debug build bundles no engine and silently falls back to Homebrew's mo 1.46.0 — upstream GPL Mole, not the 1.42.0 fork we ship. Copying the real engine into the bundle restored it.

Summary by CodeRabbit

  • New Features

    • Dry-run cleaning now displays progress updates and a completion notification with results, including total bytes and item counts—or confirmation when nothing needs cleaning.
  • Bug Fixes

    • The update-all stop action now clearly indicates when cancellation is pending.
    • The stop button is disabled after cancellation is requested to prevent duplicate actions.

…nt" respond

Two things found hand-testing the release candidate.

The scan never posted a completion notice. It is the step people walk away
from — it can run for minutes on a full disk and, unlike the clean, it ends
by just sitting there with a number — so it now opts into the same
`notifyOnEnd` the real run already used, inheriting the Settings toggle and
staying silent for anyone who turned notifications off.

It also needs its own `finalDetail`. The notification body defaults to
whatever the last streamed HUD line happened to be, and for a task report
that is the "=====" separator, so the first notice arrived as a row of
equals signs. It now says what was found, or that there was nothing.

"Stop after current" looked broken. `cancelUpdateAll()` set a flag that was
private and not @published, so SwiftUI could not observe it and the button
never changed state — the stop was queued correctly but nothing on screen
said so, and the wait for the in-flight item made the click look ignored.
The flag is published now, the label becomes "Stopping after current…", and
the button disables so it cannot be pressed twice.
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The pull request adds completion notifications to cleanup dry runs. It updates the update-all stop button to show and enforce pending cancellation. It also corrects staging-directory suffix assertions.

Changes

Cleanup and update controls

Layer / File(s) Summary
Dry-run reporting
macos/Sources/CleanView.swift
The dry run keeps streamed HUD text, enables completion notifications, and reports whether it found no items or includes the total bytes and item count.
Update-all cancellation state
macos/Sources/UpdatesView.swift, macos/Tests/UpdateWorkflowTests.swift
The model publishes cancelUpdateAllAfterCurrent. The stop button changes to “Stopping after current…” and becomes disabled after cancellation is requested. The staging-directory test accepts generated X characters and requires an alphanumeric suffix.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

  • caezium/burrow#363: Both changes modify the CleanView dry-run reporting flow.
  • caezium/burrow#367: Both changes modify the cleanup reporting and update-all cancellation workflows.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the two main changes: scan completion notifications and improved “Stop after current” behavior.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/scan-notice-and-stop-button

Comment @coderabbitai help to get the list of available commands.

The assertion I added in #367 read "no X remains in the suffix", on the
theory that a leftover X meant mkdtemp had not substituted the template.
It does not: mkdtemp draws replacements from an alphanumeric set that
INCLUDES 'X', so a perfectly good name like BurrowUpdate.YmzfxX tripped it.
Roughly a one-in-eight chance per directory, and it passed locally purely by
luck before failing on CI.

The failure actually worth guarding against is the template surviving whole,
so assert that instead — the suffix is not "XXXXXX" — plus the charset.
Ran 30 consecutive times with no failures.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@macos/Tests/UpdateWorkflowTests.swift`:
- Line 120: Rewrite the comment at the indicated assertion in
UpdateWorkflowTests to explain why the test allows X in the substituted
characters, or why the previous assertion was invalid, instead of describing the
prefix and suffix checks performed below. Keep the comment focused on rationale
and compliant with the macos Swift WHY-comment requirement.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0000c8d7-b4dd-4b06-9ebb-9f70c941c276

📥 Commits

Reviewing files that changed from the base of the PR and between 4339475 and 97a901c.

📒 Files selected for processing (1)
  • macos/Tests/UpdateWorkflowTests.swift

// they passed no matter what create() produced. Assert the real mkdtemp
// shape instead: the fixed prefix, and six substituted template
// characters with no X left unreplaced.
// shape instead: the fixed prefix and six substituted characters.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Rewrite the comment on Line 120 to explain the failure mode.

The comment restates the prefix and suffix checks implemented immediately below. Keep the explanation for allowing X, but remove this redundant summary or state why the previous assertion was invalid.

As per path instructions, comments in macos/**/*.swift must explain WHY, not what.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@macos/Tests/UpdateWorkflowTests.swift` at line 120, Rewrite the comment at
the indicated assertion in UpdateWorkflowTests to explain why the test allows X
in the substituted characters, or why the previous assertion was invalid,
instead of describing the prefix and suffix checks performed below. Keep the
comment focused on rationale and compliant with the macos Swift WHY-comment
requirement.

Source: Path instructions

@caezium
caezium merged commit c06ec07 into main Aug 10, 2026
5 checks passed
@caezium
caezium deleted the fix/scan-notice-and-stop-button branch August 10, 2026 17:09
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