Skip to content

Epic: quickfiler-bug-family — twelve QuickFiler defect clusters - #673

Merged
drmoisan merged 306 commits into
mainfrom
epic/quickfiler-bug-family-integration
Aug 28, 2026
Merged

Epic: quickfiler-bug-family — twelve QuickFiler defect clusters#673
drmoisan merged 306 commits into
mainfrom
epic/quickfiler-bug-family-integration

Conversation

@drmoisan

Copy link
Copy Markdown
Owner

Epic: quickfiler-bug-family — integration to main

Merges epic/quickfiler-bug-family-integration into main, delivering all twelve child features of the QuickFiler bug-family epic. Every child was developed in an isolated worktree, reviewed, gated, and merged into the integration branch; this pull request is the single fan-in to main.

Summary

Twelve QuickFiler defect clusters were fixed in owning-class groups. The epic is an enabler: its hypothesis is that draining the QuickFiler open-bug backlog stops that surface generating follow-on defects during unrelated feature work.

Issue Feature PR Merge commit
#484 qfc-item-controller-defects #619 363bfcdd
#446 quickfiler-bug-family #625 merged
#498 breadcrumb-router-navigation-defects #626 merged
#468 qfc-collection-controller-defects #636 merged
#442 quickfiler-home-controller-metrics #649 4f238289
#493 quickfiler-test-uithread-dispatcher #653 13a22ade
#444 quickfiler-keyboard-action-defects #654 69e83171
#476 webview2-host-initializer-defects #658 5793b8c7
#501 breadcrumb-coordinator-hub-defects #659 4cb709db
#464 efc-controller-surface-defects #661 ee7d0ec4
#489 itemviewer-surface-defects #669 12465043
#488 itemviewer-breadcrumb-lifecycle-defects #672 4b6d38dd

What changed

Production C# is 52 files, +3,330 / -2,233 lines. That is the behavioural payload.

The overall diff is much larger — 1,498 files and 2,821,016 insertions — because each child committed its evidence tree under its feature folder, as its atomic plan required. Roughly 99.5 percent of the insertions are evidence artifacts rather than code:

Category Insertions Files
Cobertura coverage XML 1,916,925 10
TRX test results 329,983 216
Other evidence 518,685 982
Other docs 40,143 117
C# source (incl. tests) 13,485 113
.claude/ 1,761 55

Ten coverage XML files account for 68 percent of the entire epic diff, at roughly 192,000 lines each. This is called out explicitly because merging makes it permanent in main history. It is the established convention reaching its natural conclusion, not a deviation; #671 is the prospective vehicle for an evidence-hygiene convention.

Verification

  • Integration CI is green on this exact tip. Run 33151121207, workflow_dispatch, success on 4b6d38dd, all five jobs: format-check, build-analyzers, build-nullable, actionlint, mstest-coverage.
  • Full suite: 6,821 passed / 0 failed across 9 discovered assemblies, run under TestCategory!=LiveOutlook with /InIsolation.
  • Coverage: line 0.85283, branch 0.792255, clearing the >= 85% line and >= 75% branch floors in .claude/rules/, and the >= 80% line floor in CLAUDE.md.
  • Every child PR carried its own dispatched CI gate green on a head SHA equal to its PR head, because ci.yml triggers pull_request only on [main, development] and therefore never fires automatically for a branch based on the integration branch.
  • Every recorded merge commit was re-tested with git merge-base --is-ancestor against the integration tip. main has zero commits absent from this branch, so there is no stale-base risk.

Deviations and known gaps

  • Bug: qfc-home-controller-metrics-never-flushed #442 wrote EfcHomeControllerTests.cs, on its plan's forbidden-to-write list, to repair a test its own change broke (_isExecuting became private int). Ratified as a documented deviation after verifying no sibling owned that file. Its AC-19 ownership-boundary criterion is correctly left unchecked.
  • Bug: uithread-dispatcher-static-swap-no-restore #493 added two Controllers\QfcItemController.UiThreadDispatcherFixture* project entries inside Bug: kbdactions-enumerable-ctor-bypasses-duplicate-guard #444's declared region. A real NFR breach, disclosed; the predicted conflict did not materialise and both features' entries coexist intact.
  • Bug: breadcrumb-hub-postjson-caches-before-broadcast-starves-attachments #501 delegated its feature review at opus where the routing table returns fable. It left model_routing_receipts empty and recorded a named deviation rather than writing a receipt for work a different model performed. The error direction is over-provisioning.
  • Bug: itemviewer-breadcrumb-pipeline-lifecycle #488 found that all 19 committed TRX files were not well-formed XML — a prior redaction wrote a bracketed token into XML attribute values — and repaired 7,306 occurrences, restoring parseability without altering any counter.
  • --require-complete checkpoint validation fails for epic children on a launch-binding requirement that no run writes. Every merged child fails it identically; recorded, not retrofitted.

Backward compatibility

No public API removals beyond chartered work. #489 removed UiScheduler, a ParentChanged handler and its Console.WriteLine, and the MenuItem_CheckedChanged overloads with their four constructor call sites; #475's CaptureCurrentOrTests removal is the single pure deletion in #488. Each was proven not to remove content the base had gained.

