Make isolated graph builds fail deterministically on undeclared cross-project targets#14280
Make isolated graph builds fail deterministically on undeclared cross-project targets#14280AlesProkop with Copilot wants to merge 7 commits into
Conversation
|
Hello @copilot, I noticed that you’re changing an .swr file or any file under src/Package/MSBuild.VSSetup.. Please make sure to validate this change by an experimental VS insertion. This is accomplished by pushing to an exp/* branch, which requires write permissions to this repo. |
…ets (fix MSB4252 scheduling nondeterminism, #14225) Co-authored-by: AlesProkop <276576870+AlesProkop@users.noreply.github.com>
|
@copilot fix the failing checks |
Co-authored-by: AlesProkop <276576870+AlesProkop@users.noreply.github.com>
Fixed. The failing checks were caused by a compile error in |
…r; exempt SkipNonexistentTargets Add Wave18_10 opt-out for the deterministic MSB4252 behavior, consolidate the duplicated GetIsolationAllowedTopLevelTargets into BuildRequestConfiguration, exempt SkipNonexistentTargets requests from the gate, and add enabled/disabled regression tests.
There was a problem hiding this comment.
Pull request overview
This PR makes -graph -isolate builds fail deterministically when a project invokes an undeclared cross-project target, eliminating scheduling-dependent behavior where node-local cached dependency results could accidentally satisfy an invalid ProjectReferenceTargets protocol reference.
Changes:
- Adds an isolation-aware gate to results-cache satisfaction so only graph-declared top-level targets can be reused across projects in strict isolation (ChangeWave 18.10 gated).
- Threads the “allowed top-level targets” restriction through scheduler and build-request-engine cache satisfaction paths.
- Adds regression/unit tests and documents the new ChangeWave behavior.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Framework/ChangeWaves.cs | Adds ChangeWave 18.10 to support opt-out for the new deterministic isolation behavior. |
| src/Build/BackEnd/Shared/BuildRequestConfiguration.cs | Computes “allowed top-level targets” for strict isolation cache satisfaction. |
| src/Build/BackEnd/Components/Scheduler/Scheduler.cs | Passes isolation “allowed targets” through scheduler cache satisfaction to enforce deterministic failures. |
| src/Build/BackEnd/Components/Caching/IResultsCache.cs | Extends SatisfyRequest API with optional allowedTopLevelTargets gate. |
| src/Build/BackEnd/Components/Caching/ResultsCache.cs | Implements the isolation gating check inside cache satisfaction. |
| src/Build/BackEnd/Components/Caching/ResultsCacheWithOverride.cs | Threads the new allowedTopLevelTargets argument through override cache implementation. |
| src/Build/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs | Applies the same isolation gate to node-local cache satisfaction in request issuance. |
| src/Build.UnitTests/Graph/IsolateProjects_Tests.cs | Adds regression tests covering deterministic MSB4252 behavior + ChangeWave opt-out behavior. |
| documentation/wiki/ChangeWaves.md | Documents ChangeWave 18.10 and the opt-out knob for this behavioral change. |
Expert review — PR #14280 · 9 files, +222/−12Methodology: portable core + dotnet/msbuild expert-reviewer · 24/24 dimensions evaluated · Mode: Deep Verdict: 🟡 COMMENT — address findings — 0 blocking, 0 major, 3 moderate, 2 nit · 20 of 24 evaluated dimensions clean The fix is well-reasoned and correct in the scenarios I traced. A forced cache miss under strict isolation routes to
|
Expert review update — PR #14280 @ 4408138I re-reviewed the current head after the latest fixes. I found one issue that should be addressed before merge. Major: persisted input/output caches bypass the new strict-isolation allow-list
That is fine for live node packets, because Relevant lines:
Concrete scenario: build a referenced project in strict isolation with an output cache, where the graph-declared entry target is Recommendation: persist I did not find other blocking issues in the 9-file PR diff. I did not run the test suite for this review. |
Expert review update — PR #14280 @ 64146a7I re-reviewed the current head after the persisted-cache fix. No remaining actionable findings from the 10-file PR diff. The previous major issue is addressed: Relevant fixed coverage:
Validation I ran:
Residual risk: the new test directly covers the serialization member that caused the cache bypass, and the existing graph test covers the in-memory cache leak path. I still do not see a full end-to-end test that writes a strict-mode output cache and consumes it later as an input cache, but I do not consider that a blocking gap now that the serialization path itself is covered. |
Fixes #14225
In
-graph -isolatebuilds, a cross-project reference to a target that only has results because it ran as aDependsOnTargetsdependency could be satisfied from a node-local (or in-proc shared) results cache when the referenced project happened to run on the same node, but miss and fail with MSB4252 when it ran on a different node. This made an incompleteProjectReferenceTargetsprotocol scheduling-dependent —/m:1passes,/m:8intermittently fails.Context
The presence of a result in the engine cache is the de-facto validation of the
ProjectReferenceTargetsprotocol: the static graph pre-builds each node with its declared entry targets, so only those results land in the shared cache. However, dependency-produced target results also accumulate in a node's local cache and can satisfy an undeclared cross-project reference, but only under scheduling where parent and child share a node. The result of an isolated build should not depend on node scheduling.Changes Made
Non-destructive gate: an isolated cross-project reference may only be satisfied from the results cache when the requested targets are among the referenced configuration's explicitly-requested (graph-declared) top-level targets. Otherwise it is treated as a cache miss, so the existing isolation constraint check fires and reports MSB4252 consistently.
IResultsCache/ResultsCache/ResultsCacheWithOverride: added optionalallowedTopLevelTargetsparameter toSatisfyRequest. When set, all requested targets (or config default targets) must be contained in it (case-insensitive) or the request is reported unsatisfied.Scheduler: newGetIsolationAllowedTopLevelTargetshelper threaded throughTrySatisfyRequestFromCacheand both cache-satisfaction sites (HandleRequestBlockedByNewRequests,ResolveRequestFromCacheAndResumeIfPossible).BuildRequestEngine.IssueBuildRequests: gated the node-localSatisfyRequestpath the same way.BuildRequestConfiguration.RequestedTargetsand applies only underProjectIsolationMode.True, for non-root, non-SkipStaticGraphIsolationConstraintsrequests, exempting self-references (a project building itself). EmptyRequestedTargetsfalls back to existing behavior.Testing
Manual repro from the issue (
root/Parent/Child+ fillers) now fails consistently with MSB4252 under both/m:1and/m:8, instead of passing only under/m:1.Notes
ProjectIsolationMode.True);MessageUponIsolationViolationand non-isolated builds retain existing behavior.BuildRequestEngine.ReportConfigurationResponsecache path is intentionally not gated — its local cache is empty in the leak-relevant scenarios and its unresolved config'sRequestedTargetsis unreliable there.