Skip to content

[Resizetizer] Invalidate image outputs when platform type changes - #36984

Merged
kubaflo merged 2 commits into
net11.0from
pureween-fix-resizetizer-platform-invalidation
Jul 31, 2026
Merged

[Resizetizer] Invalidate image outputs when platform type changes#36984
kubaflo merged 2 commits into
net11.0from
pureween-fix-resizetizer-platform-invalidation

Conversation

@PureWeen

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!

Summary

  • Persist ResizetizerPlatformType in mauiimage.inputs so platform-only changes invalidate ResizetizeImages.
  • Add a shipping-package integration test that switches an external backend from generic output paths to Android density folders, verifies stale generic outputs are removed, and verifies the following unchanged build skips.

Root cause

The external-backend support merged in #36653 passes ResizetizerPlatformType to the image task, but the value was not part of the persisted inputs manifest. Changing only that property therefore left $(_ResizetizerInputsFile) unchanged, allowing MSBuild to skip ResizetizeImages and preserve the previous platform's output shape.

The platform value belongs in the persisted manifest because WriteOnlyWhenDifferent turns a semantic property change into an input-file timestamp change. Putting the raw property directly in the target's Inputs= list would make MSBuild interpret the platform name as a file path rather than as input state.

Behavior

Before this change, switching only ResizetizerPlatformType from generic to android kept the two generic outputs and skipped image processing. After this change, image processing reruns, produces five Android drawable-* outputs, removes the stale generic files, and then skips on the next unchanged build.

Validation

  • pwsh .github/skills/run-integration-tests/scripts/Run-IntegrationTests.ps1 -TestFilter "FullyQualifiedName~ChangingExternalBackendPlatformTypeInvalidatesImages" -SkipBuild -SkipInstall -ResultsDirectory "artifacts/integration-tests/platform-invalidation-restored-fix" — passed: 1/1.
  • RED-on-revert: after reverting only the production manifest line and repacking the same shipping package, the focused test failed with ResizetizeImages should rerun when only ResizetizerPlatformType changes. Restoring the line and repacking returned the test to green.
  • .dotnet/dotnet pack src/SingleProject/Resizetizer/src/Resizetizer.csproj -c Debug --no-restore -p:WarnAsError=false — passed.
  • .dotnet/dotnet format src/TestUtils/src/Microsoft.Maui.IntegrationTests/Microsoft.Maui.IntegrationTests.csproj --no-restore --include src/TestUtils/src/Microsoft.Maui.IntegrationTests/ResizetizerTests.cs --exclude-diagnostics CA1822 --verbosity quiet — passed.

The full integration skill build/pack lane was attempted first but was blocked locally by NETSDK1147 requesting the ios workload for net11.0-ios26.5, even though the workload installation step reported success. The focused test still ran through the skill script against the freshly packed Microsoft.Maui.Resizetizer.11.0.0-dev.nupkg.

Related to #34099 and #35022. Follow-up to merged #36653.

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 31, 2026 14:22
@PureWeen
PureWeen temporarily deployed to copilot-pat-pool July 31, 2026 14:22 — 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 -- 36984

Or

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

@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.

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 improves Resizetizer incremental correctness for external backends by ensuring platform-only changes (via ResizetizerPlatformType) invalidate the image-processing target, and adds an integration test that exercises the platform switch scenario end-to-end.

Changes:

  • Persist ResizetizerPlatformType into the Resizetizer image inputs manifest so a platform-type-only change updates the manifest and forces ResizetizeImages to rerun.
  • Add an integration test that switches an external backend from generic to android, verifies stale generic outputs are removed, and verifies the following unchanged rebuild is a true no-op.
Show a summary per file
File Description
src/TestUtils/src/Microsoft.Maui.IntegrationTests/ResizetizerTests.cs Adds an integration test covering platform-type invalidation, stale output removal, and no-op rebuild behavior.
src/SingleProject/Resizetizer/src/nuget/buildTransitive/Microsoft.Maui.Resizetizer.After.targets Writes platform type into the persisted image inputs list so manifest changes when only ResizetizerPlatformType changes.

Copilot's findings

Suppressed comments (1)

src/TestUtils/src/Microsoft.Maui.IntegrationTests/ResizetizerTests.cs:164

  • Same as above: a 1-minute future sentinel can be overtaken by a slow incremental build, making this no-op rebuild assertion flaky. Use a larger margin (e.g., 1 hour) consistent with other tests in this file.
		File.SetLastWriteTimeUtc(stampFile, DateTime.UtcNow.AddMinutes(1));
  • Files reviewed: 2/2 changed files
  • Comments generated: 1

Comment thread src/TestUtils/src/Microsoft.Maui.IntegrationTests/ResizetizerTests.cs Outdated
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 31, 2026 16:04
@kubaflo

This comment has been minimized.

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 2 out of 2 changed files in this pull request and generated no new comments.

@kubaflo
kubaflo enabled auto-merge July 31, 2026 16:14
@kubaflo
kubaflo requested review from Redth and jfversluis July 31, 2026 16:14
@MauiBot MauiBot added 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-reviewed PR was reviewed by AI agent workflow (full 4-phase review) labels Jul 31, 2026
@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: 54c285c.

Gate Unknown Confidence Low Platform Android


🗂️ Review Sessions — click to expand
📋 Pre-Flight — Context & Validation

Issue: Related #34099 - Improve Extensibility 3rd Party Platform Backends; #35022 - Resizetizer: extensibility for external backends; follow-up to #36653 - [Extensibility] Resizetizer: Enable external backend processing
PR: #36984 - [Resizetizer] Invalidate image outputs when platform type changes
Platforms Affected: android; Resizetizer build infrastructure for external backends
Files Changed: 1 implementation, 1 test