Follow-ups filed

#645, #657, #662, #663, #664, #665, #666, #667, #668, #670, #671 — including #668 for the coverage-threshold discrepancy between CLAUDE.md and .claude/rules/, and #671 for the evidence-hygiene convention.

GitHub auto-close

Merging into the integration branch did not close any child issue, because GitHub registers closing references only for pull requests targeting the default branch. All twelve were verified OPEN immediately before this pull request was opened; this is the only mechanism that closes them.

drmoisan and others added 30 commits August 25, 2026 13:35
…ration' into worktree-agent-a9380db2f88f77c8e
…ration' into worktree-agent-a14c1bc047bb2e584
…ration' into worktree-agent-a6db64a81bdea4048
…worktree

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…worktree

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…cessor worktree

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 blocking and 10 non-blocking findings addressed.
Plan task count 199 to 200; spec criterion count unchanged at 74.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ions)

Blockers: add repo-local SDK bootstrap to P0-T7 (global.json pins
.dotnet-sdk, absent in worktree); tighten csharpier Branch A to an empty
BaselineUnformattedSet so a repo-wide format cannot rewrite 488/501-owned
files; split P11-T7(b) into an absolute gate over the two owned test
classes and a baseline-relative gate over the eight co-owned ones.

Also sweeps three residual defect classes to their remaining sites and
corrects four stale figures, including the ExcludeFromCodeCoverage
alternation count (261, not 269) and the integration head (f4cee61).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…re preflight residuals

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 blocking and 1 non-blocking finding addressed.
Task count unchanged at 200; spec untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Rounds used 5 of 5. Final signal PREFLIGHT: ALL CLEAR (0 blocking, 0 non-blocking).
next_step S5_atomic_execution; execution, PR authoring and CI monitoring deferred
to epic-orchestrator.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… sweeps

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…cle defects, PREFLIGHT ALL CLEAR round 5)

Agent-memory conflict in feedback_confirmatory_preflight_proportionate_bar.md resolved with -X ours,
preferring the landed integration index. Known loss: 488 added paragraph on the final-round
proportionate bar. Agent-memory scope only; feature content merged with zero conflicts.
Blocker: relativize absolute pass counts over sibling-owned tests to a
new P0-T13 BaselineNamedPins block (P6-T7, P8-T11, P8-T15, P9-T9, and
P11-T12 found by sweep).

Removes an inert using-removal clause whose retention would have shifted
ItemViewer.cs:20 and broken P10-T17/AC55; corrects the multi-phase edit
set from five to eight; widens three further pathspec gates to all 18 C#
projects; renames gitignored .log evidence to .msbuild.txt; and corrects
several unverified figures found by the final figure sweep.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Round 5 returned PREFLIGHT: ALL CLEAR with 1 non-blocking defect and 0
regressions. Trajectory 12/6 -> 5/1 -> 12/3 -> 9/1 -> 1/0, zero
re-introductions across all five rounds.

Corrects the sole finding rather than deferring it: the P6-T6 and AC
pathspec named QuickFiler/Viewers/IQfcFormViewer.cs, which does not
exist. The real path is QuickFiler/Interfaces/IQfcFormViewer.cs, which
declares TaskScheduler UiScheduler at :16. A nonexistent path can never
appear in a diff, so the clause gated nothing. One directory token in
two files; the gate is now falsifiable.

Preparation complete. Atomic execution is out of scope for this run.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…PREFLIGHT ALL CLEAR round 5)

Agent-memory index conflicts in atomic-planner/MEMORY.md and orchestrator/MEMORY.md resolved with
-X ours, preferring the landed integration index. Known loss: 489 index lines for its new memory
files. The memory FILES themselves land; only their index entries are absent. Agent-memory scope
only; feature content merged with zero conflicts.
PR 610 (quickfiler high-confidence backfill after deadline) landed on main
after feature 446 was first preflight-cleared, and shifted every line in
QfcStreamingDequeueConfidenceGate.cs from 42 onward. Re-verified every line
citation and count-based acceptance in the plan and spec against the current
tree and corrected the stale ones in place.

Corrected: the 8-parameter constructor 55-64 to 57-66; the four DequeueAsync
exits 98/113/122/148 to 100/119/128/154; the accept decision 138-141 to
144-147; the DequeueAsync signature 87-91 to 89-93; the gate file base length
171 to 177; and the gate test-method count 21 to 23.

Made the two count-based gate acceptances baseline-relative rather than
absolute, because that test file is not wholly owned by this feature and an
absolute count goes stale whenever an unrelated pull request adds a test.

Re-verified as unchanged and deliberately left alone: the CreateGate helper
range 26-156 and its four sub-ranges, the reflective DequeueAsync helper
192-205, the single gate call site in QfcDatamodel.QueueProcessing.cs at 128,
the GetConstructor counts, and 21 further citations into files PR 610 did not
touch.

Recorded the reconciliation as decision D-Plan-9. No task became redundant:
PR 610 added no stop-reason field, no rejection callback, no TopFolder
propagation and no undo-consumer change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Preflight round 1 returned REVISIONS REQUIRED. Every blocking defect was
re-verified against the tree before routing.

