Skip to content

[Extensibility] SingleProject: Fix dual-path backend activation and Compile filtering - #36957

Merged
kubaflo merged 2 commits into
net11.0from
pureween-fix-backend-msbuild-regressions
Jul 31, 2026
Merged

[Extensibility] SingleProject: Fix dual-path backend activation and Compile filtering#36957
kubaflo merged 2 commits into
net11.0from
pureween-fix-backend-msbuild-regressions

Conversation

@PureWeen

@PureWeen PureWeen commented Jul 30, 2026

Copy link
Copy Markdown
Member

Note

Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!

Description of Change

This focused follow-up addresses two empirically validated gaps found by the GPT-5.6 Sol post-merge verification of #36654.

  1. BackendIdentity now defaults ActivationValue even when TargetPlatformIdentifier or TargetPlatformIdentifiers is also present. A single registration can therefore activate through a recognized TPI or through MauiActiveBackend on a neutral TFM, while explicit ActivationValue and ActivationProperty metadata still win.
  2. platform Compile removal now starts from the Compile items in the ExcludeFromCurrentConfiguration=true metadata batch and intersects them with physical Platforms/** candidates. A fresh filesystem glob can no longer pull an explicitly false Compile item from another metadata bucket into the removal set. The helper-item removal pattern remains in place, preserving active item order and avoiding remove/re-add duplication.

Before and After

Before this change, a registration such as:

<MauiPlatformSpecificFolder Include="Platforms/MacOS/" TargetPlatformIdentifiers="macos" BackendIdentity="macos" />

worked for recognized TPI macos but did not activate on a neutral TFM with MauiActiveBackend=macos. It now supports both paths and remains inactive for another recognized TPI or a mismatched backend.

Before this change, the presence of any true Compile metadata batch caused a fresh Platforms/** glob to include physical files explicitly marked false by a downstream target. Removal is now constrained to the actual true Compile identities under the platform folder.

Tests

The real shipping SingleProject targets are covered by regressions for:

  • one dual-path macOS registration through recognized TPI and neutral backend activation, plus recognized-TPI and backend mismatch negatives;
  • two physical platform Compile files in different metadata buckets with no folder allow-list, asserting only the true item is removed and the surviving list is ordered and duplicate-free.

Validation:

  • complete MSBuildTests.SingleProject_* matrix: 46 passed, 0 failed;
  • new regression matrix: 7 passed, 0 failed;
  • Controls.Build.Tasks.csproj build: succeeded with 0 warnings and 0 errors;
  • targeted dotnet format: completed successfully.

The unfiltered local graph is unavailable on this Mac because the platform project graph requires the iOS workload (NETSDK1147) and the full BuildTasks solution filter includes .NET Framework 4.7.2 projects without local reference assemblies (MSB3644). The workload-neutral matrix above used the repository-pinned .NET 11 SDK with platform TFMs disabled and imported the exact shipping targets.

Candidate selection and final review

#36957 is the selected implementation. Alternatives #36955 and #36956 both fail their own new Windows Helix XAML regression by removing the explicit-false Compile item. This branch uses FullPath/PathLike intersection, passes the expanded 46-case matrix, preserves metadata and duplicate count, handles absolute Compile identities, and skips the platform filesystem glob when no removal batch exists.

Neutral activation of built-in backend identities is intentional: #36654 documented that built-ins use the same registration shape and that ActivationValue defaults from BackendIdentity. A dedicated regression now locks that contract.

Issues Fixed

Part of #34099
Part of #35021
Fixes #36650
Follow-up to #36654

Default backend activation for dual-path registrations and constrain platform Compile removal to the true metadata batch without perturbing unrelated items.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: ac6265fe-09a0-473c-b3f9-9ec6d6dd97cd
Copilot AI review requested due to automatic review settings July 30, 2026 20:16
@PureWeen
PureWeen temporarily deployed to copilot-pat-pool July 30, 2026 20:16 — with GitHub Actions Inactive
@github-actions

Copy link
Copy Markdown
Contributor

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 36957

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 36957"

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).
There may be pipelines that require an authorized user to comment /azp run to run.

@PureWeen
PureWeen temporarily deployed to copilot-pat-pool July 30, 2026 20:17 — with GitHub Actions Inactive
@PureWeen
PureWeen temporarily deployed to copilot-pat-pool July 30, 2026 20:18 — with GitHub Actions Inactive
@PureWeen
PureWeen temporarily deployed to copilot-pat-pool July 30, 2026 20:21 — with GitHub Actions Inactive
@PureWeen
PureWeen temporarily deployed to copilot-pat-pool July 30, 2026 20:21 — with GitHub Actions Inactive
@github-actions github-actions Bot added the area-infrastructure CI, Maestro / Coherency, upstream dependencies/versions label Jul 30, 2026
@PureWeen
PureWeen temporarily deployed to copilot-pat-pool July 30, 2026 20:22 — with GitHub Actions Inactive

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adjusts SingleProject’s platform-folder activation/removal logic to support dual-path backend activation (recognized TPI vs neutral-TFM selector) and to make platform Compile removal respect MSBuild batching semantics to avoid removing explicitly-included items.

Changes:

  • Default ActivationValue from BackendIdentity even when TargetPlatformIdentifier(s) are present, enabling a single registration to activate via either recognized TPI or neutral-TFM backend selection.
  • Rework _MauiRemovePlatformCompileItems to start from the @(Compile) batch and intersect with physical Platforms/** candidates, preventing “false” metadata buckets from being re-discovered and removed.
Show a summary per file
File Description
src/Controls/tests/Xaml.UnitTests/MSBuild/MSBuildTests.cs Adds regressions covering dual-path backend activation and Compile removal batching correctness.
src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.SingleProject.targets Updates platform Compile removal to intersect the true @(Compile) batch with physical platform-folder candidates.
src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.SingleProject.Before.targets Changes normalization so ActivationValue is derived from BackendIdentity regardless of TPI metadata presence.

Copilot's findings

  • Files reviewed: 3/3 changed files
  • Comments generated: 2

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 66f84348-6476-4097-8b7f-f240338e85c3
Copilot AI review requested due to automatic review settings July 30, 2026 22:30
@kubaflo

This comment has been minimized.

@github-actions github-actions Bot added the s/agent-review-in-progress AI review is currently running for this PR label Jul 30, 2026
@kubaflo kubaflo changed the title Fix dual-path backend activation and Compile batching [Extensibility] SingleProject: Fix dual-path backend activation and Compile filtering Jul 30, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

@kubaflo
kubaflo requested a review from Redth July 30, 2026 22:36
@kubaflo
kubaflo enabled auto-merge July 30, 2026 22:36
@kubaflo

kubaflo commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Prior main CI 1533728 failed only because Azure stopped hearing from Windows agent NetCore-Public 490 during MultiProject windows. Both Windows Helix unit-test legs, including the new SingleProject regressions, passed. Current-head replacement 1533889 is active.

@kubaflo

kubaflo commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Current-head main 1533889 has one emerging failure: Samples macOS building Maui.Controls.Sample.Sandbox fails on the same generated event-handler CS8622 nullability errors as concurrent net11.0 baseline 1533853. This is unrelated to the SingleProject targets/tests diff; remaining legs are still running.

@kubaflo kubaflo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Multi-model adversarial review — #36957 (round 1, head 256a4728)

Verdict: code is LGTM on the merits — but held from approval by a pre-existing net11.0 base breakage in CI (not caused by this PR).

Reviewed with Claude Opus 4.8 + GPT-5.5 + Gemini 3.1 Pro + GPT-5.6 Sol, each independent, then cross-pollinated and independently re-verified against the code at 256a4728.

Context

Sibling PR #36956 (the near-duplicate competing implementation) was closed/consolidated into this one, exactly as expected — so this is now the single surviving fix. This head ("Harden SingleProject backend filtering") adds a perf guard + two new tests on top of the reviewed cab41ff0.

Code review — the crux is correct

  • Fix B (_MauiRemovePlatformCompileItems) now uses consistent MatchOnMetadata="FullPath" MatchOnMetadataOptions="PathLike" on every <Compile Remove>, including the final one. This is precisely what the closed #36956 got wrong (it mixed a plain identity match on the final remove with FullPath elsewhere, leaking absolute / ./-prefixed excluded platform files). Opus empirically reproduced via dotnet msbuild that all four path forms (relative, absolute, ./-prefixed, back/forward-slash) are removed here.
  • Fix A (activation back-fill in .Before.targets) — the shared "over-activation" risk raised earlier is disproven: the collect-time inclusion condition's neutral clause is gated by '$(TargetPlatformIdentifier)' == '', so it is dead in any real (TPI-set) Windows/Android/iOS build.
  • Harden delta (cab41ff0 → 256a4728) is production-safe: the filesystem glob is now gated behind '@(_MauiPlatformCompileToRemove)' != '' (pure optimization — only globs when there's something to remove), plus a strengthened metadata-preservation assertion and two new tests (MatchesAbsoluteCompilePath, NeutralTfmCanActivateBuiltInBackendByIdentity).
  • The new MatchesAbsoluteCompilePath test passes on the Windows Helix Unit Tests leg at this head (it was RED on the closed #36956), empirically settling the absolute-path concern.

Ensemble: Opus LGTM, Gemini LGTM, GPT-5.5 0 blocking. Sol raises one non-blocking, theoretical concern (below).

💡 Non-blocking (Sol) — same-file dual-alias

Sol notes the final FullPath remove would also drop a keep-bucket Compile alias if the same physical file were referenced by both a keep alias and a remove alias. In practice a SingleProject platform file lives under exactly one Platforms/<platform>/ folder, so it is in the keep set or the remove set — never both. This requires a pathological hand-authored duplicate Compile item and doesn't apply to the SDK's normal layout. Flagging only as a discussion point.

CI status — the only failure is a confirmed base breakage ⚠️

maui-pr will go red, but the sole failing leg is Run Integration Tests – Samples (macOS + windows), and it is not caused by this PR:

  • The failure is CS8622 nullability-mismatch errors in OrdersPage.xaml.xsg.cs / ProductPage.xaml.xsg.cs (XAML source-generated) inside Controls.Sample.Sandbox, tripped by the Samples test's -p:TreatWarningsAsErrors=true.
  • This PR changes only 3 filesSingleProject.targets, SingleProject.Before.targets, MSBuildTests.cs — and does not touch the Sandbox at all.
  • The identical CS8622 errors on OrdersPage.OnOrderTapped / ProductPage.OnGoToReview appear on the net11.0 base branch (build 1533853). Base was green at 7e601062 (21:59Z) and red at e45600b0 (23:30Z) — a Sandbox nullability regression was introduced on base this evening, independent of this PR.

Every other relevant leg is green at 256a4728: macOS Build/Pack ×Debug/Release, Windows Build/Pack ×Debug/Release, Windows Helix Unit Tests ×Debug/Release (incl. the new absolute-path test), RunOnAndroid, all RunOniOS variants, MultiProject (macOS+windows), AOT/Blazor/Build (macOS).

Recommendation

The fix itself is ready — correct, well-tested, and the harden delta is safe. It is blocked only by an unrelated net11.0 base Sandbox breakage that will drag the overall gate red. Once the base Sandbox CS8622 regression is fixed (or this branch is rebased onto a green base), this is safe to merge. Holding approval purely on the CI gate, not on any code concern.

@MauiBot MauiBot added s/agent-changes-requested AI agent recommends changes - found a better alternative or issues s/agent-gate-passed AI verified tests catch the bug (fail without fix, pass with fix) labels Jul 31, 2026
@MauiBot MauiBot added s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review) labels Jul 31, 2026
@kubaflo kubaflo removed the s/agent-review-in-progress AI review is currently running for this PR label Jul 31, 2026
@kubaflo

kubaflo commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

@Redth — final handoff: head 256a4728408 is thread-clean; focused SingleProject validation passes 46/46; Copilot and multi-model expert reviews are LGTM with no blocking code finding; the only main CI failures are the exact Sandbox CS8622 failures on concurrent net11.0 baseline 1533853. Merge-commit auto-merge is armed; a human approval is the remaining blocker.

@kubaflo
kubaflo requested a review from jfversluis July 31, 2026 01:13
@MauiBot

MauiBot commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator

AI Review Summary

@PureWeen — new AI review results are available based on this last commit: 256a472.

Gate Passed Confidence Low Platform Android


🗂️ Review Sessions — click to expand
🚦 Gate — Test Before & After Fix

Gate Result: ✅ PASSED

Platform: ANDROID · Base: net11.0 · Merge base: d07c3b24

Test Without Fix (expect FAIL) With Fix (expect PASS)
📄 MSBuildTests MSBuildTests ✅ FAIL — 481s ✅ PASS — 312s
🔴 Without fix — 📄 MSBuildTests: FAIL ✅ · 481s

Error-relevant lines (filtered from the build log):

     at Microsoft.Maui.Controls.MSBuild.UnitTests.MSBuildTests.AssertTypeExists(String assemblyPath, String fullTypeName) in /_/src/Controls/tests/Xaml.UnitTests/MSBuild/MSBuildTests.cs:line 296
   at Microsoft.Maui.Controls.MSBuild.UnitTests.MSBuildTests.SingleProject_RemovePlatformCompileItems_RemovesOnlyCompileItemsMarkedExcluded() in /_/src/Controls/tests/Xaml.UnitTests/MSBuild/MSBuildTests.cs:line 1492
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
     at Microsoft.Maui.Controls.MSBuild.UnitTests.MSBuildTests.AssertTypeDoesNotExist(String assemblyPath, String fullTypeName) in /_/src/Controls/tests/Xaml.UnitTests/MSBuild/MSBuildTests.cs:line 302
   at Microsoft.Maui.Controls.MSBuild.UnitTests.MSBuildTests.SingleProject_RemovePlatformCompileItems_MatchesAbsoluteCompilePath() in /_/src/Controls/tests/Xaml.UnitTests/MSBuild/MSBuildTests.cs:line 1546
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at Microsoft.Maui.Controls.MSBuild.UnitTests.MSBuildTests.SingleProject_BackendIdentitySupportsRecognizedAndNeutralActivation(String targetPlatformIdentifier, String activeBackend, Boolean shouldIncludeMacosFile) in /_/src/Controls/tests/Xaml.UnitTests/MSBuild/MSBuildTests.cs:line 1662
   at InvokeStub_MSBuildTests.SingleProject_BackendIdentitySupportsRecognizedAndNeutralActivation(Object, Span`1)
   at System.Reflection.MethodBaseInvoker.InvokeWithFewArgs(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at Microsoft.Maui.Controls.MSBuild.UnitTests.MSBuildTests.SingleProject_NeutralTfmCanActivateBuiltInBackendByIdentity() in /_/src/Controls/tests/Xaml.UnitTests/MSBuild/MSBuildTests.cs:line 1704
🟢 With fix — 📄 MSBuildTests: PASS ✅ · 312s

(no coded error found; showing last 1200 chars)

PlatformFolderMetadataRemainsBackwardCompatible(targetPlatformIdentifier: "ios", shouldIncludeLegacyFile: True) [4 s]
  Passed SingleProject_CodesignEntitlementsRespected [3 s]
  Passed SingleProject_NeutralTfmCanActivateBuiltInBackendByIdentity [4 s]
  Passed SingleProject_DefaultEntitlementsUsedWhenNoCustomSet [3 s]
  Passed SingleProject_NeutralTfmActivatesBackendByIdentity [3 s]
  Passed DesignTimeBuild [7 s]
  Passed SingleProject_BareUnresolvedActivationValueUsesLegacySharedFolderBehavior(targetPlatformIdentifier: "ios") [3 s]
  Passed SingleProject_BareUnresolvedActivationValueUsesLegacySharedFolderBehavior(targetPlatformIdentifier: "") [3 s]
  Passed SingleProject_NonPlatformBuildExcludesPlatformSpecificFoldersButKeepsSharedFolder [3 s]
  Passed RandomEmbeddedResource [3 s]
  Passed SingleProject_RecognizedTfmIgnoresNeutralBackendSelector [3 s]
  Passed TargetsShouldSkip [7 s]
[xUnit.net 00:04:26.32]     TouchXamlFile [SKIP]
[xUnit.net 00:04:26.32]       source gen changes
[xUnit.net 00:04:26.33]   Finished:    Microsoft.Maui.Controls.Xaml.UnitTests
  Skipped TouchXamlFile [1 ms]
Test Run Successful.
Total tests: 64
     Passed: 62
    Skipped: 2
 Total time: 4.4593 Minutes
📁 Fix files reverted (2 files)
  • src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.SingleProject.Before.targets
  • src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.SingleProject.targets

📱 UI Tests — Button,Label,Layout

Detected UI test categories: Button,Label,Layout

Deep UI tests — 359 passed, 0 failed across 3 categories on platform-pool agent (replaces in-process counts above).

🧪 UI Test Execution Results (deep, platform pool)

Category Tests Snapshot diffs
Button 71/73 ✓
Label 96/98 ✓
Layout 192/195 ✓
📎 Download drop-deep-uitests artifact (TRX + snapshot diffs)

📋 Pre-Flight — Context & Validation

Issue: #36650 - SingleProject: Register and activate external backends for neutral TFMs
PR: #36957 - [Extensibility] SingleProject: Fix dual-path backend activation and Compile filtering
Platforms Affected: Android requested for validation; build-time SingleProject MSBuild targets affect all SingleProject platform configurations and neutral backend TFMs.
Files Changed: 2 implementation, 1 test

Key Findings

Code Review Summary

Verdict: NEEDS_DISCUSSION
Confidence: low
Errors: 0 | Warnings: 0 | Suggestions: 0

Key code review findings:

  • No high-confidence code findings.
  • CI status was undetermined from this unauthenticated environment; confidence is capped by pending/unverified checks rather than a code defect.
  • Failure probes covered neutral built-in backend activation, recognized TPI plus mismatched backend, explicit false Compile items, and absolute platform compile identities.

Fix Candidates

# Source Approach Test Result Files Changed Notes
PR PR #36957 Normalize BackendIdentity into ActivationValue; remove platform Compile items by starting from the true @(Compile) batch and intersecting with physical platform candidates by FullPath/PathLike. ✅ PASSED (Gate) Microsoft.Maui.Controls.SingleProject.Before.targets, Microsoft.Maui.Controls.SingleProject.targets, MSBuildTests.cs Original PR; gate already confirmed fail-without-fix/pass-with-fix.

🔬 Code Review — Deep Analysis

Code Review — PR #36957

Independent Assessment

What this changes: Updates SingleProject MSBuild target behavior so BackendIdentity can default ActivationValue, including TPI-recognized folders, and rewrites platform Compile removal to start from current @(Compile) items before intersecting with physical Platforms/** candidates. Adds MSBuild regression tests for false/true compile metadata, absolute paths, and neutral/backend activation.

Inferred motivation: Fix backend activation and compile-filtering regressions while preserving explicit metadata and item ordering.

Reconciliation with PR Narrative

Author claims: This is a focused follow-up for dual-path backend activation and compile removal batching, with targeted MSBuild tests.
Agreement/disagreement: The code matches those claims. The activation change is intentional and covered by new tests; the removal change avoids the prior fresh-glob false-bucket issue and skips the glob when no removal batch exists.

Prior Review Reconciliation

Prior ❌ Error Finding Source Status Evidence
No prior ❌ Error findings found. Public review/comment surfaces n/a Prior Copilot comments were non-❌ inline concerns; one was fixed, one was answered as intentional and covered by tests.

Blast Radius Assessment

  • Runs for all instances: Yes — these build targets run for SingleProject builds.
  • Startup impact: No runtime startup impact; build-time infrastructure only.
  • Static/shared state: No runtime static state; shared MSBuild target behavior affects many project configurations.

CI Status

  • Required-check result: gh pr checks --required unavailable due unauthenticated gh; public check API shows current maui-pr still pending with one completed failure.
  • Classification: Current Samples macOS failure appears unrelated to these changed MSBuild targets: Sandbox sample SourceGen nullability errors in generated XAML code. Several Windows integration legs remain in progress, so final CI coverage is undetermined.
  • Action taken: Invoked CI investigation path; confidence capped low and no LGTM per skill rule for pending/undetermined CI.

External Output Contract

Consumer token/pattern Producer location Producer emission condition Consumer assumption Ordinary negative case Downstream effect
n/a n/a Changed production code does not classify external tool output. n/a n/a n/a

Findings

No high-confidence code findings.

Failure-Mode Probing

  • Built-in backend activated on neutral TFM: Now intentional; MauiActiveBackend=android includes built-in Android files on neutral TFM and has explicit regression coverage.
  • Recognized platform TFM plus mismatched backend: Guard keeps backend activation to neutral TFM, so TargetPlatformIdentifier=android with MauiActiveBackend=macos does not include macOS files.
  • Compile items explicitly re-included with ExcludeFromCurrentConfiguration=false: Removal starts from true-batched @(Compile) and intersects by FullPath/PathLike, preserving the explicit false item; covered by test.
  • Absolute compile identity under Platforms/**: FullPath/PathLike matching removes excluded absolute platform paths; covered by test.

Verdict: NEEDS_DISCUSSION

Confidence: low
Summary: I found no code issues in the PR diff. However, required CI could not be verified as passing: the public check state is still pending and includes a current unrelated-looking Samples macOS failure, so the skill rules prohibit LGTM until CI completes or is conclusively classified.


🛠️ Fix — Analysis & Comparison

Fix Candidates

# Source Approach Test Result Files Changed Notes
1 try-fix-1 Split _MauiCollectPlatformSpecificCompileItems into separate legacy-shared, TPI-matched, and backend-activated collect targets; simplify activation normalization by comparing backend identity directly in collect conditions. ✅ PASS — 46/46 SingleProject tests 2 implementation files Structurally different activation collection approach, but it retained the PR-style compile-removal glob-intersection strategy, so it is not demonstrably better than the PR overall.
2 try-fix-2 Replace compile-removal glob intersection with a path predicate over each current @(Compile) item's own FullPath: excluded-from-current-configuration AND under $(PlatformsProjectFolder), then subtract kept allow-list items. ✅ PASS — 46/46 SingleProject tests 1 implementation file Materially simpler compile-filtering strategy: no fresh physical platform glob, fewer helper item types, no set-intersection stage. Before.targets activation logic remains as in PR.
PR PR #36957 Normalize BackendIdentity into ActivationValue; remove platform Compile items by starting from the true @(Compile) batch and intersecting with physical platform candidates by FullPath/PathLike. ✅ PASSED (Gate) 2 implementation files, 1 test file Original PR. Gate was completed before this phase and confirmed fail-without-fix/pass-with-fix.

Candidate Details

try-fix-1 — Split Activation Targets

Approach: Decomposed the monolithic three-branch collect condition into separate targets for legacy shared folders, recognized TPI matches, and neutral backend activation. This reduced activation-condition coupling but retained the PR's compile-removal intersection pattern.

Diff: Saved at CustomAgentLogsTmp/PRState/36957/PRAgent/try-fix/attempt-1/fix.diff.

Test Results: PASS. The targeted SingleProject MSBuild/XAML unit filter passed 46/46 tests.

Failure Analysis: Not failed. However, the candidate is not selected because its compile-filtering half is not meaningfully different from the PR and candidate 2 provides a simpler distinct strategy.

try-fix-2 — Path-Predicate Compile Filtering

Approach: Kept the PR's activation normalization, but replaced compile-removal set intersection with direct predicate filtering on current @(Compile) items. The candidate computes the canonical platforms folder path and selects removal candidates only when %(Compile.ExcludeFromCurrentConfiguration) == true and %(Compile.FullPath) is under that folder. It then subtracts _MauiPlatformSpecificCompileItems and removes by FullPath/PathLike.

Diff: Saved at CustomAgentLogsTmp/PRState/36957/PRAgent/try-fix/attempt-2/fix.diff.

Test Results: PASS. The targeted SingleProject MSBuild/XAML unit filter passed 46/46 tests on the first run.

Failure Analysis: Not failed. Self-review recorded 0 findings. The candidate directly avoids the fresh filesystem glob that caused the explicit-false compile item regression, while still handling absolute compile identities via canonical FullPath.

Cross-Pollination

Model Round New Ideas? Details
claude-opus-4.6 1 Yes Split activation collection into separate targets; passed, but not better overall because compile removal remained PR-like.
claude-opus-4.7 1 Yes Use per-item path predicate filtering for platform compile removal; passed and is materially simpler than the PR's intersection strategy.

Exhausted: No — stopped early because candidate 2 passed all targeted tests and is demonstrably better on simplicity for the compile-filtering half of the PR.
Selected Fix: Candidate #2 — It preserves the validated activation behavior, removes fewer moving parts from compile filtering, avoids fresh physical glob enumeration entirely, and passed the same 46-test SingleProject regression matrix.


📝 Recommended PR Title & Description

Assessment: ✏️ Recommend updating — the current description says neutral activation of built-in backend identities is intentional, but the winning pr-plus-reviewer candidate should prevent built-in platform folders from activating on neutral TFMs unless platform SDK setup is also enabled.

Recommended title

[Extensibility] SingleProject: Fix external backend activation and Compile filtering

Recommended description

## Description of Change

This focused follow-up addresses two empirically validated gaps found by the GPT-5.6 Sol post-merge verification of #36654, plus the expert-review finding from the final candidate comparison.

1. External `MauiPlatformSpecificFolder` registrations can use a single stable `BackendIdentity` for both recognized-TPI activation and neutral-TFM activation through `MauiActiveBackend`. Explicit `ActivationValue` and `ActivationProperty` metadata still win.
2. Built-in platform folders remain protected from neutral-TFM backend activation unless a future explicit opt-in also wires the corresponding platform SDK/resource setup. This avoids pulling normal `Platforms/Android`, `Platforms/iOS`, etc. sources into a neutral `net*` compile where platform assemblies are unavailable.
3. Platform Compile removal now starts from the `Compile` items in the `ExcludeFromCurrentConfiguration=true` metadata batch and intersects them with physical `Platforms/**` candidates. A fresh filesystem glob can no longer pull an explicitly false Compile item from another metadata bucket into the removal set. The helper-item removal pattern remains in place, preserving active item order and avoiding remove/re-add duplication.

## Before and After

Before this change, a registration such as:

```xml
<MauiPlatformSpecificFolder Include="Platforms/MacOS/" TargetPlatformIdentifiers="macos" BackendIdentity="macos" />

worked for recognized TPI macos but did not activate on a neutral TFM with MauiActiveBackend=macos. It now supports both paths for external backend registrations and remains inactive for another recognized TPI or a mismatched backend.

Built-in platform folders continue to activate through their recognized platform TFMs. They are not selected by MauiActiveBackend alone on a neutral TFM because their normal platform SDK/resource setup is tied to the platform target framework.

Before this change, the presence of any true Compile metadata batch caused a fresh Platforms/** glob to include physical files explicitly marked false by a downstream target. Removal is now constrained to the actual true Compile identities under the platform folder.

Tests

The real shipping SingleProject targets are covered by regressions for:

  • one dual-path external macOS registration through recognized TPI and neutral backend activation, plus recognized-TPI and backend mismatch negatives;
  • built-in platform folder protection on neutral TFMs so normal platform sources are not compiled without platform SDK setup;
  • two physical platform Compile files in different metadata buckets with no folder allow-list, asserting only the true item is removed and the surviving list is ordered and duplicate-free.

Validation:

  • complete MSBuildTests.SingleProject_* matrix: 46 passed, 0 failed;
  • new regression matrix: 7 passed, 0 failed;
  • Controls.Build.Tasks.csproj build: succeeded with 0 warnings and 0 errors;
  • targeted dotnet format: completed successfully.

The unfiltered local graph is unavailable on this Mac because the platform project graph requires the iOS workload (NETSDK1147) and the full BuildTasks solution filter includes .NET Framework 4.7.2 projects without local reference assemblies (MSB3644). The workload-neutral matrix above used the repository-pinned .NET 11 SDK with platform TFMs disabled and imported the exact shipping targets.

Candidate selection and final review

The selected implementation is pr-plus-reviewer: the PR fix with expert-review feedback applied. Alternatives try-fix-1 and try-fix-2 both pass the SingleProject matrix; try-fix-2 is simpler for the Compile-filtering half, but both alternatives keep the raw PR activation behavior and therefore inherit the built-in neutral activation risk. The final candidate preserves external backend activation while avoiding neutral activation of built-in platform folders without platform SDK setup.

Issues Fixed

Part of #34099
Part of #35021
Fixes #36650
Follow-up to #36654



</details>

---

<details>
<summary><strong>🏁 Report — Final Recommendation</strong></summary>
<br/>

## Comparative Report — PR #36957

### Candidate Ranking

| Rank | Candidate | Regression result | Assessment |
|---:|---|---|---|
| 1 | `pr-plus-reviewer` | Not rerun after sandbox feedback application | Best correctness profile. It preserves the validated external backend activation and compile-filtering fix while applying the expert reviewer's required safety correction: built-in platform folders should not be neutral-TFM activated unless the platform SDK/resource setup is also enabled. |
| 2 | `try-fix-2` | ✅ PASS — 46/46 SingleProject tests | Best compile-filtering implementation: replaces the PR's helper-item glob intersection with a simpler predicate over each current `Compile` item's own canonical `FullPath`. However, it keeps the PR activation changes unchanged and therefore inherits the expert finding about neutral activation of built-in Android/iOS/etc. folders. |
| 3 | `try-fix-1` | ✅ PASS — 46/46 SingleProject tests | Splits activation collection into separate targets, which improves readability of the activation condition, but keeps the PR-style compile-removal intersection and also inherits the built-in neutral activation risk. |
| 4 | `pr` | ✅ Gate PASSED | The raw PR passes the supplied gate and fixes the reported compile-filtering regression, but has the expert finding: `BackendIdentity` now activates built-in platform folders on neutral TFMs where their normal platform SDK setup is not active. |

No STEP 5a candidate is recorded as failing regression tests, so the required failed-test demotion rule does not change the ordering. The ranking is driven by correctness after expert review, then simplicity among the candidates that share the same remaining activation risk.

### Candidate Notes

#### `pr`

The raw PR has two good pieces: dual-path activation for registrations that carry both TPI and backend identity metadata, and a `Compile` removal fix that starts from the true `@(Compile)` batch instead of directly removing a physical glob. The problem is that built-in platform registrations also receive derived `ActivationValue`, so `MauiActiveBackend=android` on a neutral TFM can pull in `Platforms/Android/**/*.cs` without Android SDK references.

#### `pr-plus-reviewer`

This sandbox candidate applies the expert feedback by preserving external dual-path activation while preventing built-in platform folders from activating on neutral TFMs by identity alone. That is the only candidate that addresses the expert finding. Its tradeoff is that the current PR description/test expectation that built-in backend identities intentionally activate on neutral TFMs must be revised, and the candidate needs a follow-up regression run after materialization.

#### `try-fix-1`

This candidate decomposes the collection logic into legacy shared, TPI-matched, and backend-activated targets. It passed the SingleProject matrix, but it is more target surface area and does not improve the compile-filtering root cause as directly as `try-fix-2`.

#### `try-fix-2`

This candidate is the best alternative for the compile-filtering half. Its direct `%(Compile.FullPath).StartsWith($(_MauiFullPlatformsFolder))` predicate is easier to reason about than the PR's helper item intersection and avoids fresh filesystem enumeration entirely. It still leaves activation unchanged from the PR, so it is not the overall winner once the expert activation finding is considered.

### Winner

**Winner: `pr-plus-reviewer`.**

The single most important issue found in this phase is not the compile-filtering mechanism; it is the unsafe expansion of neutral backend activation to built-in platform folders without platform SDK setup. `pr-plus-reviewer` is the only candidate that addresses that issue while retaining the PR's tested external-backend and compile-filtering behavior.


</details>

</details>
<!-- SESSION:256a472 END -->

---

<details>
<summary><strong>🧭 Next Steps</strong> — review latest findings</summary>
<br/>

No alternative fix was selected for this run. Review the session findings and CI results before merging.

</details>

@kubaflo
kubaflo disabled auto-merge July 31, 2026 09:39
@kubaflo
kubaflo merged commit f14056c into net11.0 Jul 31, 2026
30 of 34 checks passed
@kubaflo
kubaflo deleted the pureween-fix-backend-msbuild-regressions branch July 31, 2026 09:39
@github-actions github-actions Bot added this to the .NET 11.0-preview7 milestone Jul 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-infrastructure CI, Maestro / Coherency, upstream dependencies/versions s/agent-changes-requested AI agent recommends changes - found a better alternative or issues s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates s/agent-gate-passed AI verified tests catch the bug (fail without fix, pass with fix) s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants