Files
Sharepoint-Toolbox/.planning/phases/06-global-site-selection/06-VERIFICATION.md
2026-04-07 10:18:14 +02:00

138 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
phase: 06-global-site-selection
verified: 2026-04-07T00:00:00Z
status: passed
score: 7/7 truths verified
re_verification: false
---
# Phase 06: Global Site Selection Verification Report
**Phase Goal:** Administrators can select one or more target sites once from the toolbar and have every feature tab use that selection by default
**Verified:** 2026-04-07
**Status:** PASSED
**Re-verification:** No — initial verification
---
## Goal Achievement
### Observable Truths
| # | Truth | Status | Evidence |
|---|-------|--------|----------|
| 1 | GlobalSitesChangedMessage exists following the ValueChangedMessage pattern | VERIFIED | `GlobalSitesChangedMessage.cs``sealed class ... : ValueChangedMessage<IReadOnlyList<SiteInfo>>` |
| 2 | FeatureViewModelBase receives message, stores GlobalSites, exposes virtual hook | VERIFIED | `FeatureViewModelBase.cs` lines 30, 8283, 90103 — property, registration, private receiver, virtual override |
| 3 | MainWindowViewModel owns GlobalSelectedSites, broadcasts message, clears on tenant/session | VERIFIED | `MainWindowViewModel.cs` lines 4375, 102103, 146 — collection, CollectionChanged broadcast, clear paths |
| 4 | Toolbar shows "Select Sites" button bound to OpenGlobalSitePickerCommand and a live count label | VERIFIED | `MainWindow.xaml` lines 2631; `MainWindow.xaml.cs` lines 2529 — button, TextBlock, dialog factory wired |
| 5 | Localization keys present in EN and FR for all 5 toolbar strings | VERIFIED | `Strings.resx` lines 308320; `Strings.fr.resx` lines 308320 — 5 keys each |
| 6 | All 6 consuming tab VMs override OnGlobalSitesChanged with local-override protection | VERIFIED | Grep confirms override in: PermissionsViewModel, StorageViewModel, SearchViewModel, DuplicatesViewModel, FolderStructureViewModel, TransferViewModel; BulkMembersViewModel confirmed excluded (no match) |
| 7 | 10 unit tests pass covering the full contract; no regressions in existing suite | VERIFIED | `dotnet test --filter GlobalSiteSelection` → 10 Passed; full suite → 144 Passed, 22 Skipped, 0 Failed |
**Score:** 7/7 truths verified
---
### Required Artifacts
| Artifact | Provides | Status | Details |
|----------|----------|--------|---------|
| `SharepointToolbox/Core/Messages/GlobalSitesChangedMessage.cs` | Messenger message for global site selection | VERIFIED | Exists, substantive (9 lines, ValueChangedMessage<IReadOnlyList<SiteInfo>>), registered in FeatureViewModelBase |
| `SharepointToolbox/ViewModels/FeatureViewModelBase.cs` | Base class with GlobalSites property and virtual hook | VERIFIED | Contains `GlobalSites`, `OnGlobalSitesChanged`, registration in `OnActivated` |
| `SharepointToolbox/ViewModels/MainWindowViewModel.cs` | Global site selection state, command, broadcast | VERIFIED | Contains `GlobalSelectedSites`, `OpenGlobalSitePickerCommand`, `GlobalSitesSelectedLabel`, `BroadcastGlobalSites` |
| `SharepointToolbox/MainWindow.xaml` | Toolbar with Select Sites button and count label | VERIFIED | Contains `OpenGlobalSitePickerCommand` binding and `GlobalSitesSelectedLabel` TextBlock |
| `SharepointToolbox/MainWindow.xaml.cs` | SitePickerDialog factory wiring | VERIFIED | Contains `OpenGlobalSitePickerDialog` factory lambda |
| `SharepointToolbox/Localization/Strings.resx` | EN localization keys | VERIFIED | 5 keys: toolbar.selectSites, toolbar.selectSites.tooltip, toolbar.selectSites.tooltipDisabled, toolbar.globalSites.count, toolbar.globalSites.none |
| `SharepointToolbox/Localization/Strings.fr.resx` | FR localization keys | VERIFIED | Same 5 keys with French translations |
| `SharepointToolbox/ViewModels/Tabs/PermissionsViewModel.cs` | Multi-site global consumption | VERIFIED | `OnGlobalSitesChanged` override, `_hasLocalSiteOverride`, reset in `OnTenantSwitched` |
| `SharepointToolbox/ViewModels/Tabs/StorageViewModel.cs` | Single-site global consumption | VERIFIED | `OnGlobalSitesChanged`, `OnSiteUrlChanged` partial, `_hasLocalSiteOverride`, reset in `OnTenantSwitched` |
| `SharepointToolbox/ViewModels/Tabs/SearchViewModel.cs` | Single-site global consumption | VERIFIED | `OnGlobalSitesChanged` confirmed present |
| `SharepointToolbox/ViewModels/Tabs/DuplicatesViewModel.cs` | Single-site global consumption | VERIFIED | `OnGlobalSitesChanged` confirmed present |
| `SharepointToolbox/ViewModels/Tabs/FolderStructureViewModel.cs` | Single-site global consumption | VERIFIED | `OnGlobalSitesChanged` confirmed present |
| `SharepointToolbox/ViewModels/Tabs/TransferViewModel.cs` | Single-site (SourceSiteUrl) global consumption | VERIFIED | `OnGlobalSitesChanged`, `_hasLocalSourceSiteOverride`, `OnSourceSiteUrlChanged` confirmed present |
| `SharepointToolbox.Tests/ViewModels/GlobalSiteSelectionTests.cs` | 10 unit tests for full contract | VERIFIED | All 10 tests pass |
---
### Key Link Verification
| From | To | Via | Status | Details |
|------|----|-----|--------|---------|
| `FeatureViewModelBase.cs` | `GlobalSitesChangedMessage.cs` | `Messenger.Register<GlobalSitesChangedMessage>` in OnActivated | WIRED | Line 82: `Messenger.Register<GlobalSitesChangedMessage>(this, (r, m) => ...)` |
| `MainWindowViewModel.cs` | `GlobalSitesChangedMessage.cs` | `WeakReferenceMessenger.Default.Send` in BroadcastGlobalSites | WIRED | Lines 180182: `WeakReferenceMessenger.Default.Send(new GlobalSitesChangedMessage(...))` |
| `MainWindow.xaml` | `MainWindowViewModel.cs` | Command binding for OpenGlobalSitePickerCommand | WIRED | Line 27: `Command="{Binding OpenGlobalSitePickerCommand}"` |
| `MainWindow.xaml.cs` | `SitePickerDialog.xaml.cs` | Dialog factory lambda using DI | WIRED | Lines 2529: `viewModel.OpenGlobalSitePickerDialog = () => { var factory = serviceProvider.GetRequiredService<Func<TenantProfile, SitePickerDialog>>(); ... }` |
| `PermissionsViewModel.cs` | `FeatureViewModelBase.cs` | Override of OnGlobalSitesChanged virtual method | WIRED | Line 161: `protected override void OnGlobalSitesChanged(IReadOnlyList<SiteInfo> sites)` |
| `StorageViewModel.cs` | `FeatureViewModelBase.cs` | Override of OnGlobalSitesChanged virtual method | WIRED | Line 100: `protected override void OnGlobalSitesChanged(IReadOnlyList<SiteInfo> sites)` |
| `GlobalSiteSelectionTests.cs` | `MainWindowViewModel.cs` | Tests broadcast and clear behavior | WIRED | Test 10 uses `GlobalSelectedSites`; Tests 19 send via WeakReferenceMessenger |
| `GlobalSiteSelectionTests.cs` | `StorageViewModel.cs` | Tests single-site consumption and local override | WIRED | Tests 35, 8 exercise `OnGlobalSitesChanged` via messenger send |
---
### Requirements Coverage
| Requirement | Source Plans | Description | Status | Evidence |
|-------------|-------------|-------------|--------|----------|
| SITE-01 | 06-01, 06-02, 06-03, 06-04, 06-05 | User can select one or multiple target sites from toolbar and all feature tabs use that selection as default | SATISFIED | Message contract (06-01), MainWindowViewModel broadcast (06-02), toolbar UI (06-03), tab VM consumption (06-04), unit tests (06-05) — full end-to-end chain verified |
| SITE-02 | 06-04, 06-05 | User can override global site selection per-tab for single-site operations | SATISFIED | `_hasLocalSiteOverride` field in all 6 consuming VMs; `OnSiteUrlChanged` / `OnSourceSiteUrlChanged` partial methods detect user typing; tests 4, 7 verify local override prevents global overwrite |
No orphaned requirements — REQUIREMENTS.md maps only SITE-01 and SITE-02 to Phase 6, and both are claimed and satisfied by the plans.
---
### Anti-Patterns Found
None. Files scanned for TODO/FIXME/HACK/PLACEHOLDER, empty implementations, and stub returns:
- "placeholder" occurrences in `MainWindow.xaml.cs` are code comments (`// Replace ... placeholder with the DI-resolved ...`) describing the construction pattern — they are not stub implementations.
- "placeholder" in export service HTML strings is an HTML `<input placeholder=...>` attribute — unrelated to implementation stubs.
- No empty handlers, `return null`, `return {}`, or `console.log`-only implementations found.
- Build: 0 errors, 0 warnings.
---
### Human Verification Required
The following items cannot be verified programmatically and require a running instance of the application:
#### 1. Select Sites button visual presence and position
**Test:** Launch the application, connect to a tenant profile. Observe the main toolbar.
**Expected:** A "Select Sites" button is visible after the Clear Session button separator, followed by a gray label showing "No sites selected" (or the FR equivalent if app is in French).
**Why human:** XAML rendering and visual layout cannot be verified from static file analysis.
#### 2. SitePickerDialog opens on button click
**Test:** Click the "Select Sites" toolbar button while connected to a tenant.
**Expected:** The SitePickerDialog opens, displaying the sites for the connected tenant. Selecting sites and clicking OK updates the count label (e.g., "2 site(s) selected").
**Why human:** Dialog opening requires a live DI container, real window handle, and SharePoint connectivity.
#### 3. Button disabled state when no profile is connected
**Test:** Launch the application without selecting a tenant profile (or deselect the current one).
**Expected:** The "Select Sites" button appears visually disabled and cannot be clicked.
**Why human:** WPF CanExecute rendering requires a live UI; IsEnabled binding cannot be observed statically.
#### 4. Tab pre-fill behavior end-to-end
**Test:** Select 2 sites globally. Navigate to the Storage tab, Search tab, Permissions tab, and Transfer tab.
**Expected:** Storage/Search SiteUrl fields show the first selected site URL; Permissions SelectedSites shows both sites; Transfer SourceSiteUrl shows the first site URL.
**Why human:** UI binding rendering from pre-filled ViewModel state requires a running application.
#### 5. Local override does not disrupt global selection
**Test:** With 2 global sites selected, go to the Storage tab and type a custom URL in the site URL field. Switch to the Permissions tab.
**Expected:** Permissions tab still shows the 2 globally selected sites. The Storage tab keeps the manually typed URL. The toolbar still shows "2 site(s) selected."
**Why human:** Cross-tab state isolation requires observing live UI across multiple tab switches.
---
### Gaps Summary
No gaps. All 7 observable truths are verified. All 14 required artifacts exist, are substantive, and are wired. All 8 key links are confirmed. Both requirements (SITE-01, SITE-02) are satisfied with full traceability. The test suite confirms correctness with 10 new passing tests and 0 regressions.
---
_Verified: 2026-04-07_
_Verifier: Claude (gsd-verifier)_