Nine further stale spec citations into QfcStreamingDequeueConfidenceGate.cs
that the first re-scope pass missed: the accept-decision region 133-145, the
_tryTakeNext call 116, LogDeadlineExpiry 151-159, LogScore 136, the three
TimeProvider sites 102/110/126-128, the Timeout.InfiniteTimeSpan guard 75, the
gate line count 171, the gate test-file headroom 373/127, and the Part2 count
455. All now carry post-PR-610 values.

Four spec statements pinned the citation base at 988e819, a pre-610 commit,
while the same document already carried post-610 values. Both bases cannot be
true at once, and that contradiction is what let the nine above survive. All
four now name branch HEAD and PR 610 explicitly.

Deleted two lines of committed tool-call scaffolding from the end of spec.md,
which is the sole acceptance-criteria source.

One substantive defect unrelated to PR 610: task P1-T15 instructed the executor
to retarget every mock setup of DequeueNextItemGroupAsync, including the one at
line 372. That setup belongs to a test driving the synchronous Iterate path,
which this work does not change, so retargeting it would have replaced a
deliberate arrangement with a Moq loose default and silently weakened the test.
The task's own zero-failure acceptance could not have caught it, because that
test's assertions are Times.Never and hold against the default either way.
P1-T15 now scopes to the four IterateQueueAsync setups and P1-T14 carries the
matching shared-helper caveat.

Advisory: made the P1-T11 Part2 line gate falsifiable against the recorded
baseline instead of a 500-line ceiling the file was already well under;
reconciled a twelve-versus-thirteen file count in P0-T14; corrected a field
declaration cited where the call site was meant; noted that a compile carrying
no gate property may use /t:Build; and added the read-only format gate to the
P5-T9 clean-pass record, which named the mutating pass instead.

Plan validator: ok, no acceptance-gate warnings.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two of the five blocking defects were introduced by round 1's own fixes, which
is the cost of correcting a document by line number.

Round 1 inserted a line into spec.md, which silently invalidated the
spec.md:966-967 pointer that task P0-T2 holds. Line 966 had become the
Related issues line, which P0-T2 must not edit, and one of the two lines it
was supposed to fix had fallen outside its range. Re-derived by grep after
this round's own line-count-changing edit: now 970-971.

Round 1 also re-pinned four statements from 988e819 to branch HEAD. One of
them had the research document as its subject. The research was never
re-verified and was not modified by either commit; its header still reads
988e819 and its gate citations are all pre-610 and now wrong. Re-pinning it
turned a true statement into a false one, and P0-T2 requires the executor to
read that file. It now states plainly that the research was verified at
988e819, has not been re-verified, and is authoritative on findings but not
on line numbers.

Three pre-existing defects:

Tasks P4-T22 through P4-T25 invoked the GitHub CLI to open follow-up issues
directly, which the registered enforce-promotion-mcp-only.ps1 PreToolUse hook
denies outright. All four would have been blocked before running and their
exit-code-zero acceptance was unsatisfiable. They now route through the MCP
promotion path the hook's own deny message names, with an acceptance that
records the two returned values.

Task P0-T1 omitted .claude/rules/csharp.md from the mandated read order. That
is material rather than formal: the file records Task.Delay as a banned symbol
under BannedApiAnalyzers, and P3-T3 rewrites an await Task.Delay call. Adding
it surfaces a genuine conflict, since csharp.md states a repo-wide 80% coverage
floor while AC28 deliberately demotes the repo-wide figure to record-and-report
and CLAUDE.md tells the executor to halt on conflicting instructions. D-Plan-7
now records that supersession as a settled scope decision.

Task P1-T15's round-1 caveat was inserted after a semicolon that terminated
the list, leaving the Verify-retargeting clause without a verb and inside a
conditional. Its acceptance was also vacuous: it asked the executor to verify
by reading a test body that P1-T14 is instructed to empty into a helper.

Plan validator: ok, no acceptance-gate warnings.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Round 3 moved past citation staleness into design defects.

Task P5-T7 carried an absolute 90.00 changed-file coverage gate over
QfcFormController.Actions.cs, whose UndoDialog body calls MessageBox.Show
three times with no injectable seam. UT4 prohibits exercising that surface,
D-Plan-3 already concedes the same point for the neighbouring take branch, and
no task in this plan seams UndoDialog, so roughly 35 executable lines can never
run. P5-T7 was also the only Phase 5 gate with an absolute threshold and no
pre-existing-baseline branch, while the Phase 5 preamble restarts the loop on
any failure without exempting it. The gate was therefore not merely unreachable
but non-terminating. That file now takes a no-regression carve-out with a
verbatim REMEDIATION-REQUIRED line naming the three call sites, and the
preamble exempts P5-T7 from the restart rule.

D-Plan-7's supersession clause listed three rule files and omitted CLAUDE.md,
which carries the same repo-wide 80% floor independently and outranks all
three. Because the list reads as exhaustive, the omission implied CLAUDE.md's
floor survived, which is worse than having no clause: the executor is told to
halt on conflicting instructions.

