Add flaky-test detection and auto-fix agentic workflows - #13915
Conversation
Introduce a GitHub Agentic Workflows (gh-aw) system that detects flaky tests in msbuild's public CI and tracks/fixes them: - flaky-test-detector skill: Get-FlakyTests.ps1 scans recent failed builds on the public dnceng-public pipeline (def 75) anonymously, using an evidence-source model (approved non-draft PRs on main UNION rolling main builds). A test failing across >= MinSources distinct sources is flagged. - flaky-test-detector.agent.md: daily scheduled triage that files/updates flaky-test tracking issues and dispatches the fixer (capped). - flaky-test-fix.agent.md: dispatched fixer that re-verifies, attempts a gated local reproduction, and opens a single draft PR with either a minimal determinism fix or a quarantine (Skip). Never touches .github/**. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
🔍 Skill Validator Results
Summary
Full validator output```text Found 1 skill(s) [flaky-test-detector] 📊 flaky-test-detector: 3,457 BPE tokens [chars/4: 3,346] (standard ~), 13 sections, 5 code blocks [flaky-test-detector] ⚠ Skill is 3,457 BPE tokens (chars/4 estimate: 3,346) — approaching "comprehensive" range where gains diminish. ✅ All checks passed (1 skill(s)) ``` |
There was a problem hiding this comment.
Pull request overview
This PR introduces an opt-in, agentic automation system (via GitHub Agentic Workflows / gh-aw) to detect flaky tests from public Azure DevOps CI signals, file/update flaky-test tracking issues, and (for strong candidates) dispatch a fixer workflow that opens a single draft PR containing either a minimal determinism fix or a quarantine (Skip).
Changes:
- Add a scheduled “Flaky Test Detector” workflow that runs daily, produces/consumes a structured flaky-test JSON report, and files/updates issues + optionally dispatches a fixer.
- Add a dispatched “Flaky Test Fix” workflow that re-verifies flakiness, attempts local reproduction, and opens at most one draft PR.
- Add a
flaky-test-detectorskill and PowerShell implementation that scans anonymous AzDO APIs + TRX artifacts to aggregate failures by “distinct evidence sources”.
Show a summary per file
| File | Description |
|---|---|
| .github/workflows/flaky-test-fix.agent.md | gh-aw workflow definition + agent prompt for dispatched fixer. |
| .github/workflows/flaky-test-fix.agent.lock.yml | Compiled gh-aw lock file for fixer workflow. |
| .github/workflows/flaky-test-detector.agent.md | gh-aw workflow definition + agent prompt for scheduled detector/triage. |
| .github/workflows/flaky-test-detector.agent.lock.yml | Compiled gh-aw lock file for detector workflow. |
| .github/skills/flaky-test-detector/SKILL.md | Skill documentation describing the evidence-source model + conventions. |
| .github/skills/flaky-test-detector/scripts/Get-FlakyTests.ps1 | Detector implementation: fetch failed builds, download TRX artifacts, aggregate evidence, emit JSON report. |
Copilot's findings
- Files reviewed: 6/6 changed files
- Comments generated: 5
There was a problem hiding this comment.
Expert Code Review — Flaky Test Detector
Overall assessment: Well-designed PR — solid security posture, clear documentation, good separation of concerns.
Strengths
- Security hardening is excellent: DTD processing prohibited,
XmlResolver = nullon XML parsing, zip PK-header validation, size caps on artifacts/TRX files,$MaxTrxPerArtifactlimit, artifact name sanitization for paths, and proper[uri]::EscapeDataStringfor URL construction. - The evidence-source model (collapsing PR builds, treating rolling builds independently) is well-reasoned and clearly documented.
- Temp directory cleanup in a
finallyblock ensures no orphaned files. - The
scanCompleteguard (propagated to callers via JSON) is a good design for preventing action on incomplete data. - Workflow agent definitions follow the existing repo patterns (PAT pool selection, network allowlist, etc.) and are consistent with
review.agent.md. - SKILL.md is thorough and well-structured — excellent reference for future maintainers.
Issues Found (see inline)
ReadAllBytesfor 2-byte header check — allocates potentially 200MB per artifact just to read 2 bytes. Use a stream.$scanCompletefalse-negative — relies on$buildsResponse.countwhich may be absent from AzDo API responses, silently marking truncated scans as complete.Substring(0, 10)on external data — minor robustness concern on theGet-BuildDatehelper.
Not Flagged (positive notes)
- No MSBuild engine code is modified — no backwards compat, ChangeWave, or API surface concerns.
- Lock files are auto-generated and consistent with the
.mddefinitions. - Permissions are appropriately scoped (read-only for the detector, broader for the fixer which needs to create PRs).
- The
excluded-files: [".github/**"]in the fixer workflow'screate-pull-requestconfig is a good defense-in-depth measure.
Note
🔒 Integrity filter blocked 2 items
The following items were blocked because they don't meet the GitHub integrity level.
- #13915
pull_request_read: has lower integrity than agent requires. The agent cannot read data with integrity below "approved". - #13915
pull_request_read: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
To allow these resources, lower min-integrity in your GitHub frontmatter:
tools:
github:
min-integrity: approved # merged | approved | unapproved | noneGenerated by Expert Code Review (on open) for issue #13915 · ● 17.8M
…cheduled probe
Switch the flaky-test auto-fixer's quarantine mechanism from [Fact(Skip=...)]
to Arcade's [ActiveIssue(...)] (Microsoft.DotNet.XUnitV3Extensions), and add a
scheduled AzDO pipeline that re-runs only the quarantined tests so they keep
producing pass/fail signal instead of going dark.
- src/Directory.Build.targets: make the existing --filter-not-trait
Category=failing exclusion conditional on RunQuarantinedTests. When that
property is true, flip to --filter-trait Category=failing --ignore-exit-code
8;2 to run ONLY quarantined tests and tolerate exit 8 (zero tests) / 2
(failures). Normal CI behavior is unchanged when the property is unset.
- azure-pipelines/quarantine.yml: new twice-daily (cron "0 8,20 * * *", main,
always:true) Windows pipeline mirroring the CI Windows Full job; passes
/p:RunQuarantinedTests=true and publishes TRX + logs.
- flaky-test-fix / flaky-test-detector workflows + detector SKILL: quarantine
guidance now uses additive [ActiveIssue("<issue-url>")] (keep the test body),
strongly preferring the unconditional form since the probe is Windows-only.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Mirror the per-OS test legs of .vsts-dotnet-ci.yml so platform-scoped [ActiveIssue] quarantines are re-validated on the matching platform. The Linux/macOS legs forward /p:RunQuarantinedTests=true via --stage2Properties to the stage2 -test build. Softens the Windows-only quarantine caveats in the fixer prompt and SKILL accordingly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Get-FlakyTests.ps1: fix scanComplete truncation guard (drop unreliable buildsResponse.count; treat a full \ page as potentially truncated); read only the zip's 2-byte PK header via a stream instead of ReadAllBytes; harden Get-BuildDate against short startTime strings; correct the Write-Log stream comment. - flaky-test-detector.agent.md: describe output stream-agnostically. - flaky-test-fix.agent.md: add an allowed-files allowlist (src/**/*.cs) so the fixer PR can only touch test sources, reliably blocking edits to NuGet.config and other root manifests regardless of filename casing. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace the dispatch-a-fixer-per-test model with a single daily workflow that scans CI, files/updates tracking issues, then reproduces/fixes-or-quarantines each new candidate and opens one combined draft PR per run. - flaky-test-detector.agent.md: rename to "Flaky Test Triage and Fix"; drop dispatch-workflow; add create-pull-request (max 1, draft, base main, allowed-files src/**/*.cs, excluded .github/**); bash [:*] + github [repos,issues,pull_requests]; timeout 120. New Steps 5-9 select candidates (open issue only; skip tests already in an open PR or already quarantined; cap 8), build once, fix top 3 / quarantine the rest, validate (git-diff allowlist + compile changed projects + pre-PR race re-check), open one combined PR (Fixes # for fixes, Tracked by # for quarantines). - Delete flaky-test-fix.agent.md and its lock; recompile detector lock. - SKILL.md: collapse Related Workflows to the single combined workflow. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The open combined PR is the only guard against re-quarantining a test whose previous-run quarantine is still unmerged (it lives on the PR branch, not main). Replace the fuzzy 'gh pr list --search ... in:body' (which strips HTML-comment punctuation) with a single label-scoped fetch of open flaky-test PR bodies and an exact local string match of each test's marker, in both Step 5 selection and the Step 8 pre-PR re-check. Body-only change; lock runtime-imports the body so no recompile needed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… do) gh-aw's noop safe-output defaults to report-as-issue: true, so every quiet run (incomplete scan, no flakes, or all candidates already tracked/in an open PR) would file a GitHub issue. Set noop.report-as-issue: false so a no-op run is still logged in the run summary for debuggability but creates no issue noise. Recompiled the lock (GH_AW_NOOP_REPORT_AS_ISSUE: false). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The scheduled quarantine pipeline (RunQuarantinedTests=true) runs only the flaky/quarantined tests to collect pass/fail signal via repeated execution. Coverage instrumentation adds overhead and can perturb timing-sensitive flakes, so gate the non-Windows --coverage args off RunQuarantinedTests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Rewrite Step 7 to screen all selected candidates for reproducibility concurrently (xargs -P 4) using the prebuilt test assembly directly instead of 'dotnet test', which avoids the non-Windows --coverage injection and lets many loops run without coverage-file contention. Fixes are then authored sequentially for up to the 5 strongest reproducers, time-boxed. Incorporates review hardening: - per-iteration 'timeout' (hang -> status=timeout, excluded, not quarantined) - dll-existence check (-> status=setup-error, not misread as a failing test) - fully-qualified --filter-method (Namespace.Class.Method) to avoid matching a same-named method in another class - sequential pre-fix re-confirmation alone, since parallel CPU/child-process pressure can induce false flakes - rebuild the edited project before post-fix validation (no stale binaries) - clear /tmp/repro and use sanitized result-file ids Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… flaky tests Reuse the existing detector against quarantine pipeline definition 344 instead of a separate reader. Add an opt-in -IncludePassed mode to Get-FlakyTests.ps1 that records passing observations (not just failures), queries all completed builds, and emits a passedTests aggregate. Wire the daily workflow to un-quarantine consistently-green tests and re-fix still-flaky quarantined ones, folded into the same combined draft PR with independent caps. Document the quarantine-health data model and un-quarantine criteria in SKILL.md. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…gration Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…s stage-2-only The unquoted '-stage2Properties /mt /p:RunQuarantinedTests=true' bound only /mt to stage2Properties; /p:RunQuarantinedTests=true fell through to the script's ValueFromRemainingArguments \ and was applied to both the stage 1 and stage 2 builds, defeating stage-2 isolation. Single-quoting the value (matching the Linux/macOS bash legs) keeps both tokens inside -stage2Properties so they are only appended to the stage 2 test build. Verified the single-quote form survives the cmd -> powershell -Command wrapper. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…hell-split on Unix (#13918) ## Problem The scheduled quarantine pipeline ([`azure-pipelines/quarantine.yml`](https://dev.azure.com/dnceng-public/public/_build?definitionId=344), definition 344) failed on its first real run — [build 1445333](https://dev.azure.com/dnceng-public/public/_build/results?buildId=1445333) — on the Linux and macOS legs with: ``` error MSB3073: The command "echo ... --ignore-exit-code 8;2 --results-directory ..." exited with code 127. ``` ## Root cause `RunQuarantinedTests=true` adds `--ignore-exit-code 8;2` to the xUnit v3 test command (so a quarantined-only run treats exit code `8` = zero tests ran and `2` = test failures as success — the per-test signal is the published TRX, not the exit code). Arcade's `XUnitV3.Runner.targets` assembles the command and runs it via `<Exec>`, which on non-Windows executes through `/bin/sh`. The **unquoted `;`** was interpreted by the shell as a command separator, splitting the line into: 1. `<runner> ... --ignore-exit-code 8` 2. `2 --results-directory ...` The second fragment starts with the token `2`, which is not a command, so the step failed with exit code **127** (command not found). ## Fix Quote the value: `--ignore-exit-code "8;2"`. This keeps `8;2` as a single argument on both `/bin/sh` and `cmd`. `8;2` is the correct semicolon-separated multi-code syntax for Microsoft.Testing.Platform; only the shell-level quoting was missing. Verified the parse through `/bin/sh`: - unquoted -> `2: command not found` - quoted -> `--ignore-exit-code` receives a single arg `8;2` Windows was unaffected (`cmd` does not treat `;` as a command separator), but the quoted form is correct on both. Follow-up to #13915. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Updated [Microsoft.Build.Utilities.Core](https://github.com/dotnet/msbuild) from 18.8.2 to 18.9.6. <details> <summary>Release notes</summary> _Sourced from [Microsoft.Build.Utilities.Core's releases](https://github.com/dotnet/msbuild/releases)._ ## 18.9.6 ## What's Changed * [vs18.6] Update dependencies from dotnet/arcade by @dotnet-maestro[bot] in dotnet/msbuild#13793 * [vs18.0] Update dependencies from dotnet/arcade by @dotnet-maestro[bot] in dotnet/msbuild#13859 * [vs18.6] Update dependencies from dotnet/arcade by @dotnet-maestro[bot] in dotnet/msbuild#13858 * [vs18.7] Update dependencies from dotnet/arcade by @dotnet-maestro[bot] in dotnet/msbuild#13863 * CsWin32 follow-up: CLR metadata + TypeLib interop migration by @JeremyKuhne in dotnet/msbuild#13853 * Update vmr-sb-validation.yml for Azure Pipelines by @meghnave in dotnet/msbuild#13871 * Test: keep shell alive 15s in ToolTaskCanChangeCanonicalErrorFormat (#13734) by @jankratochvilcz in dotnet/msbuild#13878 * Add vs18.8 to merge-flow config by @OvesN in dotnet/msbuild#13877 * Stable branding for 18.8 release by @OvesN in dotnet/msbuild#13883 * Bump main to 18.9.0 after vs18.8 snap by @OvesN in dotnet/msbuild#13880 * Avoid checkout in insertion pipeline by @rainersigwald in dotnet/msbuild#13887 * Report actual launch path in MSB4216 for Runtime="NET" task host by @ViktorHofer in dotnet/msbuild#13889 * Migrate Tlblmp and AxImp to Multithreaded Execution by @AlesProkop in dotnet/msbuild#13708 * Replace ErrorUtilities assertion methods with Assumed API and BCL throw helpers by @DustinCampbell in dotnet/msbuild#13790 * Fix CLR_E_SHIM_RUNTIMELOAD in RAR's IMetaDataDispenser activation by @JeremyKuhne in dotnet/msbuild#13899 * [main] Update dependencies from nuget/nuget.client by @dotnet-maestro[bot] in dotnet/msbuild#13905 * [main] Update dependencies from dotnet/arcade by @dotnet-maestro[bot] in dotnet/msbuild#13907 * [main] Update dependencies from dotnet/roslyn by @dotnet-maestro[bot] in dotnet/msbuild#13910 * [vs17.14] Update dependencies from dotnet/arcade by @dotnet-maestro[bot] in dotnet/msbuild#13908 * [vs18.0] Update dependencies from dotnet/arcade by @dotnet-maestro[bot] in dotnet/msbuild#13906 * Fix ToolTask output loss: increase EOF pipe timeout from 2s to 30s by @huulinhnguyen-dev in dotnet/msbuild#13767 * Improve symlink cycle condition by @GangWang01 in dotnet/msbuild#13901 * [vs18.6] Update dependencies from dotnet/arcade by @dotnet-maestro[bot] in dotnet/msbuild#13904 * Add flaky-test detection and auto-fix agentic workflows by @ViktorHofer in dotnet/msbuild#13915 * Quote --ignore-exit-code values so the quarantine pipeline does not shell-split on Unix by @ViktorHofer in dotnet/msbuild#13918 * Fix flaky-test detector PR-evidence loss and raise scan limits by @ViktorHofer in dotnet/msbuild#13919 * Tighten the pr review agent by @JanKrivanek in dotnet/msbuild#13921 * Add environment variables for governance detection by @ViktorHofer in dotnet/msbuild#13920 * Change IsPackable to true and add IsShipping flag by @ViktorHofer in dotnet/msbuild#13924 * [vs18.7] Update dependencies from dotnet/arcade by @dotnet-maestro[bot] in dotnet/msbuild#13911 * Make flaky detector verify recurrence postdates the fix before commenting by @ViktorHofer in dotnet/msbuild#13930 * Fix AbsolutePath.GetCanonicalForm process state leak on Windows by @OvesN in dotnet/msbuild#13788 * Fix flaky detector: unblock dnceng feed, fail fast, and defer quarantine to a second run by @ViktorHofer in dotnet/msbuild#13936 * Update documentation for ImplicitUsings element by @drewnoakes in dotnet/msbuild#13900 * [vs18.6] Point OptProf bootstrapper at rel/stable instead of int.main by @AlesProkop in dotnet/msbuild#13923 * Add CS8618 suppressor for required MSBuild task properties by @AArnott in dotnet/msbuild#13926 * Tighten NodeLaunchData.EnvironmentOverrides nullability to IDictionary<string, string?>? by @OvesN with @Copilot in dotnet/msbuild#13815 * Fix ToolTask EOF wait to be STA-safe via CountdownEvent (MSB4018 in AspNetCompiler) by @YuliiaKovalova in dotnet/msbuild#13917 * [automated] Merge branch 'vs18.6' => 'vs18.7' by @github-actions[bot] in dotnet/msbuild#13941 * Localized file check-in by OneLocBuild Task: Build definition ID 9434: Build ID 14192258 by @dotnet-bot in dotnet/msbuild#13849 * Bumping to 10.0.8 runtime packages by @OvesN in dotnet/msbuild#13898 * Flaky-test workflow: reassure on empty PR list + drop local reproduction (quarantine-first) by @ViktorHofer in dotnet/msbuild#13938 * [Flaky Test] Un-quarantine 5 consistently-green tests by @github-actions[bot] in dotnet/msbuild#13952 * Flaky-test detector: open PRs ready-for-review; drop newly-filed-issues section from PR body by @ViktorHofer in dotnet/msbuild#13958 * [Flaky Test] Quarantine 4 flaky tests by @github-actions[bot] in dotnet/msbuild#13937 * Flaky-test: fix duplicate-issue bug by switching dedup key to a visible code-block key by @ViktorHofer in dotnet/msbuild#13963 * CsWin32 follow-up: WindowsNative + VS Setup Configuration + remaining hand-rolled interop by @JeremyKuhne in dotnet/msbuild#13872 * Add the reviewer release skill checking if the Learn article Change waves is updated by @GangWang01 in dotnet/msbuild#13840 * [main] Source code updates from dotnet/dotnet by @dotnet-maestro[bot] in dotnet/msbuild#13977 ... (truncated) Commits viewable in [compare view](dotnet/msbuild@v18.8.2...v18.9.6). </details> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Summary
Adds a flaky-test detection and auto-fix system for msbuild's public CI, built on GitHub Agentic Workflows (gh-aw). The design ports the approach used by dotnet/fsharp, adapted to msbuild's anonymous-accessible
dnceng-publicpipeline.Three pieces:
1. Detector skill —
.github/skills/flaky-test-detector/Get-FlakyTests.ps1scans recent failed builds on the publicmsbuild-prpipeline (definition 75) using only anonymous Azure DevOps APIs (build list, timeline, artifact zip). It uses an evidence-source model: a test is flagged flaky when it fails across >=MinSources(default 3) distinct sources, where a source is either:main(all its failed validation builds collapse to one source), ormain(each is independent evidence, sincemainshould be green).It parses TRX results, aggregates by normalized test name, and emits an evidence-grade JSON report with a
scanCompleteflag. Smoke-tested against live CI.2. Daily triage-and-fix workflow —
.github/workflows/flaky-test-detector.agent.mdA single workflow runs daily (+ manual dispatch) and does the whole job end to end:
flaky-testtracking issue per likely-flake, deduped via a hidden<!-- flaky-test-id: -->marker.dotnet test), which avoids the non-Windows--coverageinjection so the loops don't contend. Reproduced tests then get a minimal determinism fix (authored sequentially and time-boxed, for up to the 5 strongest, test-only where possible); everything not fixed gets a quarantine with[ActiveIssue("<issue url>")](fromMicrosoft.DotNet.XUnitV3Extensions) — never[Fact(Skip=...)].Quarantine backlog (def 344 as a data source): the same daily workflow also consumes the quarantine re-validation pipeline (AzDO definition 344, see §3) to work down the existing backlog. It re-runs the same detector against def 344 with a new
-IncludePassedmode (no separate script — the quarantine pipeline mirrors the build pipeline, so the detector's failing-set aggregation already yields the "still-flaky in 344" signal;-IncludePassedadds the passing-test signal). From that it (a) un-quarantines tests that have gone consistently green — removing[ActiveIssue]only whenscanComplete, the test is green across>= 4distinct quarantine builds spanning>= 3days on every platform it's quarantined for, and it never failed in the window — and (b) re-attempts determinism fixes on tests still flaking there (when reproducible on the runner). Both fold into the same combined draft PR under independent caps (<= 5un-quarantines,<= 3backlog fixes per run). Un-quarantining relies on def 344's real-CI evidence, not a local pass.Caps per run: <= 5 new issues, <= 12 comments, exactly one combined draft PR. The PR patch is restricted to
src/**/*.cs(allowed-files) and never touches.github/**(excluded-files+ a pre-PRgit diffcheck).Fixes #is used only for real determinism fixes (auto-closes the issue on merge); quarantines useTracked by #so the tracking issue stays open.Cross-run dedup: if a previous run's combined PR is still open and unmerged, the next run fetches the open
flaky-testPR bodies and does an exact local marker match, so already-in-flight tests are skipped rather than re-quarantined (their quarantine lives on the open PR's branch, not yet onmain).3. Quarantine re-validation pipeline —
azure-pipelines/quarantine.yml[ActiveIssue]stamps theCategory=failingtrait, which normal CI excludes — so a quarantined test stops producing pass/fail signal. This scheduled AzDO pipeline runs only the quarantined tests (RunQuarantinedTests=trueflips the filter to--filter-trait Category=failing) twice daily onmain, across Windows, Linux and macOS (mirroring the per-OS test legs of.vsts-dotnet-ci.yml), so quarantines — including platform-scoped ones — keep producing data. Quarantined-test failures don't fail the pipeline (--ignore-exit-code 8;2); the per-test signal lives in the published test results, so a red run means a real infra problem. A test that goes consistently green there is a candidate to un-quarantine — and the daily workflow now acts on that signal automatically (see §2, "Quarantine backlog"). These quarantine-only runs also skip code coverage —Directory.Build.targetsgates the non-Windows--coverageargs offRunQuarantinedTests, since coverage instrumentation adds overhead and can perturb the timing-sensitive flakes being measured.Safety properties
mainbranch is considered (detector, the agentic workflow, and the quarantine pipeline schedule).mainfailures (or PR failures that only began aftermainwent red), or an N/N deterministic local repro, is treated as a likely regression — not quarantined or auto-fixed, flagged for human triage instead. This avoids masking real bugs.git diffcheck + compiling the changed test projects).close-stale-prsworkflow.Notes
*.agent.lock.yml.quarantine.ymldoes not by itself create a scheduled run — an Azure DevOps pipeline definition pointing at it must be created/enabled once.Security review (new secrets/actions introduced)
The workflow uses the established PAT-pool secrets (
COPILOT_GITHUB_TOKEN,COPILOT_GITHUB_TOKEN_1..9) and thegithub/gh-aw-actions/setupaction — identical to the already-approvedclose-stale-prs.agent.mdworkflow. No new external actions or secrets beyond that approved set.