fix(apply): reliably prompt to restart after bulk apply; keep silent settings silent - #64
Merged
Merged
Conversation
…nt settings silent Two related bugs surfaced by running the Extreme preset on a fresh Windows 11 install: Reboot prompt lost on Save & close. The manual Apply / preset path showed its reboot affordance as a button inside ApplyResultsWindow, which was owned by the Settings window. On "Save & close" the Settings window closes immediately after showing it, and WPF destroys owned windows with their owner — so a bulk apply wrote several reboot-required settings but never prompted to restart. Centralize the restart prompt in a new, unowned, app-level RebootPrompt (reusing RebootPendingWindow) that every apply path funnels through: manual Apply/preset, the background auto-apply loop, the drift-notification Apply button, and the CPU power-plan action. Because it is unowned it survives the close; deferred to the end of the batch it prompts once for the whole apply, not per setting. The now-redundant reboot button is removed from ApplyResultsWindow (the per-row "reboot to take effect" badge stays). Silent didn't mean silent. MonitorService's notification list excluded only the settings being auto-applied this tick, so an auto-apply setting that failed to verify (15-min backoff) fell through and popped a toast — on a fresh install the services/tasks Windows resists hit this repeatedly. Notifications are now gated on a pure, unit-tested SelectNotifiable rule: a setting the user set to auto-apply never notifies, on any tick, for any reason. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
| win.Closed += (_, _) => { if (ReferenceEquals(_current, win)) _current = null; }; | ||
| win.Show(); | ||
| } | ||
| catch { /* best-effort: a failed prompt must never crash the applier */ } |
| await item.Apply(); | ||
| if (item.RequiresReboot) rebootDescriptions.Add(item.Description); | ||
| } | ||
| catch { } |
| await item.Apply(); | ||
| if (item.RequiresReboot) rebootDescriptions.Add(item.Description); | ||
| } | ||
| catch { } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Two bugs surfaced by running the Extreme preset on a fresh Windows 11 install:
ApplyResultsWindow, which was owned by the Settings window. On Save & close,Close()runs immediately afterShow(), and WPF destroys owned windows with their owner — so a bulk apply wrote several reboot-required settings (VBS, Memory Integrity, Fast Startup, USB Selective Suspend…) but the prompt vanished before the user could see it.MonitorService's notification list only excluded settings being auto-applied that tick. An auto-apply setting that failed to verify entered a 15-minute backoff, dropped out of the auto set, and then fell into the notification path — popping a toast for a setting the user told it to change silently. Fresh installs hit this repeatedly on services/tasks Windows resists.Fix
Services/RebootPrompt.cs— one unowned, singleton, app-level restart prompt (reusesRebootPendingWindow). Being unowned +OnExplicitShutdownmeans it survives Save & close. Every apply path funnels through it: manual Apply/preset, background auto-apply, the drift-notification Apply button, and the CPU power-plan action. Deferred to the end of the batch → prompts once for the whole apply.ApplyResultsWindow(the per-row "reboot to take effect" badge stays as info).MonitorService— notifications gated on a pure, unit-testedSelectNotifiablerule: an auto-apply ("silently change") setting never notifies, on any tick, for any reason. Reboot notifications for silently-applied reboot settings still fire — the one intended interruption.Tests
5 new in
MonitorServiceTests.cscovering the silent-means-silent guarantee. Full suite green (dotnet test), build clean (warnings-as-errors).🤖 Generated with Claude Code