Tasks P4-T22 through P4-T25 routed defect follow-ups through the feature
potential-entry tool rather than the bug one, and supplied neither of the two
arguments the promotion call requires. Their acceptance also asserted an issue
URL returned by the promotion tool, a return shape that tool is not documented
to produce and that this repository has previously observed it does not.
Nothing staged the potential-entry files the MCP route writes, so four
untracked files would have been stranded in the worktree at plan end inside an
epic fan-in.

Advisory: repaired a dangling coordination the previous round left in all four
follow-up tasks; gave P1-T14's matcher pin a verifying conjunct, since widening
a Moq matcher only makes a setup more permissive and the stated acceptance
passed either way; and anchored P1-T15's Verify locator so it no longer also
matches the Setup sites.

Also records four hook behaviours to agent memory, two of which cost a retry
this session: both the promotion guard and the planner prerequisite guard read
prompt and command text without reading intent.

Plan validator: ok, no acceptance-gate warnings.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Round 4 found the mirror image of round 3's defect. Round 3 gave
QfcFormController.Actions.cs a coverage carve-out and hardened the surviving
clause so the other two changed files are held to 90.00 unconditionally. That
is correct for QfcStreamingDequeueConfidenceGate.cs, measured at 97.06 with
margin. It is wrong for QfcHomeController.Iteration.cs, measured at 86.25.

That file's entire uncovered set is the two catch blocks at lines 38 to 52, and
no task in the plan reaches them: the empty-batch tasks drive the else branch
instead, and the iteration test file contains zero Throws, ThrowsAsync or
OperationCanceled tokens. Both facts verified directly against the tree. The
gate would therefore have failed with no disjunct and no remediation branch,
and the Phase 5 restart rule would have sent the executor back to the format
step, where re-running the toolchain cannot move a coverage figure.

Fixed by making the gate reachable rather than by weakening it. Unlike the
MessageBox.Show case that justified the Actions.cs carve-out, these two catch
blocks are genuinely unit-testable by arranging the mocked dequeue to throw, so
carving them out would have excused a testable path. New task P1-T19 adds three
tests covering the cancelled, swallowed and rethrown paths; the terminal Phase 1
commit task moves to P1-T20. D-Plan-7 now records both measured rates so a
reviewer can see why one file is held unconditionally and the other was not.

Phase 1 runs P1-T1 through P1-T20 with no gap or duplicate. Plan validator: ok,
no acceptance-gate warnings.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ED WITHIN BOUND

Round 5 exhausted the five-round bound and returned REVISIONS REQUIRED with one
blocking defect, which round 4's own insertion had created.

Task P1-T19's acceptance required a scoped run over QfcHomeControllerIterationTests
to record 0 failed. But P1-T16 adds an expect-fail test to that same class, it
stays Failed until P2-T7 lands the SourceExhausted guard, and the substring
TestCaseFilter matches it. The gate was unsatisfiable at its position in plan
order. Verified independently against the plan: P1-T16 at line 297, P1-T19 at
300, P2-T7 at 316, one class throughout. The plan already carried the correct
idiom at P1-T8 and P1-T11; P1-T19 was the only scoped run in Phases 1 through 3
that omitted it.

Applied the dictated replacement, and folded in round 5's first advisory, which
I also verified: Token.ThrowIfCancellationRequested() sits at Iteration.cs:13,
outside the try that opens at :19, so the second new test must cancel the token
from inside the mocked callback rather than before entry, or the exception
escapes uncaught and never reaches the :44 branch.

This fix is applied but NOT re-verified by a preflight round, because the bound
was spent. The checkpoint records preflight_status NOT CLEARED WITHIN BOUND with
R5-B1 listed as remediated-but-unverified, plus seven advisories recorded and
deliberately not applied. Epic-orchestrator should re-run preflight against this
plan before executing it.

Plan validator: ok, no acceptance-gate warnings. Checkpoint JSON parses.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…cted; preflight NOT YET CLEARED)

The re-scope corrected 11 stale line citations caused by PR #610's +2/+6 line shifts in
QfcStreamingDequeueConfidenceGate.cs, and converted two absolute count gates to baseline-relative
form after finding the 21-passed figure had become 23. This state is strictly better than the stale
plan it replaces. Preflight used all five rounds and returned NOT CLEARED WITHIN BOUND: one blocking
defect remains whose fix is applied but not preflight-verified. A confirming round follows.
drmoisan and others added 27 commits August 27, 2026 23:19
…ding (RC-1 PicturesChanged unwire)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Preserves the approved 25-task remediation plan (5 phases) that adds the
17th intent detachment for PicturesChanged in UnwireIntentEvents().

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Reads the four policy files in the policy-compliance-order sequence and the
four remediation sources, then checks off P0-T1 in the remediation plan.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Captures repo state at REM_BASE, the 17-vs-16 defect measurement, the
csharpier formatting baseline, and the toolchain and coverage baseline
adopted by tree identity from the feature's Phase 11 gates.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…sChanged unwire

