Harden MT migration skill with defect classes found in a 150-task migration - #14795
Merged
Conversation
…ration
Migrating ~150 tasks across dotnet/arcade, dotnet/source-build-assets and
the dotnet/dotnet VMR surfaced 9 real defects that survived a build with
Microsoft.Build.TaskAuthoring.Analyzer enabled and 0 warnings / 0 errors.
This encodes those defect classes into the skill and reviewer agent.
Skill:
- Sin 8: swallowed exceptions hiding an unresolved path. A catch that means
a semantic answer ("not an assembly") turns a path bug into a silently
wrong result rather than a failure.
- Analyzer-invisible path consumers (AssemblyName.GetAssemblyName, XDocument
.Load(string), ZipFile.*, ...) are not on MSBuildTask0003's monitored-type
list. GetAssemblyName on a raw input was the most-repeated defect found.
- Unsafe code in an unannotated base class. The attribute is Inherited=false,
so bases are unannotated -- and under scope=multithreadable_only they are
never analyzed, though they execute multithreaded.
- Engine-owned shared state via Get/RegisterTaskObject: non-atomic, and no
static field appears, so it reads as thread-safe.
- Paths crossing interface/DI boundaries, where no System.IO type appears in
the task at all.
- New "Verification" section: a clean analyzer run is not a migration, with
the observed miss breakdown.
- New "Migrating Is Not Always the Right Answer" section: leaving a task
unannotated preserves today's TaskHost behavior and is a valid outcome.
- Sign-off checklist extended with the above; fixed a pre-existing broken
anchor link to Sin 2.
Reviewer agent:
- Operating rule: never accept a clean analyzer run as a basis for approval.
- Step 1 walks the base chain, catch blocks, caches and DI boundaries.
- Step 2 hazard table gains the analyzer-invisible APIs, DI boundaries,
semantic-answer catches and the RegisterTaskObject pair. Corrects the
GetAssemblyName row, which previously flagged only Sin 2 message leakage
and missed that the call is itself CWD-dependent.
- Step 5: approve a justified decision not to migrate.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR updates the mt-migration plugin documentation to incorporate additional defect classes observed during a large multithreaded-task migration effort, extending the playbook and reviewer agent to explicitly cover analyzer blind spots (base-class scope gaps, analyzer-invisible path consumers, semantic-answer catch blocks, engine-owned shared state via RegisterTaskObject, and DI/interface boundaries).
Changes:
- Expands the migration playbook from “7” to “8” compatibility sins, adding a new Sin 8 section and extending the sign-off checklist accordingly.
- Adds explicit guidance and hazard-table entries for analyzer-invisible path consumers (e.g.,
AssemblyName.GetAssemblyName(string)and other string-overload path sinks) and DI/interface boundary path flows. - Updates the MT migration reviewer agent rules/hazard table to enforce “clean analyzer run is not evidence” and to proactively audit base chains, semantic-answer catches, caches, and DI boundaries.
Show a summary per file
| File | Description |
|---|---|
| plugins/mt-migration/skills/multithreaded-task-migration/SKILL.md | Extends the migration playbook with new defect classes (Sin 8), new hazard categories, and an expanded verification/sign-off checklist. |
| plugins/mt-migration/README.md | Updates the plugin overview text to reflect “8 deadly sins”. |
| plugins/mt-migration/agents/mt-migration-reviewer.agent.md | Strengthens reviewer operating rules and hazard table to cover analyzer gaps and approve justified non-migrations. |
Review details
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
- Files reviewed: 3/3 changed files
- Comments generated: 1
- Review effort level: Lite
JanProvaznik
approved these changes
Aug 24, 2026
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.
Encodes into the migration skill and reviewer agent the defect classes found while migrating ~150 tasks to
[MSBuildMultiThreadableTask]across dotnet/arcade (arcade#17381), dotnet/source-build-assets (#1776) and the dotnet/dotnet VMR.Why
Microsoft.Build.TaskAuthoring.Analyzerwas enabled in all three repos and every build was 0 warnings / 0 errors. A manual audit afterwards still found 9 real defects:AssemblyName.GetAssemblyName)Every one of these was findable by reading the code with the right checklist — so they belong in the skill. Analyzer gaps are filed separately against #14772 (#14791, #14792, #14793) plus #14794 for a runtime forcing function.
Changes
SKILL.md
catchmeans a semantic answer ("not an assembly") rather than "fail", an unresolved path produces a silently wrong result instead of an error. In the VMR'sCheckForPoisonthis skipped both poison checks, turning a leaked binary into a false negative in source-build's leak-detection gate — with a green build.MSBuildTask0003monitors 8 types; anything else taking a path string is equally unsafe and silent.AssemblyName.GetAssemblyNameon a raw input was the most-repeated defect of the whole exercise. Notes the string-vs-stream overload distinction.Inherited = false, so bases are unannotated — and underscope = multithreadable_onlythey are never analyzed, despite executing multithreaded. Real case:AkaMSLinksBaseheldFile.ReadAllTexton a raw task input while both derived tasks were annotated and clean.RegisterTaskObject. Non-atomic read/write with nostaticfield in sight, so it reads as thread-safe. Includes the benign/broken decision table —LocateDotNetis fine,SingleErrorwas not.System.IOtype appears in the task at all.mt-migration-reviewer.agent.md
catchblocks, caches and DI boundaries.RegisterTaskObjectpair. Also corrects an existing row:AssemblyName.GetAssemblyNamewas listed only under Sin 2 message leakage, missing that the call is itself CWD-dependent.Docs only — no product code, no tests affected.