diff --git a/SysManager/SysManager.Tests/ArchitectureTests.cs b/SysManager/SysManager.Tests/ArchitectureTests.cs
index 4a92426b..53141c0a 100644
--- a/SysManager/SysManager.Tests/ArchitectureTests.cs
+++ b/SysManager/SysManager.Tests/ArchitectureTests.cs
@@ -1844,9 +1844,13 @@ public void EveryModelProperty_IsEitherWrittenOrShown()
}
}
- Assert.True(checkedProperties >= 40,
- $"only {checkedProperties} model properties were inspected — the detection is probably no "
- + "longer matching the [ObservableProperty] declarations.");
+ // Measured: 187 today. The floor is set just under that rather than at a token value, because the
+ // defect it has to catch is precisely a pattern that still matches MOST declarations — the previous
+ // prefix saw 164 of these 187 and its floor of 40 reported nothing wrong for as long as it shipped.
+ Assert.True(checkedProperties >= 180,
+ $"only {checkedProperties} model properties were inspected, out of 187 measured — the detection "
+ + "is no longer matching every [ObservableProperty] declaration. A pattern that matches most of "
+ + "them still leaves the rest unguarded, so fix this before trusting a pass.");
Assert.True(dead.Count == 0,
"these model properties are never written and never shown, so they can only ever present an "
@@ -1858,7 +1862,22 @@ public void EveryModelProperty_IsEitherWrittenOrShown()
private static partial Regex TypeDeclaration();
/// An [ObservableProperty] backing field, capturing the field name without its underscore.
- [GeneratedRegex(@"\[ObservableProperty\][^\n]*\n?\s*(?:private|internal)\s+[\w\?<>,\[\]\. ]+?\s+_(\w+)\s*[;=]",
+ ///
+ /// The prefix was [^\n]*\n?, which is wrong in both directions.
+ /// It let the match run to the end of the attribute's own line and then across ONE newline, so for
+ /// the single-line form followed by a plain field —
+ /// [ObservableProperty] private string _label = ""; then private string? _target; — it walked
+ /// past _label and captured _target, a field that is not observable at all. Four such
+ /// mis-captures exist in ViewModels/ today.
+ /// And one newline is not enough for the multi-attribute form, so every property carrying a
+ /// [NotifyPropertyChangedFor] beside it was invisible: 23 of the 187 properties in
+ /// Models/, including six on DiskHealthReport alone. The guard's floor of 40 could never
+ /// reveal that, since 164 clears it comfortably.
+ /// Now: optional whitespace, then any number of further attributes, then the field. Nothing on the
+ /// attribute's own line can be skipped over.
+ ///
+ [GeneratedRegex(@"\[ObservableProperty\]\s*(?:\[[^\]]*\]\s*)*(?:private|internal)\s+"
+ + @"[\w\?<>,\[\]\. ]+?\s+_(\w+)\s*[;=]",
RegexOptions.Compiled)]
private static partial Regex ObservablePropertyField();
diff --git a/SysManager/SysManager.Tests/DiskAnalyzerViewModelTests.cs b/SysManager/SysManager.Tests/DiskAnalyzerViewModelTests.cs
index 62a7ae41..cf9763d3 100644
--- a/SysManager/SysManager.Tests/DiskAnalyzerViewModelTests.cs
+++ b/SysManager/SysManager.Tests/DiskAnalyzerViewModelTests.cs
@@ -30,11 +30,13 @@ private static DiskAnalyzerViewModel NewVm()
[Fact]
public void Constructor_InitialState_IsCorrect()
{
+ // TotalFolders was asserted here too. It was computed from a full recursive
+ // Entries.Sum(e => e.FolderCount) on every scan and read by nothing — no binding, no other
+ // code — and this assertion on its default value is what made it look exercised.
var vm = NewVm();
Assert.False(vm.IsBusy);
Assert.Equal(0, vm.TotalSize);
Assert.Equal(0, vm.TotalFiles);
- Assert.Equal(0, vm.TotalFolders);
Assert.Equal(0, vm.EntryCount);
Assert.Empty(vm.Entries);
Assert.Contains("Select", vm.ScanSummary);
diff --git a/SysManager/SysManager/ViewModels/DiskAnalyzerViewModel.cs b/SysManager/SysManager/ViewModels/DiskAnalyzerViewModel.cs
index a7330f55..87962e95 100644
--- a/SysManager/SysManager/ViewModels/DiskAnalyzerViewModel.cs
+++ b/SysManager/SysManager/ViewModels/DiskAnalyzerViewModel.cs
@@ -44,9 +44,7 @@ public sealed partial class DiskAnalyzerViewModel : ViewModelBase
public bool HasTrend => !string.IsNullOrEmpty(TrendSummary);
[ObservableProperty] private long _totalSize;
[ObservableProperty] private int _totalFiles;
- [ObservableProperty] private int _totalFolders;
[ObservableProperty] private int _entryCount;
- [ObservableProperty] private string _currentFolder = "";
// Distinguishes the un-run state from a completed zero-result scan so the big empty-state overlay
// doesn't tell the user to "pick a folder and analyze" right after they did exactly that. Set true
@@ -153,7 +151,6 @@ private async Task AnalyzeAsync()
Entries.Clear();
TotalSize = 0;
TotalFiles = 0;
- TotalFolders = 0;
EntryCount = 0;
UpdateDriveInfo();
@@ -162,7 +159,6 @@ private async Task AnalyzeAsync()
{
var progress = new Progress(p =>
{
- CurrentFolder = p.CurrentFolder;
StatusMessage = $"Scanning folder {p.FoldersScanned}: {p.CurrentFolder}";
});
@@ -173,7 +169,6 @@ private async Task AnalyzeAsync()
EntryCount = Entries.Count;
TotalSize = Entries.Sum(e => e.SizeBytes);
TotalFiles = Entries.Sum(e => e.FileCount);
- TotalFolders = Entries.Sum(e => e.FolderCount);
ScanSummary = EntryCount == 0
? "No subfolders found."
@@ -201,7 +196,6 @@ private async Task AnalyzeAsync()
{
IsBusy = false;
IsProgressIndeterminate = false;
- CurrentFolder = "";
}
}
diff --git a/SysManager/SysManager/ViewModels/SpeedTestViewModel.cs b/SysManager/SysManager/ViewModels/SpeedTestViewModel.cs
index 335c90ca..f9fdac0b 100644
--- a/SysManager/SysManager/ViewModels/SpeedTestViewModel.cs
+++ b/SysManager/SysManager/ViewModels/SpeedTestViewModel.cs
@@ -45,7 +45,6 @@ public sealed partial class SpeedTestViewModel : ViewModelBase
"New York, US (ID: 10390)",
};
[ObservableProperty] private int _speedProgress;
- [ObservableProperty] private string _speedStatus = "";
[ObservableProperty] private string _httpStatus = "";
[ObservableProperty] private string _ooklaStatus = "";
[ObservableProperty] private bool _isSpeedTesting;