Skip to content

[automated] Merge branch 'main' => 'net11.0'#34789

Merged
PureWeen merged 13 commits intonet11.0from
merge/main-to-net11.0
Apr 2, 2026
Merged

[automated] Merge branch 'main' => 'net11.0'#34789
PureWeen merged 13 commits intonet11.0from
merge/main-to-net11.0

Conversation

@github-actions
Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot commented Apr 2, 2026

I detected changes in the main branch which have not been merged yet to net11.0. I'm a robot and am configured to help you automatically keep net11.0 up to date, so I've opened this PR.

This PR merges commits made on main by the following committers:

  • mattleibow
  • StephaneDelcroix
  • rmarinho
  • pictos
  • PureWeen

Instructions for merging from UI

This PR will not be auto-merged. When pull request checks pass, complete this PR by creating a merge commit, not a squash or rebase commit.

merge button instructions

If this repo does not allow creating merge commits from the GitHub UI, use command line instructions.

Instructions for merging via command line

Run these commands to merge this pull request from the command line.

git fetch
git checkout main
git pull --ff-only
git checkout net11.0
git pull --ff-only
git merge --no-ff main

# If there are merge conflicts, resolve them and then run git merge --continue to complete the merge
# Pushing the changes to the PR branch will re-trigger PR validation.
git push https://github.com/dotnet/maui HEAD:merge/main-to-net11.0
or if you are using SSH
git push git@github.com:dotnet/maui HEAD:merge/main-to-net11.0

After PR checks are complete push the branch

git push

Instructions for resolving conflicts

⚠️ If there are merge conflicts, you will need to resolve them manually before merging. You can do this using GitHub or using the command line.

Instructions for updating this pull request

Contributors to this repo have permission update this pull request by pushing to the branch 'merge/main-to-net11.0'. This can be done to resolve conflicts or make other changes to this pull request before it is merged.
The provided examples assume that the remote is named 'origin'. If you have a different remote name, please replace 'origin' with the name of your remote.

git fetch
git checkout -b merge/main-to-net11.0 origin/net11.0
git pull https://github.com/dotnet/maui merge/main-to-net11.0
(make changes)
git commit -m "Updated PR with my changes"
git push https://github.com/dotnet/maui HEAD:merge/main-to-net11.0
or if you are using SSH
git fetch
git checkout -b merge/main-to-net11.0 origin/net11.0
git pull git@github.com:dotnet/maui merge/main-to-net11.0
(make changes)
git commit -m "Updated PR with my changes"
git push git@github.com:dotnet/maui HEAD:merge/main-to-net11.0

Contact .NET Core Engineering (dotnet/dnceng) if you have questions or issues.
Also, if this PR was generated incorrectly, help us fix it. See https://github.com/dotnet/arcade/blob/main/.github/workflows/scripts/inter-branch-merge.ps1.

PureWeen and others added 9 commits March 25, 2026 09:44
…34548)

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

## Description

