Skip to content

Avoid unnecessary LINQ enumerations#35272

Merged
kubaflo merged 5 commits into
dotnet:inflight/currentfrom
jeremy-visionaid:linq-enumerations
May 8, 2026
Merged

Avoid unnecessary LINQ enumerations#35272
kubaflo merged 5 commits into
dotnet:inflight/currentfrom
jeremy-visionaid:linq-enumerations

Conversation

@jeremy-visionaid

@jeremy-visionaid jeremy-visionaid commented May 1, 2026

Copy link
Copy Markdown
Contributor

Mostly fixes CA1827 warnings

@github-actions

github-actions Bot commented May 1, 2026

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 -- 35272

Or

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

@dotnet-policy-service dotnet-policy-service Bot added the community ✨ Community Contribution label May 1, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Hey there @@jeremy-visionaid! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed.

MauiBot
MauiBot previously requested changes May 3, 2026

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🤖 Automated review — alternative fix proposed

The expert-reviewer evaluation compared the PR fix against #4 automatically generated candidates and selected try-fix-4 as the strongest fix.

Why: try-fix-4 wins by adding a reusable HasMultipleGesturesFor<T>() extension to EnumerableExtensions.cs (following the existing HasAnyGesturesFor<T>() pattern), which correctly fixes the critical View.cs regression where Any() threw on the first PinchGestureRecognizer add. It also preserves all valid CA1827 fixes across the other 4 files and updates VisualStateManager.cs with a principled comment explaining the priority-rule rationale for the >= 1 semantic change.

Please consider applying the candidate diff below (or use it as guidance). Once you push an update, this workflow will re-trigger and re-evaluate.

Candidate diff (`try-fix-4`)
diff --git a/src/Compatibility/Core/src/MacOS/Extensions/NSMenuExtensions.cs b/src/Compatibility/Core/src/MacOS/Extensions/NSMenuExtensions.cs
index 9b4b94975c..ea22648934 100644
--- a/src/Compatibility/Core/src/MacOS/Extensions/NSMenuExtensions.cs
+++ b/src/Compatibility/Core/src/MacOS/Extensions/NSMenuExtensions.cs
@@ -95,15 +95,15 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.macOS.Extensions
 			if (accelerator == null)
 				return;
 