Appends UnwireIntentEvents_DetachesPicturesChanged to this feature's own
EventWiringTests.Part2.cs continuation file. It fails against the unchanged
production code with Moq.MockException reporting the PicturesChanged removal
happening 0 times where once was expected; Moq's invocation ledger shows 17
adds against 16 removes. Records the compile build and the RED run evidence.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Adds the 17th intent detachment so every event WireIntentEvents() subscribes
is detached by UnwireIntentEvents(); after Cleanup() a controller holds zero
live subscriptions on its viewer. The RED test now passes and the merged
sibling's sixteen-detachment balance test still passes unmodified.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ischarge

Appends a dated addendum to the 16-to-17 handoff record marking the
obligation discharged in this branch, and amends spec.md in three
coordinated places: disposition 1 now covers the matching
UnwireIntentEvents detachment, the issue 486 criterion additionally
requires the addendum, and a dated amendment note records the reason.
Criterion count preserved at 62; no criterion weakened.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Captures the full toolchain pass for remediation cycle 1: csharpier format
and check, the analyzer build with its non-vacuity proof, the nullable
build, the scoped QuickFiler.Test run at 1122/0/0, the repository-wide run
and coverage refresh at line rate 0.851617 over 63902 valid lines, the
line-count refresh, the scope-lock re-verification and the loop attestation.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Substitutes the real Phase 4 commit sha into the P4-T11 record, adds the
P4-T12 clean-tree artifact, and checks off the last plan task, bringing
the remediation plan to 25 of 25.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…osed, zero blocking findings

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ration' into bug/itemviewer-surface-defects-489
Records the policy reads, feature-document reads, repo state, resolved
toolchain paths, SDK/NuGet/tool restore, and the four baseline gates:
csharpier check (0 unformatted of 1553), analyzer Rebuild (0 errors,
5 pre-existing System.Reactive advisories, 0 CoreCompile skips), nullable
Rebuild (0 errors), QuickFiler.Test (1192/1192, empty failure set), and
repository-wide coverage (line-rate 0.852607, branch-rate 0.791925 over
9 assemblies, 6812 tests).

Also records the baseline per-file coverage of the three measured owned
production files, the eight file-size rows (all matching constraint C2),
the seven-file ExcludeFromCodeCoverage counts, the eight CaptureCurrentOrTests
occurrence lines, and the capacity budget.

