[Net11]Improve label mapping performance and ensure complete coverage including ToPlatform and subsequent property changes - #35892
Conversation
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 35892Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 35892" |
AI code review refresh for net11.0 targetHead reviewed: Verdict: Needs discussion (WIP)Solid, well-reasoned approach with a large global blast radius and some scope creep. No definite bugs found in the changed source, but several items below warrant confirmation before this leaves WIP. What the change does (independent reading of the diff)
Prior review reconciliationNo prior PR reviews, review comments, or earlier fleet markers exist (only the dogfood bot comment). Nothing to reconcile; no outstanding ❌ findings. CI statusBuild 1461094 still in progress. Most build/pack/Helix/integration jobs pass; 3 iOS jobs fail: Blast radius / failure‑mode probingThe Core handler files are cross‑platform, so the mapper reordering + connection guards affect every Label, Entry, and Button instance on all platforms, not just iOS.
Concise findings
ConfidenceMedium. Source‑level reasoning is high‑confidence (changes read cleanly, key invariants verified). Runtime/visual correctness across non‑iOS platforms and snapshot validity are unverified here and depend on the in‑progress CI + device/UI tests. Automated non‑binding review. This is not an approval and does not request changes; a human maintainer owns the merge decision. |
kubaflo
left a comment
There was a problem hiding this comment.
PR #35892 — [Net11] Improve Label mapping performance + complete coverage (ToPlatform & subsequent property changes)
Verdict: NEEDS_DISCUSSION (confidence: medium) — HEAD aedd137. The core change is correct — the deep reviews (opus-4.8, opus-4.6) confirmed no Label/Entry mappings were dropped and runtime (non-connect) behavior is preserved. Three precise, non-blocking items remain (2 inline + an API note); CI red is the known flake set.
What it does (sound)
Consolidates the Label/Entry/Button mappers so Text is mapped first (into a dedicated TextMapper) and IsConnectingHandler() guards skip redundant re-mapping during connect — avoiding repeated AttributedText rebuilds on iOS. The ToNSAttributedString LineBreakMode plumbing is a real fix. Mapper consolidation and ordering were independently vetted as coherent by 3 of 4 models.
Findings (inline)
⚠️ EntryHandler.cs:30 — the Text-ordering comment is inaccurate (HorizontalTextAlignment/VerticalTextAlignment are declared beforeText) and the resulting order diverges from Label/Button. Benign at runtime, but misleading in an ordering-focused PR. (opus-4.8 + opus-4.6 consensus.)- 💡 EntryHandler.cs:39 —
EntryPriorityMapperis now orphaned dead code (confirmed viagit grepat HEAD); remove it. - 💡 FormattedStringExtensions.cs:43 — adding the optional
defaultLineBreakModeis a binary-breaking change to a shipped publicPlatformextension; handled via*REMOVED*in PublicAPI (gate satisfied) — flagging to confirm the break is intentional vs. adding a preserving overload.
Dropped (false positive)
A model flagged Entry.Mapper.cs MapTextTransform → MapText as "bypassing UpdateValue/user customizations." Dropped: the ReplaceMapping(TextTransform, MapText) wiring is pre-existing — the PR only adds an IsConnectingHandler() guard around it (a perf optimization), and opus-4.8 confirmed runtime behavior is preserved. Not a new defect.
CI — known flakes
Red legs are the universal set seen across all PRs today: Build Analysis, AOT macOS, RunOniOS_MauiRelease/MauiReleaseTrimFull/TrimFull_CoreCLR. The Debug-passes / Release+Trim+AOT-fails pattern matches trimming-baseline noise; RunOniOS_MauiDebug, MauiRelease_CoreCLR, MauiNativeAOT pass. Not PR-caused.
aedd137 to
97f0354
Compare
kubaflo
left a comment
There was a problem hiding this comment.
PR #35892 - [Net11] Improve Label mapping performance + complete coverage
Re-review at HEAD 0c2e170 (prior review: NEEDS_DISCUSSION at aedd137). Consensus verdict from all 4 models: NEEDS_CHANGES (high confidence).
What changed
This PR continues the iOS Label/Entry/Button mapping-performance work from #30864. It introduces a high-priority TextMapper so Text is mapped before dependent text-style properties, guards MapText/MapFormatting with IsConnectingHandler() to avoid rebuilding the iOS AttributedText repeatedly during handler connection, routes EntryHandler.iOS.MapFormatting through handler.UpdateValue(...), fixes span-property propagation in FormattedStringExtensions, and re-saves a large set of Android/iOS/Mac/Windows FeatureMatrix snapshots (587 additions across 104 files).
Consensus verdict: NEEDS_CHANGES
The latest push introduced a build-breaking regression. EntryHandler.iOS.cs now declares MapBackground(IEntryHandler, IEntry) twice with an identical signature and body (lines 56-78 and 80-102) - a CS0111 "member already defined" error. The file compiles for both iOS and MacCatalyst, which directly explains the red Build macOS (Debug/Release) and Pack macOS legs in CI; the duplicate did not exist at the prior head aedd137. All four models flagged this independently, and it is the single blocking issue: remove one of the two copies and the build should recover.
Prior concerns (still unaddressed, not re-filed inline)
Two non-blocking items from the prior NEEDS_DISCUSSION review remain, but are already documented in the PR discussion, so they are not re-filed as fresh inline comments: (1) EntryPriorityMapper (EntryHandler.cs:20-23) is orphaned dead code - it is no longer passed to the Mapper constructor (which chains TextMapper -> ViewMapper) and its only entry, MaxLength, is already present in TextMapper; and (2) the comment at EntryHandler.cs:30-31 states Text is mapped before HorizontalTextAlignment, yet HorizontalTextAlignment/VerticalTextAlignment (lines 28-29) are declared before Text (line 32) - harmless for iOS UITextField (alignment is view-level) but misleading in an ordering-focused PR. The core mapper consolidation itself was independently vetted as correct: no mappings were dropped and runtime (non-connect) behavior is preserved.
kubaflo
left a comment
There was a problem hiding this comment.
PR #35892 — [Net11] Improve Label mapping performance + complete coverage
Cross-pollination synthesis at HEAD 82b65cc (4 independent model reviews: gpt-5.5, claude-opus-4.8, claude-opus-4.6, gemini-3.1-pro).
Verdict: NEEDS_CHANGES (confidence: high)
| Model | Verdict | Confidence |
|---|---|---|
| gpt-5.5 | NEEDS_CHANGES | high |
| claude-opus-4.6 | NEEDS_CHANGES | high |
| claude-opus-4.8 | NEEDS_DISCUSSION | medium |
| gemini-3.1-pro | LGTM | high |
Per the most-conservative rule (NEEDS_CHANGES > NEEDS_DISCUSSION > LGTM) the synthesized verdict is NEEDS_CHANGES. The single blocking item (Finding 1) is a concrete, independently-verified test defect; the lone LGTM (gemini) simply did not catch it. 3 of 4 models did not give LGTM.
What changed
This PR continues the iOS Label/Entry/Button mapping-performance work from #30864. It introduces a high-priority TextMapper (so Text is mapped before dependent text-style properties), guards MapText/MapTextTransform with IsConnectingHandler() to avoid rebuilding iOS AttributedText repeatedly during handler connection, fixes span-property propagation in FormattedStringExtensions (adding a LineBreakMode parameter), and re-saves a large set of Android/iOS/Mac/Windows FeatureMatrix snapshots (563 additions / 98 deletions across 104 files).
Prior blocker resolved
The previous review (at an earlier head) blocked on a duplicate MapBackground(IEntryHandler, IEntry) in EntryHandler.iOS.cs causing a CS0111 build break. At HEAD 82b65cc that method is declared once (line 56) — the regression is fixed, and none of the 4 models re-flagged it.
Synthesized findings (clustered, validated against HEAD)
All findings below reference code present at HEAD 82b65cc; none were dropped. Duplicates across models were merged into one comment per unique file:line:concern.
-
[Error]
ButtonFeatureTests.cs:11—MainLabelconstant targets the wrong element.const string MainLabel = "ClickedEventLabel"taps a label with no gesture recognizer, so the page is never recreated. The recreating gesture is on theAutomationId="MainLabel"label (MainLabel_Tapped→Content = new ContentView()). EveryApp.Tap(MainLabel)no-ops, so the new "verify initial mappers after recreation" coverage silently re-checks stale page state. Fix:= "MainLabel". (gpt-5.5, opus-4.6) — blocking. -
[Warning]
FormattedStringExtensions.cs:43/86— binary-breaking public API change. The publicToNSAttributedString(FormattedString…)and(Span…)overloads gain an optional trailingLineBreakMode defaultLineBreakMode. Source-compatible but ABI-breaking vsPublicAPI.Shipped.txt. The API gate is satisfied (*REMOVED*+ new entries in bothPublicAPI.Unshipped.txtfiles) and net11 permits breaks, butpartner/syncfusionconsumers are exactly who is affected — confirm with a maintainer and document it. A naive preserving overload would be ambiguous (CS0121). (opus-4.8, gemini) — needs discussion. -
[Warning]
EntryHandler.cs:20-23—EntryPriorityMapperis orphaned dead code. No longer passed to any mapper (theMappernow chainsTextMapper, ViewMapper) and its only entry (MaxLength) already lives inTextMapper. Remove the block. (opus-4.8, opus-4.6, gemini) -
[Suggestion]
EntryHandler.cs:30— inaccurate ordering comment. Comment claimsTextis mapped beforeHorizontalTextAlignment, but alignment entries (lines 28-29) precedeText(line 32); it also referencesLineHeight/Decorationsthat Entry's mapper lacks (copied fromLabelHandler). Benign at runtime; reorder to match Label/Button or fix the comment. (opus-4.8, opus-4.6) -
[Nit]
EntryHandler.cs(+Entry.Mapper.cs,Entry.iOS.cs,Label.Mapper.cs) — missing trailing newline. Non-blocking;.editorconfigdoes not enforce it;dotnet formatrestores it. (opus-4.8) -
[Suggestion]
Entry.Mapper.cs:46-55— extend theIsConnectingHandlerguard to siblings.Button.Mapper.cs,Editor.Mapper.cs,SearchBar.Mapper.csmap bothTextandTextTransformtoMapText, soMapTextruns twice at connect — the same guard would help. Out of scope for this PR; follow-up. (gemini)
Required to clear NEEDS_CHANGES
Fix Finding 1 (the MainLabel constant). Findings 3-4 are recommended cleanup for an ordering/perf-focused PR; Finding 2 needs a maintainer sign-off on the intentional binary break; Findings 5-6 are non-blocking.
|
|
||
| public class ButtonFeatureTests : _GalleryUITest | ||
| { | ||
| const string MainLabel = "ClickedEventLabel"; |
There was a problem hiding this comment.
🤖 AI-Generated Review (multi-model: GPT-5.5, Claude Opus 4.8, Claude Opus 4.6, Gemini 3.1 Pro)
[Error] MainLabel constant targets the wrong element — page recreation never triggers, so the new Button coverage is ineffective
const string MainLabel = "ClickedEventLabel"; points at the event-result label (AutomationId="ClickedEventLabel", ButtonControlPage.xaml lines 66-67), which has no gesture recognizer. The label that actually recreates the page has AutomationId="MainLabel" (line 59) with <TapGestureRecognizer Tapped="MainLabel_Tapped"/> (line 61); MainLabel_Tapped sets Content = new ContentView() to rebuild the page (ButtonControlPage.xaml.cs lines 58-62).
Because every new App.Tap(MainLabel) call therefore taps ClickedEventLabel (a no-op), the page is never recreated and the "verify initial mappers after recreation" assertions re-check the same already-loaded page instead of a fresh one — silently defeating the coverage this PR adds. EntryFeatureTests and LabelFeatureTests correctly use "MainLabel".
Fix: const string MainLabel = "MainLabel";
Independently flagged by gpt-5.5 and claude-opus-4.6; verified against HEAD 82b65cc.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
MauiBot
left a comment
There was a problem hiding this comment.
Expert Review — 2 findings
See inline comments for details.
| TextTransform defaultTextTransform = TextTransform.Default) | ||
| => formattedString.ToNSAttributedString(fontManager, defaultLineHeight, defaultHorizontalAlignment, defaultFont, defaultColor, defaultTextTransform, LineBreakMode.WordWrap, defaultCharacterSpacing: 0d); | ||
| TextTransform defaultTextTransform = TextTransform.Default, | ||
| LineBreakMode defaultLineBreakMode = LineBreakMode.WordWrap) |
There was a problem hiding this comment.
[major] Public API Surface Design — Adding defaultLineBreakMode as an optional trailing parameter replaces the shipped 7-parameter ToNSAttributedString signatures (the PR also marks them *REMOVED* in the iOS and MacCatalyst PublicAPI files). Optional parameters are baked into call sites, so existing compiled libraries that call the old overload will look for the old metadata signature and fail with MissingMethodException after upgrading. Preserve the exact shipped overloads as forwarders, and expose the new line-break option through a binary-compatible overload shape rather than removing the shipped methods.
| #endif | ||
| EntryHandler.Mapper.ReplaceMapping<Entry, IEntryHandler>(nameof(Text), MapText); | ||
| EntryHandler.Mapper.ReplaceMapping<Entry, IEntryHandler>(nameof(TextTransform), MapText); | ||
| EntryHandler.Mapper.ReplaceMapping<Entry, IEntryHandler>(nameof(TextTransform), MapTextTransform); |
There was a problem hiding this comment.
[moderate] Android Platform / Mapper Lifecycle — This changes the TextTransform mapping to skip MapText while the legacy EntryHandler is connecting, but the Material3 Android mapping just below still uses EntryHandler2.Mapper.ReplaceMapping(... nameof(TextTransform), MapText). With RuntimeFeature.IsMaterial3Enabled, the TextTransform mapper is still appended to the handler and runs during initial UpdateProperties after the text/formatting mappers, so Material3 entries keep the old connection-time second text assignment that this PR is trying to remove. Add an EntryHandler2-compatible MapTextTransform overload and use it for the Material3 mapping as well.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 41 out of 137 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (2)
src/Controls/src/Core/Entry/Entry.Mapper.cs:50
- MapTextTransform is used for both EntryHandler (non-Material) and EntryHandler2 (Material3). With the current signature (IEntryHandler,…), the call to MapText(handler, entry) resolves to MapText(IEntryHandler,…) even when the mapper is running for EntryHandler2, bypassing the EntryHandler2-specific MapText overload (which updates handler.PlatformView.EditText). Adding an EntryHandler2 overload here ensures the Material3 path uses the correct platform view.
static void MapTextTransform(IEntryHandler handler, Entry entry)
{
if (entry.IsConnectingHandler())
{
// If we're connecting the handler, we don't want to map the text multiple times.
src/Controls/src/Core/SearchBar/SearchBar.Mapper.cs:55
- On Android Material3 (SearchBarHandler2), TextTransform is remapped to MapTextTransform(ISearchBarHandler,…). That causes MapText(handler, searchBar) to bind to MapText(ISearchBarHandler,…) (SearchViewExtensions) instead of the SearchBarHandler2-specific MapText overload (which updates handler.PlatformView.EditText). Add a SearchBarHandler2 overload for MapTextTransform so the Material3 mapping uses the correct platform view.
static void MapTextTransform(ISearchBarHandler handler, SearchBar searchBar)
{
if (searchBar.IsConnectingHandler())
{
// If we're connecting the handler, we don't want to map the text multiple times.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 41 out of 137 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (3)
src/Controls/tests/TestCases.HostApp/FeatureMatrix/Label/LabelOptionsPage.xaml.cs:251
SimpleFormattedTextCheckBox_CheckedChangedshould also keep the formatted-text options mutually exclusive; otherwiseFormattedTextCheckBoxcan remain checked even though this handler overwrote the formatted text.
src/Controls/tests/TestCases.HostApp/FeatureMatrix/Label/LabelOptionsPage.xaml.cs:240OnFormattedTextChangedandSimpleFormattedTextCheckBox_CheckedChangedcan both be checked at the same time, but they both write to the singleFormattedTextproperty. That can leave the UI in an inconsistent state (both checkboxes checked while only one formatted-text choice is actually applied). Consider making these mutually exclusive by uncheckingSimpleFormattedTextCheckBoxwhenFormattedTextCheckBoxis checked.
This issue also appears on line 242 of the same file.
src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/EntryFeatureTests.cs:1178
- Tapping hard-coded coordinates to clear focus is brittle (window size/scale/layout changes can make (50,50) hit an unintended element). Since this page exposes a stable AutomationId (
MainLabel), prefer tapping that to unfocus the Entry on Windows.
@kubaflo , I have addressed the build failures |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 40 out of 136 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (3)
src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/EntryFeatureTests.cs:199
- Avoid leaving commented-out test code in the test flow. If the pre-focus screenshot is intentionally skipped due to a known issue, keep only an explanatory comment (without the commented-out method call).
src/Controls/tests/TestCases.HostApp/FeatureMatrix/Label/LabelOptionsPage.xaml.cs:252 SimpleFormattedTextCheckBox_CheckedChangedonly handles the checked state; unchecking leaves the view model in a formatted-text state withTextstill null, which makes the option hard to toggle/compose with other options.
src/Controls/tests/TestCases.HostApp/FeatureMatrix/Label/LabelViewModel.cs:11LabelViewModelno longer initializes eitherTextorFormattedText, which makes the Label Feature Matrix page render blank until the user opens Options. Consider setting a defaultTextvalue so the sample has visible content on first load (and tests/pages relying on initial text don’t regress).
|
/azp run maui-pr-uitests , maui-pr-devicetests |
|
Azure Pipelines: Successfully started running 2 pipeline(s). |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
MauiBot
left a comment
There was a problem hiding this comment.
AI Review Summary
@devanathan-vaithiyanathan — new AI review results are available based on this last commit:
17c9127.
🗂️ Review Sessions — click to expand
🚦 Gate — Test Before & After Fix
Gate Result: ❌ FAILED
Platform: IOS · Base: net11.0 · Merge base: d07c3b24
🩺 Test does not reproduce the bug — ran the same in both states (PASS without fix, PASS with fix). The repro test is not exercising the issue. Strengthen the test before reviewing the fix.
| Test | Without Fix (expect FAIL) | With Fix (expect PASS) |
|---|---|---|
🖥️ ButtonFeatureTests ButtonFeatureTests |
❌ PASS — 2598s | ✅ PASS — 787s |
🖥️ EntryFeatureTests EntryFeatureTests |
❌ PASS — 2007s | ✅ PASS — 690s |
🔴 Without fix — 🖥️ ButtonFeatureTests: PASS ❌ · 2598s
(no coded error found; showing last 1200 chars)
s]
>>>>> 7/30/2026 4:23:27 PM VerifyVSM_Button_ResetWhileDisabled Start
>>>>> 7/30/2026 4:23:30 PM VerifyVSM_Button_ResetWhileDisabled Stop
Passed VerifyVSM_Button_ResetWhileDisabled [3 s]
>>>>> 7/30/2026 4:23:30 PM VerifyVSM_Button_PressedAndReleasedWhileDisabled Start
>>>>> 7/30/2026 4:23:33 PM VerifyVSM_Button_PressedAndReleasedWhileDisabled Stop
Passed VerifyVSM_Button_PressedAndReleasedWhileDisabled [2 s]
>>>>> 7/30/2026 4:23:33 PM VerifyVSM_Button_DisableAndEnable Start
>>>>> 7/30/2026 4:23:36 PM VerifyVSM_Button_DisableAndEnable Stop
Passed VerifyVSM_Button_DisableAndEnable [3 s]
>>>>> 7/30/2026 4:23:36 PM VerifyVSM_Button_DisableAndEnableWhilePressedAndReleased Start
>>>>> 7/30/2026 4:23:40 PM VerifyVSM_Button_DisableAndEnableWhilePressedAndReleased Stop
Passed VerifyVSM_Button_DisableAndEnableWhilePressedAndReleased [4 s]
NUnit Adapter 4.5.0.0: Test execution complete
Results File: /Users/cloudtest/vss/_work/1/s/CustomAgentLogsTmp/UITests/TestResults/ButtonFeatureTests.trx
Test Run Successful.
Total tests: 84
Passed: 84
Total time: 12.3204 Minutes
>>> TRX_RESULT_FILE: /Users/cloudtest/vss/_work/1/s/CustomAgentLogsTmp/UITests/TestResults/ButtonFeatureTests.trx
🟢 With fix — 🖥️ ButtonFeatureTests: PASS ✅ · 787s
(no coded error found; showing last 1200 chars)
s]
>>>>> 7/30/2026 5:37:11 PM VerifyVSM_Button_ResetWhileDisabled Start
>>>>> 7/30/2026 5:37:14 PM VerifyVSM_Button_ResetWhileDisabled Stop
Passed VerifyVSM_Button_ResetWhileDisabled [3 s]
>>>>> 7/30/2026 5:37:14 PM VerifyVSM_Button_PressedAndReleasedWhileDisabled Start
>>>>> 7/30/2026 5:37:17 PM VerifyVSM_Button_PressedAndReleasedWhileDisabled Stop
Passed VerifyVSM_Button_PressedAndReleasedWhileDisabled [2 s]
>>>>> 7/30/2026 5:37:17 PM VerifyVSM_Button_DisableAndEnable Start
>>>>> 7/30/2026 5:37:20 PM VerifyVSM_Button_DisableAndEnable Stop
Passed VerifyVSM_Button_DisableAndEnable [3 s]
>>>>> 7/30/2026 5:37:20 PM VerifyVSM_Button_DisableAndEnableWhilePressedAndReleased Start
>>>>> 7/30/2026 5:37:24 PM VerifyVSM_Button_DisableAndEnableWhilePressedAndReleased Stop
Passed VerifyVSM_Button_DisableAndEnableWhilePressedAndReleased [4 s]
NUnit Adapter 4.5.0.0: Test execution complete
Results File: /Users/cloudtest/vss/_work/1/s/CustomAgentLogsTmp/UITests/TestResults/ButtonFeatureTests.trx
Test Run Successful.
Total tests: 84
Passed: 84
Total time: 11.4841 Minutes
>>> TRX_RESULT_FILE: /Users/cloudtest/vss/_work/1/s/CustomAgentLogsTmp/UITests/TestResults/ButtonFeatureTests.trx
🔴 Without fix — 🖥️ EntryFeatureTests: PASS ❌ · 2007s
(no coded error found; showing last 1200 chars)
dToInvalid Start
>>>>> 7/30/2026 5:01:56 PM VerifyVSM_Entry_ValidToInvalid Stop
Passed VerifyVSM_Entry_ValidToInvalid [9 s]
>>>>> 7/30/2026 5:01:56 PM VerifyVSM_Entry_Completed Start
>>>>> 7/30/2026 5:02:01 PM VerifyVSM_Entry_Completed Stop
Passed VerifyVSM_Entry_Completed [4 s]
>>>>> 7/30/2026 5:02:01 PM VerifyVSM_Entry_CompletedAndReset Start
>>>>> 7/30/2026 5:02:06 PM VerifyVSM_Entry_CompletedAndReset Stop
Passed VerifyVSM_Entry_CompletedAndReset [5 s]
>>>>> 7/30/2026 5:02:06 PM VerifyVSM_Entry_CompletedAndRefocused Start
>>>>> 7/30/2026 5:02:11 PM VerifyVSM_Entry_CompletedAndRefocused Stop
Passed VerifyVSM_Entry_CompletedAndRefocused [5 s]
>>>>> 7/30/2026 5:02:11 PM VerifyVSM_Entry_DisableWhileCompleted Start
>>>>> 7/30/2026 5:02:17 PM VerifyVSM_Entry_DisableWhileCompleted Stop
Passed VerifyVSM_Entry_DisableWhileCompleted [5 s]
NUnit Adapter 4.5.0.0: Test execution complete
Results File: /Users/cloudtest/vss/_work/1/s/CustomAgentLogsTmp/UITests/TestResults/EntryFeatureTests.trx
Test Run Successful.
Total tests: 74
Passed: 74
Total time: 9.3061 Minutes
>>> TRX_RESULT_FILE: /Users/cloudtest/vss/_work/1/s/CustomAgentLogsTmp/UITests/TestResults/EntryFeatureTests.trx
🟢 With fix — 🖥️ EntryFeatureTests: PASS ✅ · 690s
(no coded error found; showing last 1200 chars)
dToInvalid Start
>>>>> 7/30/2026 5:48:33 PM VerifyVSM_Entry_ValidToInvalid Stop
Passed VerifyVSM_Entry_ValidToInvalid [8 s]
>>>>> 7/30/2026 5:48:33 PM VerifyVSM_Entry_Completed Start
>>>>> 7/30/2026 5:48:37 PM VerifyVSM_Entry_Completed Stop
Passed VerifyVSM_Entry_Completed [4 s]
>>>>> 7/30/2026 5:48:37 PM VerifyVSM_Entry_CompletedAndReset Start
>>>>> 7/30/2026 5:48:43 PM VerifyVSM_Entry_CompletedAndReset Stop
Passed VerifyVSM_Entry_CompletedAndReset [5 s]
>>>>> 7/30/2026 5:48:43 PM VerifyVSM_Entry_CompletedAndRefocused Start
>>>>> 7/30/2026 5:48:48 PM VerifyVSM_Entry_CompletedAndRefocused Stop
Passed VerifyVSM_Entry_CompletedAndRefocused [5 s]
>>>>> 7/30/2026 5:48:48 PM VerifyVSM_Entry_DisableWhileCompleted Start
>>>>> 7/30/2026 5:48:54 PM VerifyVSM_Entry_DisableWhileCompleted Stop
Passed VerifyVSM_Entry_DisableWhileCompleted [5 s]
NUnit Adapter 4.5.0.0: Test execution complete
Results File: /Users/cloudtest/vss/_work/1/s/CustomAgentLogsTmp/UITests/TestResults/EntryFeatureTests.trx
Test Run Successful.
Total tests: 74
Passed: 74
Total time: 9.3806 Minutes
>>> TRX_RESULT_FILE: /Users/cloudtest/vss/_work/1/s/CustomAgentLogsTmp/UITests/TestResults/EntryFeatureTests.trx
⚠️ Failure Details
- ❌ ButtonFeatureTests PASSED without fix (should fail) — tests don't catch the bug
- ❌ EntryFeatureTests PASSED without fix (should fail) — tests don't catch the bug
📁 Fix files reverted (26 files)
src/Controls/src/Core/Button/Button.Mapper.cssrc/Controls/src/Core/Button/Button.iOS.cssrc/Controls/src/Core/Editor/Editor.Android.cssrc/Controls/src/Core/Editor/Editor.Mapper.cssrc/Controls/src/Core/Editor/Editor.iOS.cssrc/Controls/src/Core/Entry/Entry.Android.cssrc/Controls/src/Core/Entry/Entry.Mapper.cssrc/Controls/src/Core/Entry/Entry.iOS.cssrc/Controls/src/Core/Label/Label.Mapper.cssrc/Controls/src/Core/Label/Label.iOS.cssrc/Controls/src/Core/Platform/iOS/Extensions/FormattedStringExtensions.cssrc/Controls/src/Core/SearchBar/SearchBar.Android.cssrc/Controls/src/Core/SearchBar/SearchBar.Mapper.cssrc/Controls/src/Core/SearchBar/SearchBar.iOS.cssrc/Core/src/Handlers/Button/ButtonHandler.cssrc/Core/src/Handlers/Button/ButtonHandler.iOS.cssrc/Core/src/Handlers/Editor/EditorHandler.cssrc/Core/src/Handlers/Editor/EditorHandler.iOS.cssrc/Core/src/Handlers/Entry/EntryHandler.cssrc/Core/src/Handlers/Entry/EntryHandler.iOS.cssrc/Core/src/Handlers/Label/LabelHandler.cssrc/Core/src/Handlers/Label/LabelHandler.iOS.cssrc/Core/src/Handlers/SearchBar/SearchBarHandler.cssrc/Core/src/Handlers/SearchBar/SearchBarHandler.iOS.cssrc/Core/src/Platform/iOS/SearchBarExtensions.cssrc/Core/src/Platform/iOS/TextFieldExtensions.cs
📱 UI Tests — Button,Editor,Entry,Label,Material3,SearchBar,ViewBaseTests
Detected UI test categories: Button,Editor,Entry,Label,Material3,SearchBar,ViewBaseTests
✅ Deep UI tests — 489 passed, 0 failed across 7 categories on platform-pool agent (replaces in-process counts above). 1 category reported 0 tests.
🧪 UI Test Execution Results (deep, platform pool)
| Category | Tests | Snapshot diffs |
|---|---|---|
Button |
71/72 ✓ | — |
Editor |
69/70 ✓ | — |
Entry |
112/113 ✓ | — |
Label |
89/91 ✓ | — |
Material3 |
0 tests | — |
SearchBar |
36/37 ✓ | — |
ViewBaseTests |
112/112 ✓ | — |
📎 Download drop-deep-uitests artifact (TRX + snapshot diffs) |
🔗 Regression Cross-Reference
🔍 Regression Cross-Reference
⚠ Overlaps with prior bug-fix PRs — same files modified, but no exact line revert detected.
| File | Fix PR | Fixed issue(s) |
|---|---|---|
src/Core/src/Handlers/Editor/EditorHandler.iOS.cs |
#35662 | #35615 |
src/Core/src/Platform/iOS/TextFieldExtensions.cs |
#32889 | #32886 |
🧪 Regression Tests to Verify
These tests were added by the overlapping fix PRs. Running them to verify no side-effect regressions:
| Fix PR | Type | Test | Filter |
|---|---|---|---|
| #35662 | DeviceTest | EditorTests | EditorTests |
| #32889 | UITest | Issue32886 | Issue32886 |
🧪 Regression Test Results
❌ FAILED — 0 passed, 1 failed, 1 skipped
| Fix PR | Test | Type | Result |
|---|---|---|---|
| #35662 | EditorTests | DeviceTest | ⏭️ ERROR |
| #32889 | Issue32886 | UITest | ❌ FAILED |
📋 Pre-Flight — Context & Validation
Issue: #30864 - Improve iOS Label performance (referenced as "Contributing to #30864"; PR has no direct Fixes/Closes issue link)
PR: #35892 - [Net11]Improve label mapping performance and ensure complete coverage including ToPlatform and subsequent property changes
Platforms Affected: iOS primary; MacCatalyst through .iOS.cs/Platform iOS APIs; Android/Windows/Mac affected by feature-matrix snapshots/tests and Android mapper additions
Files Changed: 21 implementation/source files, 12 HostApp/shared UI test files, many platform screenshot baselines
Key Findings
- PR expands the prior iOS Label performance work from #30864 by changing mapper ordering/connection-time formatting behavior for Button, Entry, Editor, Label, and SearchBar so text is mapped before dependent formatting and duplicate attributed-text work is skipped during initial handler connection.
- PR changes public iOS/MacCatalyst
FormattedStringExtensions.ToNSAttributedStringsignatures by adding line-break-mode propagation; prior inline reviews noted this is a binary-breaking public API change that appears intentionally recorded in PublicAPI.Unshipped. - Prior inline reviews found issues that were addressed or became non-blocking: duplicate
EntryHandler.iOS.MapBackgroundwas removed; Button feature testMainLabelwas corrected; dead mapper/comment/trailing-newline concerns remain non-blocking. - Gate result supplied by caller: Gate ❌ FAILED — tests did not behave as expected. Gate verification must not be re-run and
gate/content.mdmust not be overwritten. - Mandatory regression tests for every candidate after primary tests:
Run-DeviceTests.ps1 -Project Controls -Platform ios -TestFilter "EditorTests"andBuildAndRunHostApp.ps1 -Platform ios -TestFilter "Issue32886".
Code Review Summary
Verdict: NEEDS_DISCUSSION
Confidence: low
Errors: 0 | Warnings: 0 | Suggestions: 0
Key code review findings:
- ℹ No high-confidence code findings in the current diff.
- ℹ Blast radius is global for common text controls: mapper ordering and connection guards affect all Button/Entry/Editor/Label/SearchBar instances.
- ℹ CI is red/undetermined, so the review cannot be LGTM until failures are resolved or classified.
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| PR | PR #35892 | Reorder text/formatting mappers and suppress redundant formatting during handler connection, with iOS formatted-text line-break propagation and feature-matrix baseline updates | ❌ FAILED (Gate supplied by caller) | src/Core/src/Handlers/*, src/Controls/src/Core/*, UI feature tests/snapshots |
Original PR; gate failed, alternatives required |
🔬 Code Review — Deep Analysis
Code Review — PR #35892
Independent Assessment
What this changes: Reorders text/formatting mapper execution for Button, Entry, Editor, Label, and SearchBar, especially iOS attributed-text paths, so initial handler connection maps text before dependent formatting properties and avoids duplicate formatting work during connection. It also adds/updates UI feature-matrix coverage and snapshots.
Inferred motivation: Reduce redundant mapper invocations and fix incomplete iOS formatted text propagation for font, character spacing, alignment, max length, and line-break behavior.
Reconciliation with PR Narrative
Author claims: The PR improves iOS label mapping performance, fixes formatted text rendering/propagation, and updates affected visual baselines/tests.
Agreement/disagreement: The code matches those claims. I did not find a high-confidence code correctness issue in the current diff.
Prior Review Reconciliation
| Prior ❌ Error Finding | Source | Status | Evidence |
|---|---|---|---|
| Earlier mapper/Material3 and API-surface findings | MauiBot / Copilot prior reviews | 🔄 Obsolete / not reproduced at current HEAD | Latest Copilot review at 17c9127 generated no new comments; expert reviewer found no current high-confidence findings. |
| Build/test failures | Human/MauiBot prior reviews | ❌ Still unresolved as CI status | Current check-run data still shows failing maui-pr, maui-pr-uitests, and maui-pr-devicetests. |
Blast Radius Assessment
- Runs for all instances: Yes — mapper ordering and connection guards affect common text controls globally.
- Startup impact: Yes — handler initial connection/property sweep behavior changes.
- Static/shared state: No new static mutable state beyond mapper composition changes.
External Output Contract
| Consumer token/pattern | Producer location | Producer emission condition | Consumer assumption | Ordinary negative case | Downstream effect |
|---|---|---|---|---|---|
| N/A | N/A | No changed code classifies external tool output | N/A | N/A | N/A |
CI Status
- Required-check result:
gh pr checks --requiredunavailable due unauthenticatedgh; REST check-runs for HEAD show failures. - Classification: Undetermined / red CI.
- Action taken: Invoked
azdo-build-investigator;ci-analysisskill was unavailable in this environment. Confidence capped low; no LGTM.
Findings
No high-confidence code findings.
Failure-Mode Probing
- Handler connection with default/null text: guarded
MapFormattingskips during connection while reordered mapper sweep applies dependent formatting afterward. - Subsequent text changes after connection:
MapTextcallsMapFormatting, which propagates dependent properties viaUpdateValue. - Material3 Android handlers: current overloads appear wired for
EntryHandler2,EditorHandler2, andSearchBarHandler2. - Formatted Label with line-break mode: new overload passes label line-break mode into span paragraph style.
Verdict: NEEDS_DISCUSSION
Confidence: low
Summary: Code review found no current high-confidence defect, and the expert reviewer also returned no findings. However CI is still red/undetermined from available check-run data, so this cannot be LGTM until failures are classified or resolved.
🛠️ Fix — Analysis & Comparison
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| 1 | try-fix-1 | Localized iOS platform text updates preserve existing attributed-string formatting when text changes; fixes placeholder character-spacing assignment bugs | ✅ PASS | 5 files | Different from PR: no global mapper reordering, no IsConnectingHandler() guards, no handler mapper changes; all primary and mandatory regression tests passed |
| PR | PR #35892 | Reorder text/formatting mappers and suppress redundant formatting during handler connection, with iOS formatted-text line-break propagation and feature-matrix baseline updates | ❌ FAILED (Gate supplied by caller) | handlers/platform text files + UI tests/snapshots | Original PR; gate failed before this phase |
Cross-Pollination
| Model | Round | New Ideas? | Details |
|---|---|---|---|
| claude-opus-4.6 | 1 | Yes | Produced candidate #1: preserve formatting inside iOS platform text setters instead of changing mapper order/lifecycle behavior. |
| claude-opus-4.7 | N/A | Not run | Stop condition met by candidate #1: passed primary and mandatory regression tests and is demonstrably lower blast radius than the PR fix. |
| gpt-5.3-codex | N/A | Not run | Stop condition met by candidate #1. |
| gpt-5.5 | N/A | Not run | Stop condition met by candidate #1. |
Exhausted: No
Selected Fix: Candidate #1 — It passed all required validation and is demonstrably better than the PR's current fix for this review goal because it localizes the behavior to iOS platform text update helpers, avoids global mapper-order/lifecycle changes across all text handlers, and still covers the mandatory Editor and Issue32886 regression tests.
Candidate #1 Test Results
- Primary:
pwsh .github/scripts/BuildAndRunHostApp.ps1 -Platform ios -TestFilter "LabelFeatureTests|EntryFeatureTests|ButtonFeatureTests"— ✅ 213/213 passed. - Regression:
pwsh .github/skills/run-device-tests/scripts/Run-DeviceTests.ps1 -Project Controls -Platform ios -TestFilter "EditorTests"— ✅ passed, 0 failures. - Regression:
pwsh .github/scripts/BuildAndRunHostApp.ps1 -Platform ios -TestFilter "Issue32886"— ✅ 2/2 passed. - Expert self-review:
reviewer-findings.jsoncontains[].
Candidate #1 Diff
See try-fix/attempt-1/fix.diff and try-fix-1/content.md.
📝 Recommended PR Title & Description
Assessment: ✏️ Recommend updating — the current title and description describe the PR's broader mapper-ordering implementation, but the winning fix is the focused try-fix-1 platform-text approach.
Recommended title
[iOS] Text controls: Preserve attributed formatting when text changes
Recommended description
### Description of Change
This updates the iOS text-control platform helpers so changing text content preserves existing attributed-string formatting instead of dropping character spacing, paragraph style, and text-decoration attributes.
The fix is localized to the iOS platform text update path:
- Adds an internal `NSAttributedString.WithText(...)` helper that creates a new attributed string with replacement text while preserving formatting attributes such as character spacing, paragraph style, strikethrough, and underline.
- Uses that helper from `LabelExtensions.UpdateTextPlainText`, `TextFieldExtensions.UpdateText`, and `TextViewExtensions.UpdateText` so subsequent text changes keep the formatting already applied by MAUI mappers.
- Fixes iOS Entry and SearchBar placeholder character-spacing updates by assigning the `WithCharacterSpacing(...)` result back to the attributed placeholder.
This avoids changing global mapper ordering or handler connection behavior for Button, Entry, Editor, Label, and SearchBar while still addressing the formatted text rendering issue.
### Issues Fixed
Contributing to #30864
🏁 Report — Final Recommendation
Comparative Candidate Report — PR #35892
Candidates compared
| Rank | Candidate | Regression status | Assessment |
|---|---|---|---|
| 1 | try-fix-1 |
✅ Passed primary tests and mandatory regressions (EditorTests, Issue32886) |
Localizes the fix to iOS platform text update helpers, preserves existing attributed formatting when text changes, and fixes placeholder character-spacing assignment without changing global handler mapper order or connection lifecycle behavior. |
| 2 | pr |
❌ Gate failed; regression cross-check failed/error | No high-confidence code-review finding, but the fix has much broader blast radius: mapper reordering and IsConnectingHandler() guards across Button, Entry, Editor, Label, and SearchBar. The supplied gate did not prove the tests catch the bug. |
| 3 | pr-plus-reviewer |
❌ Same as pr |
Expert reviewer produced no actionable findings, so this candidate is identical to pr and inherits the same failed-gate/regression evidence. |
Winning candidate
try-fix-1 wins. It is the only candidate with passing validation evidence, and candidates that failed regression tests must rank below candidates that passed. It also has the smaller implementation surface: rather than changing mapper ordering/lifecycle behavior for every common text control instance, it makes the iOS text setters preserve attributed-string formatting when text content changes.
Why the PR fix does not win
The raw PR fix and pr-plus-reviewer may be directionally reasonable and the expert reviewer found no inline defects, but the evidence is weaker: the supplied gate failed because the selected Button/Entry tests passed without the fix, and the saved regression check reported failure/error for overlapping prior fixes. The PR also changes public iOS/MacCatalyst formatted-string API shape and global handler behavior, increasing review risk compared with the focused try-fix.
🧭 Next Steps — alternative fix proposed (try-fix-1)
Automated review — alternative fix proposed
The expert-reviewer evaluation compared the PR fix against automatically generated candidates and selected try-fix-1 as the strongest fix.
Why: try-fix-1 is the only candidate with passing primary and mandatory regression evidence. It localizes the fix to iOS platform text update helpers instead of changing global mapper ordering and handler connection behavior, so it has lower blast radius than the PR and pr-plus-reviewer candidates.
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/Core/src/Platform/iOS/AttributedStringExtensions.cs b/src/Core/src/Platform/iOS/AttributedStringExtensions.cs
index fbaba09342..f4c9aa2225 100644
--- a/src/Core/src/Platform/iOS/AttributedStringExtensions.cs
+++ b/src/Core/src/Platform/iOS/AttributedStringExtensions.cs
@@ -95,6 +95,34 @@ namespace Microsoft.Maui.Platform
? attributedString.Substring(0, maxLength)
: attributedString;
+ /// <summary>
+ /// Creates a new NSAttributedString with the given text while preserving any formatting
+ /// attributes (character spacing, line height, decorations, paragraph style) from the
+ /// existing attributed string. Returns null if there are no formatting attributes to preserve.
+ /// </summary>
+ internal static NSAttributedString? WithText(this NSAttributedString? attributedString, string newText)
+ {
+ if (attributedString == null || attributedString.Length == 0 || string.IsNullOrEmpty(newText))
+ return null;
+
+ var attrs = attributedString.GetAttributes(0, out _);
+ if (attrs == null || attrs.Count == 0)
+ return null;
+
+ // Only preserve if there are formatting-specific attributes beyond the defaults
+ // that UIKit would set automatically (Font, ForegroundColor).
+ bool hasFormattingAttrs =
+ attrs.ContainsKey(UIStringAttributeKey.KerningAdjustment) ||
+ attrs.ContainsKey(UIStringAttributeKey.ParagraphStyle) ||
+ attrs.ContainsKey(UIStringAttributeKey.StrikethroughStyle) ||
+ attrs.ContainsKey(UIStringAttributeKey.UnderlineStyle);
+
+ if (!hasFormattingAttrs)
+ return null;
+
+ return new NSAttributedString(newText, attrs);
+ }
+
static void UpdateDecoration(NSMutableAttributedString attributedString, NSString key,
NSRange range, TextDecorations decorations)
{
diff --git a/src/Core/src/Platform/iOS/LabelExtensions.cs b/src/Core/src/Platform/iOS/LabelExtensions.cs
index 743173d166..98081a5218 100644
--- a/src/Core/src/Platform/iOS/LabelExtensions.cs
+++ b/src/Core/src/Platform/iOS/LabelExtensions.cs
@@ -105,7 +105,19 @@ namespace Microsoft.Maui.Platform
internal static void UpdateTextPlainText(this UILabel platformLabel, IText label)
{
- platformLabel.Text = label.Text;
+ var newText = label.Text ?? string.Empty;
+
+ // Preserve formatting attributes (character spacing, line height, decorations)
+ // when replacing text content, so that formatting is not lost regardless of
+ // mapper property ordering.
+ var preserved = platformLabel.AttributedText?.WithText(newText);
+ if (preserved != null)
+ {
+ platformLabel.AttributedText = preserved;
+ return;
+ }
+
+ platformLabel.Text = newText;
}
}
}
diff --git a/src/Core/src/Platform/iOS/SearchBarExtensions.cs b/src/Core/src/Platform/iOS/SearchBarExtensions.cs
index a8b498e4ed..a5f16baafe 100644
--- a/src/Core/src/Platform/iOS/SearchBarExtensions.cs
+++ b/src/Core/src/Platform/iOS/SearchBarExtensions.cs
@@ -80,8 +80,8 @@ namespace Microsoft.Maui.Platform
var placeholder = searchBar.Placeholder ?? string.Empty;
var placeholderColor = searchBar.PlaceholderColor is Color color ? color.ToPlatform() : ColorExtensions.PlaceholderColor;
- textField.AttributedPlaceholder = new NSAttributedString(str: placeholder, foregroundColor: placeholderColor);
- textField.AttributedPlaceholder.WithCharacterSpacing(searchBar.CharacterSpacing);
+ var attributed = new NSAttributedString(str: placeholder, foregroundColor: placeholderColor);
+ textField.AttributedPlaceholder = attributed.WithCharacterSpacing(searchBar.CharacterSpacing) ?? attributed;
}
public static void UpdateFont(this UISearchBar uiSearchBar, ITextStyle textStyle, IFontManager fontManager)
diff --git a/src/Core/src/Platform/iOS/TextFieldExtensions.cs b/src/Core/src/Platform/iOS/TextFieldExtensions.cs
index 7d1040697b..fb4e01d0c1 100644
--- a/src/Core/src/Platform/iOS/TextFieldExtensions.cs
+++ b/src/Core/src/Platform/iOS/TextFieldExtensions.cs
@@ -11,7 +11,17 @@ namespace Microsoft.Maui.Platform
{
public static void UpdateText(this UITextField textField, IEntry entry)
{
- textField.Text = entry.Text;
+ var newText = entry.Text;
+
+ // Preserve formatting attributes when replacing text content
+ var preserved = textField.AttributedText?.WithText(newText ?? string.Empty);
+ if (preserved != null)
+ {
+ textField.AttributedText = preserved;
+ return;
+ }
+
+ textField.Text = newText;
}
public static void UpdateTextColor(this UITextField textField, ITextStyle textStyle)
@@ -109,7 +119,9 @@ namespace Microsoft.Maui.Platform
? new NSAttributedString(placeholder)
: new NSAttributedString(str: placeholder, foregroundColor: foregroundColor.ToPlatform());
- textField.AttributedPlaceholder.WithCharacterSpacing(entry.CharacterSpacing);
+ var spacedPlaceholder = textField.AttributedPlaceholder?.WithCharacterSpacing(entry.CharacterSpacing);
+ if (spacedPlaceholder != null)
+ textField.AttributedPlaceholder = spacedPlaceholder;
}
public static void UpdateIsReadOnly(this UITextField textField, IEntry entry)
diff --git a/src/Core/src/Platform/iOS/TextViewExtensions.cs b/src/Core/src/Platform/iOS/TextViewExtensions.cs
index 5c9594fad5..0f19359eb2 100644
--- a/src/Core/src/Platform/iOS/TextViewExtensions.cs
+++ b/src/Core/src/Platform/iOS/TextViewExtensions.cs
@@ -10,6 +10,15 @@ namespace Microsoft.Maui.Platform
{
string text = editor.Text;
+ // Preserve formatting attributes when replacing text content
+ var preserved = textView.AttributedText?.WithText(text ?? string.Empty);
+ if (preserved != null)
+ {
+ if (textView.AttributedText?.Value != text)
+ textView.AttributedText = preserved;
+ return;
+ }
+
if (textView.Text != text)
textView.Text = text;
}
This comment has been minimized.
This comment has been minimized.
Tests Failure Analysis
Test Failure Review: Not ready - click to expandOverall verdict: Not ready. Of 217 distinct failures, 187 are deterministic regressions vs the
Coverage: 141 checks · 118 passing · 23 failing · 0 pending · 0 inaccessible · 1 unmapped · 22 unexplained build legs · 0 unaccounted failing checks · 1 aborted failing checks · 0 canceled-build checks · 3 device-test unverified · 30 unattributed · 187 regressed-vs-base. Deterministic ceiling: Not ready — 187 leg/failures are red on the PR but green on all sampled base builds. Builds (this PR): maui-pr 1531102, maui-pr-devicetests 1531165, maui-pr-uitests 1531162. Base sampling (net11.0, 5 recent builds per definition): maui-pr 1535343, maui-pr-devicetests 1535345, maui-pr-uitests 1535443. Recommended actionA human should review the ~150 Label/VSM/VisualTransform visual-snapshot regressions — confirm whether the rendering changes are intended (and update baseline images) or a genuine regression from the mapping rework — before this PR is merged. Visual failure comparisonsFull-resolution CI baseline, actual, and diff images are embedded below. They supplement the failure classification and do not change the deterministic verdict ceiling.
|
| CI baseline | Fresh PR actual | CI diff |
|---|---|---|
![]() |
![]() |
![]() |
TitleBarWithLargeHeightShell - windows - Needs human investigation - visual comparison
CI reported 0.80% difference in build 1531162.
Relationship to PR: Needs human investigation - No decisive exact test-and-platform baseline attribution was available.
| CI baseline | Fresh PR actual | CI diff |
|---|---|---|
![]() |
![]() |
![]() |
NavBarResetsColorAfterSmallTitleBarShell - windows - Needs human investigation - visual comparison
CI reported 0.80% difference in build 1531162.
Relationship to PR: Needs human investigation - No decisive exact test-and-platform baseline attribution was available.
| CI baseline | Fresh PR actual | CI diff |
|---|---|---|
![]() |
![]() |
![]() |
NavBarResetsColorAfterLargeTitleBarShell - windows - Needs human investigation - visual comparison
CI reported 0.80% difference in build 1531162.
Relationship to PR: Needs human investigation - No decisive exact test-and-platform baseline attribution was available.
| CI baseline | Fresh PR actual | CI diff |
|---|---|---|
![]() |
![]() |
![]() |
TitleBarWithSmallHeight - windows - Needs human investigation - visual comparison
CI reported 0.80% difference in build 1531162.
Relationship to PR: Needs human investigation - No decisive exact test-and-platform baseline attribution was available.
| CI baseline | Fresh PR actual | CI diff |
|---|---|---|
![]() |
![]() |
![]() |
TitleBarWithLargeHeight - windows - Needs human investigation - visual comparison
CI reported 0.80% difference in build 1531162.
Relationship to PR: Needs human investigation - No decisive exact test-and-platform baseline attribution was available.
| CI baseline | Fresh PR actual | CI diff |
|---|---|---|
![]() |
![]() |
![]() |
NavBarResetsColorAfterSmallTitleBar - windows - Needs human investigation - visual comparison
CI reported 0.80% difference in build 1531162.
Relationship to PR: Needs human investigation - No decisive exact test-and-platform baseline attribution was available.
| CI baseline | Fresh PR actual | CI diff |
|---|---|---|
![]() |
![]() |
![]() |
NavBarResetsColorAfterLargeTitleBar - windows - Needs human investigation - visual comparison
CI reported 0.80% difference in build 1531162.
Relationship to PR: Needs human investigation - No decisive exact test-and-platform baseline attribution was available.
| CI baseline | Fresh PR actual | CI diff |
|---|---|---|
![]() |
![]() |
![]() |
VerifyBackgroundColorCleared - windows - Needs human investigation - visual comparison
CI reported 0.79% difference in build 1531162.
Relationship to PR: Needs human investigation - No decisive exact test-and-platform baseline attribution was available.
| CI baseline | Fresh PR actual | CI diff |
|---|---|---|
![]() |
![]() |
![]() |

































Note
Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!
Description of Change
The iOS Label performance was improved in PR Improve iOS Label performance #30864. In that PR, the Label and Entry Feature Matrix test sample and script were modified, which caused discrepancies in the expected images due to changes which is due to test sample's default property values. In this PR, I updated the test sample and re-saved the images accordingly.
Windows - The Entry is now unfocused, so I re-saved the latest image.
Android - I modified the test sample by altering the default values and re-saved two images.
Additionally, while working on the test sample changes, I identified and fixed issues in FormattedStringExtensions.
These updates improve formatted text rendering on iOS by correctly propagating span properties (font, character spacing, and line-break settings) from the label to each span. The layout logic is also more robust, falling back to MAUI’s calculated size when iOS has not yet provided a valid label size, preventing incorrect text positioning and rendering issues.
Issues Fixed
Contributing to #30864