You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Four related defects in QfcCollectionController's move and move-diagnostics path: a null guard
placed after the dereference it protects, a trailing null element in the returned array, positional
indexing into an unordered ConcurrentDictionary, and a declared parameter that the method body
never reads.
Data source or fixture: QuickFiler/Controllers/QfcCollectionController.cs
Steps to Reproduce
Defect 1 - unreachable null guard in GetMoveDiagnostics (:2288-2322)
Line 2288: var qf = TryGetItemGroupByIndex(k)?.ItemController; - qf may be null by
construction of the null-conditional.
Line 2289 dereferences it immediately: qf.ItemHelper.
Line 2312 dereferences it again: xComma(qf.ItemHelper.Subject).
Only at line 2313 does if (qf is not null) appear, so the else branch at :2318-2322 is dead
code and a null qf throws a NullReferenceException at 2289 before reaching the guard.
Note the issue-Bug: getmovediagnostics-null-guard #97 guard documented at QuickFiler.Test/Controllers/QfcCollectionControllerTests.cs:77-80
protects the olAppointment parameter, not this path.
Defect 2 - trailing null element (:2284-2286)
Line 2284 allocates new string[_itemGroupsToMove.Count + 1].
The loop at 2286 fills indices 0 .. Count-1.
strOutput[Count] is therefore always null.
Consumers are QuickFiler/Controllers/QfcHomeController.Metrics.cs:75 and :144.
Defect 3 - positional access into a ConcurrentDictionary (:2260-2270)
_itemGroupsToMove is declared ConcurrentDictionary<QfcItemGroup, int> at :71.
TryGetItemGroupByIndex does _itemGroupsToMove.ElementAt(index).Key at :2264.
ConcurrentDictionary enumeration order is unspecified and not stable across mutations.
MoveEmailsAsync (:2220-2223) and GetMoveDiagnostics (:2286-2288) each walk 0..Count-1
independently, so the two walks can observe different orders.
Defect 4 - MoveEmailsAsync ignores its parameter (:2206-2228)
stackMovedItems (SloStack<IMovedMailInfo>) is declared on the interface at QuickFiler/Interfaces/IQfcCollectionController.cs:50.
It is supplied by QuickFiler/Controllers/QfcFormController.EventHandlers.cs:225 as _movedItems.
The method body at :2206-2228 never reads the parameter.
Expected Behavior
The null guard should precede every dereference of qf, so a missing item controller produces the
intended diagnostic line rather than an exception.
GetMoveDiagnostics should return exactly _itemGroupsToMove.Count elements.
Index-to-group resolution should use a stable, explicitly ordered collection so that a diagnostic
line is attributed to the message it describes.
Either MoveEmailsAsync populates the undo stack it is handed, or the parameter is removed from
the contract.
Actual Behavior
A null ItemController throws NullReferenceException at :2289; the else branch is dead.
Callers receive an array whose last element is always null.
A diagnostic line can be attributed to the wrong message when the dictionary is mutated between
the two independent walks.
The undo record supplied by the caller is silently dropped, unless it is populated elsewhere.
Logs / Screenshots
Attached minimal logs or screenshot
Snippet: Confirmed directly against source at the line numbers above. Discovered during preparation
research for issue Feature: quickfiler-collection-controller-coverage #454 (epic Feature: quickfiler-80-per-file-coverage #136, child F11); full analysis in docs/features/active/2026-08-07-quickfiler-collection-controller-coverage-454/research/qfc-collection-controller.md
sections E4, E5, E6, and E15.
Impact / Severity
Blocker
High
Medium
Low
Defects 1 and 3 can produce wrong or failed move diagnostics. Defect 4 needs triage before a final
severity can be assigned: if the undo record is genuinely dropped, undo-after-move is broken, which
would be High.
Summary
Four related defects in
QfcCollectionController's move and move-diagnostics path: a null guardplaced after the dereference it protects, a trailing null element in the returned array, positional
indexing into an unordered
ConcurrentDictionary, and a declared parameter that the method bodynever reads.
Environment
QuickFiler/Controllers/QfcCollectionController.csSteps to Reproduce
Defect 1 - unreachable null guard in
GetMoveDiagnostics(:2288-2322)var qf = TryGetItemGroupByIndex(k)?.ItemController;-qfmay benullbyconstruction of the null-conditional.
qf.ItemHelper.xComma(qf.ItemHelper.Subject).if (qf is not null)appear, so theelsebranch at:2318-2322is deadcode and a null
qfthrows aNullReferenceExceptionat 2289 before reaching the guard.QuickFiler.Test/Controllers/QfcCollectionControllerTests.cs:77-80protects the
olAppointmentparameter, not this path.Defect 2 - trailing null element (
:2284-2286)new string[_itemGroupsToMove.Count + 1].0 .. Count-1.strOutput[Count]is therefore alwaysnull.QuickFiler/Controllers/QfcHomeController.Metrics.cs:75and:144.Defect 3 - positional access into a
ConcurrentDictionary(:2260-2270)_itemGroupsToMoveis declaredConcurrentDictionary<QfcItemGroup, int>at:71.TryGetItemGroupByIndexdoes_itemGroupsToMove.ElementAt(index).Keyat:2264.ConcurrentDictionaryenumeration order is unspecified and not stable across mutations.MoveEmailsAsync(:2220-2223) andGetMoveDiagnostics(:2286-2288) each walk0..Count-1independently, so the two walks can observe different orders.
Defect 4 -
MoveEmailsAsyncignores its parameter (:2206-2228)stackMovedItems(SloStack<IMovedMailInfo>) is declared on the interface atQuickFiler/Interfaces/IQfcCollectionController.cs:50.QuickFiler/Controllers/QfcFormController.EventHandlers.cs:225as_movedItems.:2206-2228never reads the parameter.Expected Behavior
qf, so a missing item controller produces theintended diagnostic line rather than an exception.
GetMoveDiagnosticsshould return exactly_itemGroupsToMove.Countelements.line is attributed to the message it describes.
MoveEmailsAsyncpopulates the undo stack it is handed, or the parameter is removed fromthe contract.
Actual Behavior
ItemControllerthrowsNullReferenceExceptionat:2289; theelsebranch is dead.null.the two independent walks.
Logs / Screenshots
research for issue Feature: quickfiler-collection-controller-coverage #454 (epic Feature: quickfiler-80-per-file-coverage #136, child F11); full analysis in
docs/features/active/2026-08-07-quickfiler-collection-controller-coverage-454/research/qfc-collection-controller.mdsections E4, E5, E6, and E15.
Impact / Severity
Defects 1 and 3 can produce wrong or failed move diagnostics. Defect 4 needs triage before a final
severity can be assigned: if the undo record is genuinely dropped, undo-after-move is broken, which
would be High.
Source
From: docs/features/potential/2026-08-07-qfc-collection-move-diagnostics-defects.md