Summary
Port upstream App-vNext/Polly@1a80392b — "Update to xunit v3" (App-vNext/Polly#3131) — to Fences.
Split out of the first upstream sync (#28), where it was triaged port, as its own piece of work. It is too large and too cross-cutting to go through the sync's normal one-commit-at-a-time porting (33 files, +1634 / −139), but it must not be left behind: every later upstream change that touches tests, build scripts, coverage or Stryker config will be written against xunit v3 / Microsoft.Testing.Platform v2. The longer Fences stays on xunit v2, the harder each future sync becomes, and the further we drift from the "rebrand, don't redesign" alignment ADR 0003 commits us to.
What the upstream commit does
From its description, and the diff:
- xunit v2 → xunit v3 (
xunit 2.9.3 → xunit.v3.mtp-v2 / xunit.v3.assert 4.0.0; FsCheck.Xunit → FsCheck.Xunit.v3). Test projects become <OutputType>Exe</OutputType>; Xunit.Abstractions usings go.
- Microsoft.Testing.Platform v2 as the test runner (
Microsoft.Testing.Platform 2.4.0).
- Replaces coverlet entirely.
coverlet.msbuild and the ReportGenerator package are removed; coverage comes from Microsoft.Testing.Extensions.CodeCoverage, written as Cobertura to one file per target framework (coverage.<tfm>.xml). Report generation and threshold enforcement move out of eng/Test.targets into cake.cs tasks (__GenerateCoverageReports, __VerifyCoverageThresholds), which still read each project's <Threshold>.
- Changes coverage thresholds:
Polly.Specs goes from 94,94,91 to 96,95,93 under the new counter.
- Stryker: disables MinVer during mutation runs to work around a Stryker issue with MTP v2 (
eng/stryker-config.json, .github/workflows/mutation-tests.yml).
- Tooling: adds
dotnet-reportgenerator-globaltool 5.5.11 as a local tool and bumps another tool 4.16.0 → 5.0.0 (.config/dotnet-tools.json).
- Production code changes, made to extend or suppress coverage where mutants went missing:
Hedging/Controller/TaskExecution.cs, Retry/RetryHelper.cs, ConcurrentDictionaryExtensions.cs, Telemetry/TelemetryOptions.cs, Telemetry/TelemetryUtil.cs. Each needs checking against ADR 0003 D7 (no public API change) and the .PublicAPI/ baselines.
- Adds a test collection for tests that depend on the system clock.
Relationship to #14
This directly affects #14, which is about coverlet's unreliable collection and the coverlet 10 upgrade (#6). Upstream no longer uses coverlet at all. See the comment on #14 for the detail. The short version: porting this likely changes #14's question, from "how do we make coverlet reliable" to "how do we validate thresholds under Microsoft's coverage tool". The two should be decided together, not on separate tracks.
Things to settle before implementing
- Dependencies. This adds, removes and bumps packages and tools.
CLAUDE.md forbids dependency changes unless asked, so this issue is the ask. Check that each version is still current when the work starts, and reconcile with whatever Fences' own Dependabot has moved in the meantime.
- Fences-only test conventions. Fences' tests diverge from upstream's (NSubstitute,
Member_Scenario_Outcome naming, test/Paramore.Fences.* project names). The xunit v3 API changes (ITestOutputHelper namespace, async lifetime, TestContext cancellation) have to be applied to Fences' own versions of the files, not copied over.
- Mutation score. Verification gate 5 says Stryker scores must not regress. The MinVer workaround and any coverage suppressions must keep that true, especially given the
mutations-core hang already seen in CI.
- CI. Codecov upload paths, the
validate-packages job, and anything else that reads artifacts/coverage-reports must follow the new layout.
Given the size, this probably merits running through the spec workflow (/spec:requirements → design → tasks) rather than a single PR.
Acceptance
Summary
Port upstream App-vNext/Polly@1a80392b — "Update to xunit v3" (App-vNext/Polly#3131) — to Fences.
Split out of the first upstream sync (#28), where it was triaged port, as its own piece of work. It is too large and too cross-cutting to go through the sync's normal one-commit-at-a-time porting (33 files, +1634 / −139), but it must not be left behind: every later upstream change that touches tests, build scripts, coverage or Stryker config will be written against xunit v3 / Microsoft.Testing.Platform v2. The longer Fences stays on xunit v2, the harder each future sync becomes, and the further we drift from the "rebrand, don't redesign" alignment ADR 0003 commits us to.
What the upstream commit does
From its description, and the diff:
xunit2.9.3 →xunit.v3.mtp-v2/xunit.v3.assert4.0.0;FsCheck.Xunit→FsCheck.Xunit.v3). Test projects become<OutputType>Exe</OutputType>;Xunit.Abstractionsusings go.Microsoft.Testing.Platform2.4.0).coverlet.msbuildand theReportGeneratorpackage are removed; coverage comes fromMicrosoft.Testing.Extensions.CodeCoverage, written as Cobertura to one file per target framework (coverage.<tfm>.xml). Report generation and threshold enforcement move out ofeng/Test.targetsintocake.cstasks (__GenerateCoverageReports,__VerifyCoverageThresholds), which still read each project's<Threshold>.Polly.Specsgoes from94,94,91to96,95,93under the new counter.eng/stryker-config.json,.github/workflows/mutation-tests.yml).dotnet-reportgenerator-globaltool5.5.11 as a local tool and bumps another tool 4.16.0 → 5.0.0 (.config/dotnet-tools.json).Hedging/Controller/TaskExecution.cs,Retry/RetryHelper.cs,ConcurrentDictionaryExtensions.cs,Telemetry/TelemetryOptions.cs,Telemetry/TelemetryUtil.cs. Each needs checking against ADR 0003 D7 (no public API change) and the.PublicAPI/baselines.Relationship to #14
This directly affects #14, which is about coverlet's unreliable collection and the coverlet 10 upgrade (#6). Upstream no longer uses coverlet at all. See the comment on #14 for the detail. The short version: porting this likely changes #14's question, from "how do we make coverlet reliable" to "how do we validate thresholds under Microsoft's coverage tool". The two should be decided together, not on separate tracks.
Things to settle before implementing
CLAUDE.mdforbids dependency changes unless asked, so this issue is the ask. Check that each version is still current when the work starts, and reconcile with whatever Fences' own Dependabot has moved in the meantime.Member_Scenario_Outcomenaming,test/Paramore.Fences.*project names). The xunit v3 API changes (ITestOutputHelpernamespace, async lifetime,TestContextcancellation) have to be applied to Fences' own versions of the files, not copied over.mutations-corehang already seen in CI.validate-packagesjob, and anything else that readsartifacts/coverage-reportsmust follow the new layout.Given the size, this probably merits running through the spec workflow (
/spec:requirements→ design → tasks) rather than a single PR.Acceptance
.PublicAPI/baselines updated where needed.1a80392bupdated to link the merged PR.