refactor: make the unreachable-surface guard see every observable property - #2115
Merged
laurentiu021 merged 1 commit intoSep 4, 2026
Merged
Conversation
…perty EveryModelProperty_IsEitherWrittenOrShown detects [ObservableProperty] fields with the prefix [^\n]*\n?, which is wrong in both directions. It skips forward: for the single-line form followed by a plain private field, the prefix eats the attribute's own line, crosses the newline and captures the NEXT field. Four such mis-captures exist in ViewModels/ today, each hiding the real property beside it. And one newline is not enough for the multi-attribute form, so every property with a [NotifyPropertyChangedFor] beside it was invisible -- 23 of the 187 declarations in Models/, six on DiskHealthReport alone. The floor is what made that survivable: 164 of 187 matched, and the assertion was >= 40. Re-measured and raised to 180. A mutation proof shows the greedy prefix now reddens, and that with the old floor of 40 it stays GREEN -- the regex was the defect, the floor value is what let it live. The corrected guard finds no new dead model surface, so this is a coverage fix rather than a bug hunt with a result. Also removes three view-model properties from the hand-measured list in #2100: SpeedStatus (declared, never assigned, never read), TotalFolders (a full recursive Sum per scan, read nowhere) and CurrentFolder (read nowhere, and the next line already puts the same value into the bound StatusMessage). The assertion on TotalFolders' default -- which is what made it look exercised -- went with it.
laurentiu021
deleted the
refactor/unreachable-surface-guard-and-dead-properties
branch
September 4, 2026 14:38
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.
Part of #2100.
refactor:— no behaviour change, no release.The guard for unreachable model surface could not see 12% of it
EveryModelProperty_IsEitherWrittenOrShownexists to catch a property that is never written and never shown. Its detection pattern was:[^\n]*\n?is wrong in both directions.It skips forward. For the single-line form followed by a plain field, the prefix consumes the attribute's own line, crosses the newline, and captures the next field:
Four such mis-captures exist in
ViewModels/today (_quickActionNavigateTarget,_suppressAllSelected,_blocker,_disposed) — private fields reported as observable properties, while the real property beside each went unchecked.And one newline is not enough. The multi-attribute form never matched at all:
That is 23 of the 187
[ObservableProperty]declarations inModels/, six of them onDiskHealthReportalone.The pattern now allows whitespace and any number of further attributes between the marker and the field, and nothing on the attribute's own line can be walked past.
The floor was the part that made it invisible
The old pattern saw 164 of 187 and the assertion was
checkedProperties >= 40, so a 12% blind spot reported perfect health for as long as it shipped. Floor re-measured and raised to 180.Mutation proof, restored byte-for-byte:
only 164 model properties were inspected, out of 187 measuredThe second row is the finding, not a footnote: with the old floor the old pattern is undetectable. The regex was the defect, the floor value is what let it live.
Re-running the corrected guard over all 187 properties finds no new dead model surface — so this is purely a coverage fix, not a bug hunt with a result.
Three view-model properties removed
From the hand-measured list in #2100, the three that are redundant rather than a missing capability:
SpeedTestViewModel.SpeedStatusSpeedStatusappeared exactly once in the whole appDiskAnalyzerViewModel.TotalFoldersEntries.Sum(e => e.FolderCount)on every scan, read nowhereDiskAnalyzerViewModel.CurrentFolderStatusMessage, which is boundConstructor_InitialState_IsCorrectassertedTotalFolders == 0, which is exactly what made it look exercised; the assertion went with the property and the reason is recorded where it was.The other four in #2100 stay open, because each is a missing capability rather than dead weight — the active Menu Style preset, clickable release-history entries, free space on the chkdsk picker, release notes on About — and they need a mockup first.
Not done here
Widening the guard to
ViewModels/is still open on #2100. It needs a different rule: a model property's mere appearance in its own file proves use, but a view-model property is normally assigned there, so every write-only property looks alive. The rule has to distinguish a read from a write, and a first pass at it produced two false positives from same-name collisions across types — which is why it is not in this PR.Verification
Builds 0 errors / 0 warnings (app + tests),
dotnet format --verify-no-changesclean on both, 143 cases green acrossArchitectureTests,DiskAnalyzerViewModelTestsandSpeedTestViewModelTests. No version bump and no CHANGELOG entry: nothing user-visible changed andrefactor:does not release.