Key Findings

  • PR changes src/SingleProject/Resizetizer/src/nuget/buildTransitive/Microsoft.Maui.Resizetizer.After.targets so a ResizetizerPlatformType change updates mauiimage.inputs and invalidates ResizetizeImages.
  • PR adds ChangingExternalBackendPlatformTypeInvalidatesImages, an integration test that switches an external backend from generic to android, verifies Android density outputs, stale generic cleanup, and unchanged rebuild skip behavior.
  • Gate result provided by caller was skipped because no gate-detected tests were found; do not overwrite gate/content.md.
  • PR discussion contained one timestamp-flakiness inline comment; the PR fixed the invalidation sentinel to use a one-hour future timestamp.
  • Impacted UI test categories: NONE; this is build-time Resizetizer infrastructure, not UI runtime behavior.

Code Review Summary

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

Key code review findings:

  • No ❌ Error, ⚠️ Warning, or 💡 Suggestion findings were reported by the independent code review.
  • CI/required-check status was undetermined because gh is unauthenticated in this environment; confidence remains low.
  • Blast radius is build-time only, running for projects with MAUI image processing enabled; no runtime startup or static/shared state impact.

Fix Candidates

# Source Approach Test Result Files Changed Notes
PR PR #36984 Persist PlatformType=$(ResizetizerPlatformType) in mauiimage.inputs, causing WriteOnlyWhenDifferent to update the input manifest when only platform changes. ⚠️ Gate skipped by prior step Microsoft.Maui.Resizetizer.After.targets, ResizetizerTests.cs Original PR; code review found no correctness issues.

🔬 Code Review — Deep Analysis

Code Review — PR #36984

Independent Assessment

What this changes: Adds ResizetizerPlatformType to the persisted mauiimage.inputs manifest so image processing reruns when only the platform backend changes. Adds an integration test switching generic to android.

Inferred motivation: Prevent stale platform-specific Resizetizer outputs from being reused after an external backend changes output shape.

Reconciliation with PR Narrative

Author claims: Platform-only changes previously left mauiimage.inputs unchanged, so ResizetizeImages could skip and preserve stale generic outputs.

Agreement/disagreement: Agrees. The code makes the semantic platform value affect the input-file timestamp without putting a raw property value directly in MSBuild Inputs= as a fake file path.

Prior Review Reconciliation

Prior ❌ Error Finding Source Status Evidence
No prior ❌ Error findings found. REST fallback: reviews, inline comments, issue comments n/a One Copilot timestamp-flakiness comment was present; current code uses AddHours(1) for the rerun sentinel, and the remaining one-minute no-op sentinel checks exact skip equality.

External Output Contract

Consumer token/pattern Producer location Producer emission condition Consumer assumption Ordinary negative case Downstream effect
n/a n/a This PR does not classify external tool output with regex/string tokens. n/a n/a n/a

Blast Radius Assessment

  • Runs for all instances: Yes, for projects where Resizetizer image processing is enabled; it only changes incremental input tracking.
  • Startup impact: No runtime startup impact; build-time MSBuild target only.
  • Static/shared state: No new static/shared state.

CI Status

  • Required-check result: pending/undetermined. gh pr checks --required was unavailable due missing auth; public REST fallback shows maui-pr queued/in progress, with several legs still in progress.
  • Classification: undetermined.
  • Action taken: invoked azdo-build-investigator; ci-analysis skill was unavailable. Confidence capped low; no LGTM while CI is pending.

Findings

No ❌ Error, ⚠️ Warning, or 💡 Suggestion findings.

Failure-Mode Probing

  • Platform changes while image files are unchanged: WriteLinesToFile WriteOnlyWhenDifferent updates mauiimage.inputs, making ResizetizeImages out-of-date.
  • Stale prior-platform outputs: rerun repopulates _ResizetizerCollectedImages; cleanup deletes outputs not in the new set.
  • No-op rebuild after stable platform: manifest stays unchanged, so the target can remain skipped.
  • Projects without external backend: built-in platform values are already set; this only adds them to incremental state.

Verdict: NEEDS_DISCUSSION

Confidence: low (CI is pending/undetermined and this is build infrastructure.)

Summary: I found no code-level correctness issues in the diff. However, CI has not completed and required-check status could not be authenticated via gh, so the skill rules prohibit LGTM until CI is known green.


🛠️ Fix — Analysis & Comparison

Fix Candidates

# Source Approach Test Result Files Changed Notes
1 maui-expert-reviewer Separate mauiimage.platform.inputs file included in target Inputs. ❌ BLOCKED 1 file Environment missing .dotnet/packs/Microsoft.Maui.Sdk; more complex than PR and task-level manifest still excludes platform state.
2 maui-expert-reviewer Track previous platform in mauiimage.platform and delete image stamp/output-list when it changes. ❌ BLOCKED 1 file Same environment blocker; active state deletion is more invasive and still outside task InputsFile.
3 maui-expert-reviewer Use platform-scoped output-list files such as mauiimage.android.outputs. ❌ BLOCKED 1 file Same environment blocker; adds extra output-list files and depends on resolved output-list property timing.
4 maui-expert-reviewer Use platform-specific stamp outputs such as mauiimage.android.stamp. ❌ BLOCKED 1 file Same environment blocker; adds per-platform stamp cleanup complexity.
PR PR #36984 Persist platform type in existing mauiimage.inputs. ⚠️ Gate skipped by prior step 2 files Simplest explored solution; independent code review found no code-level issues.

Cross-Pollination

Model Round New Ideas? Details
gpt-5.5 / maui-expert-reviewer 1 Yes Separate platform input file.
gpt-5.5 / maui-expert-reviewer 2 Yes State file plus deleting stamp/output-list on platform changes.
gpt-5.5 / maui-expert-reviewer 3 Yes Platform-scoped output-list files.
gpt-5.5 / maui-expert-reviewer 4 Yes Platform-specific stamp outputs.
gpt-5.5 / orchestrator analysis 4 No robust task-layer idea A task-layer-only change cannot help because the MSBuild target is skipped before ResizetizeImages or Resizer.IsUpToDate executes.

