Skip to content

fix(quickfiler): resolve issue #726 code-correctness sweep (6 of 8 findings) - #738

Merged
drmoisan merged 2 commits into
mainfrom
bug/quickfiler-review-sweep-code-defects-726
Sep 2, 2026
Merged

fix(quickfiler): resolve issue #726 code-correctness sweep (6 of 8 findings)#738
drmoisan merged 2 commits into
mainfrom
bug/quickfiler-review-sweep-code-defects-726

Conversation

@drmoisan

@drmoisan drmoisan commented Sep 2, 2026

Copy link
Copy Markdown
Owner

Suggested title

fix(quickfiler): resolve issue #726 code-correctness sweep (6 of 8 findings)

Summary

  • Hardens FilerQueue's consumer-running flag with a try/finally barrier so an exception in the worker loop can no longer leave the queue permanently stuck; applies the same hardening to the sibling FlagChangeTrainingQueue.
  • Routes EfcItemController's two fire-and-forget InitializeWebViewAsync calls through a new guarded wrapper, mirroring the existing QfcItemController fault boundary, so a fault is logged instead of silently discarded.
  • Guards three boundary error-sink delegates (EfcItemController, QfcItemController, EfcFormController) against a null or throwing sink, closing a latent path back to the exact unobserved-fault behavior those boundaries exist to prevent.
  • Fixes a null-guard/ordering defect in QfcHomeController's metrics write path and removes an orphaned calendar appointment when diagnostics are empty.
  • Fixes TaskViewer.ProcessCmdKey to fall through to base.ProcessCmdKey when the controller does not consume an Alt-chord keystroke, instead of unconditionally swallowing every Alt-modified key.
  • Removes dead code: two unused locals in QfcFormViewer.ProcessCmdKey, and a write-only field in QfcFormController that started a discarded, unawaited MailItemHelper.FromMailItemAsync call per item.
  • Adds a missing positive regression test for the Keys.Menu | Keys.Alt Alt-chord shape and two FilerQueue regression tests (null-item guard, empty-Helpers exceptional-exit recovery).
  • Explicitly defers three sub-findings, each with evidence, rather than forcing a fix outside this change's scope (see "Follow-ups").

Why