[P0-T1] through [P0-T18].

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…acement (#488 D1)

ConfigureBreadcrumbDropDown(environment, initializer) now disposes the outgoing
host between the same-environment early return and the construction of the
replacement, so the ordering is guaranteed by statement order rather than by
dispatcher behaviour.

The type test names the concrete BreadcrumbDropDownHost rather than
IBreadcrumbDropDownHost, so a mock host installed by the injected 3-arg overload
is not disposed here and ItemViewerDisposal_OwnsHostAndDetachesBothSurfaces keeps
its Times.Once() assertion. A fresh pattern variable is used because the one bound
in the same-environment guard is definitely assigned only on the returning branch.

Adds QuickFiler.Test/Viewers/ItemViewerBreadcrumbLifecycleRegressionTests.cs with
its own viewer scope, host accessor, context assigner, uninitialized-environment
factory, and drainable synchronization context, plus the D1 regression test. One
Compile Include line is added to QuickFiler.Test.csproj adjacent to the existing
ItemViewerBreadcrumbDropDownContractTests entry.

Fail-before evidence records the test Failed on its discriminating SetTheme
disposal-guard assertion; pass-after records all three named tests Passed with
both constraining test files byte-identical to BASE_SHA.

[P1-T1] through [P1-T15]. Six spec criteria checked off.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…d host (#488 D2)

BreadcrumbItemViewerLifecycleCoordinator now retains the last requested theme and
replays it onto the newly adopted host inside ConfigureHost's posted lambda, so a
theme set while that post is still queued is no longer lost. SetTheme assigns the
retained value before its two forwarding calls, so the retained value can never lag
the caller's most recent request.

The replay is confined to the newly-adopted branch. The UpdateRequestProviders
branch performs no theme call, which is what keeps ResetAndPooledReuse and the
mock-host replacement tests unaffected.

The guard captures the field into a local and tests `retained != null` alongside
IsNullOrWhiteSpace. The bare IsNullOrWhiteSpace form raised CS8604 because the
net481 reference assemblies carry no NotNullWhen post-condition, and that file has
`#nullable enable`, so TreatWarningsAsErrors would have promoted it to an error.
No null-forgiving operator and no suppression was used.

RecordingHost gains a ThemesApplied recorder; its Dispose body stays empty so
HostReplacement_SubscriptionsAndMessengerReplacementPreserveOrder is unaffected.

Fail-before evidence records the applied-theme sequence as empty. Pass-after records
the D2 test plus both coordinator constraining tests green, and the interaction
evidence records why the pooled-reuse "no stale pooled theme" assertion survives.
The constrained file lands at 497 lines, a +16 delta within its 19-line headroom,
and is already CSharpier-clean.

[P2-T1] through [P2-T12]. Five more spec criteria checked off (11 of 54).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…#488 D3)

InitializeBreadcrumbPipeline now retains the provider it was initialized with and
throws InvalidOperationException when a later call supplies one that is not
reference-equal, instead of discarding it through a blanket already-initialized
early return. A repeat call with the same provider reference still returns without
effect. DisposeBreadcrumbResources clears the retained reference so a pipeline
re-created after disposal is not blocked by a stale one.

A retained field is required because BreadcrumbBridgeCoordinator does not expose its
provider. The comparison is reference equality, matching what
BreadcrumbItemViewerLifecycleCoordinator.SetBridgeCoordinator already does.

No re-initialization branch is added, per constraint C7: keeping this fail-fast is
what holds the out-of-scope SetBridgeCoordinator replace-without-dispose defect
dormant, since InitializeBreadcrumbPipeline then never constructs a second bridge
coordinator.

This changes no production behaviour. The single production call site,
QfcItemController.ViewerSetup.cs:150 inside EnsureBreadcrumbPipeline, is guarded
upstream on viewer.BreadcrumbCoordinator == null in a 484-owned file, so the new
throw is unreachable from production.

Both D3 regression tests exclude ObjectDisposedException from the negative assertion,
so a D5 disposal throw cannot satisfy a D3 test by inheritance.

[P3-T1] through [P3-T12]. Five more spec criteria checked off (16 of 54).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
 D4)

Adds a private ThrowIfOffUiBoundary(string) helper to ItemViewer.Breadcrumb.cs and
invokes it as the first statement of InitializeBreadcrumbPipeline(provider, operations),
both ConfigureBreadcrumbDropDown overloads, and EnsureBreadcrumbResourceOwnership.

The comparison is reference equality against UiSyncContext, not managed thread
identity: a continuation resumed without the captured context can land on a recycled
pool thread whose id matches, so a thread id is not a boundary proof. The null-context
escape keeps a viewer constructed without an ambient context from throwing.

No Interlocked, lock, Monitor, Volatile, or Mutex construct is introduced. Atomic
initialization was rejected because it would legitimise off-thread access to WinForms
control state that is not thread-safe at all.

Both regression tests call the two-argument overload with injected operations, per
decision D-8: the one-argument overload evaluates CaptureCurrent() eagerly and that
method already throws under a null ambient context, so a test against it would have
passed before the guard existed. Each asserts the message names the operation and
excludes ObjectDisposedException. The second case installs a different non-null
context, proving the comparison is reference equality rather than a null check. Both
doc comments state that the proxy proves the guard fires and does not prove the race
is absent.

The full QuickFiler.Test assembly runs 1198/1198 green under the guard, with an empty
failing set matching the empty Phase 0 baseline. That settles the recorded C6
enumeration discrepancy: the re-derived construction-site set holds 19 executable
sites, not 13, and one of the five additions installs no synchronization context at
all. No site was edited and the guard was not weakened.

[P4-T1] through [P4-T14]. Five more spec criteria checked off (21 of 54).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…488 D5)

EnsureBreadcrumbResourceOwnership now throws ObjectDisposedException when the viewer
reports IsDisposed or Disposing, before any Container is created and before any
BreadcrumbResourceOwner is added, so no pipeline is built against a dead viewer.

Statement order follows decision D-15 and is stated explicitly in the delivered
source: ThrowIfOffUiBoundary is the first statement but is a precondition check that
returns without effect, so the disposal throw immediately following it is the first
statement that acts. Both the "first statement" and "first action" criteria are
satisfied under that reading.

Control.IsDisposed and Control.Disposing are public WinForms properties, so no new
state was needed and ItemViewer.Designer.cs (6223 lines, 489-owned) is untouched and
byte-identical to BASE_SHA.

Discharges research section 3.5: a faulted QfcItemController.InitializeWebViewAsync
task is NOT observed. Three of its four production call sites discard it
(Initialization.cs:192, :288, :324); only :256 awaits. The D5 guard is not weakened
in response, and a potential entry is filed against QfcItemController.ViewerSetup.cs.

TWO TASKS LEFT UNCHECKED. [P5-T6] and [P5-T11] both require a GitHub issue number for
that follow-up. enforce-promotion-mcp-only.ps1 forbids `gh issue create` and requires
the drm-copilot MCP promotion tools, which are not in this executor's tool set. The
forbidden path was not used and no wording was changed to evade the hook. The caller
holds those tools.

[P5-T1] through [P5-T5], [P5-T7] through [P5-T10]. Three more spec criteria checked
off (24 of 54); the research-section-3.5 criterion is left unchecked.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… all three parts)

Part 1: deletes BreadcrumbPopupUiOperations.CaptureCurrentOrTests(). A repository-wide
search of tracked .cs files now returns zero hits. CreateForCurrentThreadTests survives
unchanged on both BreadcrumbPopupUiOperations and BreadcrumbUiDispatcher: only the
ambient-probing selector is removed, so every injected test seam is preserved.

Part 2: both BreadcrumbDropDownHost seven-parameter constructor chains now supply
CaptureCurrent(). No constructor argument is reordered, which is what keeps
Constructor_NullLegacySurfaceFactory_ThrowsForSurfaceFactory passing without an ambient
context: the surfaceFactory null guard is evaluated before the operations argument.