Adds a [gh-aw (GitHub Agentic
Workflows)](https://github.github.com/gh-aw/introduction/overview/)
workflow that automatically evaluates test quality on PRs using the
`evaluate-pr-tests` skill.

### What it does

When a PR adds or modifies test files, this workflow:
1. **Checks out the PR branch** (including fork PRs) in a pre-agent step
2. **Runs the `evaluate-pr-tests` skill** via Copilot CLI in a sandboxed
container
3. **Posts the evaluation report** as a PR comment using gh-aw
safe-outputs

### Triggers

| Trigger | When | Fork PR support |
|---------|------|-----------------|
| `pull_request` | Automatic on test file changes (`src/**/tests/**`) |
❌ Blocked by `pre_activation` gate |
| `workflow_dispatch` | Manual — enter PR number | ✅ Works for all PRs |
| `issue_comment` (`/evaluate-tests`) | Comment on PR | ⚠️ Same-repo
only (see Known Limitations) |

### Security model

| Layer | Implementation |
|-------|---------------|
| **gh-aw sandbox** | Agent runs in container with scrubbed credentials,
network firewall |
| **Safe outputs** | Max 1 PR comment per run, content-limited |
| **Checkout without execution** | `steps:` checks out PR code but never
executes workspace scripts |
| **Base branch restoration** | `.github/skills/`,
`.github/instructions/`, `.github/copilot-instructions.md` restored from
base branch after checkout |
| **Fork PR activation gate** | `pull_request` events blocked for forks
via `head.repo.id == repository_id` |
| **Pinned actions** | SHA-pinned `actions/checkout`,
`actions/github-script`, etc. |
| **Minimal permissions** | Each job declares only what it needs |
| **Concurrency** | One evaluation per PR, cancels in-progress |
| **Threat detection** | gh-aw built-in threat detection analyzes agent
output |

### Files added/modified

- `.github/workflows/copilot-evaluate-tests.md` — gh-aw workflow source
- `.github/workflows/copilot-evaluate-tests.lock.yml` — Compiled
workflow (auto-generated by `gh aw compile`)
- `.github/skills/evaluate-pr-tests/scripts/Gather-TestContext.ps1` —
Test context gathering script (binary-safe file download, path traversal
protection)
- `.github/instructions/gh-aw-workflows.instructions.md` — Copilot
instructions for gh-aw development

### Known Limitations

**Fork PR evaluation via `/evaluate-tests` comment is not supported in
v1.** The gh-aw platform inserts a `checkout_pr_branch.cjs` step after
all user steps, which may overwrite base-branch skill files restored for
fork PRs. This is a known gh-aw platform limitation — user steps always
run before platform-generated steps, with no way to insert steps after.

**Workaround:** Use `workflow_dispatch` (Actions UI → "Run workflow" →
enter PR number) to evaluate fork PRs. This trigger bypasses the
platform checkout step entirely and works correctly.

**Related upstream issues:**
- [github/gh-aw#18481](github/gh-aw#18481) —
"Using gh-aw in forks of repositories"
- [github/gh-aw#18518](github/gh-aw#18518) —
Fork detection and warning in `gh aw init`
- [github/gh-aw#18520](github/gh-aw#18520) —
Fork context hint in failure messages
- [github/gh-aw#18521](github/gh-aw#18521) —
Fork support documentation

### Fixes

- Fixes #34602

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Jakub Florkowski <kubaflo123@gmail.com>
## Summary

Enables the copilot-evaluate-tests gh-aw workflow to run on fork PRs by
adding `forks: ["*"]` to the `pull_request` trigger and removing the
fork guard from `Checkout-GhAwPr.ps1`.

## Changes

1. **copilot-evaluate-tests.md**: Added `forks: ["*"]` to opt out of
gh-aw auto-injected fork activation guard. Scoped `Checkout-GhAwPr.ps1`
step to `workflow_dispatch` only (redundant for other triggers since
platform handles checkout).

2. **copilot-evaluate-tests.lock.yml**: Recompiled via `gh aw compile` —
fork guard removed from activation `if:` conditions.

3. **Checkout-GhAwPr.ps1**: Removed the `isCrossRepository` fork guard.
Updated header docs and restore comments to accurately describe behavior
for all trigger×fork combinations (including corrected step ordering).

4. **gh-aw-workflows.instructions.md**: Updated all stale references to
the removed fork guard. Documented `forks: ["*"]` opt-in, clarified
residual risk model for fork PRs, and updated troubleshooting table.

## Security Model

Fork PRs are safe because:
- Agent runs in **sandboxed container** with all credentials scrubbed
- Output limited to **1 comment** via `safe-outputs: add-comment: max:
1`
- Agent **prompt comes from base branch** (`runtime-import`) — forks
cannot alter instructions
- Pre-flight check catches missing `SKILL.md` if fork isn't rebased on
`main`
- No workspace code is executed with `GITHUB_TOKEN` (checkout without
execution)

## Testing

- ✅ `workflow_dispatch` tested against fork PR #34621
- ✅ Lock.yml statically verified — fork guard removed from `if:`
conditions
- ⏳ `pull_request` trigger on fork PRs can only be verified post-merge
(GitHub Actions reads lock.yml from default branch)

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… is compiled (#34717)

## Description

Adds regression tests for #34713 verifying the XAML source generator
correctly handles bindings with `Converter={StaticResource ...}` inside
`x:DataType` scopes.

Closes #34713

## Investigation

After thorough investigation of the source generator pipeline
(`KnownMarkups.cs`, `CompiledBindingMarkup.cs`, `NodeSGExtensions.cs`):

### When converter IS in page resources (compile-time resolution ✅)

`GetResourceNode()` walks the XAML tree, finds the converter resource,
and `ProvideValueForStaticResourceExtension` returns the variable
directly — **no runtime `ProvideValue` call**. The converter is
referenced at compile time.

### When converter is NOT in page resources (runtime resolution ✅)

`GetResourceNode()` returns null → falls through to `IsValueProvider` →
generates `StaticResourceExtension.ProvideValue(serviceProvider)`. The
`SimpleValueTargetProvider` provides the full parent chain, and
`TryGetApplicationLevelResource` checks `Application.Current.Resources`.
The binding IS still compiled into a `TypedBinding` — only the converter
resolution is deferred.

### Verified on both `main` and `net11.0`

All tests pass on both branches.

## Tests added

| Test | What it verifies |
|------|-----------------|
| `SourceGenResolvesConverterAtCompileTime_ImplicitResources` |
Converter in implicit `<Resources>` → compile-time resolution, no
`ProvideValue` |
| `SourceGenResolvesConverterAtCompileTime_ExplicitResourceDictionary` |
Converter in explicit `<ResourceDictionary>` → compile-time resolution,
no `ProvideValue` |
| `SourceGenCompilesBindingWithConverterToTypedBinding` | Converter NOT
in page resources → still compiled to `TypedBinding`, no raw `Binding`
fallback |
| `BindingWithConverterFromAppResourcesWorksCorrectly` × 3 | Runtime
behavior correct for all inflators (Runtime, XamlC, SourceGen) |

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
<!-- 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!

## Description

Adds arcade inter-branch merge workflow and configuration to automate
merging `net11.0` into the `release/11.0.1xx-preview3` branch.

### Files added

| File | Purpose |
|------|---------|
| `github-merge-flow-release-11.jsonc` | Merge flow config — source
`net11.0`, target `release/11.0.1xx-preview3` |
| `.github/workflows/merge-net11-to-release.yml` | GitHub Actions
workflow — triggers on push to net11.0, daily cron, manual dispatch |

### How it works

Uses the shared [dotnet/arcade inter-branch merge
infrastructure](https://github.com/dotnet/arcade/blob/main/.github/workflows/inter-branch-merge-base.yml):
- **Event-driven**: triggers on push to `net11.0`, with daily cron
safety net
- **ResetToTargetPaths**: auto-resets `global.json`, `NuGet.config`,
`eng/Version.Details.xml`, `eng/Versions.props`, `eng/common/*` to
target branch versions
- **QuietComments**: reduces GitHub notification noise
- Skips PRs when only Maestro bot commits exist

### Incrementing for future releases

When cutting a new release (e.g., preview4), update:
1. `github-merge-flow-release-11.jsonc` → change `MergeToBranch` value
2. `.github/workflows/merge-net11-to-release.yml` → update workflow
`name` field

Follows the same pattern as `merge-main-to-net11.yml` /
`github-merge-flow-net11.jsonc`.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->



<!-- Enter description of the fix in this section -->

### Issues Fixed

<!-- Please make sure that there is a bug logged for the issue being
fixed. The bug should describe the problem and how to reproduce it. -->

Fixes #33355

### Description of Change

This report has the goal to provide a detailed progress on the solution
of the memory-leak

The test consists doing 100 navigations between 2 pages, as the image
below suggest

<img width="876" height="502" alt="image"
src="https://github.com/user-attachments/assets/e9e80768-dd40-4445-9fc8-90469579236c"
/>


Running the gc-dump on the desired objects this is what I found.

> BaseLine is the dump when the app starts.

| | | | | |
| ------------------------------------ | ------- | ------------ |
-------------- | ------------------------ |
| Object Type | Count | Size (Bytes) | Expected Count | Status |
| **Page2** | **100** | 84,000 | 1 | ❌ **LEAKED** (99 extra) |
| **PageHandler** | **103** | 9,888 | 4 | ❌ **LEAKED** (99 extra) |
| **StackNavigationManager** | **102** | 16,320 | 1 | ❌ **LEAKED** (101
extra) |
| **StackNavigationManager.Callbacks** | **102** | 5,712 | 1 | ❌
**LEAKED** (101 extra) |
| **NavigationViewFragment** | **102** | 5,712 | ~2 | ❌ **LEAKED** (100
extra) |

So the first fix was to call `Disconnect` handler, on the
`previousDetail` during the `FlyoutPage.Detail_set`. The PageChanges and
Navigated events will not see this, since this `set` is not considered a
navigation in .Net Maui.

After that we see the following data

| | | | | |
| ------------------------------------ | ------- | ------------ |
---------------------- | ------------ |
| Object Type | Count | Size (Bytes) | vs Baseline | Status |
| **Page2** | **100** | 84,000 | Same | ❌ **LEAKED** |
| **PageHandler** | **103** | 9,888 | Same | ❌ **LEAKED** |
| **StackNavigationManager** | **102** | 16,320 | Same | ❌ **LEAKED** |
| **StackNavigationManager.Callbacks** | **1** | 56 | ✅ **FIXED!** (was
102) | ✅ **Good!** |
| **NavigationViewFragment** | **102** | 5,712 | Same | ❌ **LEAKED** |

So, calling the Disconnect handler will fix the leak at
`StackNavigationManager.Callbacks`. Next step was to investigate the
`StackNavigationManager` and see what's holding it.

On `StackNavigationManager` I see lot of object that should be cleaned
up in order to release other references from it. After cleaning it up
the result is

|   |   |   |   |   |
|---|---|---|---|---|
|Object Type|Count|Size (Bytes)|vs Baseline|Status|
|**Page2**|**1**|840|✅ **FIXED!** (was 100)|✅ **Perfect!**|
|**PageHandler**|**4**|384|✅ **FIXED!** (was 103)|✅ **Perfect!**|
|**StackNavigationManager**|**102**|16,320|❌ Still leaking (was 102)|❌
**Unchanged**|
|**StackNavigationManager.Callbacks**|**1**|56|✅ Fixed (was 102)|✅
**Good!**|
|**NavigationViewFragment**|**102**|5,712|❌ Still leaking (was 102)|❌
**Unchanged**|

So something is still holding the `StackNavigationManager` and
`NavigationViewFragment` so I changed the approach and found that
`NavigationViewFragment` is holding everything and after fixing that,
cleaning it up on `Destroy` method. here's the result

|   |   |   |   |   |
|---|---|---|---|---|
|Object Type|Count|Size (Bytes)|vs Previous|Status|
|**Page2**|**1**|840|✅ Same|✅ **Perfect!**|
|**PageHandler**|**4**|384|✅ Same|✅ **Perfect!**|
|**StackNavigationManager**|**1**|160|🎉 **FIXED!** (was 102)|🎉
**FIXED!**|
|**StackNavigationManager.Callbacks**|**1**|56|✅ Same|✅ **Perfect!**|
|**NavigationViewFragment**|**102**|5,712|⚠️ Still present|⚠️
**Remaining**|

With that there's still the leak of `NavigationViewFragment`, looking at
the graph the something on Android side is holding it, there's no root
into managed objects, as far the gcdump can tell. I tried to cleanup the
`FragmentManager`, `NavController` and so on but without success (maybe
I did it wrong).

There's still one instance of page 2, somehow it lives longer, I don't
think it's a leak object because since its value is 1. For reference the
Page2 graph is
```
Page2 (1 instance)
 └── PageHandler
     └── EventHandler<FocusChangeEventArgs>
         └── IOnFocusChangeListenerImplementor (Native Android)
             └── UNDEFINED

```


Looking into www I found that android caches those Fragments, sadly in
our case we don't reuse them. The good part is each object has only 56
bytes, so it shouldn't be a big deal, I believe we can take the
improvements made by this PR and keep an eye on that, maybe that's fixed
when moved to Navigation3 implementation.
<!-- 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

Adds the `maui device list` command specification to the existing CLI
design document (`docs/design/cli.md`). This command provides unified,
cross-platform device enumeration without requiring a project context.

See [PR #33865](#33865) for the full
DevTools spec.

## What is added

### Command: `maui device list [--platform <p>] [--json]`

Lists connected devices, running emulators, and available simulators
across all platforms in a single call.

### Two approaches analysis

The spec analyzes two discovery approaches and recommends the
project-free one:

| | MSBuild (`dotnet run --list-devices`) | Native CLI (`maui device
list`) |
|---|---|---|
| Project required | Yes | **No** |
| Cross-platform | One TFM at a time | All platforms at once |
| Speed | Slower (MSBuild eval) | Fast (<2s) |
| ID compatibility | Source of truth | Same native IDs |

### Scenarios requiring project-free discovery

1. AI agent bootstrapping (no `.csproj` yet)
2. IDE startup (device picker before project loads)
3. Environment validation ("can I see my phone?")
4. CI pipeline setup (check emulator before build)
5. Multi-project solutions (unified view)
6. Cross-platform overview (all devices at once)

### Recommended approach

`maui device list` uses direct native tool invocation (`adb devices`,
`simctl list`, `devicectl list`). Device IDs are compatible with `dotnet
run --device`, making them complementary:

```
maui device list          →  "What devices exist on this machine?"
dotnet run --list-devices →  "What devices can run this project?"
```

### Other changes

- Added references to `ComputeAvailableDevices` MSBuild targets in
[dotnet/android](https://github.com/dotnet/android) and
[dotnet/macios](https://github.com/dotnet/macios)
- Updated AI agent workflow example to include device discovery step
- Fixed AppleDev.Tools reference (xcdevice → devicectl)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…34727)

## Description

Fixes #34726

The XAML source generator interpolates `x:Key` values directly into
generated C# string literals without escaping special characters. If an
`x:Key` contains a double quote (`"`), backslash (`\`), or control
character, the generated C# is syntactically invalid.

## Changes

- **`SetPropertyHelpers.cs`** — Escape the `x:Key` value via
`CSharpExpressionHelpers.EscapeForString()` before interpolating into
the generated `resources["..."] = ...` assignment.
- **`KnownMarkups.cs`** — Same fix for `DynamicResource` key emission
(`new DynamicResource("...")`).
- **`CSharpExpressionHelpers.cs`** — Changed `EscapeForString` from
`private static` to `internal static` so it can be reused from
`SetPropertyHelpers` and `KnownMarkups`.

## Test

Added `Maui34726.xaml` / `.xaml.cs` XAML unit test with `x:Key` values
containing double quotes and backslashes:
- **SourceGen path**: Verifies the generated code compiles without
diagnostics
- **Runtime/XamlC paths**: Verifies the resources are accessible by
their original (unescaped) key names

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…34576)

> [!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

Major improvements to the Essentials AI sample app: new Landmark Detail
page with AI features, semantic search, streaming response handler
improvements, and comprehensive UI polish across all pages for a modern,
edge-to-edge experience on iOS and MacCatalyst.

### New Features

- **Landmark Detail Page** — New intermediate page between browsing and
trip planning with AI-generated travel tips, similar destinations via
semantic search, animated hashtag tags, language picker, full-bleed hero
image with scrolling gradient overlay, and Plan Trip navigation
- **Semantic Search** — Search bar on Landmarks page filters continent
groups using semantic similarity with `Timer`-based debounce (300ms) and
tracks recent searches for contextual AI descriptions
- **ISemanticSearchService abstraction** — Clean interface backed by
`EmbeddingSearchService` (Apple NL embeddings + cosine similarity +
hybrid keyword boost + sentence chunking)
- **StreamingResponseHandler passthrough mode** — Supports streaming
without buffering, with new device tests
(`DeliversMultipleIncrementalUpdates`, `ConcatenatedText`)
- **PromptBasedSchemaClient** — Prompt-based JSON schema middleware for
Phi Silica compatibility

### UI Polish

- **Edge-to-edge layout** — All pages use `SafeAreaEdges="None"` on root
Grid with back buttons wrapped in `SafeAreaEdges="Container"`
- **Scrolling gradient pattern** — Fixed gradient overlay + scrolling
gradient that transitions to solid background
- **Custom search entry** — Replaced `SearchBar` with borderless `Entry`
in rounded `Border` with native border/focus ring removed on
iOS/MacCatalyst
- **Edge-to-edge horizontal scrollers** — Scroll to screen edges, align
with page content padding at rest
- **Removed broken BoxView global style** — Was breaking gradient
overlays
- **Added missing Gray700 color** — Prevented silent navigation crash
- **Background → Background property migration** — Replaced
`BackgroundColor` with `Background` across all pages

### Code Quality

- **IDispatcher injection** instead of
`MainThread.BeginInvokeOnMainThread`
- **Only-once AI initialization** — Guard against re-entry in
`LandmarkDetailViewModel`
- **Null safety** — Fixed CS8602 warnings in DataService search methods
- **Removed debug logging**

### Navigation Flow

`LandmarksPage` (browse + search) → `LandmarkDetailPage` (details + AI
tips) → `TripPlanningPage` (itinerary generation)

### Deleted Files

- `LandmarkDescriptionView`, `LandmarkTripView` — Replaced by new pages
- `LanguagePreferenceService` — Refactored into inline language array

### New Test Coverage

- `StreamingResponseHandlerTests/Passthrough.cs` — Unit tests for
passthrough streaming mode
- `ChatClientStreamingTestsBase` — Updated device tests for streaming
scenarios

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Reset patterns:
- global.json
- NuGet.config
- eng/Version.Details.xml
- eng/Versions.props
- eng/common/*
@github-actions
Copy link
Copy Markdown
Contributor Author

github-actions Bot commented Apr 2, 2026

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://github.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 34789

Or

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

PureWeen and others added 2 commits April 2, 2026 13:52
MonoPackageVersion and MonoVersionBand were left at 10.0.100 when the
net11.0 branch was created. This causes Workloads.csproj to download the
.NET 10 Emscripten.Current manifest which conflicts with the .NET 11 SDK's
emscripten.net10 manifest (both define the same pack names).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@PureWeen PureWeen force-pushed the merge/main-to-net11.0 branch from 2880850 to 5c9494e Compare April 2, 2026 18:53
@github-actions
Copy link
Copy Markdown
Contributor Author

github-actions Bot commented Apr 2, 2026

🧪 PR Test Evaluation

Overall Verdict: ⚠️ Tests need improvement

This automated merge PR bundles several independent fixes from main. Tests cover the key areas well, but the cross-platform FlyoutPage.cs fix has only an Android-scoped memory test, and the AI device tests carry inherent flakiness risk due to non-deterministic LLM responses.

👍 / 👎 — Was this evaluation helpful? React to let us know!

📊 Expand Full Evaluation

PR Test Evaluation Report

PR: #34789[automated] Merge branch 'main' => 'net11.0'
Test files evaluated: 7
Fix files: 51 (logical groups: AI streaming, SourceGen, FlyoutPage/Android navigation)


Overall Verdict

⚠️ Tests need improvement

The FlyoutPage.cs fix (handler disconnection on detail change) is cross-platform but is only tested by an Android-scoped memory test. iOS/MacCatalyst coverage is absent despite PhoneFlyoutPageRenderer being registered in SetupBuilder. Additionally, two AI device tests assert against live LLM output, introducing non-determinism risk.


1. Fix Coverage — ✅

All three logical fix areas have accompanying tests:

  • FlyoutPage detail navigation leak (FlyoutPage.cs, FlyoutViewHandler.Android.cs, NavigationViewFragment.cs) → MemoryTests.FlyoutPageDetailNavigationDoesNotLeak iterates 4 detail replacements and verifies previous pages are GC'd. Test would fail if the handler disconnect fix were reverted. ✅
  • SourceGen converter resolution (CSharpExpressionHelpers.cs, KnownMarkups.cs, SetPropertyHelpers.cs) → Maui34713 verifies converters defined in page vs. application resources produce the correct compile-time or runtime resolution. ✅
  • SourceGen special chars in x:Key (SetPropertyHelpers.cs) → Maui34726 tests " and \ in resource keys. ✅
  • StreamingResponseHandler passthrough mode (StreamingResponseHandler.cs) → 7 unit tests + 2 device tests. ✅

2. Edge Cases & Gaps — ⚠️

Covered:

  • FlyoutPage: 4 repeated detail replacements, weak references for all intermediate pages
  • FlyoutPage: IsPresented = false after each swap
  • Maui34726: Both " and \ special characters, plus a baseline SimpleKey
  • Maui34713: Converter in page resources vs. application resources
  • StreamingResponseHandler: null input, empty string, duplicate content, passthrough vs. chunker modes

Missing:

  • iOS/MacCatalyst memory testFlyoutPage.cs change fires SendAppearing/SendDisappearing on all platforms, not just Android. The PhoneFlyoutPageRenderer registration was added to SetupBuilder, but there is no corresponding #if IOS || MACCATALYST memory test variant.
  • FlyoutPage navigation events — The fix also sends NavigatedFrom/NavigatedTo events; no test verifies these events fire correctly in sequence (e.g., NavigatedFrom on old detail, NavigatedTo on new detail).
  • IsPresented = true after swap — Memory test only exercises IsPresented = false; the flyout-open path is untested.

3. Test Type Appropriateness — ✅

Fix Area Test Type Verdict
FlyoutPage memory leak (Android) Device test ✅ Appropriate — needs platform rendering context
FlyoutPage memory leak (iOS) Missing ⚠️ Device test needed
SourceGen special chars / converter resolution XAML unit test (SourceGen path) ✅ Appropriate — compile-time behavior
StreamingResponseHandler passthrough Unit test ✅ Most preferred type for pure logic
AI streaming device behavior Device test ✅ Appropriate for platform-specific streaming clients

4. Convention Compliance — ⚠️

Script-flagged issues (false positives):

  • Maui34713.xaml and Maui34726.xaml flagged as not matching MauiXXXXX — the regex appears to be over-strict; both names follow the 5-digit convention correctly.

Real observations:

  • Maui34713.xaml.cs uses xUnit [Fact] within a [Collection("Issue")] class rather than the NUnit [Test] + [Values] XamlInflator pattern described in XAML unit test guidelines. This is intentional — the test exercises SourceGen specifically via CreateMauiCompilation() and doesn't require the XamlInflator parameter. ✅ Acceptable given the scope.
  • Maui34726.xaml.cs uses [Theory] + [XamlInflatorData] correctly for the multi-inflator scenario. ✅
  • MemoryTests correctly wraps the test in #if ANDROID since it is Android-specific. ✅
  • Unit test Passthrough.cs uses [Fact] (xUnit); 7 test methods — all convention compliant. ✅

5. Flakiness Risk — ⚠️ Medium

Risk Factor Location Severity
Non-deterministic LLM output GetStreamingResponseAsync_ConcatenatedTextMatchesNonStreaming compares streaming concatenated text to a separate non-streaming call — both LLM invocations can produce different text ⚠️ Medium
Weak assertion on streaming count Assert.True(textUpdates.Count >= 1, ...) — a single-chunk response is always valid regardless of chunking behavior ⚠️ Low
Memory tests with WaitForGC Standard pattern in the repo; GC timing can occasionally be slow in CI, but WaitForGC helper is designed for this ✅ Acceptable

Recommendation: Consider whether GetStreamingResponseAsync_ConcatenatedTextMatchesNonStreaming in device tests needs two separate LLM calls. If the goal is only to verify the streaming text is non-empty and plausible, a single streaming call with a non-empty assertion would be less fragile.

6. Duplicate Coverage — ✅ No duplicates

Existing FlyoutPage tests (FlyoutPageUnitTests.cs, Issue test files) cover different scenarios (navigation, layout behavior) rather than memory/lifecycle. No overlap with the new memory test.

7. Platform Scope — ⚠️

Fix File Platforms Affected Test Coverage
FlyoutViewHandler.Android.cs Android ✅ Android memory test
NavigationViewFragment.cs Android ✅ (indirectly via memory test)
FlyoutPage.cs All platforms ⚠️ Android only
CSharpExpressionHelpers.cs All platforms (SourceGen) ✅ SourceGen XAML tests
StreamingResponseHandler.cs All platforms ✅ Unit tests are cross-platform

Gap: FlyoutPage.cs logic runs on iOS/MacCatalyst; a memory test for those platforms would increase confidence.

8. Assertion Quality — ✅

  • Memory test uses WaitForGC with weak references to all intermediate pages — specific and meaningful. ✅
  • Maui34726 asserts exact resource keys including special characters — specific. ✅
  • StreamingResponseHandler unit tests assert exact text of each update, count of updates, and role — specific. ✅
  • AI device test GetStreamingResponseAsync_DeliversMultipleIncrementalUpdates asserts Count >= 1⚠️ minimal but acceptable for LLM integration.

9. Fix-Test Alignment — ✅

  • FlyoutPage.cs fix → MemoryTests.FlyoutPageDetailNavigationDoesNotLeak — exercises exactly the code path that was broken (replacing Detail). ✅
  • FlyoutViewHandler.Android.cs fix → same memory test (Android path). ✅
  • SourceGen changes → XAML tests for the corresponding issues. ✅
  • StreamingResponseHandler.cs → unit tests verify passthrough semantics exactly. ✅

Recommendations

  1. Add iOS/MacCatalyst memory test for FlyoutPage — A #if IOS || MACCATALYST variant of FlyoutPageDetailNavigationDoesNotLeak would cover the cross-platform code path in FlyoutPage.cs that fires SendAppearing/SendDisappearing.
  2. Simplify AI device test assertionsGetStreamingResponseAsync_ConcatenatedTextMatchesNonStreaming makes two separate LLM calls; consider reducing to one streaming call + assertion that the text is non-empty to avoid non-deterministic comparison failures.
  3. Add navigation event assertion — A small unit test verifying NavigatedFrom/NavigatedTo events fire in the correct order when FlyoutPage.Detail is replaced would complete the behavioral coverage for FlyoutPage.cs.

Warning

⚠️ Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • dc.services.visualstudio.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "dc.services.visualstudio.com"

See Network Configuration for more information.

Note

🔒 Integrity filtering filtered 1 item

Integrity filtering activated and filtered the following item during workflow execution.
This happens when a tool call accesses a resource that does not meet the required integrity or secrecy level of the workflow.

🧪 Test evaluation by Evaluate PR Tests

@PureWeen
Copy link
Copy Markdown
Member

PureWeen commented Apr 2, 2026

/azp run maui-pr-uitests, maui-pr-devicetests

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 2 pipeline(s).

The EscapeForString fix from PR #34727 only escaped x:Key in the
resources["..."] path but missed the AddFactory("...") path,
causing generated C# with unescaped quotes/backslashes in keys.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@PureWeen
Copy link
Copy Markdown
Member

PureWeen commented Apr 2, 2026

/azp run maui-pr-uitests, maui-pr-devicetests

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 2 pipeline(s).

…ublicAPI entry

VisualStateManager.cs uses #nullable disable, so the PublicAPI entry
needs the ~ prefix to indicate nullable-oblivious context.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@PureWeen
Copy link
Copy Markdown
Member

PureWeen commented Apr 2, 2026

/azp run maui-pr-uitests, maui-pr-devicetests

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 2 pipeline(s).

@PureWeen PureWeen merged commit a6e1788 into net11.0 Apr 2, 2026
187 of 221 checks passed
@PureWeen PureWeen deleted the merge/main-to-net11.0 branch April 2, 2026 21:31
@github-actions github-actions Bot locked and limited conversation to collaborators May 3, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants