fix(01-foundation): revise plans based on checker feedback

- 01-03: wave 2 → wave 3 (depends on 01-02 which is also wave 2; must be wave 3)
- 01-06: add ProgressUpdatedMessage.cs to files_modified; add third StatusBarItem (progress %) to XAML per locked CONTEXT.md decision; add ProgressUpdatedMessage subscription in MainWindowViewModel.OnActivated()
- 01-08: add comment to empty <files> element (auto task with no file output)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Dev
2026-04-02 11:44:54 +02:00
parent ff5ac94ae2
commit eeb9a3bcd1
3 changed files with 35 additions and 6 deletions

View File

@@ -2,7 +2,7 @@
phase: 01-foundation phase: 01-foundation
plan: 03 plan: 03
type: execute type: execute
wave: 2 wave: 3
depends_on: depends_on:
- 01-01 - 01-01
- 01-02 - 01-02

View File

@@ -8,6 +8,7 @@ depends_on:
- 01-04 - 01-04
- 01-05 - 01-05
files_modified: files_modified:
- SharepointToolbox/Core/Messages/ProgressUpdatedMessage.cs
- SharepointToolbox/ViewModels/FeatureViewModelBase.cs - SharepointToolbox/ViewModels/FeatureViewModelBase.cs
- SharepointToolbox/ViewModels/MainWindowViewModel.cs - SharepointToolbox/ViewModels/MainWindowViewModel.cs
- SharepointToolbox/ViewModels/ProfileManagementViewModel.cs - SharepointToolbox/ViewModels/ProfileManagementViewModel.cs
@@ -53,6 +54,10 @@ must_haves:
to: "SharepointToolbox/Core/Messages/TenantSwitchedMessage.cs" to: "SharepointToolbox/Core/Messages/TenantSwitchedMessage.cs"
via: "WeakReferenceMessenger.Default.Send on ComboBox selection change" via: "WeakReferenceMessenger.Default.Send on ComboBox selection change"
pattern: "TenantSwitchedMessage" pattern: "TenantSwitchedMessage"
- from: "SharepointToolbox/ViewModels/MainWindowViewModel.cs"
to: "SharepointToolbox/Core/Messages/ProgressUpdatedMessage.cs"
via: "Messenger.Register<ProgressUpdatedMessage> in OnActivated — updates StatusBar observable properties"
pattern: "ProgressUpdatedMessage"
--- ---
<objective> <objective>
@@ -113,6 +118,7 @@ public sealed class LanguageChangedMessage : ValueChangedMessage<string>
<task type="auto" tdd="true"> <task type="auto" tdd="true">
<name>Task 1: FeatureViewModelBase + unit tests</name> <name>Task 1: FeatureViewModelBase + unit tests</name>
<files> <files>
SharepointToolbox/Core/Messages/ProgressUpdatedMessage.cs,
SharepointToolbox/ViewModels/FeatureViewModelBase.cs, SharepointToolbox/ViewModels/FeatureViewModelBase.cs,
SharepointToolbox.Tests/ViewModels/FeatureViewModelBaseTests.cs SharepointToolbox.Tests/ViewModels/FeatureViewModelBaseTests.cs
</files> </files>
@@ -248,6 +254,8 @@ public sealed class LanguageChangedMessage : ValueChangedMessage<string>
```csharp ```csharp
[ObservableProperty] private TenantProfile? _selectedProfile; [ObservableProperty] private TenantProfile? _selectedProfile;
[ObservableProperty] private string _connectionStatus = "Not connected"; [ObservableProperty] private string _connectionStatus = "Not connected";
[ObservableProperty] private string _progressStatus = string.Empty;
[ObservableProperty] private int _progressPercentage;
public ObservableCollection<TenantProfile> TenantProfiles { get; } = new(); public ObservableCollection<TenantProfile> TenantProfiles { get; } = new();
// ConnectCommand: calls SessionManager.GetOrCreateContextAsync(SelectedProfile) // ConnectCommand: calls SessionManager.GetOrCreateContextAsync(SelectedProfile)
@@ -257,6 +265,22 @@ public sealed class LanguageChangedMessage : ValueChangedMessage<string>
// LoadProfilesAsync: called on startup, loads from ProfileService // LoadProfilesAsync: called on startup, loads from ProfileService
``` ```
Override `OnActivated()` to register for `ProgressUpdatedMessage` from any active feature ViewModel:
```csharp
protected override void OnActivated()
{
base.OnActivated();
Messenger.Register<ProgressUpdatedMessage>(this, (r, m) =>
{
r.ProgressStatus = m.Value.Message;
r.ProgressPercentage = m.Value.Total > 0
? (int)(100.0 * m.Value.Current / m.Value.Total)
: 0;
});
}
```
This wires the StatusBar operation text and progress % to live updates from any running feature operation.
**ProfileManagementViewModel.cs**: Wraps ProfileService for dialog binding. **ProfileManagementViewModel.cs**: Wraps ProfileService for dialog binding.
- `ObservableCollection<TenantProfile> Profiles` - `ObservableCollection<TenantProfile> Profiles`
- `AddCommand`, `RenameCommand`, `DeleteCommand` - `AddCommand`, `RenameCommand`, `DeleteCommand`
@@ -269,7 +293,8 @@ public sealed class LanguageChangedMessage : ValueChangedMessage<string>
- On language change: updates `TranslationSource.Instance.CurrentCulture` + calls `SettingsService.SetLanguageAsync` - On language change: updates `TranslationSource.Instance.CurrentCulture` + calls `SettingsService.SetLanguageAsync`
- `RunOperationAsync`: not applicable — stub throws `NotSupportedException` (Settings tab has no long-running operation) - `RunOperationAsync`: not applicable — stub throws `NotSupportedException` (Settings tab has no long-running operation)
**MainWindow.xaml** — Full shell layout as locked in CONTEXT.md: **MainWindow.xaml** — Full shell layout as locked in CONTEXT.md.
StatusBar MUST have three fields per the locked decision (tenant name | operation status text | progress percentage):
```xml ```xml
<Window Title="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[app.title]}" <Window Title="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[app.title]}"
MinWidth="900" MinHeight="600"> MinWidth="900" MinHeight="600">
@@ -288,11 +313,13 @@ public sealed class LanguageChangedMessage : ValueChangedMessage<string>
Command="{Binding ClearSessionCommand}" /> Command="{Binding ClearSessionCommand}" />
</ToolBar> </ToolBar>
<!-- StatusBar --> <!-- StatusBar: three fields per locked layout decision -->
<StatusBar DockPanel.Dock="Bottom" Height="24"> <StatusBar DockPanel.Dock="Bottom" Height="24">
<StatusBarItem Content="{Binding SelectedProfile.Name}" /> <StatusBarItem Content="{Binding SelectedProfile.Name}" />
<Separator /> <Separator />
<StatusBarItem Content="{Binding ConnectionStatus}" /> <StatusBarItem Content="{Binding ConnectionStatus}" />
<Separator />
<StatusBarItem Content="{Binding ProgressPercentage, StringFormat={}{0}%}" />
</StatusBar> </StatusBar>
<!-- Log Panel --> <!-- Log Panel -->
@@ -370,7 +397,7 @@ public sealed class LanguageChangedMessage : ValueChangedMessage<string>
<verify> <verify>
<automated>cd "C:\Users\dev\Documents\projets\Sharepoint" && dotnet build SharepointToolbox/SharepointToolbox.csproj 2>&1 | tail -5</automated> <automated>cd "C:\Users\dev\Documents\projets\Sharepoint" && dotnet build SharepointToolbox/SharepointToolbox.csproj 2>&1 | tail -5</automated>
</verify> </verify>
<done>Build succeeds with 0 errors. MainWindow.xaml contains RichTextBox x:Name="LogPanel". All 8 tab headers use TranslationSource bindings. Global exception handlers registered in App.xaml.cs.</done> <done>Build succeeds with 0 errors. MainWindow.xaml contains RichTextBox x:Name="LogPanel". StatusBar has three StatusBarItems (tenant name, connection status, progress %). All 8 tab headers use TranslationSource bindings. Global exception handlers registered in App.xaml.cs.</done>
</task> </task>
</tasks> </tasks>
@@ -379,13 +406,15 @@ public sealed class LanguageChangedMessage : ValueChangedMessage<string>
- `dotnet build SharepointToolbox.sln` passes with 0 errors - `dotnet build SharepointToolbox.sln` passes with 0 errors
- `dotnet test --filter "Category=Unit"` all pass - `dotnet test --filter "Category=Unit"` all pass
- MainWindow.xaml contains `x:Name="LogPanel"` RichTextBox - MainWindow.xaml contains `x:Name="LogPanel"` RichTextBox
- MainWindow.xaml StatusBar has three StatusBarItems: SelectedProfile.Name | ConnectionStatus | ProgressPercentage%
- App.xaml.cs registers `DispatcherUnhandledException` and `TaskScheduler.UnobservedTaskException` - App.xaml.cs registers `DispatcherUnhandledException` and `TaskScheduler.UnobservedTaskException`
- FeatureViewModelBase contains no `async void` methods (anti-pattern violation) - FeatureViewModelBase contains no `async void` methods (anti-pattern violation)
- ObservableCollection is never modified from Task.Run (pattern 7 compliance) - ObservableCollection is never modified from Task.Run (pattern 7 compliance)
- MainWindowViewModel.OnActivated() subscribes to ProgressUpdatedMessage and updates ProgressStatus + ProgressPercentage
</verification> </verification>
<success_criteria> <success_criteria>
Application compiles and launches to a visible WPF shell. FeatureViewModelBase tests green. All ViewModels registered in DI. Log panel wired to Serilog. Application compiles and launches to a visible WPF shell. FeatureViewModelBase tests green. All ViewModels registered in DI. Log panel wired to Serilog. StatusBar shows all three fields including live progress percentage.
</success_criteria> </success_criteria>
<output> <output>

View File

@@ -62,7 +62,7 @@ Output: Confirmed working foundation. Green light for Phase 2.
<task type="auto"> <task type="auto">
<name>Task 1: Run full test suite and verify zero failures</name> <name>Task 1: Run full test suite and verify zero failures</name>
<files></files> <files><!-- no files created or modified — test-execution-only task --></files>
<action> <action>
Run the complete test suite: Run the complete test suite:
``` ```