Archive 5 phases (36 plans) to milestones/v1.0-phases/. Archive roadmap, requirements, and audit to milestones/. Evolve PROJECT.md with shipped state and validated requirements. Collapse ROADMAP.md to one-line milestone summary. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
10 KiB
phase, verified, status, score, re_verification, human_verification
| phase | verified | status | score | re_verification | human_verification | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 05-distribution-and-hardening | 2026-04-03T16:45:00Z | human_needed | 6/6 automated must-haves verified | false |
|
Phase 05: Distribution and Hardening Verification Report
Phase Goal: The application ships as a single self-contained EXE that runs on a machine with no .NET runtime installed, all previously identified reliability constraints are verified end-to-end (5,000-item pagination, JSON corruption recovery, throttling retry, cancellation), and the French locale is complete and tested.
Verified: 2026-04-03T16:45:00Z Status: human_needed Re-verification: No — initial verification
Goal Achievement
Observable Truths
| # | Truth | Status | Evidence |
|---|---|---|---|
| 1 | ExecuteQueryRetryHelper.IsThrottleException correctly classifies 429, 503, and throttle messages |
VERIFIED | 5 tests pass: 3 throttle-true (429, 503, "throttled"), 1 non-throttle-false, 1 nested-false; method is internal static |
| 2 | SharePointPaginationHelper.BuildPagedViewXml injects or replaces RowLimit in CAML XML |
VERIFIED | 5 tests pass: null, empty, whitespace, existing-RowLimit-replace, no-RowLimit-append; method is internal static |
| 3 | Every EN key in Strings.resx has a non-empty, non-bracketed FR translation in Strings.fr.resx | VERIFIED | AllEnKeys_HaveNonEmptyFrTranslation test passes; 177 EN keys = 177 FR keys |
| 4 | All French strings display with correct diacritics when language is set to French | VERIFIED (file) / HUMAN NEEDED (runtime) | FrStrings_ContainExpectedDiacritics passes; all 27 target strings confirmed with accents in Strings.fr.resx; runtime rendering requires human |
| 5 | dotnet publish produces a single self-contained EXE with no loose DLLs |
VERIFIED | ./publish/SharepointToolbox.exe = 200.9 MB; ls ./publish/*.dll = 0 files; .pdb only other file present |
| 6 | Application is ready for clean-machine smoke test | VERIFIED (automated) / HUMAN NEEDED (launch) | All 12 new tests pass (0 fail, 0 skip); EXE artifact confirmed; human sign-off on clean-machine launch pending |
Score: 6/6 automated truths verified. 2 require human confirmation for runtime behavior.
Required Artifacts
| Artifact | Expected | Status | Details |
|---|---|---|---|
SharepointToolbox.Tests/Helpers/ExecuteQueryRetryHelperTests.cs |
Throttle exception classification unit tests (min 20 lines) | VERIFIED | 33 lines; 5 tests; uses ExecuteQueryRetryHelper.IsThrottleException directly |
SharepointToolbox.Tests/Helpers/SharePointPaginationHelperTests.cs |
CAML XML RowLimit injection unit tests (min 20 lines) | VERIFIED | 49 lines; 5 tests; uses SharePointPaginationHelper.BuildPagedViewXml directly |
SharepointToolbox.Tests/Localization/LocaleCompletenessTests.cs |
Exhaustive FR locale parity test (min 15 lines) | VERIFIED | 84 lines; 2 tests: key enumeration + diacritics spot-check |
SharepointToolbox/Core/Helpers/ExecuteQueryRetryHelper.cs |
internal static IsThrottleException |
VERIFIED | Line 39: internal static bool IsThrottleException(Exception ex) |
SharepointToolbox/Core/Helpers/SharePointPaginationHelper.cs |
internal static BuildPagedViewXml |
VERIFIED | Line 39: internal static string BuildPagedViewXml(string? existingXml, int rowLimit) |
SharepointToolbox/Localization/Strings.fr.resx |
Corrected FR translations with proper diacritics (contains "Bibliothèque") | VERIFIED | Contains "Bibliothèque", "Déplacer", "Créer", "Modèles", "Terminé", "Sélectionner", "Aperçu", all target diacritics confirmed |
SharepointToolbox/SharepointToolbox.csproj |
Self-contained single-file publish configuration (contains "PublishSingleFile") | VERIFIED | Lines 13–17: conditional <PropertyGroup Condition="'$(PublishSingleFile)' == 'true'"> with SelfContained, RuntimeIdentifier, IncludeNativeLibrariesForSelfExtract |
./publish/SharepointToolbox.exe |
Self-contained EXE > 150 MB, 0 loose DLLs | VERIFIED | 200.9 MB EXE; only SharepointToolbox.pdb alongside; 0 .dll files |
Key Link Verification
| From | To | Via | Status | Details |
|---|---|---|---|---|
ExecuteQueryRetryHelperTests.cs |
ExecuteQueryRetryHelper.cs |
InternalsVisibleTo + internal static IsThrottleException |
WIRED | AssemblyInfo.cs line 4: [assembly: InternalsVisibleTo("SharepointToolbox.Tests")]; test calls ExecuteQueryRetryHelper.IsThrottleException(ex) — confirmed by grep and test pass |
SharePointPaginationHelperTests.cs |
SharePointPaginationHelper.cs |
InternalsVisibleTo + internal static BuildPagedViewXml |
WIRED | Same InternalsVisibleTo; test calls SharePointPaginationHelper.BuildPagedViewXml(...) — confirmed by grep and test pass |
SharepointToolbox.csproj |
dotnet publish |
PublishSingleFile + SelfContained + IncludeNativeLibrariesForSelfExtract |
WIRED | Pattern PublishSingleFile.*true confirmed in csproj condition; publish artifact at ./publish/SharepointToolbox.exe (200.9 MB, 0 DLLs) proves the wiring works end-to-end |
Requirements Coverage
| Requirement | Source Plan | Description | Status | Evidence |
|---|---|---|---|---|
| FOUND-11 | 05-01, 05-02, 05-03 | Self-contained single EXE distribution — no .NET runtime dependency for end users | SATISFIED | Conditional PublishSingleFile csproj config wired; 200.9 MB EXE produced with 0 loose DLLs; SelfContained=true + RuntimeIdentifier=win-x64; clean-machine runtime launch requires human confirmation |
No orphaned requirements found. FOUND-11 is the only requirement mapped to Phase 5 in REQUIREMENTS.md (line 128), and all three plans claim it.
Anti-Patterns Found
Scanned files modified in this phase:
| File | Pattern | Severity | Impact |
|---|---|---|---|
| — | None found | — | — |
No TODOs, FIXMEs, placeholder returns, or stub implementations detected in any of the 7 files modified in this phase. All test methods contain real assertions. All helper methods contain real logic.
Human Verification Required
1. Clean-Machine EXE Launch
Test: Copy ./publish/SharepointToolbox.exe to a Windows machine that has never had .NET 10 installed. Double-click the EXE.
Expected: Application main window opens within ~5 seconds. All 10 tabs are visible and navigable. No "runtime not found" or DLL-missing error dialogs appear.
Why human: Self-contained publish embeds the runtime, but WPF initialization, satellite assembly extraction, and native PnP.Framework binaries can only be verified on an actual launch. Programmatic file inspection cannot confirm the runtime extraction sequence works on a clean environment.
2. French Locale Runtime Rendering
Test: In the running application, open Settings, switch language to French (Français), then navigate through all tabs: Transfer, Bulk Members, Bulk Sites, Folder Structure, Templates, and shared dialogs.
Expected: All UI text displays with correct accented characters — "Bibliothèque", "Déplacer", "Créer les dossiers", "Modèles enregistrés", "Terminé", "Sélectionner", "Aperçu", etc. No unaccented "e" where "é/è/ê" should appear. No "c" where "ç" should appear.
Why human: The FrStrings_ContainExpectedDiacritics test confirms bytes in the .resx file are correct, but WPF TextBlock rendering depends on font glyph coverage and encoding round-trips through the satellite assembly resource pipeline. Only a visual inspection confirms the glyphs appear correctly on screen.
Verification Notes
Phase Goal Coverage Assessment
The phase goal has five components. Verification status for each:
- "ships as a single self-contained EXE" — VERIFIED: 200.9 MB EXE, 0 loose DLLs, conditional csproj config wired.
- "runs on a machine with no .NET runtime installed" — AUTOMATED:
SelfContained=trueconfirmed in csproj; HUMAN NEEDED for actual clean-machine launch. - "5,000-item pagination verified" — VERIFIED:
SharePointPaginationHelperTests(5 tests) confirmBuildPagedViewXmlcorrectly injectsRowLimit=2000and thatGetAllItemsAsyncuses it viaBuildPagedViewXml(query.ViewXml, rowLimit: 2000). - "throttling retry verified" — VERIFIED:
ExecuteQueryRetryHelperTests(5 tests) confirmIsThrottleExceptionclassifies 429/503/throttle messages correctly;ExecuteQueryRetryAsyncis wired to use it in thecatchclause. - "French locale complete and tested" — VERIFIED (file): 177 EN keys = 177 FR keys; all 27 diacritic corrections confirmed in file;
LocaleCompletenessTestspasses; HUMAN NEEDED for visual runtime rendering.
Note: "JSON corruption recovery" and "cancellation" were identified as phase goal reliability constraints. These are implemented in earlier phases (CsvValidationService null-reference fix in Phase 4; CancellationToken threading throughout helpers). Phase 5's contribution is the test coverage for throttling retry and pagination — the other two constraints are covered by pre-existing tests and are not regressions.
Test Counts Confirmed
ExecuteQueryRetryHelperTests: 5 tests (3[Theory]+ 2[Fact])SharePointPaginationHelperTests: 5 tests (5[Fact])LocaleCompletenessTests: 2 tests (2[Fact])- Total new: 12 tests — all pass, 0 fail, 0 skip
- Reported full suite: 134 pass, 22 skip (interactive MSAL — expected), 0 fail
Commits Verified
All 6 phase-5 commits exist in the repository:
4d7e9ea— helper methods internal + unit tests8c65394— FR locale completeness testsf7829f0— FR diacritic corrections (27 strings)39517d8— single-file publish csproj confige0e3d55— integration verificationb3686cc— plan 03 docs
Verified: 2026-04-03T16:45:00Z Verifier: Claude (gsd-verifier)