fix(folder-tree): preserve Outlook STA affinity during traversal - #422
Merged
Conversation
Owner
Author
|
Reopening to trigger the repository pull_request CI workflow at the unchanged final head. |
Owner
Author
|
Reopening at 792804d to trigger the native pull_request CI event. |
Owner
Author
|
Deliberate close before a separately confirmed reopen to trigger pull_request CI. |
- Add a Func<Task<TResult>> overload to IUiDispatcher and WpfUiDispatcher so folder-tree snapshot builds await on the captured UI dispatcher instead of a dispatcher-free worker. - Harden OutlookFolderTreeService lifecycle: linked dispose cancellation, linearized scheduled refreshes, guarded SnapshotChanged dispatch, and disposed-state build authorization. - Extract FilterOlFoldersController lifecycle into a partial file with an async CreateAsync factory and deterministic subscription teardown. - Move folder-tree service construction and disposal into the AppOlObjects.FolderTreeService partial and route the ribbon folder-filter callback through async fault reporting. - Add MSTest coverage for dispatcher affinity, traversal cancellation, invalidation, disposal races, and controller initialization. Refs: #420
Preserve terminal dispatch state during folder-tree service completion.\nStop filter-view publication after controller disposal.\nAdd lifecycle, cancellation, and dispatcher regression coverage.\n\nRefs: #420
drmoisan
force-pushed
the
bug/folder-tree-dispatcher-thread-affinity-420
branch
from
August 6, 2026 23:31
792804d to
58b5167
Compare
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.
Suggested title: fix(folder-tree): preserve Outlook STA affinity during traversal
Summary
WpfDispatcherYieldstrict.Why
A cold folder-tree request initiated by
EmailDataMineron a worker could reachWpfDispatcherYieldwithout a current WPF dispatcher and raiseInvalidOperationException. ATask.Yieldfallback would avoid that immediate exception but would not restore the Outlook STA requirement for subsequent live COM access. The repair therefore establishes dispatcher ownership at service composition and retains it throughout live traversal.What Changed
Architecture / How It Fits Together
A worker caller enters the session-scoped
AppOlObjectsservice gate. Composition and live operations are marshaled through the capturedIUiDispatcher/WpfUiDispatchertoOutlookFolderTreeService, then toFolderTreeSnapshotBuilderandOutlookFolderHierarchyReader.WpfDispatcherYieldruns only within that dispatcher context, and the immutable snapshot is returned to the caller after traversal. FilterOlFolders awaits the snapshot and commits UI state only while its viewer and subscriptions remain owned and undisposed.Verification
Completed
dotnet tool run csharpier format .completed successfully;dotnet tool run csharpier check .reported no formatting changes.msbuild TaskMaster.sln /t:Build /p:Configuration=Debug /p:Platform='Any CPU' /p:EnableNETAnalyzers=true /p:EnforceCodeStyleInBuild=truecompleted with 0 errors.msbuild TaskMaster.sln /t:Build /p:Configuration=Debug /p:Platform='Any CPU' /p:Nullable=enable /p:TreatWarningsAsErrors=truecompleted with 0 errors and no nullable diagnostics.pwsh -NoProfile -ExecutionPolicy Bypass -File scripts/vscode/Invoke-MSTestWithCoverage.ps1 -SearchRoot . -Configuration Debug -CoverageOutput docs/features/active/2026-08-04-folder-tree-dispatcher-thread-affinity-420/evidence/qa-gates/remediation-cycle4-coverage-final.cobertura.xmlpassed 6,166 of 6,166 tests across eight assemblies.git diff --check origin/maincompleted with no whitespace errors.REVIEW_STATUS: PASS, and the policy, code-review, and feature-audit artifacts passed validation.Completed after rebase onto
origin/main@02ebd260The branch was rebased onto current
main(which now contains the issue #418 work merged via PR #421). The five feature commits replayed with no conflicts. The following gates were re-run against the rebased head58b51676:dotnet csharpier check .— checked 1,479 files, no formatting changes.msbuild TaskMaster.sln /t:Build /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:EnableNETAnalyzers=true /p:EnforceCodeStyleInBuild=true— exit 0.msbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:TreatWarningsAsErrors=true— exit 0, no errors.Recommended
Backward Compatibility / Migration Notes
No migration is required.
IUiDispatcher.BeginInvoke(Action): IAsyncResultremains available, the additional dispatcher operations are additive, and existing public FilterOlFolders call paths remain compatible. No package, configuration, or external-service dependency was added.Risks and Mitigations
LiveOutlook; the live VSTO exercise remains a release-validation step.Review Guide
AppOlObjectsservice composition and captured-dispatcher ownership.OutlookFolderTreeService,FolderTreeSnapshotBuilder, andOutlookFolderHierarchyReadertraversal and cleanup behavior.Follow-ups
GitHub Auto-close