Exhausted: Yes
Selected Fix: PR #36984 — no alternative candidate could be empirically validated in this environment, and all generated alternatives are more complex than the PR's direct persisted-manifest fix.

try-fix-1 — Separate platform input file

try-fix-1 — Separate platform input file

Approach

Create a dedicated $(_ResizetizerPlatformInputsFile) (mauiimage.platform.inputs), write PlatformType=$(ResizetizerPlatformType) to it with WriteOnlyWhenDifferent="true", include it in ResizetizeImages Inputs, and wire the writer into both normal and late external-backend dependency paths.

This differs from PR #36984 by keeping platform invalidation outside mauiimage.inputs rather than appending PlatformType to that manifest line.

Diff

diff --git a/src/SingleProject/Resizetizer/src/nuget/buildTransitive/Microsoft.Maui.Resizetizer.After.targets b/src/SingleProject/Resizetizer/src/nuget/buildTransitive/Microsoft.Maui.Resizetizer.After.targets
index d3fd5474e8..debc85d256 100644
--- a/src/SingleProject/Resizetizer/src/nuget/buildTransitive/Microsoft.Maui.Resizetizer.After.targets
+++ b/src/SingleProject/Resizetizer/src/nuget/buildTransitive/Microsoft.Maui.Resizetizer.After.targets
@@ -72,6 +72,7 @@
         <_ResizetizerIntermediateOutputPath Condition=" '$(_ResizetizerIntermediateOutputPath)' == '' " >$(IntermediateOutputPath)</_ResizetizerIntermediateOutputPath>
 
         <_ResizetizerInputsFile>$(_ResizetizerIntermediateOutputPath)mauiimage.inputs</_ResizetizerInputsFile>
+        <_ResizetizerPlatformInputsFile>$(_ResizetizerIntermediateOutputPath)mauiimage.platform.inputs</_ResizetizerPlatformInputsFile>
         <_ResizetizerOutputsFile>$(_ResizetizerIntermediateOutputPath)mauiimage.outputs</_ResizetizerOutputsFile>
         <_ResizetizerStampFile>$(_ResizetizerIntermediateOutputPath)mauiimage.stamp</_ResizetizerStampFile>
         <_MauiFontInputsFile>$(_ResizetizerIntermediateOutputPath)mauifont.inputs</_MauiFontInputsFile>
@@ -126,6 +127,7 @@
             ResizetizeCollectItems;
             ProcessMauiSplashScreens;
             _ReadResizetizeImagesOutputs;