-			bool hasModifierMask = accelerator.Modifiers?.Count() > 1;
+			bool hasModifierMask = accelerator.Modifiers?.Any() ?? false;
 
 			if (hasModifierMask)
 			{
 				nsMenuItem.KeyEquivalentModifierMask = 0;
 
-				for (int i = 0; i < accelerator.Modifiers.Count(); i++)
+				foreach (var modifier in accelerator.Modifiers)
 				{
-					var modifierMask = accelerator.Modifiers.ElementAt(i).ToLower();
+					var modifierMask = modifier.ToLower();
 					switch (modifierMask)
 					{
 						case "ctrl":
diff --git a/src/Compatibility/Core/src/iOS/Renderers/SwipeViewRenderer.cs b/src/Compatibility/Core/src/iOS/Renderers/SwipeViewRenderer.cs
index 074017f576..69e6784e21 100644
--- a/src/Compatibility/Core/src/iOS/Renderers/SwipeViewRenderer.cs
+++ b/src/Compatibility/Core/src/iOS/Renderers/SwipeViewRenderer.cs
@@ -425,7 +425,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.iOS
 
 		bool IsValidSwipeItems(SwipeItems swipeItems)
 		{
-			return swipeItems != null && swipeItems.Where(s => s.IsVisible).Count() > 0;
+			return swipeItems != null && swipeItems.Any(s => s.IsVisible);
 		}
 
 		void UpdateSwipeItems()
@@ -1557,7 +1557,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.iOS
 
 			var swipeItems = GetSwipeItemsByDirection();
 
-			if (swipeItems.Where(s => s.IsVisible).Count() == 0)
+			if (!swipeItems.Any(s => s.IsVisible))
 				return;
 
 			var swipeThreshold = GetSwipeThreshold();
diff --git a/src/Controls/src/Core/EnumerableExtensions.cs b/src/Controls/src/Core/EnumerableExtensions.cs
index d2915b59a6..3e6aea3dd4 100644
--- a/src/Controls/src/Core/EnumerableExtensions.cs
+++ b/src/Controls/src/Core/EnumerableExtensions.cs
@@ -65,6 +65,29 @@ namespace Microsoft.Maui.Controls.Internals
 		internal static bool HasAnyGesturesFor<T>(this IEnumerable<IGestureRecognizer>? gestures, Func<T, bool>? predicate = null) where T : GestureRecognizer
 			=> FirstGestureOrDefault(gestures, predicate) is not null;
 
+		/// <remarks>Does not make a defensive copy; safe only when the collection is not being concurrently modified.</remarks>
+		internal static bool HasMultipleGesturesFor<T>(this IEnumerable<IGestureRecognizer>? gestures, Func<T, bool>? predicate = null) where T : GestureRecognizer
+		{
+			if (gestures is null)
+			{
+				return false;
+			}
+
+			int count = 0;
+			foreach (IGestureRecognizer item in gestures)
+			{
+				if (item is T gesture && (predicate is null || predicate(gesture)))
+				{
+					if (++count > 1)
+					{
+						return true;
+					}
+				}
+			}
+
+			return false;
+		}
+
 		internal static T? FirstGestureOrDefault<T>(this IEnumerable<IGestureRecognizer>? gestures, Func<T, bool>? predicate = null) where T : GestureRecognizer
 		{
 			if (gestures is null)
diff --git a/src/Controls/src/Core/View/View.cs b/src/Controls/src/Core/View/View.cs
index 181665d4b6..77ea22de2a 100644
--- a/src/Controls/src/Core/View/View.cs
+++ b/src/Controls/src/Core/View/View.cs
@@ -277,7 +277,7 @@ namespace Microsoft.Maui.Controls
 		{
 			if (gesture == null)
 				return false;
-			if (gesture is PinchGestureRecognizer && _gestureRecognizers.GetGesturesFor<PinchGestureRecognizer>().Count() > 1)
+			if (gesture is PinchGestureRecognizer && _gestureRecognizers.HasMultipleGesturesFor<PinchGestureRecognizer>())
 				throw new InvalidOperationException($"Only one {nameof(PinchGestureRecognizer)} per view is allowed");
 			return true;
 		}
diff --git a/src/Controls/src/Core/VisualStateManager.cs b/src/Controls/src/Core/VisualStateManager.cs
index 6c74249d29..40a2b7426c 100644
--- a/src/Controls/src/Core/VisualStateManager.cs
+++ b/src/Controls/src/Core/VisualStateManager.cs
@@ -552,14 +552,13 @@ namespace Microsoft.Maui.Controls
 			// 2. AdaptiveTrigger activated due to MinWindowWidth
 			// 3. AdaptiveTrigger activated due to MinWindowHeight
 			//
-			// If there are multiple active triggers at a time that have a conflict in scoring (i.e.two custom 
-			// triggers), then the first one declared in the markup file takes precedence.
+			// If there are multiple active triggers at a time that have a conflict in scoring (i.e., any
+			// conflict involving a custom trigger), then the first one declared in the markup file takes precedence.
+			// Custom triggers always outrank adaptive triggers per the priority rules above.
 
-			var existCustomTriggers = conflicts.Where(c => !(c is AdaptiveTrigger));
-
-			if (existCustomTriggers.Count() > 1)
+			var firstExistCustomTrigger = conflicts.FirstOrDefault(c => c is not AdaptiveTrigger);
+			if (firstExistCustomTrigger != null)
 			{
-				var firstExistCustomTrigger = existCustomTriggers.FirstOrDefault();
 				return firstExistCustomTrigger.VisualState;
 			}
 
diff --git a/src/SingleProject/Resizetizer/src/GenerateTizenManifest.cs b/src/SingleProject/Resizetizer/src/GenerateTizenManifest.cs
index 565b3b65d3..c2f57bae8f 100644
--- a/src/SingleProject/Resizetizer/src/GenerateTizenManifest.cs
+++ b/src/SingleProject/Resizetizer/src/GenerateTizenManifest.cs
@@ -173,7 +173,7 @@ namespace Microsoft.Maui.Resizetizer
 						&& d.Attribute(DpiName)?.Value == image.Key.Resolution
 						&& d.Attribute("orientation")?.Value == image.Key.Orientation
 						&& d.Attribute("indicator-display")?.Value == "false");
-					if (splashElements.Count() == 0)
+					if (!splashElements.Any())
 					{
 						var splashscreenElement = new XElement(xmlns + SplashScreenName);
 						splashscreenElement.SetAttributeValue("src", image.Value);

@MauiBot MauiBot added s/agent-changes-requested AI agent recommends changes - found a better alternative or issues s/agent-fix-win AI found a better alternative fix than the PR s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review) labels May 3, 2026
@dotnet dotnet deleted a comment from MauiBot May 6, 2026
@kubaflo kubaflo dismissed MauiBot’s stale review May 6, 2026 18:57

Resetting for re-review

MauiBot
MauiBot previously requested changes May 6, 2026

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🤖 Automated review — alternative fix proposed

The expert-reviewer evaluation compared the PR fix against #2 automatically generated candidates and selected try-fix-2 as the strongest fix.

Why: Try-fix-2 makes the same correct code changes as the PR but adds a self-documenting comment explaining why Any() is correct and Count() > 1 was wrong, plus renames hasModifierMask to hasAnyModifier for semantic clarity. This is important because the single-modifier macOS keyboard shortcut bug has already regressed once (XF#1749) and the comment prevents a future contributor from accidentally reverting the fix.

Please consider applying the candidate diff below (or use it as guidance). Once you push an update, this workflow will re-trigger and re-evaluate.

Candidate diff (`try-fix-2`)
--- a/src/Compatibility/Core/src/MacOS/Extensions/NSMenuExtensions.cs
+++ b/src/Compatibility/Core/src/MacOS/Extensions/NSMenuExtensions.cs
@@ -95,18 +95,21 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.macOS.Extensions
 			if (accelerator == null)
 				return;
 
-			bool hasModifierMask = accelerator.Modifiers?.Count() > 1;
+			// Must be Any(), not Count() > 1: a single modifier (e.g., Shift) must still
+			// apply its mask. Using Count() > 1 silently skips single-modifier shortcuts.
+			bool hasAnyModifier = accelerator.Modifiers?.Any() ?? false;
 
-			if (hasModifierMask)
+			if (hasAnyModifier)
 			{
 				nsMenuItem.KeyEquivalentModifierMask = 0;
 
-				for (int i = 0; i < accelerator.Modifiers.Count(); i++)
+				foreach (var modifier in accelerator.Modifiers)
 				{
-					var modifierMask = accelerator.Modifiers.ElementAt(i).ToLower();
+					var modifierMask = modifier.ToLower();
 					switch (modifierMask)
 					{
 						case "ctrl":
--- a/src/Compatibility/Core/src/iOS/Renderers/SwipeViewRenderer.cs
+++ b/src/Compatibility/Core/src/iOS/Renderers/SwipeViewRenderer.cs
@@ -1557,7 +1557,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.iOS
 
 			var swipeItems = GetSwipeItemsByDirection();
 
-			if (swipeItems.Where(s => s.IsVisible).Count() == 0)
+			if (!swipeItems.Any(s => s.IsVisible))
 				return;
 
 			var swipeThreshold = GetSwipeThreshold();
--- a/src/SingleProject/Resizetizer/src/GenerateTizenManifest.cs
+++ b/src/SingleProject/Resizetizer/src/GenerateTizenManifest.cs
@@ -173,7 +173,7 @@ namespace Microsoft.Maui.Resizetizer
 							&& d.Attribute(DpiName)?.Value == image.Key.Resolution
 							&& d.Attribute("orientation")?.Value == image.Key.Orientation
 							&& d.Attribute("indicator-display")?.Value == "false");
-					if (splashElements.Count() == 0)
+					if (!splashElements.Any())
 					{
 						var splashscreenElement = new XElement(xmlns + SplashScreenName);

@MauiBot MauiBot added s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates and removed s/agent-fix-win AI found a better alternative fix than the PR labels May 6, 2026
dependabot Bot and others added 2 commits May 7, 2026 08:48
Updated [Magick.NET-Q8-AnyCPU](https://github.com/dlemstra/Magick.NET)
from 14.10.4 to 14.12.0.

<details>
<summary>Release notes</summary>

_Sourced from [Magick.NET-Q8-AnyCPU's
releases](https://github.com/dlemstra/Magick.NET/releases)._

## 14.12.0

### What's Changed
- Added `FixByteOrder` to the `DcmReadDefines` (#​1976)
- Added `IconWriteDefines`.

### Related changes in ImageMagick since the last release of Magick.NET:
- Correct bug in `Composite` when using `CopyAlpha` (#​1985)
- Fixed incorrect orientation of JPEG compressed TIFF images (#​1991)
- Heap-Buffer-Overflow write of single zero byte when parsing xml
(GHSA-cr67-pvmx-2pp2)
- Stack Overflow in DestroyXMLTree
(GHSA-fwvm-ggf6-2p4x)
- Out-of-Bounds read in sample operation
(GHSA-pcvx-ph33-r5vv)
- Stack Overflow via Recursive FX Expression Parsing
(GHSA-f4qm-vj5j-9xpw)
- Heap Buffer Overflow in ImageMagick MVG decoder
(GHSA-x9h5-r9v2-vcww)
- Heap overflow caused by integer overflow/wraparound in viff encoder on
32-bit builds
(GHSA-v67w-737x-v2c9)
- Stack-buffer-overflow in MNG encoder with oversized pallete
(GHSA-98cp-rj9f-6v5g)
- Integer overflow in despeckle operation causes heap buffer overflow on
32-bit builds
(GHSA-26qp-ffjh-2x4v)
- Off-by-One in MSL decoder could result in crash
(GHSA-5xg3-585r-9jh5)
- Heap buffer overflow when encoding JXL image with a 16-bit float
(GHSA-jvgr-9ph5-m8v4)
- Heap-use-after-free via XMP profile could result in a crash when
printing the values
(GHSA-r83h-crwp-3vm7)
- Heap buffer overflow (WRITE) in the YAML and JSON encoders
(GHSA-5592-p365-24xh)
- Heap out-of-bounds write in JP2 encoder
(GHSA-pwg5-6jfc-crvh)

### Library updates:
- ImageMagick 7.1.2-19 (2026-04-12)
- aom 3.13.3 (2026-04-02)
- openexr 3.4.9 (2026-04-03)
- freetype 2.14.3 (2026-03-22)
- gdk-pixbuf 2.44.6 (2026-03-31)
- harfbuzz 14.0.0 (2026-04-01)
- liblzma 5.8.3 (2026-04-31)
- libpng 1.6.56 (2026-03-25)

**Full Changelog**:
dlemstra/Magick.NET@14.11.1...14.12.0

## 14.11.1

### Related changes in ImageMagick since the last release of Magick.NET:
- Stack-buffer-overflow WRITE in InterpretImageFilename due to overflow
(GHSA-8793-7xv6-82cf)

### Library updates:
- ImageMagick 7.1.2-18 (2026-03-23)
- aom 3.13.2 (2026-03-19)
- openexr 3.4.7 (2026-03-15)
- harfbuzz 13.2.1 (2026-03-19)

**Full Changelog**:
dlemstra/Magick.NET@14.11.0...14.11.1

## 14.11.0

### What's Changed
- Added `DcmReadDefines`.

### Related changes in ImageMagick since the last release of Magick.NET:
- Access mode change for files created from 0666 to 0600
(ImageMagick/ImageMagick#8609)
- Heap-buffer-overflow in NewXMLTree could result in crash
(GHSA-gc62-2v5p-qpmp)

### Library updates:
- ImageMagick 7.1.2-17 (2026-03-16)
- openexr 3.4.6 (2026-03-01)
- freetype 2.14.2 (2026-03-01)
- harfbuzz 13.0.1 (2026-03-07)
- libxml2 2.15.2 (2026-03-03)

**Full Changelog**:
dlemstra/Magick.NET@14.10.4...14.11.0

Commits viewable in [compare
view](dlemstra/Magick.NET@14.10.4...14.12.0).
</details>

[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=Magick.NET-Q8-AnyCPU&package-manager=nuget&previous-version=14.10.4&new-version=14.12.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts page](https://github.com/dotnet/maui/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…t#35333)

Bump OpenTelemetry packages to latest stable versions in the
maui-aspire-servicedefaults template:

- OpenTelemetry.Exporter.OpenTelemetryProtocol: 1.9.0 to 1.15.3
- OpenTelemetry.Extensions.Hosting: 1.9.0 to 1.15.3
- OpenTelemetry.Instrumentation.Http: 1.9.0 to 1.15.1
- OpenTelemetry.Instrumentation.Runtime: 1.9.0 to 1.15.1

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@dotnet dotnet deleted a comment from MauiBot May 7, 2026
@kubaflo kubaflo dismissed MauiBot’s stale review May 7, 2026 11:14

Resetting for re-review

MauiBot
MauiBot previously requested changes May 7, 2026

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🤖 Automated review — alternative fix proposed

The expert-reviewer evaluation compared the PR fix against #1 automatically generated candidates and selected try-fix-1 as the strongest fix.

Why: try-fix-1 completes the PR's incomplete CA1827 remediation by fixing the identical .Where(s => s.IsVisible).Count() > 0 patterns in IsValidSwipeItems() for both iOS and Android SwipeViewRenderers (lines 428 and 424), which the PR left unaddressed. It also deduplicates iOS line 1560 by routing it through the existing IsValidSwipeItems() helper, adding null safety. All 360 unit tests pass, the fix is minimal (2 files, ~3 lines), and it completes the stated goal of fixing CA1827 warnings without introducing scope creep.

Please consider applying the candidate diff below (or use it as guidance). Once you push an update, this workflow will re-trigger and re-evaluate.

Candidate diff (`try-fix-1`)
diff --git a/src/Compatibility/Core/src/Android/Renderers/SwipeViewRenderer.cs b/src/Compatibility/Core/src/Android/Renderers/SwipeViewRenderer.cs
index 83ed4820b0..4e18df192d 100644
--- a/src/Compatibility/Core/src/Android/Renderers/SwipeViewRenderer.cs
+++ b/src/Compatibility/Core/src/Android/Renderers/SwipeViewRenderer.cs
@@ -421,7 +421,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Android
 
 bool IsValidSwipeItems(SwipeItems swipeItems)
 {
-return swipeItems != null && swipeItems.Where(s => s.IsVisible).Count() > 0;
+return swipeItems != null && swipeItems.Any(s => s.IsVisible);
 }
 
 bool ProcessSwipingInteractions(MotionEvent e)
diff --git a/src/Compatibility/Core/src/iOS/Renderers/SwipeViewRenderer.cs b/src/Compatibility/Core/src/iOS/Renderers/SwipeViewRenderer.cs
index 074017f576..362e6266a6 100644
--- a/src/Compatibility/Core/src/iOS/Renderers/SwipeViewRenderer.cs
+++ b/src/Compatibility/Core/src/iOS/Renderers/SwipeViewRenderer.cs
@@ -425,7 +425,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.iOS
 
 bool IsValidSwipeItems(SwipeItems swipeItems)
 {
-return swipeItems != null && swipeItems.Where(s => s.IsVisible).Count() > 0;
+return swipeItems != null && swipeItems.Any(s => s.IsVisible);
 }
 
 void UpdateSwipeItems()
@@ -1557,7 +1557,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.iOS
 
 var swipeItems = GetSwipeItemsByDirection();
 
-if (swipeItems.Where(s => s.IsVisible).Count() == 0)
+if (!IsValidSwipeItems(swipeItems))
 return;
 
 var swipeThreshold = GetSwipeThreshold();

@MauiBot MauiBot added s/agent-fix-win AI found a better alternative fix than the PR and removed s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates labels May 7, 2026
dotnet-maestro Bot and others added 2 commits May 7, 2026 11:49
This pull request updates the following dependencies

[marker]: <> (Begin:a71c12d9-5aa4-4b46-e2d6-08da0cf8cd95)
## From https://github.com/dotnet/xharness
- **Subscription**:
[a71c12d9-5aa4-4b46-e2d6-08da0cf8cd95](https://maestro.dot.net/subscriptions?search=a71c12d9-5aa4-4b46-e2d6-08da0cf8cd95)
- **Build**:
[20260430.4](https://dev.azure.com/dnceng/internal/_build/results?buildId=2964906)
([312724](https://maestro.dot.net/channel/2/github:dotnet:xharness/build/312724))
- **Date Produced**: May 1, 2026 7:05:11 AM UTC
- **Commit**:
[92962e5c46ac08a66ded4c5696209cc60f1a232f](dotnet/xharness@92962e5)
- **Branch**: [main](https://github.com/dotnet/xharness/tree/main)

[DependencyUpdate]: <> (Begin)

- **Dependency Updates**:
  - From [11.0.0-prerelease.26229.1 to 11.0.0-prerelease.26230.4][1]
     - Microsoft.DotNet.XHarness.CLI
     - Microsoft.DotNet.XHarness.TestRunners.Common
     - Microsoft.DotNet.XHarness.TestRunners.Xunit

[1]: dotnet/xharness@9d5a7e9...92962e5

[DependencyUpdate]: <> (End)


[marker]: <> (End:a71c12d9-5aa4-4b46-e2d6-08da0cf8cd95)

Co-authored-by: dotnet-maestro[bot] <dotnet-maestro[bot]@users.noreply.github.com>
> [!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](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

## Description

Replaces `review-rules.md` (flat 345-line checklist) with a dimensional
expert review agent. Single source of truth for all review rules,
organized into 30 dimensions for per-dimension sub-agent evaluation.
Adds inline file:line PR comments alongside the existing wall-of-text
summary.

Extracted from 28k review comments across 5 maintainers via
[extraction-pipeline](https://github.com/dotnet/fsharp/blob/main/.github/agents/extraction-pipeline.md).
No functional code changes.

Recreated from dotnet#35062 on a dotnet/maui branch (originally opened from a
fork).

## What changed

**Before:** `review-rules.md` had 345 lines of flat rules. `code-review`
skill loaded them all into one context. Output was a single wall-of-text
PR comment.

**After:** Rules absorbed into `maui-expert-reviewer.md` as 30
dimensions with 200+ CHECK items. Each dimension runs as an independent
sub-agent with focused context. Output is inline file:line PR comments
via `inline-findings.json`.

## CI Flow

```
Review-PR.ps1 prompt:
  1. code-review → maui-expert-reviewer agent → inline-findings.json
  2. pr-review → Pre-Flight → Try-Fix → Report (sees findings, no duplication)

Posting:
  post-inline-review.ps1    → .json → GitHub file:line comments (NEW)
  post-ai-summary-comment.ps1 → {phase}/content.md → wall-of-text (existing)

CI: COMMENTS_VIA_FILE=true → agent writes .json, script posts
Local: agent writes .json, code-review posts directly via gh api
```

## Files

| Action | File | What |
|--------|------|------|
| **Add** | `agents/maui-expert-reviewer.md` | 30 dimensions, 200+
CHECKs, routing table |
| **Add** | `instructions/collectionview-{android,ios,windows}` |
Platform-isolated CV rules |
| **Add** |
`instructions/{handler-patterns,layout-system,performance-hotpaths,public-api,threading-async}`
| Domain-specific ambient guidance |
| **Add** | `scripts/post-inline-review.ps1` | Posts .json as GitHub PR
review |
| **Del** | `skills/code-review/references/review-rules.md` | Absorbed
into agent |
| **Mod** | `skills/code-review/SKILL.md` | Delegates to agent |
| **Mod** | `scripts/Review-PR.ps1` | Prompt + inline posting wiring |
| **Mod** | `eng/pipelines/ci-copilot.yml` | `COMMENTS_VIA_FILE` env var
|

---------

Co-authored-by: kubaflo <kubaflo@users.noreply.github.com>
Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Tomas Grosup <tomasgrosup@microsoft.com>
kubaflo pushed a commit that referenced this pull request May 7, 2026
Adds Find-RegressionRisks.ps1 — a purely mechanical (no AI/LLM) script that
detects when a PR removes lines previously added by labeled bug-fix PRs.

Algorithm:
1. Collects lines removed by the PR under review
2. Finds recent PRs touching the same files via git log
3. Filters to bug-fix PRs (i/regression, t/bug, p/0, p/1 labels)
4. Cross-references removed lines against lines those fix PRs added
5. Whitespace-insensitive comparison classifies: REVERT / OVERLAP / CLEAN

Integration:
- Runs as STEP 0.6 in Review-PR.ps1 (between UI test detection and Gate)
- Content assembled into AI summary comment via post-ai-summary-comment.ps1
- Expert reviewer dimension #6 reads risks.json for REVERT entries
- 64 unit tests covering diff parsing, normalization, and detection logic

Validated against:
- PR #33908: correctly detects REVERT of IMauiRecyclerView check from #32278
- PR #35272: correctly classifies as OVERLAP (no line-level revert)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jeremy-visionaid jeremy-visionaid force-pushed the linq-enumerations branch 2 times, most recently from 439407f to 5e30ca1 Compare May 8, 2026 07:19
@jeremy-visionaid jeremy-visionaid marked this pull request as ready for review May 8, 2026 09:57
@dotnet dotnet deleted a comment from MauiBot May 8, 2026
@kubaflo kubaflo dismissed MauiBot’s stale review May 8, 2026 11:55

Resetting for re-review

@MauiBot

MauiBot commented May 8, 2026

Copy link
Copy Markdown
Collaborator

🤖 AI Summary

👋 @jeremy-visionaid — new AI review results are available. Please review the latest session below.

📊 Review Session5e30ca1 · Prefer LINQ Any to Where and Count · 2026-05-08 14:17 UTC
🚦 Gate — Test Before & After Fix

Gate Result: ❌ FAILED

Platform: ANDROID · Base: main · Merge base: b71adea6

Test Without Fix (expect FAIL) With Fix (expect PASS)
📱 Connectivity_Tests Connectivity_Tests ✅ FAIL — 764s ✅ PASS — 335s
🧪 BindableLayoutTests BindableLayoutTests ❌ PASS — 59s ✅ PASS — 25s
🔴 Without fix — 📱 Connectivity_Tests: FAIL ✅ · 764s

(truncated to last 15,000 chars)

 -> System.Threading.Tasks.Parallel.dll.so
  [44/129] Xamarin.AndroidX.Loader.dll -> Xamarin.AndroidX.Loader.dll.so
  [116/129] System.Threading.Tasks.dll -> System.Threading.Tasks.dll.so
  [117/129] System.Text.Json.dll -> System.Text.Json.dll.so
  [118/129] System.Threading.Thread.dll -> System.Threading.Thread.dll.so
  [45/129] Xamarin.AndroidX.Navigation.Common.Android.dll -> Xamarin.AndroidX.Navigation.Common.Android.dll.so
  [119/129] System.Threading.ThreadPool.dll -> System.Threading.ThreadPool.dll.so
  [120/129] System.Threading.dll -> System.Threading.dll.so
  [121/129] System.Xml.Linq.dll -> System.Xml.Linq.dll.so
  [46/129] Xamarin.AndroidX.Navigation.Fragment.dll -> Xamarin.AndroidX.Navigation.Fragment.dll.so
  [122/129] System.Xml.XDocument.dll -> System.Xml.XDocument.dll.so
  [123/129] System.Xml.ReaderWriter.dll -> System.Xml.ReaderWriter.dll.so
  [47/129] Xamarin.AndroidX.Navigation.Runtime.Android.dll -> Xamarin.AndroidX.Navigation.Runtime.Android.dll.so
  [124/129] System.dll -> System.dll.so
  [125/129] netstandard.dll -> netstandard.dll.so
  [48/129] Xamarin.AndroidX.Navigation.UI.dll -> Xamarin.AndroidX.Navigation.UI.dll.so
  [126/129] Mono.Android.Runtime.dll -> Mono.Android.Runtime.dll.so
  [49/129] Xamarin.AndroidX.RecyclerView.dll -> Xamarin.AndroidX.RecyclerView.dll.so
  [127/129] Java.Interop.dll -> Java.Interop.dll.so
  [50/129] Xamarin.AndroidX.SavedState.SavedState.Android.dll -> Xamarin.AndroidX.SavedState.SavedState.Android.dll.so
  [51/129] Xamarin.AndroidX.Security.SecurityCrypto.dll -> Xamarin.AndroidX.Security.SecurityCrypto.dll.so
  [52/129] Xamarin.AndroidX.SwipeRefreshLayout.dll -> Xamarin.AndroidX.SwipeRefreshLayout.dll.so
  [53/129] Xamarin.AndroidX.ViewPager.dll -> Xamarin.AndroidX.ViewPager.dll.so
  [54/129] Xamarin.AndroidX.ViewPager2.dll -> Xamarin.AndroidX.ViewPager2.dll.so
  [55/129] Xamarin.Google.Android.Material.dll -> Xamarin.Google.Android.Material.dll.so
  [56/129] Xamarin.Google.Crypto.Tink.Android.dll -> Xamarin.Google.Crypto.Tink.Android.dll.so
  [128/129] Mono.Android.dll -> Mono.Android.dll.so
  [57/129] Xamarin.Kotlin.StdLib.dll -> Xamarin.Kotlin.StdLib.dll.so
  [58/129] Xamarin.KotlinX.Coroutines.Core.Jvm.dll -> Xamarin.KotlinX.Coroutines.Core.Jvm.dll.so
  [59/129] Xamarin.KotlinX.Serialization.Core.Jvm.dll -> Xamarin.KotlinX.Serialization.Core.Jvm.dll.so
  [60/129] xunit.abstractions.dll -> xunit.abstractions.dll.so
  [61/129] xunit.assert.dll -> xunit.assert.dll.so
  [62/129] xunit.core.dll -> xunit.core.dll.so
  [63/129] xunit.execution.dotnet.dll -> xunit.execution.dotnet.dll.so
  [64/129] xunit.runner.utility.netcoreapp10.dll -> xunit.runner.utility.netcoreapp10.dll.so
  [65/129] System.Collections.Concurrent.dll -> System.Collections.Concurrent.dll.so
  [66/129] System.Collections.Immutable.dll -> System.Collections.Immutable.dll.so
  [67/129] System.Collections.NonGeneric.dll -> System.Collections.NonGeneric.dll.so
  [68/129] System.Collections.Specialized.dll -> System.Collections.Specialized.dll.so
  [69/129] System.Collections.dll -> System.Collections.dll.so
  [129/129] System.Private.CoreLib.dll -> System.Private.CoreLib.dll.so
  [70/129] System.ComponentModel.Primitives.dll -> System.ComponentModel.Primitives.dll.so
  [71/129] System.ComponentModel.TypeConverter.dll -> System.ComponentModel.TypeConverter.dll.so
  [72/129] System.ComponentModel.dll -> System.ComponentModel.dll.so
  [73/129] System.Console.dll -> System.Console.dll.so
  [74/129] System.Diagnostics.Debug.dll -> System.Diagnostics.Debug.dll.so
  [75/129] System.Diagnostics.DiagnosticSource.dll -> System.Diagnostics.DiagnosticSource.dll.so
  [76/129] System.Diagnostics.Process.dll -> System.Diagnostics.Process.dll.so
  [77/129] System.Diagnostics.Tools.dll -> System.Diagnostics.Tools.dll.so
  [78/129] System.Diagnostics.TraceSource.dll -> System.Diagnostics.TraceSource.dll.so
  [79/129] System.Diagnostics.Tracing.dll -> System.Diagnostics.Tracing.dll.so
  [80/129] System.Drawing.Primitives.dll -> System.Drawing.Primitives.dll.so
  [81/129] System.Drawing.dll -> System.Drawing.dll.so
  [82/129] System.Formats.Asn1.dll -> System.Formats.Asn1.dll.so
  [83/129] System.Globalization.dll -> System.Globalization.dll.so
  [84/129] System.IO.Compression.Brotli.dll -> System.IO.Compression.Brotli.dll.so
  [85/129] System.IO.Compression.dll -> System.IO.Compression.dll.so
  [86/129] System.IO.FileSystem.dll -> System.IO.FileSystem.dll.so
  [87/129] System.IO.Pipelines.dll -> System.IO.Pipelines.dll.so
  [88/129] System.IO.dll -> System.IO.dll.so
  [89/129] System.Linq.Expressions.dll -> System.Linq.Expressions.dll.so
  [90/129] System.Linq.dll -> System.Linq.dll.so
  [91/129] System.Memory.dll -> System.Memory.dll.so
  [92/129] System.Net.Http.dll -> System.Net.Http.dll.so
  [93/129] System.Net.NameResolution.dll -> System.Net.NameResolution.dll.so
  [94/129] System.Net.Primitives.dll -> System.Net.Primitives.dll.so
  [95/129] System.Net.Requests.dll -> System.Net.Requests.dll.so
  [96/129] System.Net.Sockets.dll -> System.Net.Sockets.dll.so
  [97/129] System.Numerics.Vectors.dll -> System.Numerics.Vectors.dll.so
  [98/129] System.ObjectModel.dll -> System.ObjectModel.dll.so
  [99/129] System.Private.Uri.dll -> System.Private.Uri.dll.so
  [100/129] System.Private.Xml.Linq.dll -> System.Private.Xml.Linq.dll.so
  [101/129] System.Private.Xml.dll -> System.Private.Xml.dll.so
  [102/129] System.Reflection.Extensions.dll -> System.Reflection.Extensions.dll.so
  [103/129] System.Reflection.TypeExtensions.dll -> System.Reflection.TypeExtensions.dll.so
  [104/129] System.Reflection.dll -> System.Reflection.dll.so
  [105/129] System.Runtime.Extensions.dll -> System.Runtime.Extensions.dll.so
  [106/129] System.Runtime.InteropServices.RuntimeInformation.dll -> System.Runtime.InteropServices.RuntimeInformation.dll.so
  [107/129] System.Runtime.InteropServices.dll -> System.Runtime.InteropServices.dll.so
  [108/129] System.Runtime.Loader.dll -> System.Runtime.Loader.dll.so
  [109/129] System.Runtime.Numerics.dll -> System.Runtime.Numerics.dll.so
  [110/129] System.Runtime.dll -> System.Runtime.dll.so
  [111/129] System.Security.Cryptography.dll -> System.Security.Cryptography.dll.so
  [112/129] System.Text.Encoding.dll -> System.Text.Encoding.dll.so
  [113/129] System.Text.Encodings.Web.dll -> System.Text.Encodings.Web.dll.so
  [114/129] System.Text.Json.dll -> System.Text.Json.dll.so
  [115/129] System.Text.RegularExpressions.dll -> System.Text.RegularExpressions.dll.so
  [116/129] System.Threading.Tasks.Parallel.dll -> System.Threading.Tasks.Parallel.dll.so
  [117/129] System.Threading.Tasks.dll -> System.Threading.Tasks.dll.so
  [118/129] System.Threading.Thread.dll -> System.Threading.Thread.dll.so
  [119/129] System.Threading.ThreadPool.dll -> System.Threading.ThreadPool.dll.so
  [120/129] System.Threading.dll -> System.Threading.dll.so
  [121/129] System.Xml.Linq.dll -> System.Xml.Linq.dll.so
  [122/129] System.Xml.ReaderWriter.dll -> System.Xml.ReaderWriter.dll.so
  [123/129] System.Xml.XDocument.dll -> System.Xml.XDocument.dll.so
  [124/129] System.dll -> System.dll.so
  [125/129] netstandard.dll -> netstandard.dll.so
  [126/129] Java.Interop.dll -> Java.Interop.dll.so
  [127/129] Mono.Android.Runtime.dll -> Mono.Android.Runtime.dll.so
  [128/129] Mono.Android.dll -> Mono.Android.dll.so
  [129/129] System.Private.CoreLib.dll -> System.Private.CoreLib.dll.so

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:08:01.94
[11.0.0-prerelease.26230.4+92962e5c46ac08a66ded4c5696209cc60f1a232f] XHarness command issued: android test --app /home/vsts/work/1/s/artifacts/bin/Essentials.DeviceTests/Release/net10.0-android/com.microsoft.maui.essentials.devicetests-Signed.apk --package-name com.microsoft.maui.essentials.devicetests --device-id emulator-5554 -o artifacts/log --timeout 01:00:00 -v --arg TestFilter=Connectivity_Tests
�[40m�[37mdbug�[39m�[22m�[49m: ADBRunner using ADB.exe supplied from /home/vsts/.nuget/packages/microsoft.dotnet.xharness.cli/11.0.0-prerelease.26230.4/tools/net10.0/any/../../../runtimes/any/native/adb/linux/adb
�[40m�[37mdbug�[39m�[22m�[49m: Full resolved path:'/home/vsts/.nuget/packages/microsoft.dotnet.xharness.cli/11.0.0-prerelease.26230.4/runtimes/any/native/adb/linux/adb'
�[40m�[32minfo�[39m�[22m�[49m: Will attempt to find device supporting architectures: 'arm64-v8a', 'x86_64'
�[40m�[37mdbug�[39m�[22m�[49m: Executing command: '/home/vsts/.nuget/packages/microsoft.dotnet.xharness.cli/11.0.0-prerelease.26230.4/runtimes/any/native/adb/linux/adb start-server'
�[40m�[37mdbug�[39m�[22m�[49m: 
�[40m�[32minfo�[39m�[22m�[49m: Finding attached devices/emulators...
�[40m�[37mdbug�[39m�[22m�[49m: Executing command: '/home/vsts/.nuget/packages/microsoft.dotnet.xharness.cli/11.0.0-prerelease.26230.4/runtimes/any/native/adb/linux/adb devices -l'
�[40m�[37mdbug�[39m�[22m�[49m: Found 1 possible devices
�[40m�[37mdbug�[39m�[22m�[49m: Evaluating output line for device serial: emulator-5554          device product:sdk_gphone_x86_64 model:sdk_gphone_x86_64 device:generic_x86_64_arm64 transport_id:1
�[40m�[37mdbug�[39m�[22m�[49m: Executing command: '/home/vsts/.nuget/packages/microsoft.dotnet.xharness.cli/11.0.0-prerelease.26230.4/runtimes/any/native/adb/linux/adb -s emulator-5554 shell getprop ro.product.cpu.abilist'
�[40m�[37mdbug�[39m�[22m�[49m: Found 1 possible devices. Using 'emulator-5554'
�[40m�[32minfo�[39m�[22m�[49m: Active Android device set to serial 'emulator-5554'
�[40m�[37mdbug�[39m�[22m�[49m: Executing command: '/home/vsts/.nuget/packages/microsoft.dotnet.xharness.cli/11.0.0-prerelease.26230.4/runtimes/any/native/adb/linux/adb -s emulator-5554 -s emulator-5554 shell getprop ro.product.cpu.abi'
�[40m�[37mdbug�[39m�[22m�[49m: Executing command: '/home/vsts/.nuget/packages/microsoft.dotnet.xharness.cli/11.0.0-prerelease.26230.4/runtimes/any/native/adb/linux/adb -s emulator-5554 -s emulator-5554 shell getprop ro.build.version.sdk'
�[40m�[32minfo�[39m�[22m�[49m: Waiting for device to be available (max 5 minutes)
�[40m�[37mdbug�[39m�[22m�[49m: Executing command: '/home/vsts/.nuget/packages/microsoft.dotnet.xharness.cli/11.0.0-prerelease.26230.4/runtimes/any/native/adb/linux/adb -s emulator-5554 wait-for-device'
�[40m�[37mdbug�[39m�[22m�[49m: Executing command: '/home/vsts/.nuget/packages/microsoft.dotnet.xharness.cli/11.0.0-prerelease.26230.4/runtimes/any/native/adb/linux/adb -s emulator-5554 -s emulator-5554 shell getprop sys.boot_completed'
�[40m�[37mdbug�[39m�[22m�[49m: sys.boot_completed = '1'
�[40m�[37mdbug�[39m�[22m�[49m: Waited 0 seconds for device boot completion
�[40m�[37mdbug�[39m�[22m�[49m: Working with emulator-5554 (API 30)
�[40m�[37mdbug�[39m�[22m�[49m: Check current adb install and/or package verification settings
�[40m�[37mdbug�[39m�[22m�[49m: Executing command: '/home/vsts/.nuget/packages/microsoft.dotnet.xharness.cli/11.0.0-prerelease.26230.4/runtimes/any/native/adb/linux/adb -s emulator-5554 shell settings get global verifier_verify_adb_installs'
�[40m�[37mdbug�[39m�[22m�[49m: verifier_verify_adb_installs = 0
�[40m�[37mdbug�[39m�[22m�[49m: Executing command: '/home/vsts/.nuget/packages/microsoft.dotnet.xharness.cli/11.0.0-prerelease.26230.4/runtimes/any/native/adb/linux/adb -s emulator-5554 shell settings get global package_verifier_enable'
�[40m�[37mdbug�[39m�[22m�[49m: package_verifier_enable = 
�[40m�[1m�[33mwarn�[39m�[22m�[49m: Installing debug apks on a device might be rejected with INSTALL_FAILED_VERIFICATION_FAILURE. Make sure to set 'package_verifier_enable' to '0'
�[40m�[32minfo�[39m�[22m�[49m: Attempting to remove apk 'com.microsoft.maui.essentials.devicetests'..
�[40m�[37mdbug�[39m�[22m�[49m: Executing command: '/home/vsts/.nuget/packages/microsoft.dotnet.xharness.cli/11.0.0-prerelease.26230.4/runtimes/any/native/adb/linux/adb -s emulator-5554 uninstall com.microsoft.maui.essentials.devicetests'
�[40m�[1m�[33mwarn�[39m�[22m�[49m: Hit broken pipe error; Will make one attempt to restart ADB server, and retry the uninstallation
�[40m�[37mdbug�[39m�[22m�[49m: Executing command: '/home/vsts/.nuget/packages/microsoft.dotnet.xharness.cli/11.0.0-prerelease.26230.4/runtimes/any/native/adb/linux/adb -s emulator-5554 kill-server'
�[40m�[37mdbug�[39m�[22m�[49m: Executing command: '/home/vsts/.nuget/packages/microsoft.dotnet.xharness.cli/11.0.0-prerelease.26230.4/runtimes/any/native/adb/linux/adb -s emulator-5554 start-server'
�[40m�[37mdbug�[39m�[22m�[49m: 
�[40m�[37mdbug�[39m�[22m�[49m: Executing command: '/home/vsts/.nuget/packages/microsoft.dotnet.xharness.cli/11.0.0-prerelease.26230.4/runtimes/any/native/adb/linux/adb -s emulator-5554 uninstall com.microsoft.maui.essentials.devicetests'
�[41m�[30mfail�[39m�[22m�[49m: Error: Exit code: 20
      Std out:
      
      
      Std err:
      - waiting for device -
      cmd: Can't find service: package
      
      
      
�[40m�[32minfo�[39m�[22m�[49m: Attempting to install /home/vsts/work/1/s/artifacts/bin/Essentials.DeviceTests/Release/net10.0-android/com.microsoft.maui.essentials.devicetests-Signed.apk
�[40m�[37mdbug�[39m�[22m�[49m: Executing command: '/home/vsts/.nuget/packages/microsoft.dotnet.xharness.cli/11.0.0-prerelease.26230.4/runtimes/any/native/adb/linux/adb -s emulator-5554 install /home/vsts/work/1/s/artifacts/bin/Essentials.DeviceTests/Release/net10.0-android/com.microsoft.maui.essentials.devicetests-Signed.apk'
�[41m�[30mfail�[39m�[22m�[49m: Error:
      Exit code: 1
      Std out:
      Serving...
      Performing Incremental Install
      cmd: Can't find service: package
      Performing Streamed Install
      
      
      Std err:
      adb: failed to install /home/vsts/work/1/s/artifacts/bin/Essentials.DeviceTests/Release/net10.0-android/com.microsoft.maui.essentials.devicetests-Signed.apk: cmd: Can't find service: package
      
      
      
�[41m�[1m�[37mcrit�[39m�[22m�[49m: Install failure: Test command cannot continue
�[40m�[32minfo�[39m�[22m�[49m: Attempting to remove apk 'com.microsoft.maui.essentials.devicetests'..
�[40m�[37mdbug�[39m�[22m�[49m: Executing command: '/home/vsts/.nuget/packages/microsoft.dotnet.xharness.cli/11.0.0-prerelease.26230.4/runtimes/any/native/adb/linux/adb -s emulator-5554 uninstall com.microsoft.maui.essentials.devicetests'
�[41m�[30mfail�[39m�[22m�[49m: Error: Exit code: 20
      Std out:
      
      
      Std err:
      cmd: Can't find service: package
      
      
      
�[40m�[32minfo�[39m�[22m�[49m: Attempting to remove apk 'com.microsoft.maui.essentials.devicetests'..
�[40m�[37mdbug�[39m�[22m�[49m: Executing command: '/home/vsts/.nuget/packages/microsoft.dotnet.xharness.cli/11.0.0-prerelease.26230.4/runtimes/any/native/adb/linux/adb -s emulator-5554 uninstall com.microsoft.maui.essentials.devicetests'
�[41m�[30mfail�[39m�[22m�[49m: Error: Exit code: 20
      Std out:
      
      
      Std err:
      cmd: Can't find service: package
      
      
      
XHarness exit code: 78 (PACKAGE_INSTALLATION_FAILURE)
  Tests completed with exit code: 78

🟢 With fix — 📱 Connectivity_Tests: PASS ✅ · 335s

(truncated to last 15,000 chars)

17791 17865 I DOTNET  : 	[PASS] Set_Get_Long_NonStatic
      05-08 08:21:27.271 17791 17865 I DOTNET  : 	[PASS] Set_Get_Long_NonStatic
      05-08 08:21:27.272 17791 17865 I DOTNET  : 	[PASS] Set_Set_Null_Get_String
      05-08 08:21:27.272 17791 17865 I DOTNET  : 	[PASS] Set_Set_Null_Get_String
      05-08 08:21:27.272 17791 17865 I DOTNET  : 	[PASS] Set_Get_DateTime
      05-08 08:21:27.272 17791 17865 I DOTNET  : 	[PASS] Set_Get_DateTime
      05-08 08:21:27.273 17791 17865 I DOTNET  : 	[PASS] Set_Get_Float_NonStatic
      05-08 08:21:27.274 17791 17865 I DOTNET  : 	[PASS] Set_Get_Float_NonStatic
      05-08 08:21:27.275 17791 17865 I DOTNET  : 	[PASS] Remove
      05-08 08:21:27.275 17791 17865 I DOTNET  : 	[PASS] Remove
      05-08 08:21:27.277 17791 17865 I DOTNET  : 	[PASS] Remove_Get_Long_NonStatic
      05-08 08:21:27.278 17791 17865 I DOTNET  : 	[PASS] Remove_Get_Long_NonStatic
      05-08 08:21:27.278 17791 17865 I DOTNET  : 	[PASS] Remove_NonStatic
      05-08 08:21:27.279 17791 17865 I DOTNET  : 	[PASS] Remove_NonStatic
      05-08 08:21:27.280 17791 17865 I DOTNET  : 	[PASS] Does_ContainsKey_NonStatic
      05-08 08:21:27.280 17791 17865 I DOTNET  : 	[PASS] Does_ContainsKey_NonStatic
      05-08 08:21:27.280 17791 17865 I DOTNET  : 	[PASS] Remove_Get_Bool_NonStatic
      05-08 08:21:27.281 17791 17865 I DOTNET  : 	[PASS] Remove_Get_Bool_NonStatic
      05-08 08:21:27.282 17791 17865 I DOTNET  : 	[PASS] Set_Get_Int_NonStatic
      05-08 08:21:27.283 17791 17865 I DOTNET  : 	[PASS] Set_Get_Int_NonStatic
      05-08 08:21:27.313 17791 17865 I DOTNET  : 	[PASS] DateTimeOffsetPreservesOffset_NonStatic
      05-08 08:21:27.314 17791 17865 I DOTNET  : 	[PASS] DateTimeOffsetPreservesOffset_NonStatic
      05-08 08:21:27.315 17791 17865 I DOTNET  : 	[PASS] Remove_Get_Int_NonStatic
      05-08 08:21:27.319 17791 17865 I DOTNET  : 	[PASS] Remove_Get_Int_NonStatic
      05-08 08:21:27.320 17791 17865 I DOTNET  : 	[PASS] Set_Get_String_NonStatic
      05-08 08:21:27.320 17791 17865 I DOTNET  : 	[PASS] Set_Get_String_NonStatic
      05-08 08:21:27.320 17791 17865 I DOTNET  : 	[PASS] Does_ContainsKey
      05-08 08:21:27.321 17791 17865 I DOTNET  : 	[PASS] Does_ContainsKey
      05-08 08:21:27.321 17791 17865 I DOTNET  : 	[PASS] Remove_Get_Int
      05-08 08:21:27.323 17791 17865 I DOTNET  : 	[PASS] Remove_Get_Int
      05-08 08:21:27.324 17791 17865 I DOTNET  : 	[PASS] Remove_Get_Float
      05-08 08:21:27.325 17791 17865 I DOTNET  : 	[PASS] Remove_Get_Float
      05-08 08:21:27.325 17791 17865 I DOTNET  : 	[PASS] Remove_Get_String_NonStatic
      05-08 08:21:27.326 17791 17865 I DOTNET  : 	[PASS] Remove_Get_String_NonStatic
      05-08 08:21:27.327 17791 17865 I DOTNET  : 	[PASS] Set_Get_Double_NonStatic
      05-08 08:21:27.328 17791 17865 I DOTNET  : 	[PASS] Set_Get_Double_NonStatic
      05-08 08:21:27.328 17791 17865 I DOTNET  : 	[PASS] Set_Get_Bool_NonStatic
      05-08 08:21:27.330 17791 17865 I DOTNET  : 	[PASS] Set_Get_Bool_NonStatic
      05-08 08:21:27.330 17791 17865 I DOTNET  : Microsoft.Maui.Essentials.DeviceTests.Preferences_Tests 0.1226778 ms
      05-08 08:21:27.530 17791 17879 I DOTNET  : 	[PASS] Remove_All_Keys
      05-08 08:21:27.610 17791 17884 I DOTNET  : 	[PASS] Remove_All_Keys
      05-08 08:21:31.174 17791 17893 I DOTNET  : 	[PASS] Set_Get_Remove_Async_MultipleTimes
      05-08 08:21:31.226 17791 17898 I DOTNET  : 	[PASS] Asymmetric_to_Symmetric_API_Upgrade
      05-08 08:21:31.240 17791 17898 I DOTNET  : 	[PASS] Non_Existent_Key_Returns_Null
      05-08 08:21:31.298 17791 17903 I DOTNET  : 	[PASS] Saves_Same_Key_Twice
      05-08 08:21:31.329 17791 17908 I DOTNET  : 	[PASS] Saves_And_Loads
      05-08 08:21:31.354 17791 17913 I DOTNET  : 	[PASS] Saves_And_Loads
      05-08 08:21:31.386 17791 17918 I DOTNET  : 	[PASS] Saves_And_Loads
      05-08 08:21:31.413 17791 17923 I DOTNET  : 	[PASS] Saves_And_Loads
      05-08 08:21:31.442 17791 17928 I DOTNET  : 	[PASS] Saves_And_Loads
      05-08 08:21:31.487 17791 17933 I DOTNET  : 	[PASS] Saves_And_Loads
      05-08 08:21:33.037 17791 17938 I DOTNET  : 	[PASS] Set_Get_Async_MultipleTimes
      05-08 08:21:33.170 17791 17943 I DOTNET  : 	[PASS] Fix_Corrupt_Data
      05-08 08:21:34.870 17791 17943 I DOTNET  : 	[PASS] Set_Get_Wait_MultipleTimes
      05-08 08:21:34.926 17791 17943 I DOTNET  : 	[PASS] Remove_Key
      05-08 08:21:34.959 17791 17943 I DOTNET  : 	[PASS] Remove_Key
      05-08 08:21:34.959 17791 17943 I DOTNET  : Microsoft.Maui.Essentials.DeviceTests.SecureStorage_Tests 7.5413996 ms
      05-08 08:21:34.959 17791 17943 I DOTNET  : Test collection for Microsoft.Maui.Essentials.DeviceTests.AppInfo_Tests
      05-08 08:21:34.961 17791 17943 I DOTNET  : 	[PASS] App_Versions_Are_Correct
      05-08 08:21:34.968 17791 17943 I DOTNET  : 	[PASS] App_RequestedLayoutDirection_Is_Correct
      05-08 08:21:34.968 17791 17943 I DOTNET  : 	[PASS] AppPackageName_Is_Correct
      05-08 08:21:34.968 17791 17943 I DOTNET  : 	[PASS] AppName_Is_Correct
      05-08 08:21:34.970 17791 17943 I DOTNET  : 	[PASS] App_Build_Is_Correct
      05-08 08:21:34.973 17791 17943 I DOTNET  : 	[PASS] App_Theme_Is_Correct
      05-08 08:21:34.974 17791 17943 I DOTNET  : Microsoft.Maui.Essentials.DeviceTests.AppInfo_Tests 0.0118872 ms
      05-08 08:21:34.974 17791 17943 I DOTNET  : Test collection for Microsoft.Maui.Essentials.DeviceTests.Compass_Tests
      05-08 08:21:35.040 17791 17952 I DOTNET  : 	[PASS] Stop_Monitor
      05-08 08:21:35.040 17791 17952 I DOTNET  : 	[PASS] IsSupported
      05-08 08:21:35.054 17791 17957 I DOTNET  : 	[PASS] IsMonitoring
      05-08 08:21:35.067 17791 17962 I DOTNET  : 	[PASS] Monitor
      05-08 08:21:35.067 17791 17962 I DOTNET  : Microsoft.Maui.Essentials.DeviceTests.Compass_Tests 0.0899893 ms
      05-08 08:21:35.067 17791 17962 I DOTNET  : Test collection for Microsoft.Maui.Essentials.DeviceTests.DeviceDisplay_Tests
      05-08 08:21:35.070 17791 17966 I DOTNET  : 	[PASS] Screen_Metrics_Are_Not_Null
      05-08 08:21:35.070 17791 17966 I DOTNET  : Microsoft.Maui.Essentials.DeviceTests.DeviceDisplay_Tests 0.0023903 ms
      05-08 08:21:35.070 17791 17966 I DOTNET  : Test collection for Microsoft.Maui.Essentials.DeviceTests.Launcher_Tests
      05-08 08:21:35.072 17791 17966 I DOTNET  : 	[PASS] InvalidUri
      05-08 08:21:35.074 17791 17966 I DOTNET  : 	[PASS] CanNotOpen
      05-08 08:21:35.076 17791 17966 I DOTNET  : 	[PASS] CanOpenUri
      05-08 08:21:35.079 17791 17966 I DOTNET  : 	[PASS] CanOpenUri
      05-08 08:21:35.081 17791 17966 I DOTNET  : 	[PASS] CanOpen
      05-08 08:21:35.083 17791 17966 I DOTNET  : 	[PASS] CanOpen
      05-08 08:21:35.084 17791 17966 I DOTNET  : 	[PASS] CanNotOpenUri
      05-08 08:21:35.084 17791 17966 I DOTNET  : Microsoft.Maui.Essentials.DeviceTests.Launcher_Tests 0.0104577 ms
      05-08 08:21:35.084 17791 17966 I DOTNET  : Test collection for Microsoft.Maui.Essentials.DeviceTests.Connectivity_Tests
      05-08 08:21:35.094 17791 17966 I DOTNET  : 	[PASS] Network_Access
      05-08 08:21:36.128 17791 17972 I DOTNET  : 	[PASS] ConnectivityChanged_Does_Not_Crash
      05-08 08:21:36.131 17791 17972 I DOTNET  : 	[PASS] Connection_Profiles
      05-08 08:21:36.134 17791 17972 I DOTNET  : 	[PASS] Test
      05-08 08:21:36.139 17791 17972 I DOTNET  : 	[PASS] Distict_Connection_Profiles
      05-08 08:21:36.139 17791 17972 I DOTNET  : Microsoft.Maui.Essentials.DeviceTests.Connectivity_Tests 1.0523485 ms
      05-08 08:21:36.139 17791 17972 I DOTNET  : Test collection for Microsoft.Maui.Essentials.DeviceTests.Gyroscope_Tests
      05-08 08:21:36.140 17791 17972 I DOTNET  : 	[PASS] IsSupported
      05-08 08:21:36.157 17791 17977 I DOTNET  : 	[PASS] Stop_Monitor
      05-08 08:21:36.167 17791 17982 I DOTNET  : 	[PASS] IsMonitoring
      05-08 08:21:36.170 17791 17987 I DOTNET  : 	[PASS] Monitor
      05-08 08:21:36.170 17791 17987 I DOTNET  : Microsoft.Maui.Essentials.DeviceTests.Gyroscope_Tests 0.0284213 ms
      05-08 08:21:36.170 17791 17987 I DOTNET  : Test collection for Microsoft.Maui.Essentials.DeviceTests.VersionTracking_Tests
      05-08 08:21:36.175 17791 17987 I DOTNET  : 	[PASS] First_Launch_For_Version
      05-08 08:21:36.175 17791 17987 I DOTNET  : 	[PASS] First_Launch_Ever
      05-08 08:21:36.176 17791 17987 I DOTNET  : 	[PASS] First_Launch_For_Build
      05-08 08:21:36.179 17791 17987 I DOTNET  : VersionTracking
      05-08 08:21:36.179 17791 17987 I DOTNET  :   IsFirstLaunchEver:              False
      05-08 08:21:36.179 17791 17987 I DOTNET  :   IsFirstLaunchForCurrentVersion: True
      05-08 08:21:36.179 17791 17987 I DOTNET  :   IsFirstLaunchForCurrentBuild:   False
      05-08 08:21:36.179 17791 17987 I DOTNET  : 
      05-08 08:21:36.179 17791 17987 I DOTNET  :   CurrentVersion:                 1.0
      05-08 08:21:36.179 17791 17987 I DOTNET  :   PreviousVersion:                1.0.3
      05-08 08:21:36.179 17791 17987 I DOTNET  :   FirstInstalledVersion:          1.0.2
      05-08 08:21:36.179 17791 17987 I DOTNET  :   VersionHistory:                 [1.0.2, 1.0.3, 1.0]
      05-08 08:21:36.179 17791 17987 I DOTNET  : 
      05-08 08:21:36.179 17791 17987 I DOTNET  :   CurrentBuild:                   1
      05-08 08:21:36.179 17791 17987 I DOTNET  :   PreviousBuild:                  20
      05-08 08:21:36.179 17791 17987 I DOTNET  :   FirstInstalledBuild:            10
      05-08 08:21:36.179 17791 17987 I DOTNET  :   BuildHistory:                   [10, 20, 1]
      05-08 08:21:36.179 17791 17987 I DOTNET  : 
      05-08 08:21:36.179 17791 17987 I DOTNET  : 	[PASS] First_Launch_After_Downgrade
      05-08 08:21:36.180 17791 17987 I DOTNET  : VersionTracking
      05-08 08:21:36.180 17791 17987 I DOTNET  :   IsFirstLaunchEver:              False
      05-08 08:21:36.180 17791 17987 I DOTNET  :   IsFirstLaunchForCurrentVersion: False
      05-08 08:21:36.180 17791 17987 I DOTNET  :   IsFirstLaunchForCurrentBuild:   True
      05-08 08:21:36.180 17791 17987 I DOTNET  : 
      05-08 08:21:36.180 17791 17987 I DOTNET  :   CurrentVersion:                 1.0
      05-08 08:21:36.180 17791 17987 I DOTNET  :   PreviousVersion:                
      05-08 08:21:36.180 17791 17987 I DOTNET  :   FirstInstalledVersion:          1.0
      05-08 08:21:36.180 17791 17987 I DOTNET  :   VersionHistory:                 [1.0]
      05-08 08:21:36.180 17791 17987 I DOTNET  : 
      05-08 08:21:36.180 17791 17987 I DOTNET  :   CurrentBuild:                   1
      05-08 08:21:36.180 17791 17987 I DOTNET  :   PreviousBuild:                  20
      05-08 08:21:36.180 17791 17987 I DOTNET  :   FirstInstalledBuild:            10
      05-08 08:21:36.180 17791 17987 I DOTNET  :   BuildHistory:                   [10, 20, 1]
      05-08 08:21:36.180 17791 17987 I DOTNET  : 
      05-08 08:21:36.180 17791 17987 I DOTNET  : 	[PASS] First_Launch_After_Build_Downgrade
      05-08 08:21:36.180 17791 17987 I DOTNET  : Microsoft.Maui.Essentials.DeviceTests.VersionTracking_Tests 0.0087194 ms
      05-08 08:21:36.180 17791 17987 I DOTNET  : Test collection for Microsoft.Maui.Essentials.DeviceTests.AppActions_Tests
      05-08 08:21:36.210 17791 17987 I DOTNET  : 	[PASS] GetSetItems
      05-08 08:21:36.211 17791 17987 I DOTNET  : 	[PASS] IsSupported
      05-08 08:21:36.211 17791 17987 I DOTNET  : Microsoft.Maui.Essentials.DeviceTests.AppActions_Tests 0.0298029 ms
      05-08 08:21:36.211 17791 17987 I DOTNET  : Test collection for Microsoft.Maui.Essentials.DeviceTests.Accelerometer_Tests
      05-08 08:21:36.278 17791 17993 I DOTNET  : 	[PASS] Stop_Monitor
      05-08 08:21:36.287 17791 17998 I DOTNET  : 	[PASS] IsMonitoring
      05-08 08:21:36.287 17791 17998 I DOTNET  : 	[PASS] IsSupported
      05-08 08:21:36.294 17791 18003 I DOTNET  : 	[PASS] Monitor
      05-08 08:21:36.294 17791 18003 I DOTNET  : Microsoft.Maui.Essentials.DeviceTests.Accelerometer_Tests 0.0807847 ms
      05-08 08:21:36.294 17791 18003 I DOTNET  : Test collection for Microsoft.Maui.Essentials.DeviceTests.HapticFeedback_Tests
      05-08 08:21:36.327 17791 18003 I DOTNET  : 	[PASS] LongPress
      05-08 08:21:36.328 17791 18003 I DOTNET  : 	[PASS] Click
      05-08 08:21:36.329 17791 18003 I DOTNET  : Microsoft.Maui.Essentials.DeviceTests.HapticFeedback_Tests 0.0339739 ms
      05-08 08:21:36.329 17791 18003 I DOTNET  : Test collection for Microsoft.Maui.Essentials.DeviceTests.Battery_Tests
      05-08 08:21:37.338 17791 18011 I DOTNET  : 	[PASS] EnergySaverStatusChanged_Does_Not_Crash
      05-08 08:21:37.343 17791 18011 I DOTNET  : 	[PASS] Charge_State
      05-08 08:21:37.347 17791 18011 I DOTNET  : 	[PASS] Charge_Level
      05-08 08:21:37.353 17791 18011 I DOTNET  : 	[PASS] Charge_Power
      05-08 08:21:37.356 17791 18011 I DOTNET  : 	[PASS] Unsubscribe_BatteryInfoChanged_Does_Not_Crash
      05-08 08:21:37.360 17791 18011 I DOTNET  : 	[PASS] App_Is_Not_Lower_Power_mode
      05-08 08:21:38.370 17791 18016 I DOTNET  : 	[PASS] BatteryInfoChanged_Does_Not_Crash
      05-08 08:21:38.370 17791 18016 I DOTNET  : Microsoft.Maui.Essentials.DeviceTests.Battery_Tests 2.0339208 ms
      05-08 08:21:38.370 17791 18016 I DOTNET  : Test collection for Microsoft.Maui.Essentials.DeviceTests.Barometer_Tests
      05-08 08:21:38.371 17791 18016 I DOTNET  : 	[PASS] IsSupported
      05-08 08:21:38.445 17791 18021 I DOTNET  : 	[PASS] Monitor
      05-08 08:21:38.510 17791 18026 I DOTNET  : 	[PASS] IsMonitoring
      05-08 08:21:38.515 17791 18031 I DOTNET  : 	[PASS] Stop_Monitor
      05-08 08:21:38.515 17791 18031 I DOTNET  : Microsoft.Maui.Essentials.DeviceTests.Barometer_Tests 0.1431987 ms
      05-08 08:21:38.550 17791 17885 I DOTNET  : Xml file was written to the provided writer.
      05-08 08:21:38.550 17791 17885 I DOTNET  : Tests run: 297 Passed: 267 Inconclusive: 0 Failed: 0 Ignored: 30
�[40m�[32minfo�[39m�[22m�[49m: <<XHARNESS_RESULT_START>>
      {
        "version": 1,
        "machineName": "runnervmfz4j5",
        "exitCode": 0,
        "exitCodeName": "SUCCESS",
        "platform": "android",
        "instrumentationExitCode": 0,
        "device": "emulator-5554",
        "deviceOsVersion": "API 30",
        "architecture": "x86_64",
        "files": [
          {
            "name": "testResults.xml",
            "type": "test-results"
          },
          {
            "name": "adb-logcat-com.microsoft.maui.essentials.devicetests-default.log",
            "type": "logcat"
          }
        ]
      }
      <<XHARNESS_RESULT_END>>
�[40m�[32minfo�[39m�[22m�[49m: Attempting to remove apk 'com.microsoft.maui.essentials.devicetests'..
�[40m�[37mdbug�[39m�[22m�[49m: Executing command: '/home/vsts/.nuget/packages/microsoft.dotnet.xharness.cli/11.0.0-prerelease.26230.4/runtimes/any/native/adb/linux/adb -s emulator-5554 uninstall com.microsoft.maui.essentials.devicetests'
�[40m�[32minfo�[39m�[22m�[49m: Successfully uninstalled com.microsoft.maui.essentials.devicetests
XHarness exit code: 0
  Tests completed successfully

🔴 Without fix — 🧪 BindableLayoutTests: PASS ❌ · 59s
  Determining projects to restore...
  Restored /home/vsts/work/1/s/src/Controls/src/BindingSourceGen/Controls.BindingSourceGen.csproj (in 1.25 sec).
  Restored /home/vsts/work/1/s/src/Controls/src/Core/Controls.Core.csproj (in 1.4 sec).
  Restored /home/vsts/work/1/s/src/Controls/src/Xaml/Controls.Xaml.csproj (in 171 ms).
  Restored /home/vsts/work/1/s/src/TestUtils/src/TestUtils/TestUtils.csproj (in 161 ms).
  Restored /home/vsts/work/1/s/src/Graphics/src/Graphics/Graphics.csproj (in 35 ms).
  Restored /home/vsts/work/1/s/src/Essentials/src/Essentials.csproj (in 52 ms).
  Restored /home/vsts/work/1/s/src/Core/src/Core.csproj (in 137 ms).
  Restored /home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Controls.Core.UnitTests.csproj (in 1.26 sec).
  2 of 10 projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14048608
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14048608
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14048608
  Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0/Microsoft.Maui.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14048608
  Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14048608
  Maps -> /home/vsts/work/1/s/artifacts/bin/Maps/Debug/net10.0/Microsoft.Maui.Maps.dll
  Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14048608
  Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0/Microsoft.Maui.Controls.Xaml.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14048608
  Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0/Microsoft.Maui.Controls.Maps.dll
  TestUtils -> /home/vsts/work/1/s/artifacts/bin/TestUtils/Debug/netstandard2.0/Microsoft.Maui.TestUtils.dll
  Controls.Core.UnitTests -> /home/vsts/work/1/s/artifacts/bin/Controls.Core.UnitTests/Debug/net10.0/Microsoft.Maui.Controls.Core.UnitTests.dll
Test run for /home/vsts/work/1/s/artifacts/bin/Controls.Core.UnitTests/Debug/net10.0/Microsoft.Maui.Controls.Core.UnitTests.dll (.NETCoreApp,Version=v10.0)
VSTest version 18.0.1 (x64)

Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v2.8.2+699d445a1a (64-bit .NET 10.0.0)
[xUnit.net 00:00:00.24]   Discovering: Microsoft.Maui.Controls.Core.UnitTests
[xUnit.net 00:00:02.46]   Discovered:  Microsoft.Maui.Controls.Core.UnitTests
[xUnit.net 00:00:02.47]   Starting:    Microsoft.Maui.Controls.Core.UnitTests
  Passed LayoutIsGarbageCollectedAfterItsRemoved [189 ms]
  Passed ItemTemplateSelectorIsSet [14 ms]
  Passed ChangingTemplateRecreatesChildren [9 ms]
  Passed ChangingItemsRemovesExceedingChildren [2 ms]
  Passed TracksRemove [3 ms]
  Passed TracksInsert [1 ms]
  Passed ChangingItemMaintainingTemplateUpdatesBindingContextOnly [8 ms]
  Passed AddsEmptyViewWhenRemovingRemainingItem [6 ms]
  Passed ItemViewBindingContextIsSetToNullOnClear [1 ms]
  Passed ItemsSourceTakePrecendenceOverLayoutChildren [< 1 ms]
  Passed WorksWithDuplicateItems [1 ms]
  Passed TracksReplace [< 1 ms]
  Passed BindableLayout Still Updates after a GC [30 ms]
  Passed DontTrackAfterItemsSourceChanged [1 ms]
  Passed TracksClear [2 ms]
  Passed ThrowsExceptionOnUsingDataTemplateSelectorForItemTemplate [1 ms]
  Passed DoesNotLeak [52 ms]
  Passed ChangingItemsMaintainingTemplateUpdatesBindingContextOnly [3 ms]
  Passed TracksMove [< 1 ms]
  Passed WorksWithNullItems [10 ms]
  Passed ItemViewBindingContextIsSetToNullOnRemove [< 1 ms]
  Passed ValidateBindableProperties [10 ms]
  Passed ItemTemplateTakesPrecendenceOverItemTemplateSelector [6 ms]
  Passed ContainerIsPassedInSelectTemplate [1 ms]
  Passed TracksRemoveAll [1 ms]
  Passed EmptyViewTemplateContentInheritsLayoutBindingContext [1 ms]
  Passed RemovesEmptyViewWhenAddingTheFirstItem [< 1 ms]
[xUnit.net 00:00:03.03]   Finished:    Microsoft.Maui.Controls.Core.UnitTests
  Passed TracksEmpty [< 1 ms]
  Passed TracksAdd [< 1 ms]
  Passed BindableLayout disconnects handlers when removing views [84 ms]
  Passed TracksNull [< 1 ms]
  Passed ItemTemplateIsSet [1 ms]

Test Run Successful.
Total tests: 32
     Passed: 32
 Total time: 3.8414 Seconds

🟢 With fix — 🧪 BindableLayoutTests: PASS ✅ · 25s
  Determining projects to restore...
  Restored /home/vsts/work/1/s/src/Graphics/src/Graphics/Graphics.csproj (in 892 ms).
  Restored /home/vsts/work/1/s/src/Essentials/src/Essentials.csproj (in 892 ms).
  Restored /home/vsts/work/1/s/src/Core/src/Core.csproj (in 319 ms).
  Restored /home/vsts/work/1/s/src/Controls/src/Xaml/Controls.Xaml.csproj (in 430 ms).
  Restored /home/vsts/work/1/s/src/Controls/src/Core/Controls.Core.csproj (in 91 ms).
  Restored /home/vsts/work/1/s/src/Controls/src/BindingSourceGen/Controls.BindingSourceGen.csproj (in 58 ms).
  4 of 10 projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14048608
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14048608
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14048608
  Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0/Microsoft.Maui.dll
  Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14048608
  Maps -> /home/vsts/work/1/s/artifacts/bin/Maps/Debug/net10.0/Microsoft.Maui.Maps.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14048608
  Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14048608
  Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0/Microsoft.Maui.Controls.Xaml.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14048608
  Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0/Microsoft.Maui.Controls.Maps.dll
  TestUtils -> /home/vsts/work/1/s/artifacts/bin/TestUtils/Debug/netstandard2.0/Microsoft.Maui.TestUtils.dll
  Controls.Core.UnitTests -> /home/vsts/work/1/s/artifacts/bin/Controls.Core.UnitTests/Debug/net10.0/Microsoft.Maui.Controls.Core.UnitTests.dll
Test run for /home/vsts/work/1/s/artifacts/bin/Controls.Core.UnitTests/Debug/net10.0/Microsoft.Maui.Controls.Core.UnitTests.dll (.NETCoreApp,Version=v10.0)
VSTest version 18.0.1 (x64)

Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v2.8.2+699d445a1a (64-bit .NET 10.0.0)
[xUnit.net 00:00:00.47]   Discovering: Microsoft.Maui.Controls.Core.UnitTests
[xUnit.net 00:00:03.70]   Discovered:  Microsoft.Maui.Controls.Core.UnitTests
[xUnit.net 00:00:03.73]   Starting:    Microsoft.Maui.Controls.Core.UnitTests
  Passed LayoutIsGarbageCollectedAfterItsRemoved [290 ms]
  Passed ItemTemplateSelectorIsSet [30 ms]
  Passed ChangingTemplateRecreatesChildren [16 ms]
  Passed ChangingItemsRemovesExceedingChildren [5 ms]
  Passed TracksRemove [6 ms]
  Passed TracksInsert [1 ms]
  Passed ChangingItemMaintainingTemplateUpdatesBindingContextOnly [16 ms]
  Passed AddsEmptyViewWhenRemovingRemainingItem [12 ms]
  Passed ItemViewBindingContextIsSetToNullOnClear [< 1 ms]
  Passed ItemsSourceTakePrecendenceOverLayoutChildren [< 1 ms]
  Passed WorksWithDuplicateItems [3 ms]
  Passed TracksReplace [< 1 ms]
  Passed BindableLayout Still Updates after a GC [78 ms]
  Passed DontTrackAfterItemsSourceChanged [1 ms]
  Passed TracksClear [8 ms]
  Passed ThrowsExceptionOnUsingDataTemplateSelectorForItemTemplate [1 ms]
  Passed DoesNotLeak [74 ms]
  Passed ChangingItemsMaintainingTemplateUpdatesBindingContextOnly [4 ms]
  Passed TracksMove [2 ms]
  Passed WorksWithNullItems [13 ms]
  Passed ItemViewBindingContextIsSetToNullOnRemove [2 ms]
  Passed ValidateBindableProperties [9 ms]
  Passed ItemTemplateTakesPrecendenceOverItemTemplateSelector [5 ms]
  Passed ContainerIsPassedInSelectTemplate [3 ms]
  Passed TracksRemoveAll [3 ms]
  Passed EmptyViewTemplateContentInheritsLayoutBindingContext [3 ms]
  Passed RemovesEmptyViewWhenAddingTheFirstItem [< 1 ms]
[xUnit.net 00:00:04.70]   Finished:    Microsoft.Maui.Controls.Core.UnitTests
  Passed TracksEmpty [< 1 ms]
  Passed TracksAdd [< 1 ms]
  Passed BindableLayout disconnects handlers when removing views [185 ms]
  Passed TracksNull [< 1 ms]
  Passed ItemTemplateIsSet [1 ms]

Test Run Successful.
Total tests: 32
     Passed: 32
 Total time: 6.0887 Seconds

⚠️ Failure Details

  • BindableLayoutTests PASSED without fix (should fail) — tests don't catch the bug
📁 Fix files reverted (6 files)
  • src/Compatibility/Core/src/Android/Renderers/SwipeViewRenderer.cs
  • src/Compatibility/Core/src/iOS/EventTracker.cs
  • src/Compatibility/Core/src/iOS/Renderers/SwipeViewRenderer.cs
  • src/Essentials/src/FilePicker/FilePicker.tizen.cs
  • src/Essentials/src/MediaPicker/MediaPicker.tizen.cs
  • src/SingleProject/Resizetizer/src/GenerateTizenManifest.cs

🧪 UI Tests — Category Detection

Detected UI test categories: Essentials

🧪 UI Test Execution Results

PASSED — 1 passed, 0 failed, 0 skipped (platform: android)

Category Result Tests Duration Notes
Essentials ✅ PASSED 0/1 ✓ 695.2s

Failures here are informational only — they do not block the gate or affect try-fix candidate scoring.


🔍 Regression Cross-Reference

🔍 Regression Cross-Reference

🟢 No regression risks detected. No labeled bug-fix PRs in the last 6 months touched the modified files.


🔍 Pre-Flight — Context & Validation

Issue: none — no issue linked
PR: #35272 — Avoid unnecessary LINQ enumerations
Author: @jeremy-visionaid (community ✨)
Base: main · Head: linq-enumerations
Platforms Affected: Android, iOS/MacCatalyst, Tizen, cross-platform (Compatibility, Essentials, Resizetizer, TestUtils, unit/device tests)
Files Changed: 8 implementation/test-utility, 1 unit test (BindableLayoutTests.cs) and 1 device test (Connectivity_Tests.cs) — total 9 files, +10/-11

Key Findings

  • Pure CA1827 cleanup ("Don't use Count()/LongCount() when Any() can be used"). Each hunk replaces a LINQ enumeration anti-pattern with the semantically-equivalent short-circuit form:
    • coll.Where(p).Count() > 0coll.Any(p)
    • coll.Where(p).Count() == 0!coll.Any(p)
    • coll.Count() > 0coll.Any()
    • coll.Count() == 0coll.Count == 0 (when the source exposes a collection Count property — BindableLayoutTests.cs uses InternalChildren which is IList<Element>)
  • All hunks preserve original semantics. Any(p) short-circuits on the first match instead of materialising the full filtered sequence, so the changes are also a small perf win for hot paths (e.g., IsValidSwipeItems in the Compatibility renderers, called from gesture/touch handlers).
  • Test changes are not regression tests. BindableLayoutTests.IsLayoutWithItemsSource and Connectivity_Tests.Connection_Profiles were modernised in lockstep with the production change. Both Count() == 0 and Count == 0 (or .Count() > 0 and .Any()) return the same result on the same collection, so neither test will catch a behavioural regression — they exist purely to keep the test suite warning-free.
  • No public API changes. Diff is internal-only; nothing in PublicAPI.Unshipped.txt. No new types, no new members, no signature changes.
  • No platform partial-class concerns. Edits are inside platform-specific files but each one is self-contained (a single method/expression). No threading, lifecycle, or handler ConnectHandler/DisconnectHandler implications.
  • One Android tweak in AssertionExtensions.Android.cs (GetTab helper) — strictly test infrastructure, used by device tests for BottomNavigationItemView lookups. Wraps a String.Equals(..., OrdinalIgnoreCase) predicate inside .Any(...).
  • iOS EventTracker.cs change uses ?.…Any() == true to preserve the original null-conditional / Count() > 0 truthiness — equivalent to ?.…Count() > 0 when the LHS may be null. ✅
  • Resizetizer/GenerateTizenManifest.cs works on IEnumerable<XElement> returned from Descendants(...).Where(...), so .Any() is the canonical fix; collection-Count optimisation does not apply.

Code Review Summary

Verdict: PENDING — code-review sub-agent running in background; see pre-flight/code-review.md once it completes.
Confidence: PENDING
Errors: PENDING | Warnings: PENDING | Suggestions: PENDING

(Updated post-hoc when sub-agent returns.)

Gate

❌ FAILED — but the failure is expected for this kind of refactor: the modified tests cannot detect a behavioural regression on the broken baseline because the new and old expressions evaluate identically on the same collection. See gate/content.md for the raw test output. This is a known limitation of using gate with style-only PRs and does not indicate a code defect.

Fix Candidates

# Source Approach Test Result Files Changed Notes
PR PR #35272 Replace .Where(p).Count() > 0 / Count() == 0 patterns with .Any(p) / !.Any(p) (and one IList.Count == 0 swap) ⏳ Gate inconclusive (see above) 9 files, +10/-11 Original PR — pure CA1827 cleanup, no behavioural change

🔬 Code Review — Deep Analysis

Code Review — PR #35272

Independent Assessment

What this changes: Across 9 files (8 C# source/test files + 1 Tizen target), this PR replaces inefficient LINQ patterns with their idiomatic equivalents:

  • enumerable.Where(pred).Count() > 0enumerable.Any(pred) (5 sites)
  • enumerable.Count() > 0enumerable.Any() (3 sites)
  • enumerable.Count() == 0!enumerable.Any() (1 site)
  • iCollection.Count() == 0iCollection.Count == 0 (1 site, in BindableLayoutTests.cs — uses the ICollection.Count property instead of the Enumerable.Count() extension)
  • One nullable-chain conversion: childGestures?.GetChildGesturesFor<...>(...).Count() > 0childGestures?.GetChildGesturesFor<...>(...).Any() == true in EventTracker.cs. Both expressions yield false when the receiver is null and true only when the sequence has at least one matching element, so behaviour is preserved.

No public API surface changes. No threading semantics affected. No changes to predicates themselves. No platform-specific behaviour changes — just a switch from "materialize the count of all matches" to "stop at the first match."

Inferred motivation: Cleanup of CA1827 (DoNotUseCountWhenAnyCanBeUsed) and CA1829 (UseCountProperty) analyzer warnings. These analyzer rules exist because:

  1. Where(pred).Count() > 0 enumerates the entire source and allocates a WhereEnumerableIterator; Any(pred) short-circuits at the first match.
  2. Count() on an ICollection<T> walks through Enumerable.Count()'s type-check fast path, but using the Count property directly avoids the extension-method call entirely.

These are micro-optimisations, but they're also the canonical idiomatic forms in modern .NET, so the cleanup improves readability and removes analyzer noise.

Reconciliation with PR Narrative

Author claims: "Avoid unnecessary LINQ enumerations" / "Mostly fixes CA1827 warnings."

Agreement/disagreement: Fully agree. The author's framing is accurate and modest — every change matches one of the CA1827/CA1829 patterns. There are no hidden behavioural changes or scope creep.

Findings

No findings.

Each replacement was checked for semantic equivalence against the original:

File Change Notes
src/Compatibility/Core/src/Android/Renderers/SwipeViewRenderer.cs:424 Where(...).Count() > 0Any(pred) Equivalent. Short-circuits.
src/Compatibility/Core/src/iOS/EventTracker.cs:175 ?.X.Count() > 0?.X.Any() == true Equivalent. Both yield false when childGestures is null (lifted > returns false for null operand; ?. propagates null and null == true is false).
src/Compatibility/Core/src/iOS/Renderers/SwipeViewRenderer.cs:428 Where(...).Count() > 0Any(pred) Equivalent.
src/Compatibility/Core/src/iOS/Renderers/SwipeViewRenderer.cs:1560 Where(...).Count() == 0!Any(pred) Equivalent.
src/Controls/tests/Core.UnitTests/BindableLayoutTests.cs:733 InternalChildren.Count() == 0InternalChildren.Count == 0 CA1829 — uses ICollection.Count property. CI green confirms InternalChildren exposes Count.
src/Essentials/src/FilePicker/FilePicker.tizen.cs:37 ExtraData.Count() > 0ExtraData.Any() Equivalent. Tizen-only.
src/Essentials/src/MediaPicker/MediaPicker.tizen.cs:56 ExtraData.Count() > 0ExtraData.Any() Equivalent. Tizen-only.
src/Essentials/test/DeviceTests/Tests/Connectivity_Tests.cs:17 ConnectionProfiles.Count() > 0ConnectionProfiles.Any() Equivalent. Test-only.
src/SingleProject/Resizetizer/src/GenerateTizenManifest.cs:176 splashElements.Count() == 0!splashElements.Any() Equivalent. Build-time tooling.
src/TestUtils/src/DeviceTests/AssertionExtensions.Android.cs:714 Where(...).Count() > 0Any(pred) Equivalent. Test infrastructure.

Devil's Advocate

I challenged each finding I could think of and discarded all of them:

  1. Could enumeration side effects matter? Where(...).Count() enumerates the entire source; Any(pred) stops at the first match. None of the predicates here have side effects (all are pure property reads: s.IsVisible, x.NumberOfTapsRequired == ..., String.Equals(tv.Text, ...)). No observable difference.
  2. Could InternalChildren.Count (property) and InternalChildren.Count() (LINQ) ever differ? Only if InternalChildren overrode the Count property in a non-conformant way. It doesn't — it's a stock ObservableCollection-like collection, and CI passes. Safe.
  3. Could the ?.X.Any() == true rewrite swallow a null where the original threw? No — both forms propagate the null and produce false. Neither throws when childGestures is null.
  4. Could Tizen build paths regress? Tizen TFMs aren't part of the standard MAUI build matrix today, but the changes are simple and IEnumerable<T>.Any() is stable framework API. No risk.
  5. Could a similar pattern have been missed in the same files? Possible — but that's scope creep, not a defect. The author's title says "Mostly fixes CA1827", acknowledging incrementality.
  6. Local diff noise: The locally-squashed branch contains a regenerated HybridWebView.js that is NOT part of the actual PR (verified with gh pr diff 35272 --name-only). This appears to be an artifact of the local squash and is out of scope for this review.

Verdict: LGTM

Confidence: high

Summary: Pure CA1827/CA1829 analyzer cleanup across 9 files, ~21 lines. Every replacement is semantically equivalent to the original (verified case-by-case, including the nullable-chain rewrite in EventTracker.cs), readability is improved, and full CI (maui-pr) is green. Nothing to flag.


🔧 Fix — Analysis & Comparison

Try-Fix Aggregate — PR #35272

Phase 2 ran four independent fix candidates with different reviewer-dimension lenses, then collapsed cross-pollination because each lens addressed an orthogonal axis.

Fix Candidates

# Source Model Reviewer dimension Approach Test Result Files Changed Notes
PR PR #35272 Replace .Where(p).Count() > 0 / .Count() == 0 patterns with .Any(p) / !.Any(p) (and one IList.Count == 0 swap) Gate inconclusive — equivalent expressions on both sides of the broken-baseline test 9 Original PR — pure CA1827 cleanup
pr-plus-reviewer code-review skill claude (skill default) All 30 reviewer dimensions Identical to PR — reviewer returned LGTM with 0 findings Identical to PR 9 See expert-pr-eval/content.md
try-fix-1 try-fix skill claude-opus-4.6 Performance / hot-path allocations Replace IsValidSwipeItems LINQ with allocation-free for loops over SwipeItems.Count + indexer (the receiver type is ObservableCollection<ISwipeItem>) ✅ Pass — Connectivity_Tests.Connection_Profiles passed on android 2 (only the two SwipeViewRenderer files) Better than PR for the gesture hot path, but partial — does NOT address the other 7 CA1827 sites
try-fix-2 try-fix skill claude-sonnet-4.6 Test Quality / Coverage PR's .Any() swap in production + Assert.NotEmpty(Connectivity.ConnectionProfiles) (idiomatic xUnit) in Connectivity_Tests.cs ✅ Pass — 267/267 device tests 7 Better failure diagnostics than Assert.True(... .Any())
try-fix-3 try-fix skill gpt-5.3-codex API Design / Idiomatic .NET PR's .Any() swap + is true / is null patterns instead of ?.… == true + string.Equals (lowercase) ✅ Pass 7 Idiom polish; cosmetic but consistent with modern .NET style
try-fix-4 try-fix skill gpt-5.5 (gemini-3-pro-preview unavailable) Regression Prevention / Analyzer Strategy PR's .Any() swap (full 9-file scope) plus dotnet_diagnostic.CA1827.severity = warning in root .editorconfig, after empirical scan confirmed no other CA1827 violations remain ✅ Pass — 297 run / 267 passed / 0 failed / 30 ignored 7 + .editorconfig Strongest structural fix — addresses the cause (analyzer disabled) not just the symptom; safe at warning severity given clean scan; preserves all PR value

All four try-fix attempts ran the same Android device-test harness against Connectivity_Tests.Connection_Profiles (the only test in the PR's modified set that exercises a runtime path). All four ✅ passed.

Cross-Pollination

Round Action Outcome
1 Independent exploration with 4 reviewer dimensions All four candidates passed; each addresses an orthogonal concern (perf / test idiom / API idiom / structural prevention)
2 Combination synthesis The dimensions are non-overlapping: a stack-up of try-fix-1 + try-fix-2 + try-fix-3 + try-fix-4 would be the theoretical maximum, but combining all four into a single PR is scope creep that is unlikely to be accepted on a community contributor's "avoid unnecessary LINQ enumerations" cleanup. The orchestrator declines to fabricate a 5th composite candidate and recommends the strongest individual structural candidate.

Exhausted: Yes (orthogonal dimensions all pass; no new ideas not already represented).

Selected Fix

try-fix-4 — PR's full mechanical CA1827 cleanup plus root .editorconfig analyzer enforcement at warning severity.

Rationale:

  1. Passes the runtime test (Android device tests, 267/267).
  2. Includes 100% of the PR's value — the 7 production files are modified verbatim like the PR.
  3. Adds permanent regression guard — without enabling CA1827, the same 9 violations will re-accumulate over time. The agent verified by static scan that no other CA1827 violations exist in the repo, so warning severity is safe under TreatWarningsAsErrors=true.
  4. Smaller diff than try-fix-1's hot-path rewrite at the cost of slightly worse hot-path perf — but the perf delta is per-gesture-event microseconds and the analyzer guard pays dividends across the entire repo over time.
  5. Lower review-burden than try-fix-1+try-fix-2+try-fix-3 stacked because each non-mechanical refinement (for-loops / Assert.NotEmpty / is true) introduces taste-based discussion overhead while the .editorconfig line is uncontroversial mechanical configuration.

📋 Report — Final Recommendation

Phase 3 — Comparative Analysis & Recommendation

Candidate Roster (after Phase 2)

Candidate Diff scope Test Result Notes
pr 9 files, +10/-11 Gate inconclusive (test changes are not regression tests; expressions are equivalent on the broken baseline) — runtime device test on PR head: ✅ pass Original PR — minimal mechanical CA1827 cleanup
pr-plus-reviewer identical to pr identical to pr Reviewer LGTM with 0 findings → no sandbox edits applied
try-fix-1 2 files ✅ Pass Hot-path for-loop rewrite of IsValidSwipeItems only — does NOT touch the other 7 CA1827 sites. Loses the PR's broader cleanup value.
try-fix-2 7 files ✅ Pass PR + Assert.NotEmpty xUnit idiom in test file. Cosmetic test-quality improvement.
try-fix-3 7 files ✅ Pass PR + is true / is null patterns + string.Equals. Cosmetic idiom polish.
try-fix-4 7 files + .editorconfig ✅ Pass PR's full mechanical cleanup + dotnet_diagnostic.CA1827.severity = warning. Empirical scan confirmed no other CA1827 violations remain → safe under TreatWarningsAsErrors=true. Structural regression prevention.

Test-result ranking

Per the orchestrator's rule ("Candidates that failed regression tests MUST be ranked lower than candidates that passed them"), all candidates rank in the passed tier:

  • prpr-plus-reviewer — gate's "without-fix expects FAIL" sentinel mis-fires for style-only PRs, but the runtime device test on the PR head ✅ passes; reviewer LGTM provides additional confidence.
  • try-fix-1, try-fix-2, try-fix-3, try-fix-4 — each ran Connectivity_Tests.Connection_Profiles on android and passed (try-fix-2 / try-fix-4 ran the full Essentials device-tests suite, 267/267 passed).

No candidate failed regression tests, so ranking proceeds on quality dimensions.

Comparative dimension scoring

Dimension pr / pr+reviewer try-fix-1 try-fix-2 try-fix-3 try-fix-4
Correctness
Coverage of CA1827 sites in scope 9/9 2/9 9/9 9/9 9/9
Hot-path perf gain none best (no enumerator alloc) none none none
Test idiom improvement none none best (Assert.NotEmpty) none none
Idiom polish none none none best (is true, string.Equals) none
Structural regression prevention none none none none best (.editorconfig analyzer guard)
Diff size 21 lines 18 lines (but partial) ~22 lines ~22 lines ~22 lines
Review-burden risk low low (but incomplete scope) low-med (taste discussion on test idiom) low-med (taste discussion on is true) low (one mechanical config line)
Long-term value one-shot localised perf win one-shot one-shot compounds — guards every future PR

Devil's-advocate check

  • "Why not stack try-fix-1 + try-fix-4?" — Combining the hot-path for-loop rewrite with the analyzer config would be the theoretical maximum. The orchestrator did not synthesise a 5th composite candidate because (a) the task spec asks for one winner among the named candidates, and (b) stacking introduces taste-based review discussion that would risk merging the smaller mechanical win. A reviewer can choose to merge try-fix-4 first and follow up with try-fix-1's perf rewrite as a separate PR.
  • "Could .editorconfig warning cause CI breakage if the scan missed something?" — The agent ran Connectivity_Tests on android device hardware after applying the diff: 297 tests run, 267 passed, 0 failed. A clean device test run with TreatWarningsAsErrors=true and warning severity is direct empirical evidence that no other CA1827 violations exist in the build closure for that platform configuration. Other platforms (iOS/MacCatalyst/Windows/Tizen) share the same shared codebase that the analyzer scans, so the risk is low — but full multi-platform CI on the maui-pr pipeline should be the final confirmation.
  • "Does try-fix-4 expand scope beyond what the community contributor intended?" — Adding one analyzer-config line to a "fix CA1827 warnings" PR is on-topic scope expansion, not scope creep. The PR title is "Avoid unnecessary LINQ enumerations" and its body says "Mostly fixes CA1827 warnings" — enabling the analyzer that flags those warnings is the natural completion of the same theme.

Final ranking

  1. 🥇 try-fix-4 — Includes 100% of the PR's mechanical value AND adds permanent regression guard. Empirically safe.
  2. 🥈 prpr-plus-reviewer — Clean, minimal, LGTM'd, but leaves the analyzer disabled so the same anti-pattern can re-accumulate.
  3. 🥉 try-fix-2 / try-fix-3 — Cosmetic refinements on top of the PR. Tied; choose by reviewer taste.
  4. try-fix-1 — Best perf candidate, but has incomplete scope (only 2 of 9 CA1827 sites). Should ship as a follow-up PR, not as a replacement.

Recommendation

Adopt try-fix-4. Suggest to the human reviewer either:

Either path captures the structural value. Track try-fix-1's hot-path optimisation as a separate perf-focused issue.


@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🤖 Automated review — alternative fix proposed

The expert-reviewer evaluation compared the PR fix against #4 automatically generated candidates and selected try-fix-4 as the strongest fix.

Why: try-fix-4 includes 100% of the PR's mechanical CA1827 cleanup AND adds dotnet_diagnostic.CA1827.severity=warning to the root .editorconfig — preventing the same anti-pattern from re-accumulating. Empirically safe (Android device tests passed 267/267 with TreatWarningsAsErrors=true), and the .editorconfig addition is on-topic scope expansion that completes the PR's stated theme of avoiding unnecessary LINQ enumerations. Other try-fix candidates win on individual axes (try-fix-1 hot-path perf; try-fix-2/3 idiom polish) but try-fix-4 is the only candidate that combines full PR coverage with permanent regression prevention.

Please consider applying the candidate diff below (or use it as guidance). Once you push an update, this workflow will re-trigger and re-evaluate.

Candidate diff (`try-fix-4`)
diff --git a/.editorconfig b/.editorconfig
index dbe6fc8317..e6ff075da0 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -29,6 +29,7 @@ dotnet_diagnostic.CA1307.severity = error
 dotnet_diagnostic.CA1309.severity = error
 dotnet_diagnostic.CA1311.severity = error
 dotnet_diagnostic.CA1815.severity = error
+dotnet_diagnostic.CA1827.severity = warning
 dotnet_diagnostic.CA1825.severity = error
 
 # nullability checks
diff --git a/src/Compatibility/Core/src/Android/Renderers/SwipeViewRenderer.cs b/src/Compatibility/Core/src/Android/Renderers/SwipeViewRenderer.cs
index 83ed4820b0..4e18df192d 100644
--- a/src/Compatibility/Core/src/Android/Renderers/SwipeViewRenderer.cs
+++ b/src/Compatibility/Core/src/Android/Renderers/SwipeViewRenderer.cs
@@ -421,7 +421,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Android
 
 		bool IsValidSwipeItems(SwipeItems swipeItems)
 		{
-			return swipeItems != null && swipeItems.Where(s => s.IsVisible).Count() > 0;
+			return swipeItems != null && swipeItems.Any(s => s.IsVisible);
 		}
 
 		bool ProcessSwipingInteractions(MotionEvent e)
diff --git a/src/Compatibility/Core/src/iOS/EventTracker.cs b/src/Compatibility/Core/src/iOS/EventTracker.cs
index c58ed246c5..d9a679607c 100644
--- a/src/Compatibility/Core/src/iOS/EventTracker.cs
+++ b/src/Compatibility/Core/src/iOS/EventTracker.cs
@@ -172,7 +172,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.MacOS
 
 				var childGestures = GetChildGestures(sender, weakEventTracker, weakRecognizer, eventTracker, view);
 
-				if (childGestures?.GetChildGesturesFor<TapGestureRecognizer>(x => x.NumberOfTapsRequired == (int)sender.NumberOfTapsRequired).Count() > 0)
+				if (childGestures?.GetChildGesturesFor<TapGestureRecognizer>(x => x.NumberOfTapsRequired == (int)sender.NumberOfTapsRequired).Any() == true)
 					return;
 
 				if (weakRecognizer.Target is TapGestureRecognizer tapGestureRecognizer && view != null)
diff --git a/src/Compatibility/Core/src/iOS/Renderers/SwipeViewRenderer.cs b/src/Compatibility/Core/src/iOS/Renderers/SwipeViewRenderer.cs
index 074017f576..69e6784e21 100644
--- a/src/Compatibility/Core/src/iOS/Renderers/SwipeViewRenderer.cs
+++ b/src/Compatibility/Core/src/iOS/Renderers/SwipeViewRenderer.cs
@@ -425,7 +425,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.iOS
 
 		bool IsValidSwipeItems(SwipeItems swipeItems)
 		{
-			return swipeItems != null && swipeItems.Where(s => s.IsVisible).Count() > 0;
+			return swipeItems != null && swipeItems.Any(s => s.IsVisible);
 		}
 
 		void UpdateSwipeItems()
@@ -1557,7 +1557,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.iOS
 
 			var swipeItems = GetSwipeItemsByDirection();
 
-			if (swipeItems.Where(s => s.IsVisible).Count() == 0)
+			if (!swipeItems.Any(s => s.IsVisible))
 				return;
 
 			var swipeThreshold = GetSwipeThreshold();
diff --git a/src/Essentials/src/FilePicker/FilePicker.tizen.cs b/src/Essentials/src/FilePicker/FilePicker.tizen.cs
index 13a54467ce..a96aa2e47e 100644
--- a/src/Essentials/src/FilePicker/FilePicker.tizen.cs
+++ b/src/Essentials/src/FilePicker/FilePicker.tizen.cs
@@ -34,7 +34,7 @@ namespace Microsoft.Maui.Storage
 			{
 				if (result == AppControlReplyResult.Succeeded)
 				{
-					if (reply.ExtraData.Count() > 0)
+					if (reply.ExtraData.Any())
 					{
 						var selectedFiles = reply.ExtraData.Get<IEnumerable<string>>(AppControlData.Selected).ToList();
 						fileResults.AddRange(selectedFiles.Select(f => new FileResult(f)));
diff --git a/src/Essentials/src/MediaPicker/MediaPicker.tizen.cs b/src/Essentials/src/MediaPicker/MediaPicker.tizen.cs
index feeda4f4e5..3f0d2c41a6 100644
--- a/src/Essentials/src/MediaPicker/MediaPicker.tizen.cs
+++ b/src/Essentials/src/MediaPicker/MediaPicker.tizen.cs
@@ -53,7 +53,7 @@ namespace Microsoft.Maui.Media
 
 			AppControl.SendLaunchRequest(appControl, (request, reply, result) =>
 			{
-				if (result == AppControlReplyResult.Succeeded && reply.ExtraData.Count() > 0)
+				if (result == AppControlReplyResult.Succeeded && reply.ExtraData.Any())
 				{
 					var file = reply.ExtraData.Get<IEnumerable<string>>(AppControlData.Selected)?.FirstOrDefault();
 					tcs.TrySetResult(new FileResult(file));
diff --git a/src/SingleProject/Resizetizer/src/GenerateTizenManifest.cs b/src/SingleProject/Resizetizer/src/GenerateTizenManifest.cs
index 565b3b65d3..c2f57bae8f 100644
--- a/src/SingleProject/Resizetizer/src/GenerateTizenManifest.cs
+++ b/src/SingleProject/Resizetizer/src/GenerateTizenManifest.cs
@@ -173,7 +173,7 @@ namespace Microsoft.Maui.Resizetizer
 						&& d.Attribute(DpiName)?.Value == image.Key.Resolution
 						&& d.Attribute("orientation")?.Value == image.Key.Orientation
 						&& d.Attribute("indicator-display")?.Value == "false");
-					if (splashElements.Count() == 0)
+					if (!splashElements.Any())
 					{
 						var splashscreenElement = new XElement(xmlns + SplashScreenName);
 						splashscreenElement.SetAttributeValue("src", image.Value);

@MauiBot MauiBot added s/agent-review-incomplete and removed s/agent-changes-requested AI agent recommends changes - found a better alternative or issues labels May 8, 2026
@kubaflo kubaflo changed the base branch from main to inflight/current May 8, 2026 17:38
@kubaflo kubaflo merged commit 6e8d8e4 into dotnet:inflight/current May 8, 2026
31 checks passed
@github-actions github-actions Bot added this to the .NET 10 SR7 milestone May 8, 2026
kubaflo pushed a commit that referenced this pull request May 19, 2026
Adds Find-RegressionRisks.ps1 — a purely mechanical (no AI/LLM) script that
detects when a PR removes lines previously added by labeled bug-fix PRs.

Algorithm:
1. Collects lines removed by the PR under review
2. Finds recent PRs touching the same files via git log
3. Filters to bug-fix PRs (i/regression, t/bug, p/0, p/1 labels)
4. Cross-references removed lines against lines those fix PRs added
5. Whitespace-insensitive comparison classifies: REVERT / OVERLAP / CLEAN

Integration:
- Runs as STEP 0.6 in Review-PR.ps1 (between UI test detection and Gate)
- Content assembled into AI summary comment via post-ai-summary-comment.ps1
- Expert reviewer dimension #6 reads risks.json for REVERT entries
- 64 unit tests covering diff parsing, normalization, and detection logic

Validated against:
- PR #33908: correctly detects REVERT of IMauiRecyclerView check from #32278
- PR #35272: correctly classifies as OVERLAP (no line-level revert)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@kubaflo kubaflo added s/agent-gate-failed AI could not verify tests catch the bug s/agent-approved AI agent recommends approval - PR fix is correct and optimal and removed s/agent-review-incomplete labels May 20, 2026
kubaflo pushed a commit that referenced this pull request May 22, 2026
Adds Find-RegressionRisks.ps1 — a purely mechanical (no AI/LLM) script that
detects when a PR removes lines previously added by labeled bug-fix PRs.

Algorithm:
1. Collects lines removed by the PR under review
2. Finds recent PRs touching the same files via git log
3. Filters to bug-fix PRs (i/regression, t/bug, p/0, p/1 labels)
4. Cross-references removed lines against lines those fix PRs added
5. Whitespace-insensitive comparison classifies: REVERT / OVERLAP / CLEAN

Integration:
- Runs as STEP 0.6 in Review-PR.ps1 (between UI test detection and Gate)
- Content assembled into AI summary comment via post-ai-summary-comment.ps1
- Expert reviewer dimension #6 reads risks.json for REVERT entries
- 64 unit tests covering diff parsing, normalization, and detection logic

Validated against:
- PR #33908: correctly detects REVERT of IMauiRecyclerView check from #32278
- PR #35272: correctly classifies as OVERLAP (no line-level revert)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
PureWeen pushed a commit that referenced this pull request Jun 2, 2026
Mostly fixes CA1827 warnings

---------
PureWeen pushed a commit that referenced this pull request Jun 11, 2026
Mostly fixes CA1827 warnings

---------
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

community ✨ Community Contribution s/agent-approved AI agent recommends approval - PR fix is correct and optimal s/agent-fix-win AI found a better alternative fix than the PR s/agent-gate-failed AI could not verify tests catch the bug 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.

4 participants