Part 3: EnsureBreadcrumbLifecycle takes a Func<BreadcrumbPopupUiOperations>, invoked
exactly once and only after the already-initialized early return, with all three call
sites updated. This is required rather than opportunistic: the member discards its
operations argument whenever the coordinator already exists, so an eager argument would
make a pure no-op call throw on any thread without a context.

Replaces the deleted boundary test with
CaptureCurrent_NullAndControlledContexts_FailFastAndCapture, retaining the
controlled-context half. Adds the constructor fail-fast and seam-preservation regression
tests, bringing the new file to 8 test methods.

The new test file first measured 521 lines. Per capacity rule 3 the doc comments were
compacted to 480 rather than dropping a method or creating a second file; every
acceptance-required clause was preserved and re-verified. BreadcrumbPopupUiOperations.cs
is 489, strictly below its 494 baseline, by a pure deletion with zero additions.

Fail-before evidence for the constructor test was taken by temporarily restoring a local
ambient-probing selector, rebuilding (exit 0), observing the failure, then restoring to a
byte-identical file (SHA verified) and rebuilding again (exit 0).

[P6-T1] through [P6-T17]. Seven more spec criteria checked off (31 of 54).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Re-runs the nine constraining tests: all nine Passed, each matching its Phase 0
baseline of Passed, zero failures.

Verifies the changed-file set: 78 paths, zero outside the permitted set of four owned
production files, three owned test files, QuickFiler.Test.csproj, the feature folder,
and docs/features/potential/. All eleven forbidden files produce an empty
git diff --name-only against BASE_SHA.

Public surface: three added members all private (ThrowIfOffUiBoundary,
_breadcrumbProvider, the retained-theme field), one re-signed member the private
EnsureBreadcrumbLifecycle, one removed member the internal static CaptureCurrentOrTests.
Zero public members added, removed, or re-signed; both seven-parameter
BreadcrumbDropDownHost constructor signatures unchanged.

Re-checks all six 489 dependencies against current source; all confirmed. D489-4's two
collision searches return zero matches across every other ItemViewer partial. Records a
correction to constraint C6's reachability argument: the delivered ItemViewer constructor
calls Dispatcher.CurrentDispatcher, not TaskScheduler.FromCurrentSynchronizationContext,
so a viewer with a null UiSyncContext is constructible. No delivered design changes.

csproj diff confirmed exactly 1 added / 0 deleted, at line 88 immediately below the
ItemViewerBreadcrumbDropDownContractTests entry, BOM and CRLF preserved.

Creates the three out-of-scope follow-up potential entries (D1c; SetBridgeCoordinator
replace-without-dispose; Reset synchrony mismatch, naming both its files) and confirms no
fix for any appears in the diff.

Writes the change description quoting the spec and both D4 test doc comments verbatim.

[P7-T1] through [P7-T18]. Nine more spec criteria checked off (40 of 54).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Format: csharpier format over the seven owned paths, exit 0. Per-file SHA-256 shows
exactly one file changed, ItemViewer.Breadcrumb.cs, by a cosmetic lambda reflow.
csharpier check . then reports zero unformatted of 1554 files, matching the empty
Phase 0 baseline set.

Analyzers: msbuild /t:Rebuild with EnableNETAnalyzers, exit 0, 0 errors, 5 warnings
(all the pre-existing System.Reactive packages.config advisory). Per-file analyzer
warning count for each owned production file is 0, equal to baseline. Zero
"Skipping target CoreCompile" against 83 CoreCompile executions.

Nullable: msbuild /t:Rebuild with TreatWarningsAsErrors, exit 0, 0 errors, zero CS86xx.
Nullable=enable not supplied; target was Rebuild. Zero CoreCompile skips against 76
executions.

Tests: 1201/1201 passed, 0 failed, exactly BASELINE_PASSED 1192 + 9. All ten added
tests enumerated and Passed; the deleted test absent from the TRX.

Coverage: repository-wide 6821/6821 passed over 9 assemblies. Four figures recorded --
baseline raw 0.852607 and testable 0.850562; post-change raw 0.852830 and testable
0.850799. Both denominators rose. All 14 measured added lines are covered.

File sizes: all eight at most 500; the two constrained files at 497 and 489;
BreadcrumbDropDownIntegrationTests.cs exactly 500 and byte-identical to BASE_SHA.

Exemptions: per-file ExcludeFromCodeCoverage counts equal baseline exactly across all
seven owned files; none added, none removed.

Also removes host identity from evidence: /EnableCodeCoverage deposited attachments
named after the account and machine, and the TRX format records computerName on every
result. The attachments were deleted and all 19 evidence TRX files scrubbed, with zero
residual references and all counters preserved.

Test policy audit records one honest exception: the replacement boundary test retains a
Task.Run from the deleted test's controlled-context half, exactly as [P6-T3] instructs.
It is deterministic and does not affect the criterion, which bans sleeps, delays,
wall-clock waits, and temporary files -- all four absent.

