Repository navigation
August 10th, Candidate - #37393
August 10th, Candidate#37393
Conversation
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 37393Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 37393" |
|
Azure Pipelines: Successfully started running 1 pipeline(s). There may be pipelines that require an authorized user to comment /azp run to run. |
|
/azp run maui-pr-uitests |
|
/azp run maui-pr-devicetests |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
1 similar comment
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
|
/azp run maui-pr-devicetests |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
This comment has been minimized.
This comment has been minimized.
MauiBot
left a comment
There was a problem hiding this comment.
Expert Review — 5 findings
See inline comments for details.
| @@ -18,7 +18,7 @@ public partial class TimePickerHandler : ITimePickerHandler | |||
| { | |||
| public static IPropertyMapper<ITimePicker, ITimePickerHandler> Mapper = new PropertyMapper<ITimePicker, ITimePickerHandler>(ViewHandler.ViewMapper) | |||
| { | |||
| #if ANDROID || WINDOWS | |||
| #if IOS || ANDROID || WINDOWS | |||
There was a problem hiding this comment.
🔍 AI-Generated Review (multi-model)
[moderate] Platform-Specific Code Scoping — This guard adds IOS but omits MACCATALYST, while this same PR adds a new TimePickerHandler.MacCatalyst.cs MapBackground implementation (the one that calls RemoveBackgroundLayer() / resets BackgroundColor when the brush is cleared). MACCATALYST and IOS are separate compilation symbols in this repo (see the #if IOS || MACCATALYST pattern used throughout src/Core/src/Handlers, and ImageButtonHandler.cs in this same PR which spells out __IOS__ || MACCATALYST), so on MacCatalyst the entry is never added to the mapper and the new MacCatalyst code is dead. Concrete scenario: set TimePicker.Background to a gradient and then clear it on MacCatalyst — the specialized clear path never runs and the stale background layer remains. Suggested: #if IOS || MACCATALYST || ANDROID || WINDOWS.
| @@ -25,6 +25,7 @@ public partial class DatePickerHandler : IDatePickerHandler | |||
| #if ANDROID || WINDOWS | |||
| [nameof(IDatePicker.Background)] = MapBackground, | |||
| #elif IOS | |||
| [nameof(IDatePicker.Background)] = MapBackground, | |||
There was a problem hiding this comment.
🔍 AI-Generated Review (multi-model)
[moderate] Platform-Specific Code Scoping — Same gap as TimePickerHandler.cs: this new [nameof(IDatePicker.Background)] = MapBackground entry sits under #elif IOS, which does not include MacCatalyst, yet the PR adds MapBackground to DatePickerHandler.MacCatalyst.cs (registered nowhere else — the only mapper registrations for this handler are lines 26 and 28 plus DatePickerHandler2.Android.cs). On MacCatalyst the DatePicker falls back to the generic ViewMapper background mapping, so the newly added ImageSourcePaint support and the RemoveBackgroundLayer() clear path never execute. Suggested: extend the branch to #elif IOS || MACCATALYST (keeping MapFlowDirection iOS-only if that is intended).
|
|
||
| // Strong reference to the launching activity — prevents GC from collecting the CWT entry | ||
| // before Register() can migrate the TCS to the new activity after a config change. | ||
| ComponentActivity _inFlightActivity; |
There was a problem hiding this comment.
🔍 AI-Generated Review (multi-model)
[moderate] Memory Leak Prevention — _inFlightActivity is a strong reference held by a process-wide singleton (PickVisualMediaForResult.Instance / PickMultipleVisualMediaForResult.Instance), replacing the previous WeakReference<ComponentActivity>. It is cleared only in the result callback, in CancelPendingRequest (which ActivityStateManager.OnActivityDestroyed invokes only when IsFinishing == true), and in MigratePendingRequests (only when IsChangingConfigurations == true). Concrete scenario: the picker is open and the OS destroys the launching Activity to reclaim memory — IsFinishing and IsChangingConfigurations are both false, so no path clears the field and the destroyed Activity plus its whole view hierarchy is retained until the next picker launch. Consider storing a WeakReference<ComponentActivity> here (the ConditionalWeakTable entry is already kept alive by the callback's captured registeredActivity).
| { | ||
| lock (gate) | ||
| { | ||
| PruneDeadSubscriptions(); |
There was a problem hiding this comment.
🔍 AI-Generated Review (multi-model)
[moderate] Performance-Critical Path — HasHandlers calls PruneDeadSubscriptions() inside the lock, directly contradicting the doc comment immediately above it ("This is a plain count check and does not prune dead subscriptions on every read ... so it is cheap to query on every sensor reading"). Accelerometer.OnChanged gates shake processing on HasHandlers, so every accelerometer sample (up to SensorSpeed.Fastest) now takes a lock and walks/mutates the whole subscription list instead of doing the advertised count check. The same pattern is duplicated at line 329. Either drop the PruneDeadSubscriptions() call (pruning already happens in Raise/Subscribe/Unsubscribe) or correct the documented contract.
| // would incorrectly skip cleanup the next time it disconnects a newly connected, | ||
| // non-disposed UIStepper if the handler instance is reused. | ||
| _platformViewDisposed = false; | ||
|
|
||
| _proxy.Connect(VirtualView, platformView); | ||
| } | ||
|
|
||
| protected override void DisconnectHandler(UIStepper platformView) | ||
| { | ||
| base.DisconnectHandler(platformView); |
There was a problem hiding this comment.
🔍 AI-Generated Review (multi-model)
[minor] Handler Mapper and Property Patterns — The _platformViewDisposed guard added below (line 84) is documented as running "before touching platformView again ... [so] a second DisconnectHandler call on an already-disposed platform view" is safe, but base.DisconnectHandler(platformView) is invoked first on line 79, i.e. before the guard. On a second disconnect of the same UIStepper (which this code disposes at line 113 on iOS/Mac 26+), any base-class access to the native handle happens on an already-disposed object. Moving if (_platformViewDisposed) return; above the base call would make the code match its stated intent.
|
/azp run |
|
Azure Pipelines: Successfully started running 3 pipeline(s). |
Updated [ShimSkiaSharp](https://github.com/wieslawsoltes/Svg.Skia) from 5.1.1 to 5.2.3. <details> <summary>Release notes</summary> _Sourced from [ShimSkiaSharp's releases](https://github.com/wieslawsoltes/Svg.Skia/releases)._ ## 5.2.3 ## What's Changed * Update SVG upstream and prepare v5.2.3 by @wieslawsoltes in wieslawsoltes/Svg.Skia#562 **Full Changelog**: wieslawsoltes/Svg.Skia@v5.2.2...v5.2.3 ## 5.2.2 ## What's Changed * Add styled Avalonia SVG source resources by @wieslawsoltes in wieslawsoltes/Svg.Skia#560 * Keep run typeface when character fallback finds nothing by @donaldsteele in wieslawsoltes/Svg.Skia#559 * Add net10.0 target to MAUI controls by @wieslawsoltes in wieslawsoltes/Svg.Skia#561 ## New Contributors * @donaldsteele made their first contribution in wieslawsoltes/Svg.Skia#559 **Full Changelog**: wieslawsoltes/Svg.Skia@v5.2.1...v5.2.2 ## 5.2.1 ## What's Changed * Fix Linux SkiaSharp native asset version mismatch by @wieslawsoltes in wieslawsoltes/Svg.Skia#555 * Fix Avalonia SVG opacity layers by @wieslawsoltes in wieslawsoltes/Svg.Skia#556 **Full Changelog**: wieslawsoltes/Svg.Skia@v5.2.0...v5.2.1 ## 5.2.0 ## What's Changed * Update SkiaSharp to 4.148.0 and HarfBuzzSharp to 14.2.0 by @mattleibow in wieslawsoltes/Svg.Skia#544 * Restore Avalonia CurrentColor and CSS overrides by @wieslawsoltes in wieslawsoltes/Svg.Skia#549 * Strong-name sign all packaged assemblies by @wieslawsoltes in wieslawsoltes/Svg.Skia#547 * Honor variable font weights during text shaping by @wieslawsoltes in wieslawsoltes/Svg.Skia#548 * Ensure svg model has no trimmer warnings by @OleRoss in wieslawsoltes/Svg.Skia#551 ## New Contributors * @OleRoss made their first contribution in wieslawsoltes/Svg.Skia#551 **Full Changelog**: wieslawsoltes/Svg.Skia@v5.1.1...v5.2.0 Commits viewable in [compare view](wieslawsoltes/Svg.Skia@v5.1.1...v5.2.3). </details> [](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 <dependency name> major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore <dependency name> minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore <dependency name>` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore <dependency name>` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore <dependency name> <ignore condition>` will remove the ignore condition of the specified dependency and ignore conditions </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
|
/azp run |
|
Azure Pipelines: Successfully started running 3 pipeline(s). |
This comment has been minimized.
This comment has been minimized.
MauiBot
left a comment
There was a problem hiding this comment.
AI Review Summary
@kubaflo — new AI review results are available based on commit
bcf0c90.
🗂️ Review Sessions — click to expand
🚦 Gate — Test Before & After Fix
Gate Result: ✅ PASSED
Platform: ANDROID · Base: main · Merge base: 699f16e4
✅ Fix verified — 3 test(s) reproduce the bug (FAIL without the fix → PASS with it). 1 test(s) pass in both states and are not bug-reproducing; under the "at least one test reproduces the bug and none regress" rule they don't block the gate.
⚠️ Gate coverage limitations
- The A/B gate did not verify 15 dropped DeviceTest group(s): MauiWindowInsetListenerTests (ViewTrackedBeforeImeAnimationStaysGatedAndAttachedViewBypassesGateOnce, GateExemptionIsClearedWhenTheAnimationEnds, GateReleasesSynchronouslyWhenNoAttachedViewIsAvailable, ReapplyStaysOwedWhenTheAnimationEndsWithNoUsablePoster, GatedDispatchesTriggerOneReapplyWhenTheAnimationEnds, StaleGateReleaseDoesNotOpenTheGateOfTheNextAnimation), ExplicitIntentTestActivity, HybridWebViewTests_MessageOrigins (RawMessagesFromOtherOriginsAreIgnored, InvokeCompletionsFromOtherOriginsAreIgnored), BlazorWebViewTests (BlazorWebViewDoesNotClampSmallCssFontSizes, OrdinaryExternalUriCreatesViewIntent, AndroidAppUriPreservesImplicitRoutingData, IntentUriPreservesImplicitRoutingData, StructuredIntentUriRemovesExplicitTargets, StructuredIntentUriRemovesUnsupportedActivityFlags, StructuredIntentUriWithExplicitComponentDoesNotLaunchActivity, IntentUriWithoutBrowsableHandlerDoesNotLaunchActivity, IntentUriWithBrowsableHandlerLaunchesActivity, BlazorStartupSetsUpWindowExternal, BlazorStartupSetsStartingAndStartedFlags, BlazorStartupCapturesNativePort, BlazorStartupScriptIsIdempotent, BlazorStartupRejectionPreservesLiveBridge, BlazorMessageDispatchOnlyProcessesNativeSourceMessages), EntryHandlerTests (SemanticDescriptionInitializesAccessibilityContentDescription, PasswordKeyboardRespectsIsPasswordFalseInitially, PasswordKeyboardIsPasswordToggleWorksCorrectly), CollectionViewTests (ItemsSourceDoesNotLeak), FormattedStringTests (UpdatingFormattedTextClearsPreviousHighlights), SwipeViewTests (SwipeItemCommandExecutesViaAccessibilityActionClick, SwipeItemViewCommandExecutesViaAccessibilityActionClick), MapTests (UpdatingSingleElementPreservesTrackingForOtherElements), CarouselView2 (TableViewSourceReplacementUnsubscribesPreviousSource, ContextActionsCellDisposalUnsubscribesCell, SecondaryToolbarItemDisposalUnsubscribesAfterCustomViewReplacement, HandlerDoesNotLeak), NavigationPageTests (PushingToPageWithoutNavigationBarClearsAppBarInsetPadding), PickerHandlerTests (LongSelectedTextScrollsHorizontallyAndRemainsReadOnly, TapJitterClicksButFastSwipeDoesNot, ExactTouchSlopDoesNotClick, VerticalDragDoesNotClick, CanceledDragDoesNotSuppressNextTap, PointerReplacementWithoutMovementRemainsATap, MovementMethodRemainsDisabled), ScrollViewTests (DoesNotLeak), ControlsHandlerTestBase, WebViewHelpers. Deep UI Tests runs HostApp UI categories only and does not execute DeviceTests; separate device-test validation is required.
- The A/B gate did not verify 53 dropped UI test group(s): Issue35890, Issue36179, Issue36267, Issue36302, Issue36523, Issue36543, Issue36629, Issue36652, Issue36694, Issue36697, Issue36801, Issue36801DeferredElement, Issue36933, Issue37012, Issue35643, Issue37145, Issue34472, Issue34271, ShellSearchHandlerFeatureTests, ShellFlyoutHeaderScrollViewContent, SafeArea_GridFeatureTests, Issue17389, Issue34396, SafeArea_BorderFeatureTests, Issue19883, Issue30381, Issue31480, Issue31917, Issue26924, Issue37187, Material3ImageFeatureTests, Material3TimePickerFeatureTests, SafeArea_ContentPageFeatureTests, SafeArea_ContentViewFeatureTests, ShapesFeatureTests, Material3SwitchFeatureTests, Material3LabelFeatureTests, SoftInputExtensionsPageTests, BorderFeatureTests, SwitchFeatureTests, Issue34898, Issue33034, Issue31731, Issue26049, IndicatorViewFeatureTests, ImageFeatureTests, ImageButtonMaterial3FeatureTests, ImageButtonFeatureTests, ButtonMaterial3FeatureTests, ButtonFeatureTests, Bugzilla44166, LabelFeatureTests, TimePickerFeatureTests. Those UI categories are exercised separately by the Deep UI Tests stage, without the gate's before/after comparison.
| Test | Without Fix (expect FAIL) | With Fix (expect PASS) |
|---|---|---|
🧪 CommandTests CommandTests |
🛠️ BUILD ERROR | ✅ PASS — 97s |
🧪 CSharpExpressionDiagnosticsTests CSharpExpressionDiagnosticsTests |
✅ FAIL — 37s | ✅ PASS — 24s |
🧪 FlexLayoutTests FlexLayoutTests |
🛠️ BUILD ERROR | ✅ PASS — 14s |
🧪 FormattedStringTests FormattedStringTests |
🛠️ BUILD ERROR | ✅ PASS — 14s |
🧪 GeometryGroupMemoryTests GeometryGroupMemoryTests |
🛠️ BUILD ERROR | ✅ PASS — 14s |
🧪 IndicatorViewTests IndicatorViewTests |
🛠️ BUILD ERROR | ✅ PASS — 14s |
🧪 IntegrationTests IntegrationTests |
✅ FAIL — 31s | ✅ PASS — 20s |
🧪 LayoutMemoryTests LayoutMemoryTests |
🛠️ BUILD ERROR | ✅ PASS — 14s |
🧪 LinearGradientBrushTests LinearGradientBrushTests |
🛠️ BUILD ERROR | ✅ PASS — 14s |
🧪 ScrollViewUnitTests ScrollViewUnitTests |
🛠️ BUILD ERROR | ✅ PASS — 14s |
🧪 TableViewUnitTests TableViewUnitTests |
🛠️ BUILD ERROR | ✅ PASS — 14s |
📄 CSharpExpressions.sgen CSharpExpressions.sgen |
🛠️ BUILD ERROR | 🔍 NO MATCH |
📄 Tests Tests |
🛠️ BUILD ERROR | ✅ PASS — 119s |
📱 Android_Permissions_Tests (RequestAsync_FromBackgroundThread_ThrowsPermissionException) Category=Permissions |
✅ FAIL — 765s | ✅ PASS — 353s |
📱 ShellTests (ImplicitLabelStyleOverridesDefaultFlyoutItemTextColor, FlyoutItemLabelClassStyleOverridesDefaultFlyoutItemTextColor, HiddenShellNavigationBarClearsAppBarInsetPadding) Category=Shell |
🛠️ BUILD ERROR | ✅ PASS — 465s |
🖥️ Issue36505 Issue36505 |
🔍 NO MATCH | 🔍 NO MATCH |
🖥️ Issue35889 Issue35889 |
❌ PASS — 1755s | ✅ PASS — 564s |
🔴 Without fix — 🧪 CommandTests: 🛠️ BUILD ERROR · 126s
Error-relevant lines (filtered from the build log):
/home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/ScrollViewUnitTests.cs(987,77): error CS0234: The type or namespace name 'IScrollViewportProvider' does not exist in the namespace 'Microsoft.Maui.Handlers' (are you missing an assembly reference?) [/home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Controls.Core.UnitTests.csproj]
🟢 With fix — 🧪 CommandTests: PASS ✅ · 97s
(no coded error found; showing last 1200 chars)
Passed GenericCanExecute(expected: True) [< 1 ms]
Passed GenericCanExecute(expected: False) [< 1 ms]
This Gate section was shortened to keep every required review section visible. Full details remain available in the pipeline build artifacts.
📋 Pre-Flight — Context & Validation
Pre-Flight: PR #37393
PR Context
- Title: August 10th, Candidate
- State: Open draft
- Base / head:
main/inflight/candidate - Remote head:
bcf0c90b67dff60de8d6df806258f6c945639a5a - Local review materialization:
ab5238f090(PR #37393 squashed for review) - Merge base:
699f16e4c239cae5486c63ed472039aa5c4e6cf2 - Scope: 1,541 files, 32,078 additions, 3,474 deletions. This is the .NET 10 SR11 candidate rollup, not a single-purpose bug-fix PR.
Bounded STEP 5a Target
The Android permissions regression is the bounded target because the gate recorded a genuine behavioral fail/pass result for it and the implementation is independently traceable in git history to Fix stale Android permission requests after off-main-thread failures (#37056).
The existing implementation in src/Essentials/src/Permissions/Permissions.android.cs:
- Checks
MainThread.IsMainThreadbefore allocating or registering a pending request. - Replaces the shared mutable request-code field with a request-local value.
- Removes the matching pending request if
ActivityCompat.RequestPermissionsthrows. - Removes the request under the lock in
OnRequestPermissionsResult, then completes its task outside the lock.
The added regression test, src/Essentials/test/DeviceTests/Tests/Android/Permissions_Tests.cs, invokes a runtime permission request from Task.Run, expects PermissionException, and verifies that the pending-request dictionary count is unchanged.
Test Evidence and Scope
- Platform: Android
- Primary command:
pwsh .github/skills/run-device-tests/scripts/Run-DeviceTests.ps1 -Project Essentials -Platform android -TestFilter "Category=Permissions" - Primary test:
Android_Permissions_Tests.RequestAsync_FromBackgroundThread_ThrowsPermissionException - Gate result: FAIL without the fix (1 failed test), PASS with the fix.
- No separate mandatory regression command was supplied for STEP 5a. The primary category is the only requested test scope for this bounded target; the gate must not be re-run.
The gate also detected unrelated source-generation and integration fail/pass signals across the rollup. Those are outside this bounded Android candidate target. Its Shell device-test group failed to build in the broken baseline because other candidate APIs were removed, so it is not evidence for the permission-request mechanism.
Try-Fix Constraints
- Target implementation file:
src/Essentials/src/Permissions/Permissions.android.cs. - The PR-added permission test is evidence only and must not be modified.
- Each attempt must use
EstablishBrokenBaseline.ps1and obey itsRevertedFilesallow-list. - The candidate rollup includes PR-added production files. If
.github/.baseline-state.jsonhas anyNewFiles, the try-fix skill requires a truthfulBlockedresult before editing, followed by the exact scripted restore. - Pre-existing dirty and untracked pipeline files are harness-owned and must remain untouched.
🔬 Code Review — Deep Analysis
Expert PR Evaluation
Verdict: NEEDS_DISCUSSION
Confidence: low
Independent Assessment
What this changes: The Android permission request path now rejects off-main-thread calls before registering pending state, uses a request-local request code, removes the exact pending entry if native request dispatch throws, and removes callback state under the lock before completing its task outside the lock.
Inferred motivation: Prevent failed permission requests from leaving stale entries in the static pending-request dictionary, avoid races through a shared mutable request code, and avoid task-continuation reentrancy while holding the dictionary lock.
Findings
No actionable defects were found on added or modified lines. The required inline findings artifact contains [].
Test Assessment
The added Android device test directly covers the reported background-thread regression by asserting both PermissionException and an unchanged pending-request count. The trusted Gate reports that this test fails without the fix and passes with it.
The expert identified one non-blocking coverage improvement: add a focused device test that forces ActivityCompat.RequestPermissions to throw on the main thread and verifies the newly added catch removes the matching pending entry. This would directly cover the rollback branch rather than only the earlier background-thread guard.
Failure-Mode Probing
- Off-main-thread request: Throws before activity lookup, request-code allocation, or dictionary registration, so no stale pending entry is created.
- Native request dispatch throws synchronously: The
catchremoves only the entry whose request code and completion source both match this request, then rethrows. - Concurrent callback completion: The callback obtains and removes its completion source under the lock, then completes it outside the lock; a later duplicate callback finds no entry and returns.
- Concurrent request-code reuse: Cleanup checks both the key and
TaskCompletionSourceidentity, so an old failing request cannot remove a newer request that reused the same code.
External Output Contract
Not applicable.
Summary
The submitted mechanism is sound for the bounded Android permissions regression, and no inline code defect was found. The verdict remains NEEDS_DISCUSSION with low confidence only because the expert could not independently retrieve required-check status; the caller-provided trusted Gate does establish targeted fail-without/pass-with evidence.
🛠️ Try-Fix — Analysis & Comparison
Aggregate Try-Fix Results: PR #37393
Candidate 1 — Registration Lease
- Model:
gpt-5.3-codex - Approach: Encapsulate pending-request ownership in a scoped registration lease that removes its request entry unless ownership is explicitly transferred to the asynchronous Android permission callback.
- Prior approach avoided: The existing #37056 implementation relies on an early main-thread precheck plus branch-specific cleanup around
ActivityCompat.RequestPermissions, a request-local code, and callback dequeue/completion separation. - Mechanism-level difference: A dispose-by-default lease would make cleanup an ownership invariant rather than relying on each synchronous failure path to remember to remove the dictionary entry.
- Files changed: None.
- Diff: Empty.
- Test: Not run; the attempt was blocked before edits.
- Result: Blocked
- Failure analysis:
EstablishBrokenBaseline.ps1rejected the pre-existing dirty tracked worktree. No.github/.baseline-state.jsonwas created, so noRevertedFilesedit allow-list existed and the skill prohibited implementation or testing. - Self-review: 0 findings.
- Artifacts:
CustomAgentLogsTmp/PRState/37393/PRAgent/try-fix/attempt-1/ - Detailed narrative:
CustomAgentLogsTmp/PRState/37393/PRAgent/try-fix-1/content.md - Restoration: The exact command
pwsh .github/scripts/EstablishBrokenBaseline.ps1 -Restoreran and reported the valid no-state blocked result (No baseline state found,Restored False).
Candidate 2 — Completion-Coupled Eviction
- Model:
gpt-5.6-sol - Approach: Associate each request-local code and completion source with cleanup triggered by the request task reaching a terminal result or exception.
- Prior approaches avoided: Unlike the current #37056 implementation, cleanup would not depend on an early guard plus explicit rollback branches. Unlike candidate 1, it would not use a scoped registration lease or dispose-by-default ownership.
- Mechanism-level difference: Pending-state eviction would be coupled to task completion, making result or exception completion the single cleanup trigger rather than precondition branches or lease disposal.
- Files changed: None.
- Diff: Empty.
- Test: Not run; the attempt was blocked before edits.
- Result: Blocked
- Failure analysis:
EstablishBrokenBaseline.ps1again rejected the pre-existing dirty tracked worktree. No.github/.baseline-state.jsonwas created, so noRevertedFilesedit allow-list existed and the skill prohibited implementation or testing. - Self-review: 0 findings.
- Artifacts:
CustomAgentLogsTmp/PRState/37393/PRAgent/try-fix/attempt-2/ - Detailed narrative:
CustomAgentLogsTmp/PRState/37393/PRAgent/try-fix-2/content.md - Restoration: The exact command
pwsh .github/scripts/EstablishBrokenBaseline.ps1 -Restoreran and reported the valid no-state blocked result (No baseline state found,Restored False). Target files remained unchanged.
Current Aggregate
| Candidate | Model | Result | Code/Test Outcome |
|---|---|---|---|
| 1 | gpt-5.3-codex |
Blocked | No edit or test; baseline state could not be established |
| 2 | gpt-5.6-sol |
Blocked | No edit or test; baseline state could not be established |
STEP 5a Outcome
Two bounded, mechanism-level alternatives were designed, but neither could be implemented or tested because the mandatory baseline script rejected the harness's pre-existing dirty tracked worktree before creating its restoration state. No candidate code changes remain in the worktree. STEP 5b must treat both candidates as Blocked, not as passing alternatives.
📝 PR Finalize — Recommended Title & Description
Assessment: ✏️ Recommend updating — the current title is not searchable or specific, and the description's snapshot is two commits behind the submitted PR HEAD (113 commits at bcf0c90b, not 111 at b643a7e3).
Recommended title
[Cross-platform] .NET 10 SR11: Promote inflight/candidate into main
Recommended description
## What's Coming
This draft promotes the current `inflight/candidate` contents into `main` for the .NET 10 SR11 (`10.0.110`) candidate cycle.
## Candidate Snapshot
- Initial source: `inflight/current`, followed by candidate-specific stabilization and approved backports
- Rebased onto `main`: [`b96aa036`](https://github.com/dotnet/maui/commit/b96aa036b89fe41fe1ce6cae63a3f2d1550e5682)
- Current candidate head: [`bcf0c90b`](https://github.com/dotnet/maui/commit/bcf0c90b67dff60de8d6df806258f6c945639a5a)
- Final candidate commits relative to `main`: [113 commits](https://github.com/dotnet/maui/compare/b96aa036b89fe41fe1ce6cae63a3f2d1550e5682...inflight/candidate)
- Rebase accounting: all 111 pre-rebase commits map exactly to 111 rebased commits, with no modified, dropped, or added patches; two stabilization commits were added afterward
- Current candidate tree: `67c056e509c2332ed17e14de6fc2fca848d22b0d`
- Patch version: `110`
- PR #37033 remains intentionally excluded because it merged into `inflight/current` after the initial candidate cut.
## Stabilization Since the Initial Cut
- #37669 fixes the MauiBlazorWebView device-test build.
- #37672 reverts unstable iOS and Mac Catalyst leak tests.
- #37810 reverts the iOS wrapped-scroll-content large-title change.
- #37837 completes iOS `ScrollView` requests inside collapsed branches.
- #37438 updates the first set of candidate test failures.
- #38021 fixes the Windows `ContentPresenter` device-test regression; its patch is now supplied by `main`.
- #38096 reverts the Accelerometer weak-event change.
- #38126 backports the BlazorWebView and HybridWebView fixes.
- #38028 updates the remaining candidate test failures and stale iOS snapshots.
- #38392 updates candidate test failures after the latest stabilization.
- #38390 updates the SkiaSharp dependency group.
## Rebase Validation
- [x] Commit accounting: 111 exact pre-rebase mappings with no modified, dropped, or added patches
- [x] At candidate head `b643a7e3`, the independent reference merge and rebased branch had the identical tree ID `3e10281363c889cbafd4de790911efb0ae365e2a`
- [x] Two post-rebase stabilization commits advance the submitted candidate to `bcf0c90b`
This pr-finalize section was shortened to keep every required review section visible. Full details remain available in the pipeline build artifacts.
🏁 Report — Final Recommendation
⚠️ Final Recommendation: REQUEST CHANGES
Winner: pr-plus-reviewer
pr-plus-reviewer preserves the submitted production fix and adds direct regression coverage for its synchronous native-dispatch rollback path. Its one required Android validation run passed, including both the original background-thread regression test and the new rollback test.
Comparative Ranking
| Rank | Candidate | Implementation | Evidence | Assessment |
|---|---|---|---|---|
| 1 | pr-plus-reviewer |
Raw PR fix plus one test-only refinement that forces AndroidX request dispatch to throw after pending-state registration and verifies cleanup | Candidate-root build succeeded with 0 warnings/errors; 283 tests passed, 0 failed; both bounded permission tests passed | Winner. Same sound production mechanism as the PR, with direct coverage of the otherwise untested catch cleanup branch |
| 2 | pr |
Rejects off-main-thread requests before registration, uses a request-local code, conditionally rolls back synchronous dispatch failures, and completes callbacks outside the lock | Trusted Gate: test fails without fix and passes with fix; expert review found no actionable defect | Correct and proven for the reported stale-request regression, but its submitted test covers only the early main-thread guard, not the new post-registration rollback branch |
| 3 | try-fix-1 |
Proposed a dispose-by-default registration lease | Blocked before edits; empty diff; no tests run | Design-only candidate with no executable evidence |
| 4 | try-fix-2 |
Proposed completion-coupled pending-state eviction | Blocked before edits; empty diff; no tests run | Design-only candidate with no executable evidence and a broader lifecycle change than needed |
No candidate failed a regression test. The two passing candidates therefore rank above both blocked try-fix candidates, which produced neither code nor test evidence.
Expert Review Reconciliation
The single MAUI expert pass found no actionable file:line defect in the submitted Android permission implementation or regression test; inline-findings.json is []. It identified one worthwhile non-blocking improvement: directly exercise cleanup when ActivityCompat.RequestPermissions throws synchronously. pr-plus-reviewer implements exactly that suggestion without adding a production hook, changing public API, or altering the submitted fix.
Why the Submitted PR Still Needs Changes
The raw PR is behaviorally sound, and the trusted Gate proves the reported fix. However, pr-plus-reviewer is the stronger candidate because its validated test locks in the second cleanup invariant introduced by the production change. Since the winning test is not present in submitted PR HEAD, the required recommendation is REQUEST CHANGES.
Validation and Uncertainty
The candidate command was run exactly once from /home/vsts/work/_temp/pr-37393-pr-plus-reviewer; no iterative repair/retest loop or full-suite run was performed. This comparative recommendation is bounded to the Android permissions fix selected in STEP 5a and does not claim to audit the unrelated 1,541-file SR11 rollup.
📱 UI Tests — Border,Brush,Button,CarouselView,CollectionView,DatePicker,Editor,Entry,Image,ImageButton,IndicatorView,Label,Layout,ListView,Material3,Page,RadioButton,SafeAreaEdges,ScrollView,Shape,Shell,SoftInput,SwipeView,Switch,TableView,TimePicker,ViewBaseTests,WebView
Detected UI test categories: Border,Brush,Button,CarouselView,CollectionView,DatePicker,Editor,Entry,Image,ImageButton,IndicatorView,Label,Layout,ListView,Material3,Page,RadioButton,SafeAreaEdges,ScrollView,Shape,Shell,SoftInput,SwipeView,Switch,TableView,TimePicker,ViewBaseTests,WebView
❌ Deep UI tests — 1019 passed, 2 failed, 13 skipped across 12 categories on platform-pool agent (replaces in-process counts above). The build failed to compile for 1 category (ListView), so those deep UI tests could not run. The compiler reported: error NU1801: Warning As Error: Unable to load the service index for source https://pkgs.dev.azure.com/dnceng/public/_packaging/darc-pub-dotnet-aspnetcore-58518050/nuget/v3/index.json. [/home/vsts/work/1/s/src/Controls/tests/TestCases.Andro…. The cause is undetermined: the diagnostic is reported in unchanged file src/Essentials/src/Essentials.csproj, but a PR API/signature change can break an unchanged consumer. Compare the same build against the reviewed base before attributing it; inspect build-output.log, then re-comment /review after the build issue is resolved. The deep UI run for 1 category (CollectionView) exceeded the per-category time budget (a very long-running category or a slow build/deploy) and was stopped before finishing. This is an infrastructure/timeout issue, not a code problem; re-run the review, and if a category consistently needs more time the per-category budget can be raised (DEEP_UITEST_CATEGORY_CAP_MIN / DEEP_UITEST_HARDSTOP_MIN). See the build-output.log in the drop-deep-uitests artifact.
🧪 UI Test Execution Results (deep, platform pool)
| Category | Tests | Snapshot diffs |
|---|---|---|
Border |
65/65 ✓ | — |
Brush |
42/42 ✓ | — |
Button |
104/106 (2 skipped) ✓ | — |
CarouselView |
98/99 (1 ❌) | 1 diff PNG |
DatePicker |
45/45 ✓ | — |
Editor |
85/88 (3 skipped) ✓ | — |
Entry |
111/113 (1 ❌, 1 skipped) | — |
Image |
50/52 (2 skipped) ✓ | — |
ImageButton |
58/58 ✓ | — |
IndicatorView |
43/43 ✓ | — |
Label |
123/125 (2 skipped) ✓ | — |
Layout |
195/198 (3 skipped) ✓ | — |
🔍 AI analysis of failures — PR-related vs unrelated
🔍 AI-generated triage (GitHub Copilot CLI) — a heuristic judgement of whether each deep UI test failure is connected to this PR's changes. Verify before relying on it.
Mixed / uncertain: see the grouped assessment below.
- ℹ Uncertain — Android CarouselView visual comparison (~1 test): the 4.87% snapshot mismatch could be a baseline-only issue, but the unavailable changed-file and diff evidence prevents ruling out a PR change to shared or Android CarouselView rendering.
- ● Unrelated — UI automation stale-element failure (~1 test): the Entry test failed because the cached
ThemeButtondisappeared from the DOM, a non-deterministic Selenium synchronization pattern rather than evidence of a product regression.
Strongest signal: the stale-element exception is clearly test automation flakiness; the CarouselView result needs PR scope or snapshot comparison evidence for attribution.
❌ CarouselView — 1 failed test
VerticalCarouselMandatorySingleSnapAdvancesOneCard
VisualTestUtils.VisualTestFailedException :
Snapshot different than baseline: VerticalCarouselMandatorySingleSnapAdvancesOneCard.png (4.87% difference)
If the correct baseline has changed (this isn't a a bug), then update the baseline image.
See test attachment or download the build artifacts to get the new snapshot file.
More info: https://aka.ms/visual-test-workflow
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 296
at Microsoft.Maui.TestCases.Tests.Issues.Issue33308.VerticalCarouselMandatorySingleSnapAdvancesOneCard() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue33308.cs:line 26
at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, Bi
...
❌ Entry — 1 failed test
EntryClearButtonColorShouldUpdateOnThemeChange
OpenQA.Selenium.StaleElementReferenceException : Cached elements 'By.id: com.microsoft.maui.uitests:id/ThemeButton' do not exist in DOM anymore; For documentation on this error, please visit: https://www.selenium.dev/documentation/webdriver/troubleshooting/errors#stale-element-reference-exception
at OpenQA.Selenium.WebDriver.UnpackAndThrowOnError(Response errorResponse, String commandToExecute)
at OpenQA.Selenium.WebDriver.ExecuteAsync(String driverCommandToExecute, Dictionary`2 parameters)
at OpenQA.Selenium.WebDriver.InternalExecute(String driverCommandToExecute, Dictionary`2 parameters)
at OpenQA.Selenium.WebElement.Execute(String commandToExecute, Dictionary`2 parameters)
at OpenQA.Selenium.Appium.AppiumElement.Execute(String commandName, Dictionary`2 parameters)
at OpenQA.Selenium.Appium.AppiumElement._GetAttribute(String attributeName)
at OpenQA.Selenium.Appium.AppiumElement.<>c__DisplayClass21_0.<GetAttribute>b__0()
at OpenQA.Selenium.Appium.AppiumElement.Ca
...
📎 Download drop-deep-uitests artifact (TRX + snapshot diffs)
🧭 Next Steps — reviewer changes required
The reviewer-enhanced candidate identified changes that are not yet in the submitted PR.
Why: The submitted production fix is sound and passes the trusted Gate, while pr-plus-reviewer adds direct coverage for synchronous native-dispatch rollback without changing product code. Its candidate-root Android validation passed both bounded permission tests with no failures.
Address the actionable findings in this review before merging.
|
all tests are green |
|
Azure Pipelines: Successfully started running 1 pipeline(s). There may be pipelines that require an authorized user to comment /azp run to run. |
<!-- Please let the below note in for people that find this PR --> > [!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! ## Summary Advance `main` to the .NET 10 SR12 development cycle now that `release/10.0.1xx-sr11` has been cut from the merge of #37393 (`e047434fd22752a3e96187d55cd554a4a1c200b5`). Change only `PatchVersion` in `eng/Versions.props` from `110` to `120`. Keep `SdkBandVersion=10.0.100`, `PreReleaseVersionLabel=ci.main` (including the inflight override), and `StabilizePackageVersion=false` unchanged. This is separate from the SR11 servicing-flip PR and does not change the release branch. Related: #38210. ## Validation - Evaluated `eng/Versions.props` using `dotnet msbuild -getProperty`: version `10.0.120`, SDK band `10.0.100`, prerelease label `ci.main`, stable versions disabled. - Ran the repository formatter scoped to `eng/Versions.props` and confirmed the final diff is exactly one changed line.
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!
What's Coming
This draft promotes the current
inflight/candidatecontents intomainfor the .NET 10 SR11 (10.0.110) candidate cycle.Candidate Snapshot
inflight/current, followed by candidate-specific stabilization and approved backportsmain:b96aa036b643a7e3main: 111 commits110inflight/currentafter the initial candidate cut.Stabilization Since the Initial Cut
ScrollViewrequests inside collapsed branches.ContentPresenterdevice-test regression; its patch is now supplied bymain.Rebase Validation
3e10281363c889cbafd4de790911efb0ae365e2aScrollViewUnitTestspassmaui-pr,maui-pr-devicetests, andmaui-pr-uitestsruns completeThis PR remains a draft while candidate validation and stabilization continue.