This consolidates eight code-correctness findings surfaced during the bugs-638-644-647 parallel-orchestration review sweep. Each finding was identified by a prior item's feature-review agent but deliberately left unfixed at the time because fixing it would have exceeded that item's declared file-footprint scope. Rather than run eight separate bug-fix cycles for findings that are each small in isolation, they are consolidated into this one issue (see issue #726 body, and the repo's established practice for consolidated multi-defect issues per #451 and #619).

Two findings are rated High severity individually:

  • The FilerQueue flag leak (finding 1) can hang the background mail-filing mover once the narrow trigger condition — an exception inside the diagnostic branch of the catch handler, or a null item — is hit.
  • The EfcItemController unguarded fire-and-forget (finding 4) is classified live by the same reasoning that made the sibling fix in issue Bug: qfc-initializewebviewasync-fault-is-unobserved #670 necessary: a discarded faulted Task under .NET Framework 4.5+ is silently finalized with no diagnostic.

What Changed

Core logic:

  • QuickFiler/Controllers/FilerQueue.cs — null guard on Enqueue; ConsumeAsync narrowed to internal (no external callers); worker loop body wrapped in try/finally clearing _consumerRunning under the lock on every exit path; empty/null-safe diagnostic logging extracted to LogItemFailure.
  • TaskVisualization/FlagChangeTrainingQueue.cs — the identical try/finally guard-reset hardening applied to this sibling queue's consumer loop.
  • QuickFiler/Controllers/EfcItemController.cs + new QuickFiler/Controllers/EfcItemController.WebViewFaultBoundary.cs — both InitializeWebViewAsync call sites now go through InitializeWebViewGuardedAsync, which catches and routes faults to an injectable WebViewInitializationErrorSink.
  • QuickFiler/Controllers/QfcItemController.WebViewFaultBoundary.cs and QuickFiler/Controllers/EfcFormController.cs — sink invocations wrapped so a null or throwing sink delegate falls back to the logger instead of faulting the guard task.
  • QuickFiler/Controllers/QfcHomeController.Metrics.cs — null-safe diagnostics line array; deletes the orphaned calendar appointment when diagnostics are empty (kept the existing call order because GetMoveDiagnostics takes the appointment by ref).
  • TaskVisualization/TaskViewer.csProcessCmdKey now returns true only when the controller actually consumed the Alt-chord keystroke, otherwise falls through to base.ProcessCmdKey.
  • QuickFiler/Viewers/QfcFormViewer.cs — removed two dead locals with no effect on the real event pipeline.
  • QuickFiler/Controllers/QfcFormController.cs + QfcFormController.Actions.cs — removed the write-only _helperTasks field, which started a MailItemHelper.FromMailItemAsync call per item and discarded the result unawaited; the sync pipeline it fed builds its own MailItemHelper via a separate synchronous constructor.

Tests:

  • QuickFiler.Test/Controllers/FilerQueueTests.csEnqueue_NullItem_ThrowsArgumentNullException; ConsumeAsync_ItemWithEmptyHelpersThrows_ConsumerRecoversForLaterItems (proves the consumer recovers and processes a later item after an exceptional exit, not just the normal empty-queue exit).
  • QuickFiler.Test/Controllers/EfcViewerTests.csClaimsAltChord_WithMenuKeyAndAlt_ReturnsTrue (the Keys.Menu disjunct of ClaimsAltChord's guard was previously deletable without failing any existing test).

Build:

  • QuickFiler/QuickFiler.csproj — registers the new EfcItemController.WebViewFaultBoundary.cs compile item.

Architecture / How It Fits Together

No new components or wiring. Each fix stays within the file(s) that own the defective behavior:

  • FilerQueue / FlagChangeTrainingQueue: internal loop hardening, no external contract change (ConsumeAsync's narrowing to internal was verified to have zero external callers).
  • EfcItemController's new fault boundary is a partial class file mirroring the existing QfcItemController.WebViewFaultBoundary.cs pattern already in the codebase, so both viewers now expose the same shape of injectable error sink.
  • The QfcFormController dead-field removal has no downstream effect: the field was never read, so the pipeline's actual behavior (a fresh MailItemHelper built synchronously per item inside QfcItemController.Initialize) is unchanged.

Verification

Completed:

  • dotnet tool run csharpier format . — clean, 14 files in the intended change set, no unrelated drift.
  • msbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:EnableNETAnalyzers=true /p:EnforceCodeStyleInBuild=true — Build succeeded, 0 Error(s).
  • msbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:TreatWarningsAsErrors=true — Build succeeded, 0 Error(s).
  • vstest.console.exe QuickFiler.Test.dll TaskVisualization.Test.dll /Platform:x64 /InIsolation — 1475/1475 tests passed, including the three new regression tests.

Recommended:

  • CI pipeline run against this branch (not verified in this PR beyond the local toolchain above).

Backward Compatibility / Migration Notes

  • FilerQueue.ConsumeAsync visibility narrowed from public to internal. Verified via repository-wide grep that it has no external callers; the Consumer property that tests read remains public and unchanged.
  • No other public API surface changed.

Risks and Mitigations

  • Risk: the try/finally change to FilerQueue's and FlagChangeTrainingQueue's consumer loops changes control flow in a background worker.
    Mitigation: the normal empty-queue exit path still clears the flag inline as before; the finally only adds coverage for the previously-unhandled exceptional exit. New regression test ConsumeAsync_ItemWithEmptyHelpersThrows_ConsumerRecoversForLaterItems proves the consumer keeps draining after an exceptional item.
  • Risk: removing _helperTasks eliminates a live Outlook COM call (FromMailItemAsync) per item in the sync LoadItems path.
    Mitigation: confirmed by repository-wide grep that the field was write-only (no reader anywhere, including tests); the call's result was never consumed, so no behavior depended on it running.

Review Guide

Suggested order:

  1. QuickFiler/Controllers/FilerQueue.cs + FilerQueueTests.cs — the highest-severity fix and its regression tests.
  2. TaskVisualization/FlagChangeTrainingQueue.cs — the same pattern applied to the sibling queue.
  3. QuickFiler/Controllers/EfcItemController.cs + EfcItemController.WebViewFaultBoundary.cs (new file) + QfcItemController.WebViewFaultBoundary.cs + EfcFormController.cs — the fault-boundary guarding cluster (findings 4 and 5).
  4. QuickFiler/Controllers/QfcHomeController.Metrics.cs — the null-guard/appointment-deletion fix.
  5. TaskVisualization/TaskViewer.cs and QuickFiler/Viewers/QfcFormViewer.cs + EfcViewerTests.cs — the Alt-chord/ProcessCmdKey cluster (findings 7 and 8).
  6. QuickFiler/Controllers/QfcFormController.cs + QfcFormController.Actions.cs — the dead-field removal (finding 6, live sub-part).

No mechanical moves or renames in this change.

Follow-ups

Three sub-findings from the issue are explicitly deferred, not fixed here:

  • Finding 3 (StoreWrapperController.EvaluateLaunchReadiness conflates two distinct causes): already tracked as an open item in docs/features/active/2026-07-09-storewrapper-dialog-imprecise-for-genuine-failure-287/spec.md; resolving it needs a new readiness state and crosses the UtilitiesCS/TaskMaster assembly boundary.
  • Finding 6, LoadFolderHandler/InitAsync gap: FolderPredictor has only an async InitAsync, no synchronous equivalent. The sync LoadFolderHandler's three production call sites run through PopulateFolderComboBox, which checks InvokeRequired — forcing a synchronous block on the async init risks a UI-thread deadlock. A minimal fix here would trade a latent hang for a more certain one; needs a dedicated design decision, not a one-line patch.
  • Finding 6, dead QfcHighConfidencePreFilter.FilterAsync: confirmed unreachable in production by grep (HighConfidencePreFilterLoader is declared with a default delegate but never invoked anywhere). Removal cascades into three test files (QfcHighConfidencePreFilterTests.cs, QfcHomeControllerIssue218Tests.cs, QfcHomeControllerRunAsyncHighConfidenceTests.cs), exceeding this change's minimal-fix scope.
  • Finding 6, two stale comments and one stale test docstring from item Bug: quickfiler-carry-folder-predictor-to-item-controller #678's remediation: the issue gives no file/line citation, and Bug: quickfiler-carry-folder-predictor-to-item-controller #678 touches 26 files in this repo — too broad to identify reliably without expanding scope for a documentation-only latent nit.

GitHub Auto-close

drmoisan and others added 2 commits September 2, 2026 06:53
…ndings)

Consolidated fix for eight code-correctness findings surfaced during the
bugs-638-644-647 parallel-orchestration review sweep, each left unfixed by
its originating item to stay within that item's declared file-footprint.

1. FilerQueue drain-barrier hardening (Major): wrap the consumer loop body
   in try/finally so _consumerRunning always clears, add a null guard on
   Enqueue, and a null/empty-safe diagnostic path in the catch handler.
   ConsumeAsync narrowed to internal (no external callers). Applied the
   identical try/finally hardening to the sibling
   TaskVisualization/FlagChangeTrainingQueue.cs guard-reset.
2. QfcHomeController.Metrics: null-guard the diagnostics line array and
   delete the orphaned calendar appointment when diagnostics are empty,
   instead of reordering (GetMoveDiagnostics takes the appointment by ref).
4. EfcItemController: route both InitializeWebViewAsync fire-and-forget
   call sites through a new guarded wrapper (mirroring QfcItemController's
   existing fault boundary) so a fault is logged instead of silently
   finalized away.
5. Guard both WebView fault-boundary sinks (Efc and Qfc) and
   EfcFormController.BoundaryErrorSink against a null or throwing sink
   delegate, so a misconfigured sink cannot reinstate an unobserved fault.
6. Removed QfcFormController's dead _helperTasks field: it started a
   FromMailItemAsync call per item and discarded the result unawaited,
   while the sync pipeline it feeds builds its own MailItemHelper via a
   separate synchronous constructor -- confirmed by grep as write-only
   with no reader anywhere in the repo.
7. TaskViewer.ProcessCmdKey now falls through to base.ProcessCmdKey when
   the controller does not consume the Alt-chord keystroke, instead of
   unconditionally claiming every Alt-modified key.
8. QfcFormViewer.ProcessCmdKey: removed two dead locals with no effect on
   the real event pipeline. Added the missing positive regression test for
   Keys.Menu | Keys.Alt in EfcViewerTests (the Keys.Menu disjunct of
   ClaimsAltChord's guard was previously deletable without failing any
   test).

Deferred, with evidence, not fixed in this change:
- Finding 3 (StoreWrapperController.EvaluateLaunchReadiness): already
  tracked as an open item in
  docs/features/active/2026-07-09-storewrapper-dialog-imprecise-for-genuine-failure-287/spec.md,
  crosses the UtilitiesCS/TaskMaster assembly boundary.
- Finding 6, LoadFolderHandler/InitAsync gap: the sync LoadFolderHandler
  has no synchronous equivalent of FolderPredictor.InitAsync, and its
  three call sites run through PopulateFolderComboBox, which checks
  InvokeRequired -- forcing a synchronous await risks a UI-thread
  deadlock. A minimal fix here would trade a latent hang for a more
  certain one.
- Finding 6, dead QfcHighConfidencePreFilter.FilterAsync: confirmed
  unreachable in production (HighConfidencePreFilterLoader is declared
  but never invoked), but removal cascades into three test files
  (QfcHighConfidencePreFilterTests.cs,
  QfcHomeControllerIssue218Tests.cs,
  QfcHomeControllerRunAsyncHighConfidenceTests.cs), exceeding this
  change's minimal-fix scope.
- Finding 6, two stale comments and one stale test docstring from item
  #678's remediation: the issue gives no file/line citation and #678
  touches 26 files, too broad to identify reliably without expanding
  scope for a documentation-only latent nit.

New regression tests: FilerQueue null-Enqueue and
empty-Helpers-drain-recovery; EfcViewer Keys.Menu | Keys.Alt positive
Alt-chord match.

Toolchain: CSharpier format, analyzer rebuild
(EnableNETAnalyzers+EnforceCodeStyleInBuild), nullable rebuild
(TreatWarningsAsErrors), MSTest 1475/1475 passed across
QuickFiler.Test + TaskVisualization.Test.

Fixes #726

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ATYLDoRLKXS5sgAzegW7ZL
@drmoisan
drmoisan merged commit c442a96 into main Sep 2, 2026
5 checks passed
@drmoisan
drmoisan deleted the bug/quickfiler-review-sweep-code-defects-726 branch September 2, 2026 13:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: quickfiler-review-sweep-code-defects

1 participant