[P8-T1] through [P8-T11].

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Writes the fail-before index covering all six defect units, each citing an artifact
recording a non-zero EXIT_CODE with ExpectedExitCode: 1 (verified by direct search).
#475 carries two, because the constructor observation required a temporary revert with
a rebuild on each side.

Checks off 53 of the 54 spec criteria. No criterion text was modified: the spec.md diff
is 53 added / 53 deleted, every changed line is a checkbox line, and stripping the
checkbox prefix from both sides of the diff yields identical text sets.

ONE CRITERION REMAINS UNCHECKED and the reconciliation is recorded as
remediation-required, not a pass. The research section 3.5 criterion has two of its
three clauses delivered -- the open item is discharged (the faulted
InitializeWebViewAsync task is NOT observed; three of four call sites discard it) and
the D5 guard is not weakened -- but the GitHub issue it specifically requires could not
be opened. enforce-promotion-mcp-only.ps1 forbids `gh issue create` and requires the
drm-copilot MCP promotion tools, which are not in this executor's tool set. The
forbidden path was not used and no wording was altered to evade the hook. The follow-up
is prepared as a potential entry and needs only promotion.

The authorized pre-existing-unformatted-file exception was not used and does not apply:
both the Phase 0 baseline and the final csharpier check reported empty sets.

[P9-T1] through [P9-T16].

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
git status --porcelain produces no output lines; nothing under .claude/agent-memory is
dirty. git diff --name-only against BASE_SHA lists 107 paths, all of which are the four
owned production files, the three owned test files, QuickFiler.Test.csproj, paths under
the feature folder, or paths under docs/features/potential/; a mechanical filter for
anything outside that set returns 0.

Ten commits on the branch, one per phase. Nothing pushed.

[P9-T17]. 143 of 145 plan tasks checked off; [P5-T6] and [P5-T11] remain blocked on
MCP-only issue promotion.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The executor delivered 143 of 145 plan tasks and 53 of 54 acceptance
criteria. The single gap was the research 3.5 criterion, which requires a
GitHub issue to be opened against QfcItemController.ViewerSetup.cs and
referenced from the spec. The executor prepared the follow-up entry but
could not promote it: the approved MCP promotion tools are absent from its
tool set, and it correctly declined to use the hook-forbidden alternative
or to reword anything to get around the gate.

The orchestrator holds those tools and ran the approved promotion path,
producing issue 670 (qfc-initializewebviewasync-fault-is-unobserved),
verified OPEN. The faulted task is confirmed unobserved at three of its
four production call sites, and the D5 guard is delivered unweakened, as
the criterion requires.

Records the receipt in the D5 evidence artifact, adds the issue reference
to the spec D5 design section, and checks off the criterion plus plan
tasks P5-T6 and P5-T11. The executor's blocked-state record is retained
rather than deleted, since it documents a tool-set boundary a future
executor will meet again.

Result: 145 of 145 plan tasks, 54 of 54 acceptance criteria. No criterion
text was modified and the criterion count is unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Feature review returned PASS with zero Blocking findings and six
Non-blocking ones. Adds the three audit artifacts and remediates the one
finding that was actionable before fan-in.

PA-1 asked for a mechanical sanitization pass over the TRX evidence. All
19 files now carry REDACTED-WORKTREE-ROOT in place of the absolute
worktree path and REDACTED-DOMAIN-USER in place of the runUser domain
token. A case-insensitive sweep of the feature folder for the account and
machine names returns zero files. The only remaining occurrences in the
repository are in four previously merged promoted potential entries and in
untracked build outputs, none of them in this branch's diff.

The same pass uncovered a defect the audit had not detected. The original
scrub substituted the placeholder into XML attribute values using angle
brackets, which are not legal there, so all 19 committed TRX files were
not well-formed and would not parse. Verified against the committed blobs,
so the defect predates this change. Replacing the 7306 occurrences with a
bracket-free token restores well-formedness: all 19 parse, zero failures.

Only path and identity attributes changed; every counter is preserved.
Re-parsing them independently corroborates the delivered result: baseline
1192 passed, final 1201 passed, the D4 full-suite run 1198 of 1198, and
genuine red fail-before runs for all six defect units. The evidence is
strictly more useful than before, having gone from unparseable to
machine-readable.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The feature review's PA-1 recommended a repo-wide cleanup entry for the
host tokens already present in merged sibling evidence, and PA-2 left the
raw-Cobertura size question owed to a maintainer decision. Both are real
and neither is curable by this branch alone.

Files them as issue 671, covering the pre-existing tokens in features 501,
608 and 439, the angle-bracket placeholder trap that silently breaks TRX
well-formedness, and the coverage-artifact size convention. Filed rather
than left as prose, because a finding recorded only in a feature folder
stops being visible once the feature merges.

Issue 671 is a follow-up and is deliberately excluded from this branch's
pull-request closing list.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ycle-defects-488

fix(quickfiler): itemviewer breadcrumb lifecycle defects D1-D5 and #475
@drmoisan
drmoisan merged commit f387ea3 into main Aug 28, 2026
10 checks passed
@drmoisan
drmoisan deleted the epic/quickfiler-bug-family-integration branch August 28, 2026 12:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment