fix(#877): make QuickFiler.Test self-sufficient for the netstandard 2.1 bind - #880
Merged
drmoisan merged 9 commits intoSep 13, 2026
Merged
Conversation
…older Issue 877: QuickFiler.Test relies on an AppDomain.CurrentDomain.AssemblyResolve handler installed by UtilitiesCS.Test, so it fails under class-level parallelism. Seeds issue.md with the diagnosis and an explicit Acceptance Criteria section. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The deny text names the correct feature folder and blames a missing Work Mode marker, but folder resolution succeeded and a repo-relative Test-Path at hook line 108 resolved against the session root instead. Observed on a standalone child worktree, not only in parallel items. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Replaces the refuted sibling-assembly attribution in Summary, Suspected Cause and AC1-AC5 with the verified mechanism, and records both refuted explanations with the evidence that killed them. AC6-AC8 are unchanged. Adds the M-matrix and the pre-fix evidence projections. Promotes the production-side risk as issue #879 rather than folding it into 877. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Four preflight rounds, 25 defects closed. Two were existential: every pwsh payload would have run in the coordinator session worktree, which has its own TaskMaster.sln, so msbuild would have built the wrong checkout and csharpier would have reformatted another tree; and vstest.console.exe is not on PATH, so no test span would have resolved. The plan now mandates a Set-Location prefix on every payload and vswhere resolution for vstest. M3 run alone with no runsettings is recorded as the sole discriminator; M2 and the full suite are non-probative regression checks.
…solve self-sufficiency Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… a shared TestSupport source file Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… acceptance criteria check-off Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
pwsh payloads start in the coordinator session worktree, which has its own TaskMaster.sln, so an unqualified msbuild builds the wrong checkout and returns a vacuously green result. Delta application is itself a defect source: rounds 2 and 3 mostly found damage from applying the prior round's delta.
5 tasks
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.
Summary
QuickFiler.Testwas not self-sufficient for assembly resolution. Three of its tests load Deedle, and that load requires a bind tonetstandard, Version=2.1.0.0, PublicKeyToken=cc7b13ffcd2ddd51that nothing in the repository or on the build machine satisfies. The bind succeeds only while a process-globalAppDomain.CurrentDomain.AssemblyResolvefallback matching on simple name plus public key token is already installed.QuickFiler.Testinstalled no such fallback; it had been borrowing one by accident fromSVGControl, whose resolver is installed lazily from theSVGControl.SvgRendererstatic constructor and therefore only after some earlier test class touches an SVG-bearing control. When the Deedle-using class runs first, the bind fails.This installs the fallback in
QuickFiler.Test's own[AssemblyInitialize], which MSTest runs before any test in that assembly, so the assembly no longer depends on what ran before it.Fixes #877
Verified mechanism
The
netstandard 2.1.0.0requirement enters the closure through the FSharp.Core redirect, not through Deedle:Deedle.dllreferencesFSharp.Core 4.5.0.0andnetstandard 2.0.0.0only.app.configredirect FSharp.Core to11.0.0.0.FSharp.Core 11.0.0.0referencesnetstandard 2.1.0.0.netstandard 2.1.0.0exists nowhere on the machine; the GAC holds onlyv4.0_2.0.0.0__cc7b13ffcd2ddd51, and no*.configin the repository contains the stringnetstandard.Two earlier explanations were held with confidence and are recorded as refuted in
issue.md, with the evidence that killed each: sibling-assembly initialiser ordering, and a Deedle static-initialiser race. Neither was implemented.Why only one test run proves this
The suite result is nondeterministic. Two runs of the identical full-assembly command, both totalling 1395 tests, disagreed: 1392 passed / 3 FAILED on one occasion and 1395 passed / 0 failed on another. Whether the bind succeeds depends on which class happens to touch
SvgRendererfirst, which the run shape does not fix.The discriminating run is the Deedle-using class executed alone, with no runsettings file, so no other class can install a resolver first:
The full-assembly run (1395 passed, exit 0) and the
UtilitiesCS.Testrun (4926 passed, exit 0) are regression checks only and are explicitly non-probative. Neither can confirm this fix and neither can refute it; they are reported to show nothing got worse.Changes
Five files. Zero production source files are touched.
TestSupport/TestAssemblyResolver.cs(new) — the shared resolver, linked into both test projects from one file so the two copies cannot drift. Placed at the repository root because putting it inside either test project would make one test assembly reach into the other's folder.QuickFiler.Test/QuickFiler.Test.csproj,UtilitiesCS.Test/UtilitiesCS.Test.csproj— one additive<Compile>item each with a<Link>. Both are legacy non-SDK projects with explicit items, so nothing is globbed and the link must be declared by hand.QuickFiler.Test/SetupAssemblyInitializer.cs— installs the resolver alongside the existingEnableVisualStylesandSetCompatibleTextRenderingDefaultcalls.UtilitiesCS.Test/TestAssemblyInitializer.cs— rewired to the shared type; behaviour unchanged in effect.The resolver is spelled with an explicit null test rather than a null-coalescing assignment:
QuickFiler.Testdeclares no<LangVersion>and targetsv4.8.1, so it compiles at the C# 7.3 default where??=is CS8370. The semantics are identical.SVGControlis not modified. Three near-identical resolvers exist after this change, which is accepted; consolidating them into production code has a different blast radius and is out of scope.Out of scope
The same unsatisfiable bind exists in production, where only the lazy
SVGControlhandler is available. The add-in appears safe only because the VSTO surface renders SVG before anything reaches Deedle, which is an ordering accident rather than a guarantee. Tracked separately as #879.Validation
Was not formatted./t:Rebuild): exit 0,0 Warning(s),0 Error(s)./t:Rebuild /p:TreatWarningsAsErrors=true): exit 0,0 Warning(s),0 Error(s).scripts/vscode/TaskMaster.cli.runsettingsis unmodified (SHA-256 unchanged). The diff contains no[DoNotParallelize], noWorkerschange, no retry, no sleep and no timing tolerance. All 8 acceptance criteria are checked off inissue.md.Coverage gates are not the gate for this change: it touches zero production files, so no coverage figure is attributable to it and none is claimed.
🤖 Generated with Claude Code