Skip to content

fix: stop raising findings no repair can clear - #50

Merged
SecretLUL merged 3 commits into
mainfrom
fix/recurring-scan-findings
Sep 6, 2026
Merged

SecretLUL merged 3 commits into
mainfrom
fix/recurring-scan-findings

Conversation

@SecretLUL

Copy link
Copy Markdown
Owner

Three findings survived their own repair: scan, repair, reboot, scan again β€” and there they were, unchanged. Each measured something the repair it offered could not touch.

Diagnosed against a real machine's last_scan.json, audit log and registry rather than from first principles.

wu_reboot_pending β€” a key the restart leaves behind

The check tested whether Component Based Servicing\RebootPending exists. Windows creates it while servicing and files the outstanding work underneath it; the restart consumes that work and empties the key, but leaves the key itself in place β€” permanently. On the machine this was found on it had been sitting there empty (0 subkeys, 0 values) while Auto Update\RebootRequired was absent: a restart that no restart could clear.

The CBS key now counts only while it still holds entries, and the two signals a boot really does clear are read alongside it β€” Auto Update\RebootRequired and PendingFileRenameOperations. pending_reboot_reason takes the three signals as data, so the verdict is testable without a registry to write into.

sys_clean_winsxs β€” a repair that could not move the number

The finding was raised on DISM's own "cleanup recommended" verdict. That verdict also weighs backups and disabled features, which only /ResetBase reclaims and which WinMedic deliberately never touches. StartComponentCleanup β€” the one repair offered here β€” removes superseded packages and nothing else. With 4.43 GB of backups and zero reclaimable packages the flag stayed Yes however often the repair ran, DISM answered "completed successfully" every time, and the audit log recorded a cleaned store.

  • the finding now needs a reclaimable package to exist; a recommendation with nothing to reclaim goes to the scan log with the reason
  • the repair reads the store back afterwards and reports what is left, instead of trusting an exit code that says the same thing either way
  • both DISM calls pass /English. The output arrives in the console code page, so from_utf8_lossy had already cost the parser the store-size and cache lines on a German machine β€” visible in the finding's details as a missing "Explorer size"

sys_clean_setup_logs β€” the scan finding its own log

"13.2 MB, 2 files" were CBS.log, held open by TrustedInstaller since the log was created a month earlier, and dism.log β€” written by this module's own AnalyzeComponentStore call 34 seconds before the same scan measured it.

Both the measurement and the sweep now ask Windows for DELETE access first. That is exactly the question remove_file asks later, and with a fully permissive share mode the probe blocks nobody. What is counted is what can be removed; a rotated CbsPersist_*.log still is.

Checks

cargo fmt, cargo clippy --all-targets -D warnings and the full suite pass: 361 unit + 266 integration tests, 8 of them new for these three cases β€” an empty CBS key, a CBS key still holding work, a recommendation with nothing reclaimable, a cleanup that reclaimed nothing, and a log held open with FILE_SHARE_NONE that is neither counted nor reported as a failed deletion.

πŸ€– Generated with Claude Code

SecretLUL and others added 3 commits September 6, 2026 12:33
`save_scan_state` wrote to `%APPDATA%\WinMedic\last_scan.json` from any
`App`, including the dozens the suite builds. Ticking a checkbox in a
test therefore overwrote the scan the developer's own WinMedic had left
behind β€” which is exactly what `SystemActions` exists to prevent for the
browser, the UAC prompt and restore points.

Persistence now sits behind the same seam: off by default, switched on
by the desktop front end through `enable_real_system_actions`.

That surfaced an integration test which assumed `App::new` starts with no
issues. It restores the last scan, so on a machine that has actually run
WinMedic `issues[0]` was a real finding rather than the one the test was
about; it now clears the list first, the way the window tests already do.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Nothing in the findings list could be ticked. The row was an
`egui::Frame` whose response was handed a click sense afterwards, and a
`Frame` registers its response *after* everything drawn inside it β€” so
the row's click target sat on top of its own checkbox and swallowed every
click meant for it. The boxes were drawn, they just could not be reached.

The row is now a `Ui` with `UiBuilder::sense`, which registers itself
before its contents and leaves the checkbox on top. Labels sense clicks
for text selection and would have taken the row's place at the front, so
selectable labels are off inside a row: a finding's title is a list
entry, not prose. Ticking a box also moves the detail pane to that
finding, the way `space` already did.

The severity marks are drawn geometry rather than text: an octagon for
critical, a rounded triangle for warning, a disc for info. egui's bundled
fonts have no warning sign in them, so a written mark would have reached
some machines as an empty box β€” the same reason the navigation icons are
painted. They replace the `[!] CRITICAL` text badges in the list, the
detail pane, the filter chips and the dashboard cards, and each carries
its name for a screen reader. `Severity::badge` keeps the written form
for the report file, which is now its only caller.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Three findings came back unchanged after a scan, a repair and a reboot.
Each one measured something its own repair could not touch.

`wu_reboot_pending` tested whether the CBS `RebootPending` key exists.
Windows creates it while servicing and files the outstanding work
underneath; the restart consumes that work and empties the key, but
leaves the key itself behind β€” permanently. On the machine this was
found on it has sat there empty (0 subkeys, 0 values) while
`Auto Update\RebootRequired` was absent, so WinMedic reported a restart
that no restart could clear. The key now counts only while it still
holds entries, and the two signals a boot really does clear β€”
`Auto Update\RebootRequired` and `PendingFileRenameOperations` β€” are read
alongside it. `pending_reboot_reason` takes the three as data so the
verdict is testable without a registry to write into.

`sys_clean_winsxs` was raised on DISM's own "cleanup recommended"
verdict. That verdict also weighs backups and disabled features, which
only `/ResetBase` reclaims and which WinMedic deliberately never
touches; `StartComponentCleanup`, the one repair offered, removes
superseded packages and nothing else. With 4.43 GB of backups and zero
reclaimable packages the flag stayed "Yes" however often the repair ran,
DISM answered "completed successfully" every time, and the audit log
recorded a cleaned store. The finding now needs a reclaimable package to
exist, the repair reads the store back before it claims anything, and
both DISM calls pass `/English`: the output arrives in the console code
page, so `from_utf8_lossy` had already cost the parser the store size and
cache lines on a German machine.

`sys_clean_setup_logs` reported "13.2 MB, 2 files" that were `CBS.log`,
held open by TrustedInstaller since the log was created a month earlier,
and `dism.log` β€” written by this module's own `AnalyzeComponentStore`
call 34 seconds before the same scan measured it. Both the measurement
and the sweep now ask Windows for `DELETE` access first, which is exactly
the question `remove_file` asks later and, with a fully permissive share
mode, blocks nobody. What is counted is what can be removed; a rotated
`CbsPersist_*.log` still is.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@SecretLUL
SecretLUL merged commit a587070 into main Sep 6, 2026
4 checks passed
@SecretLUL
SecretLUL deleted the fix/recurring-scan-findings branch September 6, 2026 11:03
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