fix(quickfiler): repair three QfcExplorerController latent defects and remove its coverage exclusion (#449) - #585
Merged
drmoisan merged 3 commits intoAug 22, 2026
Conversation
) Addresses issue #449, epic child of quickfiler-suite-determinism-foundation. Defect 2 (behavioural, regression-tested): NavigateToOutlookFolder re-resolved _globals.Ol.App.ActiveExplorer() at call time instead of using the explorer captured in the constructor, so when the active explorer changed between construction and the call the wrong window was navigated. Fixed by assigning through _activeExplorer. A failing-before test was observed (EXIT 1, Moq VerifySet 0 times) and passes after. Defect 1 (contract): Removed the unimplemented ExplConvView_Cleanup member from IQfcExplorerController and its throwing implementation. It had zero compiled callers; the compiler enforces the paired edit on the single implementer. Defect 3 (dead code): Deleted the 139-line "Email Sorting To Rewrite" region, six unreachable private/internal statics duplicated from SortEmail.cs / EmailFiler.cs / SortItemsToExistingFolder.cs. Two latent defects inside it (transposed Path.Combine arguments, a write into a null ref string[]) are deleted rather than fixed, since unreachable code has no observable behaviour. Coverage seam (D5): Removed the class-level [ExcludeFromCodeCoverage] and added the injectable NotInViewDialogInvoker seam so both OpenQFItem branches are testable headlessly. The seam is declared as a fully-qualified System.Func<...> so it does not resurrect the orphaned "using System;" directive. Ten orphaned using directives removed; the analyzer build confirms none was required. Tests: 15 new MSTest cases (Moq + FluentAssertions), split across two files to respect the 500-line cap. Suite 6437 -> 6452 passed, 0 failed, 0 skipped, with a byte-identical pass set across two consecutive runs. Coverage: repo-wide 85.3290% -> 85.3571%; QuickFiler package 80.9163% -> 80.9898% (epic NFR met); QfcExplorerController absent-from-report -> 87.8261%; changed-line coverage 100% (3/3). Toolchain (single uninterrupted pass, all green): dotnet tool restore; csharpier format/check (0 files needing formatting); msbuild /t:Rebuild with analyzers (0 errors, 5 pre-existing System.Reactive warnings); msbuild /t:Rebuild with TreatWarningsAsErrors (0 errors); vstest with /InIsolation and coverage.
Completes issue #449. Marks all sixteen acceptance criteria in spec.md as delivered and adds the three remaining Phase 7 evidence artifacts: - ac12-csproj-diff shared-surface project-file diff; the Form1 regions owned by sibling child #491 are untouched - ac16-file-size-cap every non-Markdown file in the diff under 500 lines; SortEmail.cs and Legacy/QuickFileController.cs are pre-existing over-cap files absent from the diff - ac-status-summary 16/16 criteria PASS, 0 remaining Two reconciliations are recorded rather than silently absorbed: - AC-12's "exactly one appended line" is superseded by two, and AC-16's project-file figure of 485 by 486, because the [P6-T14] 500-line cap split required a second test file (569 lines -> 387 + 205). - AC-8's prose says "nine directives" while enumerating ten line numbers. The D4 table is authoritative: nine were removed in Phase 4 and the tenth in Phase 5. No directive was restored. The plan checklist is fully checked off: 98 of 98 tasks across Phases 0-7.
Adds the three feature-review artifacts produced for issue #449: policy-audit, code-review, and feature-audit (all 2026-08-22T10-58). Verdict: 0 Blocking findings. All 16 spec.md acceptance criteria PASS, independently re-verified by the reviewer against the raw Cobertura reports rather than accepted from the executor's evidence. Three non-blocking findings are recorded rather than remediated: - NB-1 two unused using directives stranded by the [P6-T14] test-file split; no gate fires (CS8019 is hidden, IDE0005 is not wired into these non-SDK projects), so this is fixed on next touch instead of spinning a remediation cycle for it. - NB-2 residual bookkeeping for the flaky-test promotion, resolved by the orchestrator: the promoted document could not ride this branch under the epic's docs/features/potential/** prohibition, and potential_to_issue had copied only its Summary section, so the full analysis was posted to issue #584 as a comment and the untracked local copy removed. Issue #584 is the durable record. - NB-3 traceability note for the AC-12/AC-16 supersession (one appended csproj line to two, 485 to 486), pre-authorized by the spec's split provision and evidenced in evidence/other/test-file-size. Also records two orchestrator memories learned on this run: that potential_to_issue retains only the Summary section, and that an epic kickoff's measured facts require independent verification. Refs #449, #584 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
drmoisan
merged commit Aug 22, 2026
5d1c207
into
epic/quickfiler-suite-determinism-foundation-integrationdrmoisan added a commit
that referenced
this pull request
Aug 22, 2026
Children 449 (PR #585, follow-up #590), 445 (PR #587), and 491 (PR #588) are merged; each merge commit was confirmed reachable from the fetched integration head rather than taken from a completion notification. Child 511 remains in atomic execution. Records seven carried findings, two of which correct this epic's own inputs: epic.md misattributed QuickFiler/Legacy/QuickFileController.cs's 1,065 lines to QuickFiler/Controllers/QfcExplorerController.cs (182 lines after change, and the legacy file has zero compile references), and collect_pr_context writes into the shared main checkout, letting one child overwrite a sibling's PR context (issue #589). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UHj7wjLweuwfAP8NDA4iiP
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 freeto 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.
fix(quickfiler): repair three QfcExplorerController latent defects and remove its coverage exclusion (#449)
Summary
ExplConvView_Cleanup()fromIQfcExplorerControllerand deletes itsNotImplementedExceptionimplementation, eliminating a runtime trap for the next caller of a public interface member.OpenQFItemso it reuses the constructor-captured_activeExplorerinstead of re-resolvingActiveExplorer(), removing both a redundant COM round-trip and an internal-consistency hazard. Carried by a genuine fail-before/pass-after regression test.#region Email Sorting To Rewriteblock, whose six private/internal statics had a provably empty inbound call graph, and removes tenusingdirectives orphaned by the deletions.[ExcludeFromCodeCoverage], putting the file into the coverage denominator for the first time, behind a new injectable modal-dialog seam that makes bothOpenQFItembranches testable headlessly.QuickFilerpackage coverage moves 80.9163% to 80.9898% and the previously unmeasured class enters at 87.8261%.Why
Three latent defects were found by reading during coverage research for issue #435, and none could be fixed there because that work's acceptance criteria forbid behavior changes. Recording them as prose inside a feature folder would have lost them at merge, so they were promoted to issue #449.
The coverage-exclusion removal is the substantive design decision (spec decision D5). The attribute was added on 2026-06-13 in commit
a564add0das part of the ratified COM/VSTO exemption, but it suppressed the whole class, including members that are testable once the one genuinely untestable dependency — a modal WinForms dialog — is placed behind a seam. Narrowing the attribute ontoOpenQFItemwas considered and rejected: the seam makes both of that method's branches reachable in a headless test, so narrowing would have left testable code unmeasured.What Changed
Core fix —
QuickFiler/Controllers/QfcExplorerController.cs(323 to 182 lines)NavigateToOutlookFolder(MailItem)assigns_activeExplorer.CurrentFolderrather than_globals.Ol.App.ActiveExplorer().CurrentFolder.ExplConvView_Cleanup()implementation is deleted.#region Email Sorting To Rewriteblock is deleted whole. Two further latent defects inside it — transposedPath.Combinearguments and a write into a nullref string[]— were deleted rather than fixed, since repairing unreachable code produces no observable effect.NotInViewDialogInvoker, aninternalsettable delegate seam defaulting toMessageBox.Show. The dialog's text, buttons, and icon are byte-identical to before; only the invocation route changes.Contract —
QuickFiler/Interfaces/IQfcExplorerController.csvoid ExplConvView_Cleanup();removed. The interface has exactly one implementer, so the compiler (CS0535) enforces the paired edit.Tests — two new files, 592 lines total
QuickFiler.Test/Controllers/QfcExplorerControllerTests.cs(387 lines) andQfcExplorerController.ConversationViewTests.cs(205 lines). The split exists to keep every file under the 500-line cap; the combined file measured 569.QuickFiler.Test/QuickFiler.Test.csprojgains exactly two<Compile Include>entries in theControllersitem group.Documentation and evidence
spec.mdacceptance criteria AC-1 through AC-16 checked off, 43 evidence artifacts, and the three feature-review audit artifacts.Architecture / How It Fits Together
QfcExplorerControlleris an Outlook-Interop-bound controller reached fromIFilerHomeController. It captures the activeExploreronce in its constructor and was inconsistently mixing that captured reference with freshActiveExplorer()resolutions.The seam follows the repository's existing settable-delegate idiom, demonstrated by
QfcHomeController.QfcExplorerControllerLoader. It is declared with the fully-qualified typeSystem.Func<...>rather than a bareFunc<...>specifically so it does not resurrect theusing System;directive the same change removes — the file already uses fully-qualifiedlog4net.ILogandSystem.Reflection.MethodBasein the same style.Tests reach the
internalmembers through the existing[assembly: InternalsVisibleTo("QuickFiler.Test")]inQuickFiler/Properties/AssemblyInfo.cs.Verification
Completed — full local C# toolchain, single clean pass
dotnet tool run csharpier check .msbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:EnableNETAnalyzers=true /p:EnforceCodeStyleInBuild=trueSkipping target "CoreCompile"occurrencesmsbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:TreatWarningsAsErrors=truevstest.console.exe ... /EnableCodeCoverage /InIsolation /TestCaseFilter:"TestCategory!=LiveOutlook"/t:Rebuildis load-bearing: a warm/t:BuildskipsCoreCompileon every project and returns exit 0 having run no analyzers, so the gate could not fail. The analyzer evidence therefore asserts a zero count ofSkipping target "CoreCompile"rather than acsc.execount.Coverage
QuickFilerpackageQfcExplorerControllerThe baseline value for the class is recorded as absent, not 0%: the class-level attribute suppressed it entirely, so it contributed no
<class>element. The post-change figure aggregates four<class>elements, becauseOpenQFItemisasyncand the compiler emits its state machine and lambdas as separate elements; reading a single element would report a figure for a fragment of the file.Determinism: the full suite was run twice consecutively with byte-identical pass sets, and the added tests contain no
Thread.Sleep,Task.Delay,MessageBox.Show, temporary-file API, orFormconstruction.Fail-before evidence: defect 2 has a real failing-then-passing pair (EXIT 1 with a verbatim
Moq.MockException, then EXIT 0). Defects 1 and 3 carry fail-before-exception dossiers, because removing an uncalled member and deleting provably unreachable code present no observable behavior a test could assert both before and after.CI note: this PR targets the epic integration branch.
.github/workflows/ci.ymltriggerspull_requestonly on[main, development], so no workflow fires and zero checks are expected. The absence of checks here is not a failure. The full local toolchain above is the green gate.Recommended: reviewers wanting to reproduce should run the four commands above in order from a bootstrapped worktree.
Backward Compatibility / Migration Notes
IQfcExplorerController.ExplConvView_Cleanup()is removed. The interface isinternaltoQuickFilerwith exactly one implementer and no compiled caller, so no in-repo caller required updating. The removed member's legacy semantics are preserved verbatim inspec.mdunder## Removed contract — legacy semantics for future restoration, so the behavior can be reimplemented deliberately rather than rediscovered.QuickFiler/Notes/notes_interfaces.csdeclares a duplicateIQfcExplorerControllerstill carrying the removed member. It is not compiled and is deliberately left inconsistent with the compiled contract; it is out of scope here.QuickFilerchanges. The user-visible dialog is unchanged.Risks and Mitigations
SortEmail.cs,EmailFiler.cs, andSortItemsToExistingFolder.cs, which carry their own tests. Verified by a zero-match search whose non-vacuity was checked (12 matches at merge-base, 0 now).[ExcludeFromCodeCoverage]drags coverage downMessageBox.Showin the file and that it sits inside the seam's default initialiser.git revertof03b50117restores prior behavior including the attribute.Review Guide
QuickFiler/Interfaces/IQfcExplorerController.cs— one deleted line, establishes the contract change.QuickFiler/Controllers/QfcExplorerController.cs— the substantive diff. The 139-line region deletion is mechanical bulk; the meaningful edits are theNavigateToOutlookFolderassignment target, the seam declaration, and the seam routing.QuickFiler.Test/Controllers/*.cs— new tests (net-new, no prior file existed).QuickFiler.Test/QuickFiler.Test.csproj— two added lines; see the shared-surface note below.spec.mdandevidence/— verification trail, safe to skim.Shared-surface note:
QuickFiler.Test.csprojis co-owned with concurrent sibling child #491, which owns theForm1compile region and theForm1.resxembedded resource. This PR's entire csproj diff is a single hunk at lines 117-123 in theControllersgroup, deliberately placed 42 lines clear of theForm1region to avoid a three-line merge-context collision. TheForm1regions are untouched.Follow-ups
UiThread.Dispatcherexposes anull!backing field with no lazy initialization, andProgressTrackerAsync.InitializeAsync()dereferences it on the next statement, producing a non-deterministicNullReferenceExceptionunder full-suite load. One such failure was observed during this change's QC run inUtilitiesCS.Test, a tree this PR does not touch. It was disclosed rather than suppressed — no test was modified, no retry added, no timing tolerance applied. Issue Bug: uithread-dispatcher-null-race-progresstrackerasync #584 also cross-references related issue Bug: uithread-dispatcher-static-swap-no-restore #493.usingdirectives (System.Collections,System.Collections.Generic) remain at the head ofQfcExplorerControllerTests.cs, stranded when the test file was split. No gate fires on them (CS8019 is hidden and IDE0005's analyzer is not wired into these non-SDK projects). Left for the next touch of the file rather than triggering a full toolchain re-run that would invalidate the audit artifacts.evidence/other/test-file-size.2026-08-22T09-16.md.GitHub Auto-close
This PR targets
epic/quickfiler-suite-determinism-foundation-integration, not the default branch, so a closing keyword would not fire on merge in any case. Issue #449 is referenced, not closed, and should be closed by the epic's final integration-to-main pull request.