+            _WriteResizetizeImagePlatformInputs;
         </ResizetizeDependsOnTargets>
         <!-- Ensures project-reference MauiAsset items are collected before ProcessMauiAssets
              for backends that opt in at evaluation time (ResizetizerPlatformType set in props
@@ -341,7 +343,7 @@
         <!-- This allows us to invalidate the build based on not just input image files changing but project item metadata as well -->
         <WriteLinesToFile
             File="$(_ResizetizerInputsFile)"
-            Lines="PlatformType=$(ResizetizerPlatformType);@(MauiImage->'File=%(Identity);Link=%(Link);BaseSize=%(BaseSize);Resize=%(Resize);TintColor=%(TintColor);Color=%(Color);IsAppIcon=%(IsAppIcon);ForegroundScale=%(ForegroundScale);ForegroundFile=%(ForegroundFile);MonochromeFile=%(MonochromeFile)')"
+            Lines="@(MauiImage->'File=%(Identity);Link=%(Link);BaseSize=%(BaseSize);Resize=%(Resize);TintColor=%(TintColor);Color=%(Color);IsAppIcon=%(IsAppIcon);ForegroundScale=%(ForegroundScale);ForegroundFile=%(ForegroundFile);MonochromeFile=%(MonochromeFile)')"
             Overwrite="true"
             WriteOnlyWhenDifferent="true" />
 
@@ -391,7 +393,7 @@
 
     <Target Name="_PrepareExternalMauiImages"
         BeforeTargets="ResizetizeImages"
-        DependsOnTargets="ResizetizeCollectItems;ProcessMauiSplashScreens;_ReadResizetizeImagesOutputs"
+        DependsOnTargets="ResizetizeCollectItems;ProcessMauiSplashScreens;_ReadResizetizeImagesOutputs;_WriteResizetizeImagePlatformInputs"
         Condition="'$(_ResizetizerIsCompatibleApp)' != 'True' And '$(ResizetizerPlatformType)' != ''" />
 
     <Target Name="ProcessMauiAssets"
@@ -683,9 +685,22 @@
         </ReadLinesFromFile>
     </Target>
 
+    <Target Name="_WriteResizetizeImagePlatformInputs"
+        Condition="'$(EnableMauiImageProcessing)' == 'true'">
+        <WriteLinesToFile
+            File="$(_ResizetizerPlatformInputsFile)"
+            Lines="PlatformType=$(ResizetizerPlatformType)"
+            Overwrite="true"
+            WriteOnlyWhenDifferent="true" />
+
+        <ItemGroup>
+            <FileWrites Include="$(_ResizetizerPlatformInputsFile)" />
+        </ItemGroup>
+    </Target>
+
     <Target Name="ResizetizeImages"
         Condition="'$(EnableMauiImageProcessing)' == 'true'"
-        Inputs="$(MSBuildThisFileFullPath);$(_ResizetizerTaskAssemblyName);$(_ResizetizerInputsFile);@(MauiImage)"
+        Inputs="$(MSBuildThisFileFullPath);$(_ResizetizerTaskAssemblyName);$(_ResizetizerInputsFile);$(_ResizetizerPlatformInputsFile);@(MauiImage)"
         Outputs="$(_ResizetizerStampFile);$(_ResizetizerOutputsFile);@(_ResizetizerOutputs)"
         AfterTargets="$(ResizetizeAfterTargets)"
         BeforeTargets="$(ResizetizeBeforeTargets)"

Test Results

❌ BLOCKED — focused integration runner exited before running tests because local MAUI SDK packs are missing:

ERROR: Microsoft.Maui.Sdk packs not found at: /home/vsts/work/1/s/.dotnet/packs/Microsoft.Maui.Sdk

Command attempted:

pwsh .github/skills/run-integration-tests/scripts/Run-IntegrationTests.ps1 -TestFilter "FullyQualifiedName~ChangingExternalBackendPlatformTypeInvalidatesImages" -SkipBuild -SkipInstall -ResultsDirectory "artifacts/integration-tests/try-fix-1"

Failure Analysis

The candidate was not empirically evaluated because the environment is missing provisioned local MAUI packs. The patch is conceptually plausible, but it is more complex than the PR's one-line persisted-manifest fix and has a subtle risk: the resizer task itself still receives only $(_ResizetizerInputsFile) as InputsFile, so this approach relies entirely on the MSBuild target-level incremental check and does not make the task's own internal input manifest describe platform state.

try-fix-2 — Delete incremental state when platform changes

try-fix-2 — Delete incremental state when platform changes

Approach

Track the previous ResizetizerPlatformType in $(_ResizetizerPlatformStateFile) (mauiimage.platform). Before reading prior image outputs, compare the saved value to the current platform and delete mauiimage.stamp / mauiimage.outputs when the value changes. This forces ResizetizeImages to rerun while leaving mauiimage.inputs scoped to image item metadata.

This differs from PR #36984 by invalidating target state directly instead of changing the existing inputs manifest. It also differs from try-fix-1 by not adding a platform file to the target Inputs list.

Diff

diff --git a/src/SingleProject/Resizetizer/src/nuget/buildTransitive/Microsoft.Maui.Resizetizer.After.targets b/src/SingleProject/Resizetizer/src/nuget/buildTransitive/Microsoft.Maui.Resizetizer.After.targets
index d3fd5474e8..b038bc0aef 100644
--- a/src/SingleProject/Resizetizer/src/nuget/buildTransitive/Microsoft.Maui.Resizetizer.After.targets
+++ b/src/SingleProject/Resizetizer/src/nuget/buildTransitive/Microsoft.Maui.Resizetizer.After.targets
@@ -74,6 +74,7 @@
         <_ResizetizerInputsFile>$(_ResizetizerIntermediateOutputPath)mauiimage.inputs</_ResizetizerInputsFile>
         <_ResizetizerOutputsFile>$(_ResizetizerIntermediateOutputPath)mauiimage.outputs</_ResizetizerOutputsFile>
         <_ResizetizerStampFile>$(_ResizetizerIntermediateOutputPath)mauiimage.stamp</_ResizetizerStampFile>
+        <_ResizetizerPlatformStateFile>$(_ResizetizerIntermediateOutputPath)mauiimage.platform</_ResizetizerPlatformStateFile>
         <_MauiFontInputsFile>$(_ResizetizerIntermediateOutputPath)mauifont.inputs</_MauiFontInputsFile>
         <_MauiFontStampFile>$(_ResizetizerIntermediateOutputPath)mauifont.stamp</_MauiFontStampFile>
         <_MauiSplashInputsFile>$(_ResizetizerIntermediateOutputPath)mauisplash.inputs</_MauiSplashInputsFile>
@@ -125,6 +126,7 @@
             $(ResizetizeDependsOnTargets);
             ResizetizeCollectItems;
             ProcessMauiSplashScreens;
+            _InvalidateResizetizeImagesOnPlatformChange;
             _ReadResizetizeImagesOutputs;
         </ResizetizeDependsOnTargets>
         <!-- Ensures project-reference MauiAsset items are collected before ProcessMauiAssets
@@ -341,7 +343,7 @@
         <!-- This allows us to invalidate the build based on not just input image files changing but project item metadata as well -->
         <WriteLinesToFile
             File="$(_ResizetizerInputsFile)"
-            Lines="PlatformType=$(ResizetizerPlatformType);@(MauiImage->'File=%(Identity);Link=%(Link);BaseSize=%(BaseSize);Resize=%(Resize);TintColor=%(TintColor);Color=%(Color);IsAppIcon=%(IsAppIcon);ForegroundScale=%(ForegroundScale);ForegroundFile=%(ForegroundFile);MonochromeFile=%(MonochromeFile)')"
+            Lines="@(MauiImage->'File=%(Identity);Link=%(Link);BaseSize=%(BaseSize);Resize=%(Resize);TintColor=%(TintColor);Color=%(Color);IsAppIcon=%(IsAppIcon);ForegroundScale=%(ForegroundScale);ForegroundFile=%(ForegroundFile);MonochromeFile=%(MonochromeFile)')"
             Overwrite="true"
             WriteOnlyWhenDifferent="true" />
 
@@ -677,6 +679,36 @@
         DependsOnTargets="$(ResizetizerAfterFontProcessingTargets)"
         Condition="'$(EnableMauiFontProcessing)' == 'true' And '$(ResizetizerAfterFontProcessingTargets)' != ''" />
 
+    <Target Name="_InvalidateResizetizeImagesOnPlatformChange"
+        Condition="'$(EnableMauiImageProcessing)' == 'true'">
+        <ReadLinesFromFile File="$(_ResizetizerPlatformStateFile)" Condition="Exists('$(_ResizetizerPlatformStateFile)')">
+            <Output TaskParameter="Lines" ItemName="_PreviousResizetizerPlatformTypeLine" />
+        </ReadLinesFromFile>
+
+        <PropertyGroup>
+            <_PreviousResizetizerPlatformType>@(_PreviousResizetizerPlatformTypeLine)</_PreviousResizetizerPlatformType>
+            <_ResizetizerImagePlatformChanged Condition="'$(_PreviousResizetizerPlatformType)' != '' And '$(_PreviousResizetizerPlatformType)' != '$(ResizetizerPlatformType)'">True</_ResizetizerImagePlatformChanged>
+            <_ResizetizerImagePlatformChanged Condition="'$(_PreviousResizetizerPlatformType)' == '' And !Exists('$(_ResizetizerPlatformStateFile)') And (Exists('$(_ResizetizerStampFile)') Or Exists('$(_ResizetizerOutputsFile)'))">True</_ResizetizerImagePlatformChanged>
+        </PropertyGroup>
+
+        <ItemGroup Condition="'$(_ResizetizerImagePlatformChanged)' == 'True'">
+            <_ResizetizerImageIncrementalState Include="$(_ResizetizerStampFile)" />
+            <_ResizetizerImageIncrementalState Include="$(_ResizetizerOutputsFile)" />
+        </ItemGroup>
+
+        <Delete Files="@(_ResizetizerImageIncrementalState)" Condition="'@(_ResizetizerImageIncrementalState)' != ''" />
+
+        <WriteLinesToFile
+            File="$(_ResizetizerPlatformStateFile)"
+            Lines="$(ResizetizerPlatformType)"
+            Overwrite="true"
+            WriteOnlyWhenDifferent="true" />
+
+        <ItemGroup>
+            <FileWrites Include="$(_ResizetizerPlatformStateFile)" />
+        </ItemGroup>
+    </Target>
+
     <Target Name="_ReadResizetizeImagesOutputs">
         <ReadLinesFromFile File="$(_ResizetizerOutputsFile)" Condition="Exists ('$(_ResizetizerOutputsFile)')">
             <Output TaskParameter="Lines" ItemName="_ResizetizerOutputs" />

Test Results

❌ BLOCKED — same environment blocker as try-fix-1; focused integration runner exited before running tests because local MAUI SDK packs are missing:

ERROR: Microsoft.Maui.Sdk packs not found at: /home/vsts/work/1/s/.dotnet/packs/Microsoft.Maui.Sdk

Command attempted:

pwsh .github/skills/run-integration-tests/scripts/Run-IntegrationTests.ps1 -TestFilter "FullyQualifiedName~ChangingExternalBackendPlatformTypeInvalidatesImages" -SkipBuild -SkipInstall -ResultsDirectory "artifacts/integration-tests/try-fix-2"

Failure Analysis

The candidate could not be empirically evaluated. It is intentionally different, but it is more invasive than the PR fix and adds active deletion of incremental state, including a one-time rebuild for existing obj folders that lack the new state file. It also still does not put platform state into the task's own InputsFile, so the PR's persisted-manifest approach remains more holistic.

try-fix-3 — Platform-scoped output list

try-fix-3 — Platform-scoped output list

Approach

Resolve a platform-specific output-list file such as mauiimage.android.outputs and include it in ResizetizeImages Outputs. Keep mauiimage.outputs as the current-output alias for existing consumers/tests. Changing from generic to android makes the current platform output-list missing, forcing the target to run without adding platform state to mauiimage.inputs.

This differs from PR #36984 by changing output-list identity rather than input manifest content. It differs from try-fix-1 and try-fix-2 by not adding a platform input and not deleting incremental state based on comparison.

Diff

diff --git a/src/SingleProject/Resizetizer/src/nuget/buildTransitive/Microsoft.Maui.Resizetizer.After.targets b/src/SingleProject/Resizetizer/src/nuget/buildTransitive/Microsoft.Maui.Resizetizer.After.targets
index d3fd5474e8..c483734182 100644
--- a/src/SingleProject/Resizetizer/src/nuget/buildTransitive/Microsoft.Maui.Resizetizer.After.targets
+++ b/src/SingleProject/Resizetizer/src/nuget/buildTransitive/Microsoft.Maui.Resizetizer.After.targets
@@ -73,6 +73,7 @@
 
         <_ResizetizerInputsFile>$(_ResizetizerIntermediateOutputPath)mauiimage.inputs</_ResizetizerInputsFile>
         <_ResizetizerOutputsFile>$(_ResizetizerIntermediateOutputPath)mauiimage.outputs</_ResizetizerOutputsFile>
+        <_ResizetizerCurrentPlatformOutputsFile>$(_ResizetizerOutputsFile)</_ResizetizerCurrentPlatformOutputsFile>
         <_ResizetizerStampFile>$(_ResizetizerIntermediateOutputPath)mauiimage.stamp</_ResizetizerStampFile>
         <_MauiFontInputsFile>$(_ResizetizerIntermediateOutputPath)mauifont.inputs</_MauiFontInputsFile>
         <_MauiFontStampFile>$(_ResizetizerIntermediateOutputPath)mauifont.stamp</_MauiFontStampFile>
@@ -341,7 +342,7 @@
         <!-- This allows us to invalidate the build based on not just input image files changing but project item metadata as well -->
         <WriteLinesToFile
             File="$(_ResizetizerInputsFile)"
-            Lines="PlatformType=$(ResizetizerPlatformType);@(MauiImage->'File=%(Identity);Link=%(Link);BaseSize=%(BaseSize);Resize=%(Resize);TintColor=%(TintColor);Color=%(Color);IsAppIcon=%(IsAppIcon);ForegroundScale=%(ForegroundScale);ForegroundFile=%(ForegroundFile);MonochromeFile=%(MonochromeFile)')"
+            Lines="@(MauiImage->'File=%(Identity);Link=%(Link);BaseSize=%(BaseSize);Resize=%(Resize);TintColor=%(TintColor);Color=%(Color);IsAppIcon=%(IsAppIcon);ForegroundScale=%(ForegroundScale);ForegroundFile=%(ForegroundFile);MonochromeFile=%(MonochromeFile)')"
             Overwrite="true"
             WriteOnlyWhenDifferent="true" />
 
@@ -677,8 +678,17 @@
         DependsOnTargets="$(ResizetizerAfterFontProcessingTargets)"
         Condition="'$(EnableMauiFontProcessing)' == 'true' And '$(ResizetizerAfterFontProcessingTargets)' != ''" />
 
-    <Target Name="_ReadResizetizeImagesOutputs">
-        <ReadLinesFromFile File="$(_ResizetizerOutputsFile)" Condition="Exists ('$(_ResizetizerOutputsFile)')">
+    <Target Name="_ResolveResizetizerImageOutputListFile">
+        <PropertyGroup>
+            <_ResizetizerImageOutputListPlatform Condition="'$(ResizetizerPlatformType)' != ''">$([System.Text.RegularExpressions.Regex]::Replace('$(ResizetizerPlatformType)', '[^A-Za-z0-9_.-]', '_').ToLowerInvariant())</_ResizetizerImageOutputListPlatform>
+            <_ResizetizerCurrentPlatformOutputsFile Condition="'$(_ResizetizerImageOutputListPlatform)' != ''">$(_ResizetizerIntermediateOutputPath)mauiimage.$(_ResizetizerImageOutputListPlatform).outputs</_ResizetizerCurrentPlatformOutputsFile>
+            <_ResizetizerCurrentPlatformOutputsFile Condition="'$(_ResizetizerCurrentPlatformOutputsFile)' == ''">$(_ResizetizerOutputsFile)</_ResizetizerCurrentPlatformOutputsFile>
+        </PropertyGroup>
+    </Target>
+
+    <Target Name="_ReadResizetizeImagesOutputs"
+        DependsOnTargets="_ResolveResizetizerImageOutputListFile">
+        <ReadLinesFromFile File="$(_ResizetizerCurrentPlatformOutputsFile)" Condition="Exists ('$(_ResizetizerCurrentPlatformOutputsFile)')">
             <Output TaskParameter="Lines" ItemName="_ResizetizerOutputs" />
         </ReadLinesFromFile>
     </Target>
@@ -686,7 +696,7 @@
     <Target Name="ResizetizeImages"
         Condition="'$(EnableMauiImageProcessing)' == 'true'"
         Inputs="$(MSBuildThisFileFullPath);$(_ResizetizerTaskAssemblyName);$(_ResizetizerInputsFile);@(MauiImage)"
-        Outputs="$(_ResizetizerStampFile);$(_ResizetizerOutputsFile);@(_ResizetizerOutputs)"
+        Outputs="$(_ResizetizerStampFile);$(_ResizetizerOutputsFile);$(_ResizetizerCurrentPlatformOutputsFile);@(_ResizetizerOutputs)"
         AfterTargets="$(ResizetizeAfterTargets)"
         BeforeTargets="$(ResizetizeBeforeTargets)"
         DependsOnTargets="$(ResizetizeDependsOnTargets)">
@@ -748,6 +758,12 @@
              target runs; the Exists() recovery path (line ~663) still forces a rebuild if the
              file is deleted. -->
         <WriteLinesToFile
+            File="$(_ResizetizerCurrentPlatformOutputsFile)"
+            Lines="@(_ResizetizerCollectedImages->'%(Identity)')"
+            Overwrite="true"
+        />
+        <WriteLinesToFile
+            Condition="'$(_ResizetizerCurrentPlatformOutputsFile)' != '$(_ResizetizerOutputsFile)'"
             File="$(_ResizetizerOutputsFile)"
             Lines="@(_ResizetizerCollectedImages->'%(Identity)')"
             Overwrite="true"
@@ -757,6 +773,7 @@
         <ItemGroup>
             <FileWrites Include="@(_ResizetizerCollectedImages)" />
             <FileWrites Include="$(_ResizetizerStampFile)" />
+            <FileWrites Include="$(_ResizetizerCurrentPlatformOutputsFile)" />
             <FileWrites Include="$(_ResizetizerOutputsFile)" />
         </ItemGroup>
     </Target>

Test Results

❌ BLOCKED — focused integration runner exited before running tests because local MAUI SDK packs are missing:

ERROR: Microsoft.Maui.Sdk packs not found at: /home/vsts/work/1/s/.dotnet/packs/Microsoft.Maui.Sdk

Command attempted:

pwsh .github/skills/run-integration-tests/scripts/Run-IntegrationTests.ps1 -TestFilter "FullyQualifiedName~ChangingExternalBackendPlatformTypeInvalidatesImages" -SkipBuild -SkipInstall -ResultsDirectory "artifacts/integration-tests/try-fix-3"

Failure Analysis

The candidate could not be empirically evaluated. It is distinct and avoids fake Inputs paths, but it adds extra per-platform output-list files and depends on resolving $(_ResizetizerCurrentPlatformOutputsFile) before MSBuild evaluates ResizetizeImages Outputs. It also may surprise tooling that assumes only mauiimage.outputs exists.

try-fix-4 — Platform-specific stamp output

try-fix-4 — Platform-specific stamp output

Approach

Resolve a platform-specific stamp such as mauiimage.android.stamp, include it in ResizetizeImages Outputs, touch it when the target runs, and remove other platform stamps. Switching platform makes the current platform stamp missing, forcing ResizetizeImages to run while keeping mauiimage.outputs unscoped and avoiding input manifest changes.

This differs from PR #36984 by changing stamp outputs rather than persisted input content. It differs from try-fix-1 through try-fix-3 by not adding a platform input, not deleting the primary stamp/output list based on state comparison, and not platform-scoping the output list.

Diff

diff --git a/src/SingleProject/Resizetizer/src/nuget/buildTransitive/Microsoft.Maui.Resizetizer.After.targets b/src/SingleProject/Resizetizer/src/nuget/buildTransitive/Microsoft.Maui.Resizetizer.After.targets
index d3fd5474e8..0883d507fc 100644
--- a/src/SingleProject/Resizetizer/src/nuget/buildTransitive/Microsoft.Maui.Resizetizer.After.targets
+++ b/src/SingleProject/Resizetizer/src/nuget/buildTransitive/Microsoft.Maui.Resizetizer.After.targets
@@ -341,7 +341,7 @@
         <!-- This allows us to invalidate the build based on not just input image files changing but project item metadata as well -->
         <WriteLinesToFile
             File="$(_ResizetizerInputsFile)"
-            Lines="PlatformType=$(ResizetizerPlatformType);@(MauiImage->'File=%(Identity);Link=%(Link);BaseSize=%(BaseSize);Resize=%(Resize);TintColor=%(TintColor);Color=%(Color);IsAppIcon=%(IsAppIcon);ForegroundScale=%(ForegroundScale);ForegroundFile=%(ForegroundFile);MonochromeFile=%(MonochromeFile)')"
+            Lines="@(MauiImage->'File=%(Identity);Link=%(Link);BaseSize=%(BaseSize);Resize=%(Resize);TintColor=%(TintColor);Color=%(Color);IsAppIcon=%(IsAppIcon);ForegroundScale=%(ForegroundScale);ForegroundFile=%(ForegroundFile);MonochromeFile=%(MonochromeFile)')"
             Overwrite="true"
             WriteOnlyWhenDifferent="true" />
 
@@ -677,7 +677,16 @@
         DependsOnTargets="$(ResizetizerAfterFontProcessingTargets)"
         Condition="'$(EnableMauiFontProcessing)' == 'true' And '$(ResizetizerAfterFontProcessingTargets)' != ''" />
 
-    <Target Name="_ReadResizetizeImagesOutputs">
+    <Target Name="_ResolveResizetizerPlatformStampFile">
+        <PropertyGroup>
+            <_ResizetizerPlatformStampName Condition="'$(ResizetizerPlatformType)' != ''">$([System.Text.RegularExpressions.Regex]::Replace('$(ResizetizerPlatformType)', '[^A-Za-z0-9_.-]', '_').ToLowerInvariant())</_ResizetizerPlatformStampName>
+            <_ResizetizerPlatformStampFile Condition="'$(_ResizetizerPlatformStampName)' != ''">$(_ResizetizerIntermediateOutputPath)mauiimage.$(_ResizetizerPlatformStampName).stamp</_ResizetizerPlatformStampFile>
+            <_ResizetizerPlatformStampFile Condition="'$(_ResizetizerPlatformStampFile)' == ''">$(_ResizetizerStampFile)</_ResizetizerPlatformStampFile>
+        </PropertyGroup>
+    </Target>
+
+    <Target Name="_ReadResizetizeImagesOutputs"
+        DependsOnTargets="_ResolveResizetizerPlatformStampFile">
         <ReadLinesFromFile File="$(_ResizetizerOutputsFile)" Condition="Exists ('$(_ResizetizerOutputsFile)')">
             <Output TaskParameter="Lines" ItemName="_ResizetizerOutputs" />
         </ReadLinesFromFile>
@@ -686,7 +695,7 @@
     <Target Name="ResizetizeImages"
         Condition="'$(EnableMauiImageProcessing)' == 'true'"
         Inputs="$(MSBuildThisFileFullPath);$(_ResizetizerTaskAssemblyName);$(_ResizetizerInputsFile);@(MauiImage)"
-        Outputs="$(_ResizetizerStampFile);$(_ResizetizerOutputsFile);@(_ResizetizerOutputs)"
+        Outputs="$(_ResizetizerStampFile);$(_ResizetizerPlatformStampFile);$(_ResizetizerOutputsFile);@(_ResizetizerOutputs)"
         AfterTargets="$(ResizetizeAfterTargets)"
         BeforeTargets="$(ResizetizeBeforeTargets)"
         DependsOnTargets="$(ResizetizeDependsOnTargets)">
@@ -723,6 +732,9 @@
             <_ResizetizerExistingImages Include="$(_MauiIntermediateImages)\**\*" />
             <_ResizetizerImagesToDelete Include="@(_ResizetizerExistingImages->'%(FullPath)')" />
             <_ResizetizerImagesToDelete Remove="@(_ResizetizerCollectedImages)" />
+            <_ResizetizerExistingPlatformStampFiles Include="$(_ResizetizerIntermediateOutputPath)mauiimage.*.stamp" Condition="'$(_ResizetizerPlatformStampFile)' != '$(_ResizetizerStampFile)'" />
+            <_ResizetizerPlatformStampFilesToDelete Include="@(_ResizetizerExistingPlatformStampFiles)" />
+            <_ResizetizerPlatformStampFilesToDelete Remove="$(_ResizetizerPlatformStampFile)" />
         </ItemGroup>
 
         <!-- Remove files which are no longer needed -->
@@ -731,12 +743,18 @@
             Files="@(_ResizetizerImagesToDelete)"
         />
 
+        <Delete
+            Condition="'@(_ResizetizerPlatformStampFilesToDelete->Count())' != '0'"
+            Files="@(_ResizetizerPlatformStampFilesToDelete)"
+        />
+
         <ItemGroup>
             <MauiProcessedImage Include="@(_ResizetizerCollectedImages)" />
         </ItemGroup>
 
         <!-- Touch/create our stamp file for outputs -->
         <Touch Files="$(_ResizetizerStampFile)" AlwaysCreate="True" />
+        <Touch Files="$(_ResizetizerPlatformStampFile)" AlwaysCreate="True" Condition="'$(_ResizetizerPlatformStampFile)' != ''" />
         <!-- NOTE: do NOT set WriteOnlyWhenDifferent="true" here. This file is listed in the
              target's Outputs (line ~671), so its mtime is the target's up-to-date signal.
              The file's content is only the SET of output filenames, so editing an existing
@@ -757,6 +775,7 @@
         <ItemGroup>
             <FileWrites Include="@(_ResizetizerCollectedImages)" />
             <FileWrites Include="$(_ResizetizerStampFile)" />
+            <FileWrites Include="$(_ResizetizerPlatformStampFile)" Condition="'$(_ResizetizerPlatformStampFile)' != ''" />
             <FileWrites Include="$(_ResizetizerOutputsFile)" />
         </ItemGroup>
     </Target>

Test Results

❌ BLOCKED — focused integration runner exited before running tests because local MAUI SDK packs are missing:

ERROR: Microsoft.Maui.Sdk packs not found at: /home/vsts/work/1/s/.dotnet/packs/Microsoft.Maui.Sdk

Command attempted:

pwsh .github/skills/run-integration-tests/scripts/Run-IntegrationTests.ps1 -TestFilter "FullyQualifiedName~ChangingExternalBackendPlatformTypeInvalidatesImages" -SkipBuild -SkipInstall -ResultsDirectory "artifacts/integration-tests/try-fix-4"

Failure Analysis

The candidate could not be empirically evaluated. It is a plausible target-level invalidation mechanism and avoids fake file paths, but it adds per-platform stamp files, cleanup complexity, and another resolved property that must be available before ResizetizeImages Outputs are evaluated. It is less direct than the PR's persisted-manifest line.


🏁 Report — Final Recommendation

Comparative Report — PR #36984

Candidates Compared

Rank Candidate Result Assessment
1 pr Best Persists ResizetizerPlatformType in the existing mauiimage.inputs manifest. This is the most direct fix because it updates both the MSBuild target input timestamp and the task-level InputsFile used by per-image up-to-date checks. The added integration test covers generic-to-Android invalidation, stale-output cleanup, and no-op rebuild behavior.
1 pr-plus-reviewer Equivalent to pr The expert reviewer produced no actionable inline findings, so no sandbox changes were applied. This candidate is functionally identical to pr.
3 try-fix-1 Blocked Adds a separate platform input file to the target Inputs. Plausible, but more complex than the PR and leaves the task's own InputsFile without platform state. It could not be empirically validated because the local environment was missing .dotnet/packs/Microsoft.Maui.Sdk.
4 try-fix-4 Blocked Uses platform-specific stamp outputs. Plausible target-level invalidation, but adds stamp resolution and cleanup complexity and depends on the resolved property being available for target output evaluation. It could not be empirically validated.
5 try-fix-3 Blocked Uses platform-scoped output-list files. This avoids synthetic input paths but adds extra output-list files and may surprise tooling that expects mauiimage.outputs. It could not be empirically validated.
6 try-fix-2 Blocked Tracks previous platform state and actively deletes stamp/output-list files on change. This is the most invasive alternative, creates extra state, and still does not place platform state in the task-level InputsFile. It could not be empirically validated.

No candidate failed regression tests. All try-fix-* candidates were blocked before test execution, so they rank below the PR candidates, whose focused validation is documented in the PR description and whose implementation is simpler and better aligned with the existing incremental model.

Winning Candidate

Winner: pr

The raw PR fix is the winning candidate. It is the smallest complete fix, updates the persisted semantic input state that already drives incremental image processing, and preserves the existing target/output-list model without introducing additional files, deletion heuristics, or property-resolution timing dependencies. pr-plus-reviewer is equivalent because the expert reviewer found no actionable changes, so selecting pr avoids implying that an additional patch is needed.


🧭 Next Steps — review latest findings

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

@MauiBot MauiBot removed the s/agent-review-in-progress AI review is currently running for this PR label Jul 31, 2026
@kubaflo kubaflo removed the s/agent-changes-requested AI agent recommends changes - found a better alternative or issues label Jul 31, 2026
@kubaflo kubaflo removed the s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates label Jul 31, 2026
@kubaflo

kubaflo commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

@Redth @jfversluis — final approval handoff for head 54c285c32a2: official Android expert review 14834473 is clean with inline-findings.json = [] and winner pr; the exact AzDO regression ChangingExternalBackendPlatformTypeInvalidatesImages passed in build 1534908 (4.88s); all completed main-build and integration legs are green, with only two Windows integration jobs still running. Merge-commit auto-merge is armed.

kubaflo pushed a commit that referenced this pull request Jul 31, 2026
…eview

The AnalyzeCopilotTokenUsage stage is pure telemetry, but it could mark the whole
build failed when a run produced no token-usage data: on a SKIPPED-gate run the
Copilot agent consumed no tokens, so no copilot-token-usage directory was created,
and PublishPipelineArtifact failed with "Path does not exist" — reddening a build
whose review had already posted its summary fine. (build 14834473, PR #36984.)

- Always create the output dir up front so the publish never hits a missing path.
- Mark both the Aggregate step and the Publish task continueOnError:true so a missing
  artifact or transient publish error can't fail the build. The review stages
  (ReviewPR / RunDeepUITests / UpdateAISummaryComment) remain the real signal.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 15d2af20-e4ab-4e88-9011-cfbd83513bc0
@kubaflo
kubaflo requested a review from mattleibow July 31, 2026 18:21
@kubaflo
kubaflo disabled auto-merge July 31, 2026 21:06
@kubaflo
kubaflo merged commit 7ad533a into net11.0 Jul 31, 2026
33 checks passed
@kubaflo
kubaflo deleted the pureween-fix-resizetizer-platform-invalidation branch July 31, 2026 21:07
@github-actions github-actions Bot added this to the .NET 11.0-preview7 milestone Jul 31, 2026
kubaflo pushed a commit that referenced this pull request Aug 1, 2026
…eview

The AnalyzeCopilotTokenUsage stage is pure telemetry, but it could mark the whole
build failed when a run produced no token-usage data: on a SKIPPED-gate run the
Copilot agent consumed no tokens, so no copilot-token-usage directory was created,
and PublishPipelineArtifact failed with "Path does not exist" — reddening a build
whose review had already posted its summary fine. (build 14834473, PR #36984.)

- Always create the output dir up front so the publish never hits a missing path.
- Mark both the Aggregate step and the Publish task continueOnError:true so a missing
  artifact or transient publish error can't fail the build. The review stages
  (ReviewPR / RunDeepUITests / UpdateAISummaryComment) remain the real signal.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 15d2af20-e4ab-4e88-9011-cfbd83513bc0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-resizetizer 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